summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/aoa/core/gpio-feature.c3
-rw-r--r--sound/aoa/fabrics/layout.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c2
-rw-r--r--sound/arm/aaci.c23
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c31
-rw-r--r--sound/arm/pxa2xx-ac97.c2
-rw-r--r--sound/arm/pxa2xx-pcm.c10
-rw-r--r--sound/atmel/abdac.c5
-rw-r--r--sound/atmel/ac97c.c1
-rw-r--r--sound/core/Makefile10
-rw-r--r--sound/core/compress_offload.c75
-rw-r--r--sound/core/init.c61
-rw-r--r--sound/core/jack.c19
-rw-r--r--sound/core/memalloc.c366
-rw-r--r--sound/core/pcm.c4
-rw-r--r--sound/core/pcm_dmaengine.c22
-rw-r--r--sound/core/pcm_lib.c2
-rw-r--r--sound/core/pcm_memory.c24
-rw-r--r--sound/core/pcm_misc.c39
-rw-r--r--sound/core/pcm_native.c10
-rw-r--r--sound/core/sound.c22
-rw-r--r--sound/drivers/opl3/opl3_midi.c5
-rw-r--r--sound/drivers/pcsp/pcsp.c5
-rw-r--r--sound/firewire/Kconfig15
-rw-r--r--sound/firewire/Makefile2
-rw-r--r--sound/firewire/amdtp.c210
-rw-r--r--sound/firewire/amdtp.h47
-rw-r--r--sound/firewire/cmp.c50
-rw-r--r--sound/firewire/dice-interface.h371
-rw-r--r--sound/firewire/dice.c1494
-rw-r--r--sound/firewire/fcp.c2
-rw-r--r--sound/firewire/isight.c43
-rw-r--r--sound/firewire/lib.c24
-rw-r--r--sound/firewire/lib.h7
-rw-r--r--sound/firewire/scs1x.c8
-rw-r--r--sound/firewire/speakers.c16
-rw-r--r--sound/i2c/other/ak4114.c8
-rw-r--r--sound/i2c/other/ak4xxx-adda.c2
-rw-r--r--sound/isa/cmi8328.c2
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c4
-rw-r--r--sound/isa/sb/sb16_csp.c1
-rw-r--r--sound/isa/wavefront/wavefront_synth.c2
-rw-r--r--sound/mips/ad1843.c2
-rw-r--r--sound/oss/dmabuf.c14
-rw-r--r--sound/oss/dmasound/dmasound.h1
-rw-r--r--sound/oss/dmasound/dmasound_core.c28
-rw-r--r--sound/oss/midibuf.c18
-rw-r--r--sound/oss/msnd_pinnacle.c31
-rw-r--r--sound/oss/sb_ess.c2
-rw-r--r--sound/oss/sequencer.c16
-rw-r--r--sound/oss/sleep.h18
-rw-r--r--sound/oss/swarm_cs4297a.c14
-rw-r--r--sound/oss/vwsnd.c14
-rw-r--r--sound/pci/Kconfig13
-rw-r--r--sound/pci/ac97/ac97_codec.c1
-rw-r--r--sound/pci/ad1889.c2
-rw-r--r--sound/pci/ali5451/ali5451.c2
-rw-r--r--sound/pci/asihpi/asihpi.c9
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c2
-rw-r--r--sound/pci/au88x0/au88x0_synth.c29
-rw-r--r--sound/pci/azt3328.c14
-rw-r--r--sound/pci/cs46xx/cs46xx.h5
-rw-r--r--sound/pci/cs46xx/cs46xx_image.h3468
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c266
-rw-r--r--sound/pci/cs46xx/imgs/cwc4630.h320
-rw-r--r--sound/pci/cs46xx/imgs/cwcasync.h176
-rw-r--r--sound/pci/cs46xx/imgs/cwcbinhack.h48
-rw-r--r--sound/pci/cs46xx/imgs/cwcdma.asp170
-rw-r--r--sound/pci/cs46xx/imgs/cwcdma.h68
-rw-r--r--sound/pci/cs46xx/imgs/cwcsnoop.h46
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio_olpc.c4
-rw-r--r--sound/pci/ctxfi/ctatc.c5
-rw-r--r--sound/pci/ctxfi/ctdaio.c4
-rw-r--r--sound/pci/ctxfi/cthardware.c6
-rw-r--r--sound/pci/emu10k1/emufx.c76
-rw-r--r--sound/pci/es1968.c28
-rw-r--r--sound/pci/hda/Kconfig132
-rw-r--r--sound/pci/hda/Makefile49
-rw-r--r--sound/pci/hda/hda_auto_parser.c20
-rw-r--r--sound/pci/hda/hda_beep.c15
-rw-r--r--sound/pci/hda/hda_codec.c461
-rw-r--r--sound/pci/hda/hda_codec.h567
-rw-r--r--sound/pci/hda/hda_eld.c220
-rw-r--r--sound/pci/hda/hda_generic.c247
-rw-r--r--sound/pci/hda/hda_generic.h10
-rw-r--r--sound/pci/hda/hda_hwdep.c62
-rw-r--r--sound/pci/hda/hda_intel.c113
-rw-r--r--sound/pci/hda/hda_jack.c32
-rw-r--r--sound/pci/hda/hda_jack.h1
-rw-r--r--sound/pci/hda/hda_local.h35
-rw-r--r--sound/pci/hda/hda_proc.c34
-rw-r--r--sound/pci/hda/patch_analog.c120
-rw-r--r--sound/pci/hda/patch_ca0132.c2
-rw-r--r--sound/pci/hda/patch_cirrus.c156
-rw-r--r--sound/pci/hda/patch_conexant.c39
-rw-r--r--sound/pci/hda/patch_hdmi.c1181
-rw-r--r--sound/pci/hda/patch_realtek.c674
-rw-r--r--sound/pci/hda/patch_sigmatel.c600
-rw-r--r--sound/pci/hda/patch_via.c1
-rw-r--r--sound/pci/hda/thinkpad_helper.c100
-rw-r--r--sound/pci/ice1712/psc724.c4
-rw-r--r--sound/pci/ice1712/quartet.c2
-rw-r--r--sound/pci/ice1712/wm8766.c3
-rw-r--r--sound/pci/ice1712/wm8776.c5
-rw-r--r--sound/pci/intel8x0.c17
-rw-r--r--sound/pci/lola/lola.c2
-rw-r--r--sound/pci/lx6464es/lx6464es.c4
-rw-r--r--sound/pci/lx6464es/lx_core.c4
-rw-r--r--sound/pci/oxygen/Makefile2
-rw-r--r--sound/pci/oxygen/cs4245.h7
-rw-r--r--sound/pci/oxygen/oxygen.h2
-rw-r--r--sound/pci/oxygen/oxygen_io.c25
-rw-r--r--sound/pci/oxygen/oxygen_mixer.c1
-rw-r--r--sound/pci/oxygen/oxygen_regs.h1
-rw-r--r--sound/pci/oxygen/xonar_dg.c651
-rw-r--r--sound/pci/oxygen/xonar_dg.h48
-rw-r--r--sound/pci/oxygen/xonar_dg_mixer.c477
-rw-r--r--sound/pci/rme96.c10
-rw-r--r--sound/pci/rme9652/hdsp.c11
-rw-r--r--sound/pci/rme9652/hdspm.c7
-rw-r--r--sound/pci/rme9652/rme9652.c12
-rw-r--r--sound/ppc/keywest.c4
-rw-r--r--sound/ppc/pmac.c2
-rw-r--r--sound/ppc/snd_ps3.c6
-rw-r--r--sound/ppc/tumbler.c1
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile6
-rw-r--r--sound/soc/adi/Kconfig21
-rw-r--r--sound/soc/adi/Makefile5
-rw-r--r--sound/soc/adi/axi-i2s.c276
-rw-r--r--sound/soc/adi/axi-spdif.c271
-rw-r--r--sound/soc/atmel/Kconfig2
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c1
-rw-r--r--sound/soc/atmel/atmel-pcm-pdc.c1
-rw-r--r--sound/soc/atmel/atmel-pcm.c13
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c32
-rw-r--r--sound/soc/atmel/atmel_wm8904.c8
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c1
-rw-r--r--sound/soc/atmel/sam9x5_wm8731.c6
-rw-r--r--sound/soc/au1x/dbdma2.c9
-rw-r--r--sound/soc/au1x/dma.c14
-rw-r--r--sound/soc/bcm/Kconfig9
-rw-r--r--sound/soc/bcm/Makefile5
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c879
-rw-r--r--sound/soc/blackfin/Kconfig11
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c12
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c13
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c1
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c32
-rw-r--r--sound/soc/blackfin/bf6xx-i2s.c1
-rw-r--r--sound/soc/cirrus/Kconfig2
-rw-r--r--sound/soc/cirrus/edb93xx.c2
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c20
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c22
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c35
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.h22
-rw-r--r--sound/soc/cirrus/simone.c2
-rw-r--r--sound/soc/cirrus/snappercl15.c2
-rw-r--r--sound/soc/codecs/88pm860x-codec.c78
-rw-r--r--sound/soc/codecs/88pm860x-codec.h117
-rw-r--r--sound/soc/codecs/Kconfig2
-rw-r--r--sound/soc/codecs/ab8500-codec.c33
-rw-r--r--sound/soc/codecs/ad1836.c12
-rw-r--r--sound/soc/codecs/ad193x.c16
-rw-r--r--sound/soc/codecs/adau1373.c308
-rw-r--r--sound/soc/codecs/adau1701.c36
-rw-r--r--sound/soc/codecs/adav80x.c183
-rw-r--r--sound/soc/codecs/ak4104.c11
-rw-r--r--sound/soc/codecs/ak4641.c40
-rw-r--r--sound/soc/codecs/ak4642.c142
-rw-r--r--sound/soc/codecs/alc5623.c10
-rw-r--r--sound/soc/codecs/alc5632.c10
-rw-r--r--sound/soc/codecs/arizona.c223
-rw-r--r--sound/soc/codecs/arizona.h22
-rw-r--r--sound/soc/codecs/cq93vc.c46
-rw-r--r--sound/soc/codecs/cs4271.c9
-rw-r--r--sound/soc/codecs/cs42l51.c14
-rw-r--r--sound/soc/codecs/cs42l52.c162
-rw-r--r--sound/soc/codecs/cs42l52.h4
-rw-r--r--sound/soc/codecs/cs42l73.c114
-rw-r--r--sound/soc/codecs/cs42l73.h105
-rw-r--r--sound/soc/codecs/da7210.c16
-rw-r--r--sound/soc/codecs/da7213.c10
-rw-r--r--sound/soc/codecs/da732x.c10
-rw-r--r--sound/soc/codecs/da9055.c21
-rw-r--r--sound/soc/codecs/hdmi.c12
-rw-r--r--sound/soc/codecs/isabelle.c6
-rw-r--r--sound/soc/codecs/max98088.c638
-rw-r--r--sound/soc/codecs/max98090.c25
-rw-r--r--sound/soc/codecs/max98095.c492
-rw-r--r--sound/soc/codecs/max9850.c47
-rw-r--r--sound/soc/codecs/mc13783.c171
-rw-r--r--sound/soc/codecs/ml26124.c2
-rw-r--r--sound/soc/codecs/pcm1681.c3
-rw-r--r--sound/soc/codecs/pcm1792a.c3
-rw-r--r--sound/soc/codecs/rt5640.c32
-rw-r--r--sound/soc/codecs/sgtl5000.c76
-rw-r--r--sound/soc/codecs/si476x.c64
-rw-r--r--sound/soc/codecs/sn95031.c35
-rw-r--r--sound/soc/codecs/ssm2518.c8
-rw-r--r--sound/soc/codecs/ssm2602.c70
-rw-r--r--sound/soc/codecs/tas5086.c173
-rw-r--r--sound/soc/codecs/tlv320aic23.c84
-rw-r--r--sound/soc/codecs/tlv320aic26.c139
-rw-r--r--sound/soc/codecs/tlv320aic26.h5
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c129
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h3
-rw-r--r--sound/soc/codecs/tlv320aic3x.c364
-rw-r--r--sound/soc/codecs/tpa6130a2.c53
-rw-r--r--sound/soc/codecs/twl4030.c434
-rw-r--r--sound/soc/codecs/twl6040.c243
-rw-r--r--sound/soc/codecs/uda1380.c6
-rw-r--r--sound/soc/codecs/wm0010.c11
-rw-r--r--sound/soc/codecs/wm2000.c15
-rw-r--r--sound/soc/codecs/wm5100.c5
-rw-r--r--sound/soc/codecs/wm5102.c12
-rw-r--r--sound/soc/codecs/wm5110.c518
-rw-r--r--sound/soc/codecs/wm8350.c2
-rw-r--r--sound/soc/codecs/wm8400.c95
-rw-r--r--sound/soc/codecs/wm8510.c6
-rw-r--r--sound/soc/codecs/wm8523.c6
-rw-r--r--sound/soc/codecs/wm8580.c8
-rw-r--r--sound/soc/codecs/wm8711.c6
-rw-r--r--sound/soc/codecs/wm8728.c6
-rw-r--r--sound/soc/codecs/wm8731.c10
-rw-r--r--sound/soc/codecs/wm8741.c6
-rw-r--r--sound/soc/codecs/wm8750.c6
-rw-r--r--sound/soc/codecs/wm8753.c6
-rw-r--r--sound/soc/codecs/wm8776.c9
-rw-r--r--sound/soc/codecs/wm8804.c6
-rw-r--r--sound/soc/codecs/wm8900.c17
-rw-r--r--sound/soc/codecs/wm8904.c7
-rw-r--r--sound/soc/codecs/wm8940.c221
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c2
-rw-r--r--sound/soc/codecs/wm8962.c255
-rw-r--r--sound/soc/codecs/wm8974.c54
-rw-r--r--sound/soc/codecs/wm8985.c6
-rw-r--r--sound/soc/codecs/wm8988.c6
-rw-r--r--sound/soc/codecs/wm8990.c258
-rw-r--r--sound/soc/codecs/wm8990.h9
-rw-r--r--sound/soc/codecs/wm8991.c293
-rw-r--r--sound/soc/codecs/wm8991.h9
-rw-r--r--sound/soc/codecs/wm8994.c11
-rw-r--r--sound/soc/codecs/wm8995.c6
-rw-r--r--sound/soc/codecs/wm8996.c14
-rw-r--r--sound/soc/codecs/wm8997.c14
-rw-r--r--sound/soc/codecs/wm9081.c2
-rw-r--r--sound/soc/codecs/wm9713.c3
-rw-r--r--sound/soc/codecs/wm_adsp.c260
-rw-r--r--sound/soc/codecs/wm_adsp.h12
-rw-r--r--sound/soc/codecs/wm_hubs.c3
-rw-r--r--sound/soc/davinci/Kconfig35
-rw-r--r--sound/soc/davinci/Makefile7
-rw-r--r--sound/soc/davinci/davinci-evm.c237
-rw-r--r--sound/soc/davinci/davinci-mcasp.c1178
-rw-r--r--sound/soc/davinci/davinci-mcasp.h292
-rw-r--r--sound/soc/davinci/davinci-pcm.c42
-rw-r--r--sound/soc/fsl/Kconfig10
-rw-r--r--sound/soc/fsl/Makefile6
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c15
-rw-r--r--sound/soc/fsl/fsl_dma.c20
-rw-r--r--sound/soc/fsl/fsl_esai.c815
-rw-r--r--sound/soc/fsl/fsl_esai.h354
-rw-r--r--sound/soc/fsl/fsl_sai.c459
-rw-r--r--sound/soc/fsl/fsl_sai.h114
-rw-r--r--sound/soc/fsl/fsl_spdif.c31
-rw-r--r--sound/soc/fsl/fsl_ssi.c1062
-rw-r--r--sound/soc/fsl/fsl_ssi.h2
-rw-r--r--sound/soc/fsl/imx-audmux.c9
-rw-r--r--sound/soc/fsl/imx-mc13783.c2
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c16
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c66
-rw-r--r--sound/soc/fsl/imx-pcm.h5
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c21
-rw-r--r--sound/soc/fsl/imx-spdif.c89
-rw-r--r--sound/soc/fsl/imx-ssi.c32
-rw-r--r--sound/soc/fsl/imx-ssi.h3
-rw-r--r--sound/soc/fsl/imx-wm8962.c22
-rw-r--r--sound/soc/fsl/mpc5200_dma.c16
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c2
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c3
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c1
-rw-r--r--sound/soc/fsl/p1022_ds.c1
-rw-r--r--sound/soc/fsl/p1022_rdk.c1
-rw-r--r--sound/soc/fsl/pcm030-audio-fabric.c3
-rw-r--r--sound/soc/generic/simple-card.c216
-rw-r--r--sound/soc/intel/Kconfig (renamed from sound/soc/mid-x86/Kconfig)0
-rw-r--r--sound/soc/intel/Makefile (renamed from sound/soc/mid-x86/Makefile)0
-rw-r--r--sound/soc/intel/mfld_machine.c (renamed from sound/soc/mid-x86/mfld_machine.c)10
-rw-r--r--sound/soc/intel/sst_dsp.h (renamed from sound/soc/mid-x86/sst_dsp.h)0
-rw-r--r--sound/soc/intel/sst_platform.c (renamed from sound/soc/mid-x86/sst_platform.c)16
-rw-r--r--sound/soc/intel/sst_platform.h (renamed from sound/soc/mid-x86/sst_platform.h)4
-rw-r--r--sound/soc/jz4740/Kconfig1
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c135
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c362
-rw-r--r--sound/soc/jz4740/jz4740-pcm.h20
-rw-r--r--sound/soc/jz4740/qi_lb60.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c29
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c124
-rw-r--r--sound/soc/kirkwood/kirkwood-openrd.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-t5325.c2
-rw-r--r--sound/soc/kirkwood/kirkwood.h4
-rw-r--r--sound/soc/mxs/mxs-pcm.c14
-rw-r--r--sound/soc/mxs/mxs-pcm.h1
-rw-r--r--sound/soc/mxs/mxs-saif.c60
-rw-r--r--sound/soc/mxs/mxs-saif.h5
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c20
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c12
-rw-r--r--sound/soc/omap/Kconfig5
-rw-r--r--sound/soc/omap/mcbsp.c12
-rw-r--r--sound/soc/omap/n810.c11
-rw-r--r--sound/soc/omap/omap-dmic.c4
-rw-r--r--sound/soc/omap/omap-mcpdm.c16
-rw-r--r--sound/soc/omap/omap-pcm.c13
-rw-r--r--sound/soc/omap/omap-twl4030.c5
-rw-r--r--sound/soc/pxa/Kconfig2
-rw-r--r--sound/soc/pxa/brownstone.c1
-rw-r--r--sound/soc/pxa/corgi.c1
-rw-r--r--sound/soc/pxa/e740_wm9705.c1
-rw-r--r--sound/soc/pxa/e750_wm9705.c1
-rw-r--r--sound/soc/pxa/e800_wm9712.c1
-rw-r--r--sound/soc/pxa/imote2.c1
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c1
-rw-r--r--sound/soc/pxa/mmp-pcm.c27
-rw-r--r--sound/soc/pxa/mmp-sspa.c5
-rw-r--r--sound/soc/pxa/palm27x.c1
-rw-r--r--sound/soc/pxa/poodle.c1
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c56
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c3
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c11
-rw-r--r--sound/soc/pxa/tosa.c1
-rw-r--r--sound/soc/pxa/ttc-dkb.c1
-rw-r--r--sound/soc/s6000/s6000-i2s.c3
-rw-r--r--sound/soc/s6000/s6000-pcm.c19
-rw-r--r--sound/soc/samsung/Kconfig21
-rw-r--r--sound/soc/samsung/Makefile6
-rw-r--r--sound/soc/samsung/ac97.c57
-rw-r--r--sound/soc/samsung/bells.c1
-rw-r--r--sound/soc/samsung/dma.c25
-rw-r--r--sound/soc/samsung/dma.h6
-rw-r--r--sound/soc/samsung/dmaengine.c83
-rw-r--r--sound/soc/samsung/h1940_uda1380.c1
-rw-r--r--sound/soc/samsung/i2s.c35
-rw-r--r--sound/soc/samsung/idma.c19
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c1
-rw-r--r--sound/soc/samsung/pcm.c18
-rw-r--r--sound/soc/samsung/regs-ac97.h9
-rw-r--r--sound/soc/samsung/regs-iis.h9
-rw-r--r--sound/soc/samsung/rx1950_uda1380.c1
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c12
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c2
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c2
-rw-r--r--sound/soc/samsung/smartq_wm8987.c1
-rw-r--r--sound/soc/samsung/smdk_wm8994.c18
-rw-r--r--sound/soc/sh/Kconfig2
-rw-r--r--sound/soc/sh/dma-sh7760.c17
-rw-r--r--sound/soc/sh/fsi.c42
-rw-r--r--sound/soc/sh/rcar/adg.c162
-rw-r--r--sound/soc/sh/rcar/core.c100
-rw-r--r--sound/soc/sh/rcar/gen.c419
-rw-r--r--sound/soc/sh/rcar/rsnd.h55
-rw-r--r--sound/soc/sh/rcar/scu.c196
-rw-r--r--sound/soc/sh/rcar/ssi.c74
-rw-r--r--sound/soc/sh/siu_dai.c3
-rw-r--r--sound/soc/soc-cache.c269
-rw-r--r--sound/soc/soc-compress.c301
-rw-r--r--sound/soc/soc-core.c390
-rw-r--r--sound/soc/soc-dapm.c252
-rw-r--r--sound/soc/soc-devres.c127
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c270
-rw-r--r--sound/soc/soc-io.c30
-rw-r--r--sound/soc/soc-jack.c7
-rw-r--r--sound/soc/soc-pcm.c333
-rw-r--r--sound/soc/soc-utils.c17
-rw-r--r--sound/soc/spear/spdif_in.c23
-rw-r--r--sound/soc/spear/spdif_out.c24
-rw-r--r--sound/soc/spear/spear_pcm.c42
-rw-r--r--sound/soc/spear/spear_pcm.h24
-rw-r--r--sound/soc/tegra/Kconfig12
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c17
-rw-r--r--sound/soc/tegra/tegra20_i2s.c32
-rw-r--r--sound/soc/tegra/tegra20_spdif.c16
-rw-r--r--sound/soc/tegra/tegra30_ahub.c255
-rw-r--r--sound/soc/tegra/tegra30_ahub.h49
-rw-r--r--sound/soc/tegra/tegra30_i2s.c158
-rw-r--r--sound/soc/tegra/tegra30_i2s.h10
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c2
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h1
-rw-r--r--sound/soc/tegra/tegra_max98090.c275
-rw-r--r--sound/soc/tegra/tegra_pcm.c21
-rw-r--r--sound/soc/tegra/tegra_pcm.h5
-rw-r--r--sound/soc/tegra/tegra_wm9712.c1
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c8
-rw-r--r--sound/soc/txx9/txx9aclc.c14
-rw-r--r--sound/soc/ux500/mop500.c2
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c146
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c56
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h2
-rw-r--r--sound/soc/ux500/ux500_pcm.c65
-rw-r--r--sound/sound_core.c17
-rw-r--r--sound/sparc/cs4231.c13
-rw-r--r--sound/spi/at73c213.c2
-rw-r--r--sound/usb/6fire/chip.c2
-rw-r--r--sound/usb/Kconfig1
-rw-r--r--sound/usb/caiaq/control.c92
-rw-r--r--sound/usb/caiaq/device.c25
-rw-r--r--sound/usb/caiaq/device.h5
-rw-r--r--sound/usb/card.c22
-rw-r--r--sound/usb/card.h12
-rw-r--r--sound/usb/endpoint.c153
-rw-r--r--sound/usb/endpoint.h4
-rw-r--r--sound/usb/format.c6
-rw-r--r--sound/usb/helper.c1
-rw-r--r--sound/usb/hiface/pcm.c6
-rw-r--r--sound/usb/mixer.c4
-rw-r--r--sound/usb/mixer_maps.c10
-rw-r--r--sound/usb/mixer_quirks.c92
-rw-r--r--sound/usb/pcm.c40
-rw-r--r--sound/usb/quirks-table.h176
-rw-r--r--sound/usb/quirks.c23
-rw-r--r--sound/usb/stream.c33
-rw-r--r--sound/usb/usbaudio.h1
-rw-r--r--sound/usb/usx2y/us122l.c4
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c22
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c7
427 files changed, 20249 insertions, 14552 deletions
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index faa317490545..f34153962d07 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -10,8 +10,9 @@
* registers.
*/
-#include <asm/pmac_feature.h>
+#include <linux/of_irq.h>
#include <linux/interrupt.h>
+#include <asm/pmac_feature.h>
#include "../aoa.h"
/* TODO: these are lots of global variables
diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c
index 61ab640e195f..9dc5806d23dd 100644
--- a/sound/aoa/fabrics/layout.c
+++ b/sound/aoa/fabrics/layout.c
@@ -644,7 +644,7 @@ static int n##_control_put(struct snd_kcontrol *kcontrol, \
struct snd_ctl_elem_value *ucontrol) \
{ \
struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \
- if (gpio->methods && gpio->methods->get_##n) \
+ if (gpio->methods && gpio->methods->set_##n) \
gpio->methods->set_##n(gpio, \
!!ucontrol->value.integer.value[0]); \
return 1; \
@@ -1135,7 +1135,7 @@ static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
{
struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
- if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
+ if (ldev->gpio.methods && ldev->gpio.methods->all_amps_restore)
ldev->gpio.methods->all_amps_restore(&ldev->gpio);
return 0;
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 15e76131b501..467836057ee5 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -11,6 +11,8 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <sound/core.h>
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 1ca8dc2ccb89..c421fdb3c7a1 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -753,7 +753,7 @@ static struct snd_pcm_ops aaci_capture_ops = {
* Power Management.
*/
#ifdef CONFIG_PM
-static int aaci_do_suspend(struct snd_card *card, unsigned int state)
+static int aaci_do_suspend(struct snd_card *card)
{
struct aaci *aaci = card->private_data;
snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
@@ -761,28 +761,28 @@ static int aaci_do_suspend(struct snd_card *card, unsigned int state)
return 0;
}
-static int aaci_do_resume(struct snd_card *card, unsigned int state)
+static int aaci_do_resume(struct snd_card *card)
{
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
-static int aaci_suspend(struct amba_device *dev, pm_message_t state)
+static int aaci_suspend(struct device *dev)
{
- struct snd_card *card = amba_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
return card ? aaci_do_suspend(card) : 0;
}
-static int aaci_resume(struct amba_device *dev)
+static int aaci_resume(struct device *dev)
{
- struct snd_card *card = amba_get_drvdata(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
return card ? aaci_do_resume(card) : 0;
}
+
+static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
+#define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
#else
-#define aaci_do_suspend NULL
-#define aaci_do_resume NULL
-#define aaci_suspend NULL
-#define aaci_resume NULL
+#define AACI_DEV_PM_OPS NULL
#endif
@@ -1100,11 +1100,10 @@ MODULE_DEVICE_TABLE(amba, aaci_ids);
static struct amba_driver aaci_driver = {
.drv = {
.name = DRIVER_NAME,
+ .pm = AACI_DEV_PM_OPS,
},
.probe = aaci_probe,
.remove = aaci_remove,
- .suspend = aaci_suspend,
- .resume = aaci_resume,
.id_table = aaci_ids,
};
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index e6f4633b8dd5..66de90ed30ca 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -117,8 +117,7 @@ static inline void pxa_ac97_warm_pxa25x(void)
{
gsr_bits = 0;
- GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
- wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+ GCR |= GCR_WARM_RST;
}
static inline void pxa_ac97_cold_pxa25x(void)
@@ -129,8 +128,6 @@ static inline void pxa_ac97_cold_pxa25x(void)
gsr_bits = 0;
GCR = GCR_COLD_RST;
- GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
- wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
}
#endif
@@ -149,8 +146,6 @@ static inline void pxa_ac97_warm_pxa27x(void)
static inline void pxa_ac97_cold_pxa27x(void)
{
- unsigned int timeout;
-
GCR &= GCR_COLD_RST; /* clear everything but nCRST */
GCR &= ~GCR_COLD_RST; /* then assert nCRST */
@@ -161,29 +156,20 @@ static inline void pxa_ac97_cold_pxa27x(void)
udelay(5);
clk_disable(ac97conf_clk);
GCR = GCR_COLD_RST | GCR_WARM_RST;
- timeout = 100; /* wait for the codec-ready bit to be set */
- while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
- mdelay(1);
}
#endif
#ifdef CONFIG_PXA3xx
static inline void pxa_ac97_warm_pxa3xx(void)
{
- int timeout = 100;
-
gsr_bits = 0;
/* Can't use interrupts */
GCR |= GCR_WARM_RST;
- while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
- mdelay(1);
}
static inline void pxa_ac97_cold_pxa3xx(void)
{
- int timeout = 1000;
-
/* Hold CLKBPB for 100us */
GCR = 0;
GCR = GCR_CLKBPB;
@@ -199,14 +185,13 @@ static inline void pxa_ac97_cold_pxa3xx(void)
GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
GCR = GCR_WARM_RST | GCR_COLD_RST;
- while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
- mdelay(10);
}
#endif
bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
{
unsigned long gsr;
+ unsigned int timeout = 100;
#ifdef CONFIG_PXA25x
if (cpu_is_pxa25x())
@@ -223,7 +208,11 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
pxa_ac97_warm_pxa3xx();
else
#endif
- BUG();
+ snd_BUG();
+
+ while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+ mdelay(1);
+
gsr = GSR | gsr_bits;
if (!(gsr & (GSR_PCR | GSR_SCR))) {
printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
@@ -239,6 +228,7 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
{
unsigned long gsr;
+ unsigned int timeout = 1000;
#ifdef CONFIG_PXA25x
if (cpu_is_pxa25x())
@@ -255,7 +245,10 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
pxa_ac97_cold_pxa3xx();
else
#endif
- BUG();
+ snd_BUG();
+
+ while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
+ mdelay(1);
gsr = GSR | gsr_bits;
if (!(gsr & (GSR_PCR | GSR_SCR))) {
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 5066a3768b28..9a2ac1e0f77a 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -185,7 +185,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
goto err;
card->dev = &dev->dev;
- strncpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
+ strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
if (ret)
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index 69a2455b4472..e6c727b317fb 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
+#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <sound/core.h>
@@ -83,8 +84,6 @@ static struct snd_pcm_ops pxa2xx_pcm_ops = {
.mmap = pxa2xx_pcm_mmap,
};
-static u64 pxa2xx_pcm_dmamask = 0xffffffff;
-
int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
struct snd_pcm **rpcm)
{
@@ -100,10 +99,9 @@ int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
pcm->private_data = client;
pcm->private_free = pxa2xx_pcm_free_dma_buffers;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &pxa2xx_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = 0xffffffff;
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ goto out;
if (play) {
int stream = SNDRV_PCM_STREAM_PLAYBACK;
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
index 872d59e35ee2..3519518e25a0 100644
--- a/sound/atmel/abdac.c
+++ b/sound/atmel/abdac.c
@@ -354,10 +354,11 @@ static int set_sample_rates(struct atmel_abdac *dac)
/* 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)
+ if (new_rate <= 0)
break;
/* make sure we are below the ABDAC clock */
- if (new_rate <= clk_get_rate(dac->pclk)) {
+ if (index < MAX_NUM_RATES &&
+ new_rate <= clk_get_rate(dac->pclk)) {
dac->rates[index] = new_rate / 256;
index++;
}
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index ae63d22c0f88..c5f0ddd729b3 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -34,7 +34,6 @@
#include <linux/dw_dmac.h>
#include <mach/cpu.h>
-#include <mach/gpio.h>
#ifdef CONFIG_ARCH_AT91
#include <mach/hardware.h>
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 5e890cfed423..394a38909f6b 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -10,14 +10,12 @@ snd-$(CONFIG_SND_VMASTER) += vmaster.o
snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o
snd-$(CONFIG_SND_JACK) += jack.o
-snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
- pcm_memory.o
+snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
+ pcm_memory.o memalloc.o
+snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
snd-pcm-dmaengine-objs := pcm_dmaengine.o
-snd-page-alloc-y := memalloc.o
-snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
-
snd-rawmidi-objs := rawmidi.o
snd-timer-objs := timer.o
snd-hrtimer-objs := hrtimer.o
@@ -31,7 +29,7 @@ obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
obj-$(CONFIG_SND_TIMER) += snd-timer.o
obj-$(CONFIG_SND_HRTIMER) += snd-hrtimer.o
obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
-obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
+obj-$(CONFIG_SND_PCM) += snd-pcm.o
obj-$(CONFIG_SND_DMAENGINE_PCM) += snd-pcm-dmaengine.o
obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 98969541cbcc..7a20897d33db 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -139,6 +139,18 @@ static int snd_compr_open(struct inode *inode, struct file *f)
static int snd_compr_free(struct inode *inode, struct file *f)
{
struct snd_compr_file *data = f->private_data;
+ struct snd_compr_runtime *runtime = data->stream.runtime;
+
+ switch (runtime->state) {
+ case SNDRV_PCM_STATE_RUNNING:
+ case SNDRV_PCM_STATE_DRAINING:
+ case SNDRV_PCM_STATE_PAUSED:
+ data->stream.ops->trigger(&data->stream, SNDRV_PCM_TRIGGER_STOP);
+ break;
+ default:
+ break;
+ }
+
data->stream.ops->free(&data->stream);
kfree(data->stream.runtime->buffer);
kfree(data->stream.runtime);
@@ -372,8 +384,7 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait)
return -EFAULT;
mutex_lock(&stream->device->lock);
- if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED ||
- stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
+ if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) {
retval = -EBADFD;
goto out;
}
@@ -490,9 +501,6 @@ static int snd_compress_check_input(struct snd_compr_params *params)
if (params->codec.ch_in == 0 || params->codec.ch_out == 0)
return -EINVAL;
- if (!(params->codec.sample_rate & SNDRV_PCM_RATE_8000_192000))
- return -EINVAL;
-
return 0;
}
@@ -668,14 +676,48 @@ static int snd_compr_stop(struct snd_compr_stream *stream)
return -EPERM;
retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP);
if (!retval) {
- stream->runtime->state = SNDRV_PCM_STATE_SETUP;
- wake_up(&stream->runtime->sleep);
+ snd_compr_drain_notify(stream);
stream->runtime->total_bytes_available = 0;
stream->runtime->total_bytes_transferred = 0;
}
return retval;
}
+static int snd_compress_wait_for_drain(struct snd_compr_stream *stream)
+{
+ int ret;
+
+ /*
+ * We are called with lock held. So drop the lock while we wait for
+ * drain complete notfication from the driver
+ *
+ * It is expected that driver will notify the drain completion and then
+ * stream will be moved to SETUP state, even if draining resulted in an
+ * error. We can trigger next track after this.
+ */
+ stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
+ mutex_unlock(&stream->device->lock);
+
+ /* we wait for drain to complete here, drain can return when
+ * interruption occurred, wait returned error or success.
+ * For the first two cases we don't do anything different here and
+ * return after waking up
+ */
+
+ ret = wait_event_interruptible(stream->runtime->sleep,
+ (stream->runtime->state != SNDRV_PCM_STATE_DRAINING));
+ if (ret == -ERESTARTSYS)
+ pr_debug("wait aborted by a signal");
+ else if (ret)
+ pr_debug("wait for drain failed with %d\n", ret);
+
+
+ wake_up(&stream->runtime->sleep);
+ mutex_lock(&stream->device->lock);
+
+ return ret;
+}
+
static int snd_compr_drain(struct snd_compr_stream *stream)
{
int retval;
@@ -683,12 +725,15 @@ static int snd_compr_drain(struct snd_compr_stream *stream)
if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED ||
stream->runtime->state == SNDRV_PCM_STATE_SETUP)
return -EPERM;
+
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN);
- if (!retval) {
- stream->runtime->state = SNDRV_PCM_STATE_DRAINING;
+ if (retval) {
+ pr_debug("SND_COMPR_TRIGGER_DRAIN failed %d\n", retval);
wake_up(&stream->runtime->sleep);
+ return retval;
}
- return retval;
+
+ return snd_compress_wait_for_drain(stream);
}
static int snd_compr_next_track(struct snd_compr_stream *stream)
@@ -724,9 +769,14 @@ static int snd_compr_partial_drain(struct snd_compr_stream *stream)
return -EPERM;
retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_PARTIAL_DRAIN);
+ if (retval) {
+ pr_debug("Partial drain returned failure\n");
+ wake_up(&stream->runtime->sleep);
+ return retval;
+ }
stream->next_track = false;
- return retval;
+ return snd_compress_wait_for_drain(stream);
}
static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
@@ -837,7 +887,8 @@ static int snd_compress_dev_disconnect(struct snd_device *device)
struct snd_compr *compr;
compr = device->device_data;
- snd_unregister_device(compr->direction, compr->card, compr->device);
+ snd_unregister_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card,
+ compr->device);
return 0;
}
diff --git a/sound/core/init.c b/sound/core/init.c
index 6b9087115da2..0d42fcda0de2 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -66,7 +66,7 @@ static int module_slot_match(struct module *module, int idx)
#ifdef MODULE
const char *s1, *s2;
- if (!module || !module->name || !slots[idx])
+ if (!module || !*module->name || !slots[idx])
return 0;
s1 = module->name;
@@ -131,6 +131,31 @@ static inline int init_info_for_card(struct snd_card *card)
#define init_info_for_card(card)
#endif
+static int check_empty_slot(struct module *module, int slot)
+{
+ return !slots[slot] || !*slots[slot];
+}
+
+/* return an empty slot number (>= 0) found in the given bitmask @mask.
+ * @mask == -1 == 0xffffffff means: take any free slot up to 32
+ * when no slot is available, return the original @mask as is.
+ */
+static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
+ struct module *module)
+{
+ int slot;
+
+ for (slot = 0; slot < SNDRV_CARDS; slot++) {
+ if (slot < 32 && !(mask & (1U << slot)))
+ continue;
+ if (!test_bit(slot, snd_cards_lock)) {
+ if (check(module, slot))
+ return slot; /* found */
+ }
+ }
+ return mask; /* unchanged */
+}
+
/**
* snd_card_create - create and initialize a soundcard structure
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
@@ -152,7 +177,7 @@ int snd_card_create(int idx, const char *xid,
struct snd_card **card_ret)
{
struct snd_card *card;
- int err, idx2;
+ int err;
if (snd_BUG_ON(!card_ret))
return -EINVAL;
@@ -167,32 +192,10 @@ int snd_card_create(int idx, const char *xid,
strlcpy(card->id, xid, sizeof(card->id));
err = 0;
mutex_lock(&snd_card_mutex);
- if (idx < 0) {
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
- /* idx == -1 == 0xffff means: take any free slot */
- if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
- continue;
- if (!test_bit(idx2, snd_cards_lock)) {
- if (module_slot_match(module, idx2)) {
- idx = idx2;
- break;
- }
- }
- }
- }
- if (idx < 0) {
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
- /* idx == -1 == 0xffff means: take any free slot */
- if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
- continue;
- if (!test_bit(idx2, snd_cards_lock)) {
- if (!slots[idx2] || !*slots[idx2]) {
- idx = idx2;
- break;
- }
- }
- }
- }
+ if (idx < 0) /* first check the matching module-name slot */
+ idx = get_slot_from_bitmask(idx, module_slot_match, module);
+ if (idx < 0) /* if not matched, assign an empty slot */
+ idx = get_slot_from_bitmask(idx, check_empty_slot, module);
if (idx < 0)
err = -ENODEV;
else if (idx < snd_ecards_limit) {
@@ -597,7 +600,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
/* last resort... */
snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
if (card->proc_root->name)
- strcpy(card->id, card->proc_root->name);
+ strlcpy(card->id, card->proc_root->name, sizeof(card->id));
}
/**
diff --git a/sound/core/jack.c b/sound/core/jack.c
index b35fe7345c20..8658578eb584 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -34,12 +34,12 @@ static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
SW_LINEIN_INSERT,
};
-static int snd_jack_dev_free(struct snd_device *device)
+static int snd_jack_dev_disconnect(struct snd_device *device)
{
struct snd_jack *jack = device->device_data;
- if (jack->private_free)
- jack->private_free(jack);
+ if (!jack->input_dev)
+ return 0;
/* If the input device is registered with the input subsystem
* then we need to use a different deallocator. */
@@ -47,6 +47,18 @@ static int snd_jack_dev_free(struct snd_device *device)
input_unregister_device(jack->input_dev);
else
input_free_device(jack->input_dev);
+ jack->input_dev = NULL;
+ return 0;
+}
+
+static int snd_jack_dev_free(struct snd_device *device)
+{
+ struct snd_jack *jack = device->device_data;
+
+ if (jack->private_free)
+ jack->private_free(jack);
+
+ snd_jack_dev_disconnect(device);
kfree(jack->id);
kfree(jack);
@@ -110,6 +122,7 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
static struct snd_device_ops ops = {
.dev_free = snd_jack_dev_free,
.dev_register = snd_jack_dev_register,
+ .dev_disconnect = snd_jack_dev_disconnect,
};
jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index bdf826f4fe0c..4595f93d151e 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -21,59 +21,18 @@
*
*/
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/seq_file.h>
-#include <asm/uaccess.h>
#include <linux/dma-mapping.h>
-#include <linux/moduleparam.h>
-#include <linux/mutex.h>
+#include <linux/genalloc.h>
#include <sound/memalloc.h>
-
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
-MODULE_DESCRIPTION("Memory allocator for ALSA system.");
-MODULE_LICENSE("GPL");
-
-
-/*
- */
-
-static DEFINE_MUTEX(list_mutex);
-static LIST_HEAD(mem_list_head);
-
-/* buffer preservation list */
-struct snd_mem_list {
- struct snd_dma_buffer buffer;
- unsigned int id;
- struct list_head list;
-};
-
-/* id for pre-allocated buffers */
-#define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
-
/*
*
* Generic memory allocators
*
*/
-static long snd_allocated_pages; /* holding the number of allocated pages */
-
-static inline void inc_snd_pages(int order)
-{
- snd_allocated_pages += 1 << order;
-}
-
-static inline void dec_snd_pages(int order)
-{
- snd_allocated_pages -= 1 << order;
-}
-
/**
* snd_malloc_pages - allocate pages with the given size
* @size: the size to allocate in bytes
@@ -86,7 +45,6 @@ static inline void dec_snd_pages(int order)
void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
{
int pg;
- void *res;
if (WARN_ON(!size))
return NULL;
@@ -94,9 +52,7 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
return NULL;
gfp_flags |= __GFP_COMP; /* compound page lets parts be mapped */
pg = get_order(size);
- if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
- inc_snd_pages(pg);
- return res;
+ return (void *) __get_free_pages(gfp_flags, pg);
}
/**
@@ -113,7 +69,6 @@ void snd_free_pages(void *ptr, size_t size)
if (ptr == NULL)
return;
pg = get_order(size);
- dec_snd_pages(pg);
free_pages((unsigned long) ptr, pg);
}
@@ -128,7 +83,6 @@ void snd_free_pages(void *ptr, size_t size)
static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
{
int pg;
- void *res;
gfp_t gfp_flags;
if (WARN_ON(!dma))
@@ -138,11 +92,7 @@ static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *d
| __GFP_COMP /* compound page lets parts be mapped */
| __GFP_NORETRY /* don't trigger OOM-killer */
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
- res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
- if (res != NULL)
- inc_snd_pages(pg);
-
- return res;
+ return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
}
/* free the coherent DMA pages */
@@ -154,9 +104,49 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
if (ptr == NULL)
return;
pg = get_order(size);
- dec_snd_pages(pg);
dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
}
+
+#ifdef CONFIG_GENERIC_ALLOCATOR
+/**
+ * snd_malloc_dev_iram - allocate memory from on-chip internal ram
+ * @dmab: buffer allocation record to store the allocated data
+ * @size: number of bytes to allocate from the iram
+ *
+ * This function requires iram phandle provided via of_node
+ */
+static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size)
+{
+ struct device *dev = dmab->dev.dev;
+ struct gen_pool *pool = NULL;
+
+ dmab->area = NULL;
+ dmab->addr = 0;
+
+ if (dev->of_node)
+ pool = of_get_named_gen_pool(dev->of_node, "iram", 0);
+
+ if (!pool)
+ return;
+
+ /* Assign the pool into private_data field */
+ dmab->private_data = pool;
+
+ dmab->area = gen_pool_dma_alloc(pool, size, &dmab->addr);
+}
+
+/**
+ * snd_free_dev_iram - free allocated specific memory from on-chip internal ram
+ * @dmab: buffer allocation record to store the allocated data
+ */
+static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
+{
+ struct gen_pool *pool = dmab->private_data;
+
+ if (pool && dmab->area)
+ gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes);
+}
+#endif /* CONFIG_GENERIC_ALLOCATOR */
#endif /* CONFIG_HAS_DMA */
/*
@@ -197,6 +187,16 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->addr = 0;
break;
#ifdef CONFIG_HAS_DMA
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ case SNDRV_DMA_TYPE_DEV_IRAM:
+ snd_malloc_dev_iram(dmab, size);
+ if (dmab->area)
+ break;
+ /* Internal memory might have limited size and no enough space,
+ * so if we fail to malloc, try to fetch memory traditionally.
+ */
+ dmab->dev.type = SNDRV_DMA_TYPE_DEV;
+#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
break;
@@ -269,6 +269,11 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
snd_free_pages(dmab->area, dmab->bytes);
break;
#ifdef CONFIG_HAS_DMA
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ case SNDRV_DMA_TYPE_DEV_IRAM:
+ snd_free_dev_iram(dmab);
+ break;
+#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
break;
@@ -283,256 +288,6 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
}
}
-
-/**
- * snd_dma_get_reserved - get the reserved buffer for the given device
- * @dmab: the buffer allocation record to store
- * @id: the buffer id
- *
- * Looks for the reserved-buffer list and re-uses if the same buffer
- * is found in the list. When the buffer is found, it's removed from the free list.
- *
- * Return: The size of buffer if the buffer is found, or zero if not found.
- */
-size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
-{
- struct snd_mem_list *mem;
-
- if (WARN_ON(!dmab))
- return 0;
-
- mutex_lock(&list_mutex);
- list_for_each_entry(mem, &mem_list_head, list) {
- if (mem->id == id &&
- (mem->buffer.dev.dev == NULL || dmab->dev.dev == NULL ||
- ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev)))) {
- struct device *dev = dmab->dev.dev;
- list_del(&mem->list);
- *dmab = mem->buffer;
- if (dmab->dev.dev == NULL)
- dmab->dev.dev = dev;
- kfree(mem);
- mutex_unlock(&list_mutex);
- return dmab->bytes;
- }
- }
- mutex_unlock(&list_mutex);
- return 0;
-}
-
-/**
- * snd_dma_reserve_buf - reserve the buffer
- * @dmab: the buffer to reserve
- * @id: the buffer id
- *
- * Reserves the given buffer as a reserved buffer.
- *
- * Return: Zero if successful, or a negative code on error.
- */
-int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
-{
- struct snd_mem_list *mem;
-
- if (WARN_ON(!dmab))
- return -EINVAL;
- mem = kmalloc(sizeof(*mem), GFP_KERNEL);
- if (! mem)
- return -ENOMEM;
- mutex_lock(&list_mutex);
- mem->buffer = *dmab;
- mem->id = id;
- list_add_tail(&mem->list, &mem_list_head);
- mutex_unlock(&list_mutex);
- return 0;
-}
-
-/*
- * purge all reserved buffers
- */
-static void free_all_reserved_pages(void)
-{
- struct list_head *p;
- struct snd_mem_list *mem;
-
- mutex_lock(&list_mutex);
- while (! list_empty(&mem_list_head)) {
- p = mem_list_head.next;
- mem = list_entry(p, struct snd_mem_list, list);
- list_del(p);
- snd_dma_free_pages(&mem->buffer);
- kfree(mem);
- }
- mutex_unlock(&list_mutex);
-}
-
-
-#ifdef CONFIG_PROC_FS
-/*
- * proc file interface
- */
-#define SND_MEM_PROC_FILE "driver/snd-page-alloc"
-static struct proc_dir_entry *snd_mem_proc;
-
-static int snd_mem_proc_read(struct seq_file *seq, void *offset)
-{
- long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
- struct snd_mem_list *mem;
- int devno;
- static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
-
- mutex_lock(&list_mutex);
- seq_printf(seq, "pages : %li bytes (%li pages per %likB)\n",
- pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
- devno = 0;
- list_for_each_entry(mem, &mem_list_head, list) {
- devno++;
- seq_printf(seq, "buffer %d : ID %08x : type %s\n",
- devno, mem->id, types[mem->buffer.dev.type]);
- seq_printf(seq, " addr = 0x%lx, size = %d bytes\n",
- (unsigned long)mem->buffer.addr,
- (int)mem->buffer.bytes);
- }
- mutex_unlock(&list_mutex);
- return 0;
-}
-
-static int snd_mem_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, snd_mem_proc_read, NULL);
-}
-
-/* FIXME: for pci only - other bus? */
-#ifdef CONFIG_PCI
-#define gettoken(bufp) strsep(bufp, " \t\n")
-
-static ssize_t snd_mem_proc_write(struct file *file, const char __user * buffer,
- size_t count, loff_t * ppos)
-{
- char buf[128];
- char *token, *p;
-
- if (count > sizeof(buf) - 1)
- return -EINVAL;
- if (copy_from_user(buf, buffer, count))
- return -EFAULT;
- buf[count] = '\0';
-
- p = buf;
- token = gettoken(&p);
- if (! token || *token == '#')
- return count;
- if (strcmp(token, "add") == 0) {
- char *endp;
- int vendor, device, size, buffers;
- long mask;
- int i, alloced;
- struct pci_dev *pci;
-
- if ((token = gettoken(&p)) == NULL ||
- (vendor = simple_strtol(token, NULL, 0)) <= 0 ||
- (token = gettoken(&p)) == NULL ||
- (device = simple_strtol(token, NULL, 0)) <= 0 ||
- (token = gettoken(&p)) == NULL ||
- (mask = simple_strtol(token, NULL, 0)) < 0 ||
- (token = gettoken(&p)) == NULL ||
- (size = memparse(token, &endp)) < 64*1024 ||
- size > 16*1024*1024 /* too big */ ||
- (token = gettoken(&p)) == NULL ||
- (buffers = simple_strtol(token, NULL, 0)) <= 0 ||
- buffers > 4) {
- printk(KERN_ERR "snd-page-alloc: invalid proc write format\n");
- return count;
- }
- vendor &= 0xffff;
- device &= 0xffff;
-
- alloced = 0;
- pci = NULL;
- while ((pci = pci_get_device(vendor, device, pci)) != NULL) {
- if (mask > 0 && mask < 0xffffffff) {
- if (pci_set_dma_mask(pci, mask) < 0 ||
- pci_set_consistent_dma_mask(pci, mask) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", mask, vendor, device);
- pci_dev_put(pci);
- return count;
- }
- }
- for (i = 0; i < buffers; i++) {
- struct snd_dma_buffer dmab;
- memset(&dmab, 0, sizeof(dmab));
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
- size, &dmab) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
- pci_dev_put(pci);
- return count;
- }
- snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
- }
- alloced++;
- }
- if (! alloced) {
- for (i = 0; i < buffers; i++) {
- struct snd_dma_buffer dmab;
- memset(&dmab, 0, sizeof(dmab));
- /* FIXME: We can allocate only in ZONE_DMA
- * without a device pointer!
- */
- if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, NULL,
- size, &dmab) < 0) {
- printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size);
- break;
- }
- snd_dma_reserve_buf(&dmab, (unsigned int)((vendor << 16) | device));
- }
- }
- } else if (strcmp(token, "erase") == 0)
- /* FIXME: need for releasing each buffer chunk? */
- free_all_reserved_pages();
- else
- printk(KERN_ERR "snd-page-alloc: invalid proc cmd\n");
- return count;
-}
-#endif /* CONFIG_PCI */
-
-static const struct file_operations snd_mem_proc_fops = {
- .owner = THIS_MODULE,
- .open = snd_mem_proc_open,
- .read = seq_read,
-#ifdef CONFIG_PCI
- .write = snd_mem_proc_write,
-#endif
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-#endif /* CONFIG_PROC_FS */
-
-/*
- * module entry
- */
-
-static int __init snd_mem_init(void)
-{
-#ifdef CONFIG_PROC_FS
- snd_mem_proc = proc_create(SND_MEM_PROC_FILE, 0644, NULL,
- &snd_mem_proc_fops);
-#endif
- return 0;
-}
-
-static void __exit snd_mem_exit(void)
-{
- remove_proc_entry(SND_MEM_PROC_FILE, NULL);
- free_all_reserved_pages();
- if (snd_allocated_pages > 0)
- printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
-}
-
-
-module_init(snd_mem_init)
-module_exit(snd_mem_exit)
-
-
/*
* exports
*/
@@ -540,8 +295,5 @@ EXPORT_SYMBOL(snd_dma_alloc_pages);
EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
EXPORT_SYMBOL(snd_dma_free_pages);
-EXPORT_SYMBOL(snd_dma_get_reserved_buf);
-EXPORT_SYMBOL(snd_dma_reserve_buf);
-
EXPORT_SYMBOL(snd_malloc_pages);
EXPORT_SYMBOL(snd_free_pages);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 17f45e8aa89c..e1e9e0c999fe 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -49,6 +49,8 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
struct snd_pcm *pcm;
list_for_each_entry(pcm, &snd_pcm_devices, list) {
+ if (pcm->internal)
+ continue;
if (pcm->card == card && pcm->device == device)
return pcm;
}
@@ -60,6 +62,8 @@ static int snd_pcm_next(struct snd_card *card, int device)
struct snd_pcm *pcm;
list_for_each_entry(pcm, &snd_pcm_devices, list) {
+ if (pcm->internal)
+ continue;
if (pcm->card == card && pcm->device > device)
return pcm->device;
else if (pcm->card->number > card->number)
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c
index aa924d9b7986..94d08733cb38 100644
--- a/sound/core/pcm_dmaengine.c
+++ b/sound/core/pcm_dmaengine.c
@@ -63,23 +63,19 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
struct dma_slave_config *slave_config)
{
enum dma_slave_buswidth buswidth;
+ int bits;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
+ bits = snd_pcm_format_physical_width(params_format(params));
+ if (bits < 8 || bits > 64)
+ return -EINVAL;
+ else if (bits == 8)
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
- break;
- case SNDRV_PCM_FORMAT_S16_LE:
+ else if (bits == 16)
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
- break;
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S32_LE:
+ else if (bits <= 32)
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
- break;
- default:
- return -EINVAL;
- }
+ else
+ buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config->direction = DMA_MEM_TO_DEV;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 6e03b465e44e..a2104671f51d 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1937,6 +1937,8 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
case SNDRV_PCM_STATE_DISCONNECTED:
err = -EBADFD;
goto _endloop;
+ case SNDRV_PCM_STATE_PAUSED:
+ continue;
}
if (!tout) {
snd_printd("%s write error (DMA or IRQ trouble?)\n",
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
index 0af622c34e19..54debc07f5cb 100644
--- a/sound/core/pcm_memory.c
+++ b/sound/core/pcm_memory.c
@@ -51,17 +51,9 @@ static const size_t snd_minimum_buffer = 16384;
static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t size)
{
struct snd_dma_buffer *dmab = &substream->dma_buffer;
+ size_t orig_size = size;
int err;
- /* already reserved? */
- if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) {
- if (dmab->bytes >= size)
- return 0; /* yes */
- /* no, free the reserved block */
- snd_dma_free_pages(dmab);
- dmab->bytes = 0;
- }
-
do {
if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev,
size, dmab)) < 0) {
@@ -72,6 +64,10 @@ static int preallocate_pcm_pages(struct snd_pcm_substream *substream, size_t siz
size >>= 1;
} while (size >= snd_minimum_buffer);
dmab->bytes = 0; /* tell error */
+ pr_warn("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n",
+ substream->pcm->card->number, substream->pcm->device,
+ substream->stream ? 'c' : 'p', substream->number,
+ substream->pcm->name, orig_size);
return 0;
}
@@ -82,10 +78,7 @@ static void snd_pcm_lib_preallocate_dma_free(struct snd_pcm_substream *substream
{
if (substream->dma_buffer.area == NULL)
return;
- if (substream->dma_buf_id)
- snd_dma_reserve_buf(&substream->dma_buffer, substream->dma_buf_id);
- else
- snd_dma_free_pages(&substream->dma_buffer);
+ snd_dma_free_pages(&substream->dma_buffer);
substream->dma_buffer.area = NULL;
}
@@ -260,11 +253,6 @@ static int snd_pcm_lib_preallocate_pages1(struct snd_pcm_substream *substream,
*
* Do pre-allocation for the given DMA buffer type.
*
- * When substream->dma_buf_id is set, the function tries to look for
- * the reserved buffer, and the buffer is not freed but reserved at
- * destruction time. The dma_buf_id must be unique for all systems
- * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id().
- *
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 43f24cce3dec..4560ca0e5651 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -514,3 +514,42 @@ unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit)
return 0;
}
EXPORT_SYMBOL(snd_pcm_rate_bit_to_rate);
+
+static unsigned int snd_pcm_rate_mask_sanitize(unsigned int rates)
+{
+ if (rates & SNDRV_PCM_RATE_CONTINUOUS)
+ return SNDRV_PCM_RATE_CONTINUOUS;
+ else if (rates & SNDRV_PCM_RATE_KNOT)
+ return SNDRV_PCM_RATE_KNOT;
+ return rates;
+}
+
+/**
+ * snd_pcm_rate_mask_intersect - computes the intersection between two rate masks
+ * @rates_a: The first rate mask
+ * @rates_b: The second rate mask
+ *
+ * This function computes the rates that are supported by both rate masks passed
+ * to the function. It will take care of the special handling of
+ * SNDRV_PCM_RATE_CONTINUOUS and SNDRV_PCM_RATE_KNOT.
+ *
+ * Return: A rate mask containing the rates that are supported by both rates_a
+ * and rates_b.
+ */
+unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
+ unsigned int rates_b)
+{
+ rates_a = snd_pcm_rate_mask_sanitize(rates_a);
+ rates_b = snd_pcm_rate_mask_sanitize(rates_b);
+
+ if (rates_a & SNDRV_PCM_RATE_CONTINUOUS)
+ return rates_b;
+ else if (rates_b & SNDRV_PCM_RATE_CONTINUOUS)
+ return rates_a;
+ else if (rates_a & SNDRV_PCM_RATE_KNOT)
+ return rates_b;
+ else if (rates_b & SNDRV_PCM_RATE_KNOT)
+ return rates_a;
+ return rates_a & rates_b;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_rate_mask_intersect);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a68d4c6d702c..01a5e05ede95 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2428,6 +2428,7 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
goto __badfd;
+ /* Fall through */
case SNDRV_PCM_STATE_RUNNING:
if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
break;
@@ -2460,6 +2461,7 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream,
case SNDRV_PCM_STATE_DRAINING:
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
goto __badfd;
+ /* Fall through */
case SNDRV_PCM_STATE_RUNNING:
if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
break;
@@ -3199,6 +3201,14 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+#ifdef CONFIG_GENERIC_ALLOCATOR
+ if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
+ area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
+ return remap_pfn_range(area, area->vm_start,
+ substream->dma_buffer.addr >> PAGE_SHIFT,
+ area->vm_end - area->vm_start, area->vm_page_prot);
+ }
+#endif /* CONFIG_GENERIC_ALLOCATOR */
#ifdef ARCH_HAS_DMA_MMAP_COHERENT
if (!substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
diff --git a/sound/core/sound.c b/sound/core/sound.c
index f002bd911dae..437c25ea6403 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -153,7 +153,7 @@ static int snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
- const struct file_operations *old_fops;
+ const struct file_operations *new_fops;
int err = 0;
if (minor >= ARRAY_SIZE(snd_minors))
@@ -167,24 +167,14 @@ static int snd_open(struct inode *inode, struct file *file)
return -ENODEV;
}
}
- old_fops = file->f_op;
- file->f_op = fops_get(mptr->f_ops);
- if (file->f_op == NULL) {
- file->f_op = old_fops;
- err = -ENODEV;
- }
+ new_fops = fops_get(mptr->f_ops);
mutex_unlock(&sound_mutex);
- if (err < 0)
- return err;
+ if (!new_fops)
+ return -ENODEV;
+ replace_fops(file, new_fops);
- if (file->f_op->open) {
+ if (file->f_op->open)
err = file->f_op->open(inode, file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
- }
- fops_put(old_fops);
return err;
}
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 0c796bcbc0a3..6c6d09a51f42 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -390,6 +390,11 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
voice = snd_opl3_oss_map[chan->number];
}
+ if (voice < 0) {
+ spin_unlock_irqrestore(&opl3->voice_lock, flags);
+ return;
+ }
+
if (voice < MAX_OPL2_VOICES) {
/* Left register block for voices 0 .. 8 */
reg_side = OPL3_LEFT;
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 1c19cd7ad26e..328bd29264ce 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -46,8 +46,9 @@ static int snd_pcsp_create(struct snd_card *card)
int err;
int div, min_div, order;
+ hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+
if (!nopcm) {
- hrtimer_get_res(CLOCK_MONOTONIC, &tp);
if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
"(%linS)\n", tp.tv_nsec);
@@ -187,8 +188,8 @@ static int pcsp_probe(struct platform_device *dev)
static int pcsp_remove(struct platform_device *dev)
{
struct snd_pcsp *chip = platform_get_drvdata(dev);
- alsa_card_pcsp_exit(chip);
pcspkr_input_remove(chip->input_dev);
+ alsa_card_pcsp_exit(chip);
return 0;
}
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index ea063e1f8722..b3e274fe4a77 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -11,6 +11,21 @@ config SND_FIREWIRE_LIB
tristate
depends on SND_PCM
+config SND_DICE
+ tristate "DICE-based DACs (EXPERIMENTAL)"
+ select SND_HWDEP
+ select SND_PCM
+ select SND_FIREWIRE_LIB
+ help
+ Say Y here to include support for many DACs based on the DICE
+ chip family (DICE-II/Jr/Mini) from TC Applied Technologies.
+
+ At the moment, this driver supports playback only. If you
+ want to use devices that support capturing, use FFADO instead.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-dice.
+
config SND_FIREWIRE_SPEAKERS
tristate "FireWire speakers"
select SND_PCM
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index 460179df5bb5..509955061d30 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -1,10 +1,12 @@
snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp.o
+snd-dice-objs := dice.o
snd-firewire-speakers-objs := speakers.o
snd-isight-objs := isight.o
snd-scs1x-objs := scs1x.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
+obj-$(CONFIG_SND_DICE) += snd-dice.o
obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index ea995af6d049..9048777228e2 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -42,9 +42,6 @@ static void pcm_period_tasklet(unsigned long data);
int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
enum cip_out_flags flags)
{
- if (flags != CIP_NONBLOCKING)
- return -EINVAL;
-
s->unit = fw_unit_get(unit);
s->flags = flags;
s->context = ERR_PTR(-1);
@@ -62,73 +59,91 @@ EXPORT_SYMBOL(amdtp_out_stream_init);
*/
void amdtp_out_stream_destroy(struct amdtp_out_stream *s)
{
- WARN_ON(!IS_ERR(s->context));
+ WARN_ON(amdtp_out_stream_running(s));
mutex_destroy(&s->mutex);
fw_unit_put(s->unit);
}
EXPORT_SYMBOL(amdtp_out_stream_destroy);
+const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT] = {
+ [CIP_SFC_32000] = 8,
+ [CIP_SFC_44100] = 8,
+ [CIP_SFC_48000] = 8,
+ [CIP_SFC_88200] = 16,
+ [CIP_SFC_96000] = 16,
+ [CIP_SFC_176400] = 32,
+ [CIP_SFC_192000] = 32,
+};
+EXPORT_SYMBOL(amdtp_syt_intervals);
+
/**
- * amdtp_out_stream_set_rate - set the sample rate
+ * amdtp_out_stream_set_parameters - set stream parameters
* @s: the AMDTP output stream to configure
* @rate: the sample rate
+ * @pcm_channels: the number of PCM samples in each data block, to be encoded
+ * as AM824 multi-bit linear audio
+ * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
*
- * The sample rate must be set before the stream is started, and must not be
+ * The parameters must be set before the stream is started, and must not be
* changed while the stream is running.
*/
-void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate)
+void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s,
+ unsigned int rate,
+ unsigned int pcm_channels,
+ unsigned int midi_ports)
{
- static const struct {
- unsigned int rate;
- unsigned int syt_interval;
- } rate_info[] = {
- [CIP_SFC_32000] = { 32000, 8, },
- [CIP_SFC_44100] = { 44100, 8, },
- [CIP_SFC_48000] = { 48000, 8, },
- [CIP_SFC_88200] = { 88200, 16, },
- [CIP_SFC_96000] = { 96000, 16, },
- [CIP_SFC_176400] = { 176400, 32, },
- [CIP_SFC_192000] = { 192000, 32, },
+ static const unsigned int rates[] = {
+ [CIP_SFC_32000] = 32000,
+ [CIP_SFC_44100] = 44100,
+ [CIP_SFC_48000] = 48000,
+ [CIP_SFC_88200] = 88200,
+ [CIP_SFC_96000] = 96000,
+ [CIP_SFC_176400] = 176400,
+ [CIP_SFC_192000] = 192000,
};
unsigned int sfc;
- if (WARN_ON(!IS_ERR(s->context)))
+ if (WARN_ON(amdtp_out_stream_running(s)))
return;
- for (sfc = 0; sfc < ARRAY_SIZE(rate_info); ++sfc)
- if (rate_info[sfc].rate == rate) {
- s->sfc = sfc;
- s->syt_interval = rate_info[sfc].syt_interval;
- return;
- }
+ for (sfc = 0; sfc < CIP_SFC_COUNT; ++sfc)
+ if (rates[sfc] == rate)
+ goto sfc_found;
WARN_ON(1);
+ return;
+
+sfc_found:
+ s->dual_wire = (s->flags & CIP_HI_DUALWIRE) && sfc > CIP_SFC_96000;
+ if (s->dual_wire) {
+ sfc -= 2;
+ rate /= 2;
+ pcm_channels *= 2;
+ }
+ s->sfc = sfc;
+ s->data_block_quadlets = pcm_channels + DIV_ROUND_UP(midi_ports, 8);
+ s->pcm_channels = pcm_channels;
+ s->midi_ports = midi_ports;
+
+ s->syt_interval = amdtp_syt_intervals[sfc];
+
+ /* default buffering in the device */
+ s->transfer_delay = TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+ if (s->flags & CIP_BLOCKING)
+ /* additional buffering needed to adjust for no-data packets */
+ s->transfer_delay += TICKS_PER_SECOND * s->syt_interval / rate;
}
-EXPORT_SYMBOL(amdtp_out_stream_set_rate);
+EXPORT_SYMBOL(amdtp_out_stream_set_parameters);
/**
* amdtp_out_stream_get_max_payload - get the stream's packet size
* @s: the AMDTP output stream
*
* This function must not be called before the stream has been configured
- * with amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and
- * amdtp_out_stream_set_midi().
+ * with amdtp_out_stream_set_parameters().
*/
unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s)
{
- static const unsigned int max_data_blocks[] = {
- [CIP_SFC_32000] = 4,
- [CIP_SFC_44100] = 6,
- [CIP_SFC_48000] = 6,
- [CIP_SFC_88200] = 12,
- [CIP_SFC_96000] = 12,
- [CIP_SFC_176400] = 23,
- [CIP_SFC_192000] = 24,
- };
-
- s->data_block_quadlets = s->pcm_channels;
- s->data_block_quadlets += DIV_ROUND_UP(s->midi_ports, 8);
-
- return 8 + max_data_blocks[s->sfc] * 4 * s->data_block_quadlets;
+ return 8 + s->syt_interval * s->data_block_quadlets * 4;
}
EXPORT_SYMBOL(amdtp_out_stream_get_max_payload);
@@ -138,19 +153,26 @@ static void amdtp_write_s16(struct amdtp_out_stream *s,
static void amdtp_write_s32(struct amdtp_out_stream *s,
struct snd_pcm_substream *pcm,
__be32 *buffer, unsigned int frames);
+static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames);
+static void amdtp_write_s32_dualwire(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames);
/**
* amdtp_out_stream_set_pcm_format - set the PCM format
* @s: the AMDTP output stream to configure
* @format: the format of the ALSA PCM device
*
- * The sample format must be set before the stream is started, and must not be
- * changed while the stream is running.
+ * The sample format must be set after the other paramters (rate/PCM channels/
+ * MIDI) and before the stream is started, and must not be changed while the
+ * stream is running.
*/
void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
snd_pcm_format_t format)
{
- if (WARN_ON(!IS_ERR(s->context)))
+ if (WARN_ON(amdtp_out_stream_running(s)))
return;
switch (format) {
@@ -158,10 +180,16 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
WARN_ON(1);
/* fall through */
case SNDRV_PCM_FORMAT_S16:
- s->transfer_samples = amdtp_write_s16;
+ if (s->dual_wire)
+ s->transfer_samples = amdtp_write_s16_dualwire;
+ else
+ s->transfer_samples = amdtp_write_s16;
break;
case SNDRV_PCM_FORMAT_S32:
- s->transfer_samples = amdtp_write_s32;
+ if (s->dual_wire)
+ s->transfer_samples = amdtp_write_s32_dualwire;
+ else
+ s->transfer_samples = amdtp_write_s32;
break;
}
}
@@ -248,7 +276,7 @@ static unsigned int calculate_syt(struct amdtp_out_stream *s,
s->last_syt_offset = syt_offset;
if (syt_offset < TICKS_PER_CYCLE) {
- syt_offset += TRANSFER_DELAY_TICKS - TICKS_PER_CYCLE;
+ syt_offset += s->transfer_delay;
syt = (cycle + syt_offset / TICKS_PER_CYCLE) << 12;
syt += syt_offset % TICKS_PER_CYCLE;
@@ -268,7 +296,7 @@ static void amdtp_write_s32(struct amdtp_out_stream *s,
channels = s->pcm_channels;
src = (void *)runtime->dma_area +
- s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+ frames_to_bytes(runtime, s->pcm_buffer_pointer);
remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
frame_step = s->data_block_quadlets - channels;
@@ -294,7 +322,7 @@ static void amdtp_write_s16(struct amdtp_out_stream *s,
channels = s->pcm_channels;
src = (void *)runtime->dma_area +
- s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+ frames_to_bytes(runtime, s->pcm_buffer_pointer);
remaining_frames = runtime->buffer_size - s->pcm_buffer_pointer;
frame_step = s->data_block_quadlets - channels;
@@ -310,6 +338,68 @@ static void amdtp_write_s16(struct amdtp_out_stream *s,
}
}
+static void amdtp_write_s32_dualwire(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames)
+{
+ struct snd_pcm_runtime *runtime = pcm->runtime;
+ unsigned int channels, frame_adjust_1, frame_adjust_2, i, c;
+ const u32 *src;
+
+ channels = s->pcm_channels;
+ src = (void *)runtime->dma_area +
+ s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+ frame_adjust_1 = channels - 1;
+ frame_adjust_2 = 1 - (s->data_block_quadlets - channels);
+
+ channels /= 2;
+ for (i = 0; i < frames; ++i) {
+ for (c = 0; c < channels; ++c) {
+ *buffer = cpu_to_be32((*src >> 8) | 0x40000000);
+ src++;
+ buffer += 2;
+ }
+ buffer -= frame_adjust_1;
+ for (c = 0; c < channels; ++c) {
+ *buffer = cpu_to_be32((*src >> 8) | 0x40000000);
+ src++;
+ buffer += 2;
+ }
+ buffer -= frame_adjust_2;
+ }
+}
+
+static void amdtp_write_s16_dualwire(struct amdtp_out_stream *s,
+ struct snd_pcm_substream *pcm,
+ __be32 *buffer, unsigned int frames)
+{
+ struct snd_pcm_runtime *runtime = pcm->runtime;
+ unsigned int channels, frame_adjust_1, frame_adjust_2, i, c;
+ const u16 *src;
+
+ channels = s->pcm_channels;
+ src = (void *)runtime->dma_area +
+ s->pcm_buffer_pointer * (runtime->frame_bits / 8);
+ frame_adjust_1 = channels - 1;
+ frame_adjust_2 = 1 - (s->data_block_quadlets - channels);
+
+ channels /= 2;
+ for (i = 0; i < frames; ++i) {
+ for (c = 0; c < channels; ++c) {
+ *buffer = cpu_to_be32((*src << 8) | 0x40000000);
+ src++;
+ buffer += 2;
+ }
+ buffer -= frame_adjust_1;
+ for (c = 0; c < channels; ++c) {
+ *buffer = cpu_to_be32((*src << 8) | 0x40000000);
+ src++;
+ buffer += 2;
+ }
+ buffer -= frame_adjust_2;
+ }
+}
+
static void amdtp_fill_pcm_silence(struct amdtp_out_stream *s,
__be32 *buffer, unsigned int frames)
{
@@ -344,8 +434,14 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
return;
index = s->packet_index;
- data_blocks = calculate_data_blocks(s);
+ /* this module generate empty packet for 'no data' */
syt = calculate_syt(s, cycle);
+ if (!(s->flags & CIP_BLOCKING))
+ data_blocks = calculate_data_blocks(s);
+ else if (syt != 0xffff)
+ data_blocks = s->syt_interval;
+ else
+ data_blocks = 0;
buffer = s->buffer.packets[index].buffer;
buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
@@ -386,6 +482,9 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
s->packet_index = index;
if (pcm) {
+ if (s->dual_wire)
+ data_blocks *= 2;
+
ptr = s->pcm_buffer_pointer + data_blocks;
if (ptr >= pcm->runtime->buffer_size)
ptr -= pcm->runtime->buffer_size;
@@ -455,9 +554,8 @@ static int queue_initial_skip_packets(struct amdtp_out_stream *s)
* @speed: firewire speed code
*
* The stream cannot be started until it has been configured with
- * amdtp_out_stream_set_hw_params(), amdtp_out_stream_set_pcm(), and
- * amdtp_out_stream_set_midi(); and it must be started before any
- * PCM or MIDI device can be started.
+ * amdtp_out_stream_set_parameters() and amdtp_out_stream_set_pcm_format(),
+ * and it must be started before any PCM or MIDI device can be started.
*/
int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed)
{
@@ -477,7 +575,7 @@ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed)
mutex_lock(&s->mutex);
- if (WARN_ON(!IS_ERR(s->context) ||
+ if (WARN_ON(amdtp_out_stream_running(s) ||
(!s->pcm_channels && !s->midi_ports))) {
err = -EBADFD;
goto err_unlock;
@@ -573,7 +671,7 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s)
{
mutex_lock(&s->mutex);
- if (IS_ERR(s->context)) {
+ if (!amdtp_out_stream_running(s)) {
mutex_unlock(&s->mutex);
return;
}
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index f6103d68c4b1..2746ecd291af 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -1,8 +1,10 @@
#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
#define SOUND_FIREWIRE_AMDTP_H_INCLUDED
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <sound/asound.h>
#include "packets-buffer.h"
/**
@@ -11,9 +13,18 @@
* sample_rate/8000 samples, with rounding up or down to adjust
* for clock skew and left-over fractional samples. This should
* be used if supported by the device.
+ * @CIP_BLOCKING: In blocking mode, each packet contains either zero or
+ * SYT_INTERVAL samples, with these two types alternating so that
+ * the overall sample rate comes out right.
+ * @CIP_HI_DUALWIRE: At rates above 96 kHz, pretend that the stream runs
+ * at half the actual sample rate with twice the number of channels;
+ * two samples of a channel are stored consecutively in the packet.
+ * Requires blocking mode and SYT_INTERVAL-aligned PCM buffer size.
*/
enum cip_out_flags {
- CIP_NONBLOCKING = 0,
+ CIP_NONBLOCKING = 0x00,
+ CIP_BLOCKING = 0x01,
+ CIP_HI_DUALWIRE = 0x02,
};
/**
@@ -27,6 +38,7 @@ enum cip_sfc {
CIP_SFC_96000 = 4,
CIP_SFC_176400 = 5,
CIP_SFC_192000 = 6,
+ CIP_SFC_COUNT
};
#define AMDTP_OUT_PCM_FORMAT_BITS (SNDRV_PCM_FMTBIT_S16 | \
@@ -43,6 +55,7 @@ struct amdtp_out_stream {
struct mutex mutex;
enum cip_sfc sfc;
+ bool dual_wire;
unsigned int data_block_quadlets;
unsigned int pcm_channels;
unsigned int midi_ports;
@@ -51,6 +64,7 @@ struct amdtp_out_stream {
__be32 *buffer, unsigned int frames);
unsigned int syt_interval;
+ unsigned int transfer_delay;
unsigned int source_node_id_field;
struct iso_packets_buffer buffer;
@@ -74,7 +88,10 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
enum cip_out_flags flags);
void amdtp_out_stream_destroy(struct amdtp_out_stream *s);
-void amdtp_out_stream_set_rate(struct amdtp_out_stream *s, unsigned int rate);
+void amdtp_out_stream_set_parameters(struct amdtp_out_stream *s,
+ unsigned int rate,
+ unsigned int pcm_channels,
+ unsigned int midi_ports);
unsigned int amdtp_out_stream_get_max_payload(struct amdtp_out_stream *s);
int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed);
@@ -87,31 +104,11 @@ void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s);
unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s);
void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s);
-/**
- * amdtp_out_stream_set_pcm - configure format of PCM samples
- * @s: the AMDTP output stream to be configured
- * @pcm_channels: the number of PCM samples in each data block, to be encoded
- * as AM824 multi-bit linear audio
- *
- * This function must not be called while the stream is running.
- */
-static inline void amdtp_out_stream_set_pcm(struct amdtp_out_stream *s,
- unsigned int pcm_channels)
-{
- s->pcm_channels = pcm_channels;
-}
+extern const unsigned int amdtp_syt_intervals[CIP_SFC_COUNT];
-/**
- * amdtp_out_stream_set_midi - configure format of MIDI data
- * @s: the AMDTP output stream to be configured
- * @midi_ports: the number of MIDI ports (i.e., MPX-MIDI Data Channels)
- *
- * This function must not be called while the stream is running.
- */
-static inline void amdtp_out_stream_set_midi(struct amdtp_out_stream *s,
- unsigned int midi_ports)
+static inline bool amdtp_out_stream_running(struct amdtp_out_stream *s)
{
- s->midi_ports = midi_ports;
+ return !IS_ERR(s->context);
}
/**
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index 645cb0ba4293..efdbf585e404 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -48,9 +48,6 @@ static int pcr_modify(struct cmp_connection *c,
int (*check)(struct cmp_connection *c, __be32 pcr),
enum bus_reset_handling bus_reset_handling)
{
- struct fw_device *device = fw_parent_device(c->resources.unit);
- int generation = c->resources.generation;
- int rcode, errors = 0;
__be32 old_arg, buffer[2];
int err;
@@ -59,36 +56,31 @@ static int pcr_modify(struct cmp_connection *c,
old_arg = buffer[0];
buffer[1] = modify(c, buffer[0]);
- rcode = fw_run_transaction(
- device->card, TCODE_LOCK_COMPARE_SWAP,
- device->node_id, generation, device->max_speed,
+ err = snd_fw_transaction(
+ c->resources.unit, TCODE_LOCK_COMPARE_SWAP,
CSR_REGISTER_BASE + CSR_IPCR(c->pcr_index),
- buffer, 8);
-
- if (rcode == RCODE_COMPLETE) {
- if (buffer[0] == old_arg) /* success? */
- break;
-
- if (check) {
- err = check(c, buffer[0]);
- if (err < 0)
- return err;
- }
- } else if (rcode == RCODE_GENERATION)
- goto bus_reset;
- else if (rcode_is_permanent_error(rcode) || ++errors >= 3)
- goto io_error;
+ buffer, 8,
+ FW_FIXED_GENERATION | c->resources.generation);
+
+ if (err < 0) {
+ if (err == -EAGAIN &&
+ bus_reset_handling == SUCCEED_ON_BUS_RESET)
+ err = 0;
+ return err;
+ }
+
+ if (buffer[0] == old_arg) /* success? */
+ break;
+
+ if (check) {
+ err = check(c, buffer[0]);
+ if (err < 0)
+ return err;
+ }
}
c->last_pcr_value = buffer[1];
return 0;
-
-io_error:
- cmp_error(c, "transaction failed: %s\n", fw_rcode_string(rcode));
- return -EIO;
-
-bus_reset:
- return bus_reset_handling == ABORT_ON_BUS_RESET ? -EAGAIN : 0;
}
@@ -108,7 +100,7 @@ int cmp_connection_init(struct cmp_connection *c,
err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
CSR_REGISTER_BASE + CSR_IMPR,
- &impr_be, 4);
+ &impr_be, 4, 0);
if (err < 0)
return err;
impr = be32_to_cpu(impr_be);
diff --git a/sound/firewire/dice-interface.h b/sound/firewire/dice-interface.h
new file mode 100644
index 000000000000..27b044f84c81
--- /dev/null
+++ b/sound/firewire/dice-interface.h
@@ -0,0 +1,371 @@
+#ifndef SOUND_FIREWIRE_DICE_INTERFACE_H_INCLUDED
+#define SOUND_FIREWIRE_DICE_INTERFACE_H_INCLUDED
+
+/*
+ * DICE device interface definitions
+ */
+
+/*
+ * Generally, all registers can be read like memory, i.e., with quadlet read or
+ * block read transactions with at least quadlet-aligned offset and length.
+ * Writes are not allowed except where noted; quadlet-sized registers must be
+ * written with a quadlet write transaction.
+ *
+ * All values are in big endian. The DICE firmware runs on a little-endian CPU
+ * and just byte-swaps _all_ quadlets on the bus, so values without endianness
+ * (e.g. strings) get scrambled and must be byte-swapped again by the driver.
+ */
+
+/*
+ * Streaming is handled by the "DICE driver" interface. Its registers are
+ * located in this private address space.
+ */
+#define DICE_PRIVATE_SPACE 0xffffe0000000uLL
+
+/*
+ * The registers are organized in several sections, which are organized
+ * separately to allow them to be extended individually. Whether a register is
+ * supported can be detected by checking its offset against its section's size.
+ *
+ * The section offset values are relative to DICE_PRIVATE_SPACE; the offset/
+ * size values are measured in quadlets. Read-only.
+ */
+#define DICE_GLOBAL_OFFSET 0x00
+#define DICE_GLOBAL_SIZE 0x04
+#define DICE_TX_OFFSET 0x08
+#define DICE_TX_SIZE 0x0c
+#define DICE_RX_OFFSET 0x10
+#define DICE_RX_SIZE 0x14
+#define DICE_EXT_SYNC_OFFSET 0x18
+#define DICE_EXT_SYNC_SIZE 0x1c
+#define DICE_UNUSED2_OFFSET 0x20
+#define DICE_UNUSED2_SIZE 0x24
+
+/*
+ * Global settings.
+ */
+
+/*
+ * Stores the full 64-bit address (node ID and offset in the node's address
+ * space) where the device will send notifications. Must be changed with
+ * a compare/swap transaction by the owner. This register is automatically
+ * cleared on a bus reset.
+ */
+#define GLOBAL_OWNER 0x000
+#define OWNER_NO_OWNER 0xffff000000000000uLL
+#define OWNER_NODE_SHIFT 48
+
+/*
+ * A bitmask with asynchronous events; read-only. When any event(s) happen,
+ * the bits of previous events are cleared, and the value of this register is
+ * also written to the address stored in the owner register.
+ */
+#define GLOBAL_NOTIFICATION 0x008
+/* Some registers in the Rx/Tx sections may have changed. */
+#define NOTIFY_RX_CFG_CHG 0x00000001
+#define NOTIFY_TX_CFG_CHG 0x00000002
+/* Lock status of the current clock source may have changed. */
+#define NOTIFY_LOCK_CHG 0x00000010
+/* Write to the clock select register has been finished. */
+#define NOTIFY_CLOCK_ACCEPTED 0x00000020
+/* Lock status of some clock source has changed. */
+#define NOTIFY_EXT_STATUS 0x00000040
+/* Other bits may be used for device-specific events. */
+
+/*
+ * A name that can be customized for each device; read/write. Padded with zero
+ * bytes. Quadlets are byte-swapped. The encoding is whatever the host driver
+ * happens to be using.
+ */
+#define GLOBAL_NICK_NAME 0x00c
+#define NICK_NAME_SIZE 64
+
+/*
+ * The current sample rate and clock source; read/write. Whether a clock
+ * source or sample rate is supported is device-specific; the internal clock
+ * source is always available. Low/mid/high = up to 48/96/192 kHz. This
+ * register can be changed even while streams are running.
+ */
+#define GLOBAL_CLOCK_SELECT 0x04c
+#define CLOCK_SOURCE_MASK 0x000000ff
+#define CLOCK_SOURCE_AES1 0x00000000
+#define CLOCK_SOURCE_AES2 0x00000001
+#define CLOCK_SOURCE_AES3 0x00000002
+#define CLOCK_SOURCE_AES4 0x00000003
+#define CLOCK_SOURCE_AES_ANY 0x00000004
+#define CLOCK_SOURCE_ADAT 0x00000005
+#define CLOCK_SOURCE_TDIF 0x00000006
+#define CLOCK_SOURCE_WC 0x00000007
+#define CLOCK_SOURCE_ARX1 0x00000008
+#define CLOCK_SOURCE_ARX2 0x00000009
+#define CLOCK_SOURCE_ARX3 0x0000000a
+#define CLOCK_SOURCE_ARX4 0x0000000b
+#define CLOCK_SOURCE_INTERNAL 0x0000000c
+#define CLOCK_RATE_MASK 0x0000ff00
+#define CLOCK_RATE_32000 0x00000000
+#define CLOCK_RATE_44100 0x00000100
+#define CLOCK_RATE_48000 0x00000200
+#define CLOCK_RATE_88200 0x00000300
+#define CLOCK_RATE_96000 0x00000400
+#define CLOCK_RATE_176400 0x00000500
+#define CLOCK_RATE_192000 0x00000600
+#define CLOCK_RATE_ANY_LOW 0x00000700
+#define CLOCK_RATE_ANY_MID 0x00000800
+#define CLOCK_RATE_ANY_HIGH 0x00000900
+#define CLOCK_RATE_NONE 0x00000a00
+#define CLOCK_RATE_SHIFT 8
+
+/*
+ * Enable streaming; read/write. Writing a non-zero value (re)starts all
+ * streams that have a valid iso channel set; zero stops all streams. The
+ * streams' parameters must be configured before starting. This register is
+ * automatically cleared on a bus reset.
+ */
+#define GLOBAL_ENABLE 0x050
+
+/*
+ * Status of the sample clock; read-only.
+ */
+#define GLOBAL_STATUS 0x054
+/* The current clock source is locked. */
+#define STATUS_SOURCE_LOCKED 0x00000001
+/* The actual sample rate; CLOCK_RATE_32000-_192000 or _NONE. */
+#define STATUS_NOMINAL_RATE_MASK 0x0000ff00
+
+/*
+ * Status of all clock sources; read-only.
+ */
+#define GLOBAL_EXTENDED_STATUS 0x058
+/*
+ * The _LOCKED bits always show the current status; any change generates
+ * a notification.
+ */
+#define EXT_STATUS_AES1_LOCKED 0x00000001
+#define EXT_STATUS_AES2_LOCKED 0x00000002
+#define EXT_STATUS_AES3_LOCKED 0x00000004
+#define EXT_STATUS_AES4_LOCKED 0x00000008
+#define EXT_STATUS_ADAT_LOCKED 0x00000010
+#define EXT_STATUS_TDIF_LOCKED 0x00000020
+#define EXT_STATUS_ARX1_LOCKED 0x00000040
+#define EXT_STATUS_ARX2_LOCKED 0x00000080
+#define EXT_STATUS_ARX3_LOCKED 0x00000100
+#define EXT_STATUS_ARX4_LOCKED 0x00000200
+#define EXT_STATUS_WC_LOCKED 0x00000400
+/*
+ * The _SLIP bits do not generate notifications; a set bit indicates that an
+ * error occurred since the last time when this register was read with
+ * a quadlet read transaction.
+ */
+#define EXT_STATUS_AES1_SLIP 0x00010000
+#define EXT_STATUS_AES2_SLIP 0x00020000
+#define EXT_STATUS_AES3_SLIP 0x00040000
+#define EXT_STATUS_AES4_SLIP 0x00080000
+#define EXT_STATUS_ADAT_SLIP 0x00100000
+#define EXT_STATUS_TDIF_SLIP 0x00200000
+#define EXT_STATUS_ARX1_SLIP 0x00400000
+#define EXT_STATUS_ARX2_SLIP 0x00800000
+#define EXT_STATUS_ARX3_SLIP 0x01000000
+#define EXT_STATUS_ARX4_SLIP 0x02000000
+#define EXT_STATUS_WC_SLIP 0x04000000
+
+/*
+ * The measured rate of the current clock source, in Hz; read-only.
+ */
+#define GLOBAL_SAMPLE_RATE 0x05c
+
+/*
+ * The version of the DICE driver specification that this device conforms to;
+ * read-only.
+ */
+#define GLOBAL_VERSION 0x060
+
+/* Some old firmware versions do not have the following global registers: */
+
+/*
+ * Supported sample rates and clock sources; read-only.
+ */
+#define GLOBAL_CLOCK_CAPABILITIES 0x064
+#define CLOCK_CAP_RATE_32000 0x00000001
+#define CLOCK_CAP_RATE_44100 0x00000002
+#define CLOCK_CAP_RATE_48000 0x00000004
+#define CLOCK_CAP_RATE_88200 0x00000008
+#define CLOCK_CAP_RATE_96000 0x00000010
+#define CLOCK_CAP_RATE_176400 0x00000020
+#define CLOCK_CAP_RATE_192000 0x00000040
+#define CLOCK_CAP_SOURCE_AES1 0x00010000
+#define CLOCK_CAP_SOURCE_AES2 0x00020000
+#define CLOCK_CAP_SOURCE_AES3 0x00040000
+#define CLOCK_CAP_SOURCE_AES4 0x00080000
+#define CLOCK_CAP_SOURCE_AES_ANY 0x00100000
+#define CLOCK_CAP_SOURCE_ADAT 0x00200000
+#define CLOCK_CAP_SOURCE_TDIF 0x00400000
+#define CLOCK_CAP_SOURCE_WC 0x00800000
+#define CLOCK_CAP_SOURCE_ARX1 0x01000000
+#define CLOCK_CAP_SOURCE_ARX2 0x02000000
+#define CLOCK_CAP_SOURCE_ARX3 0x04000000
+#define CLOCK_CAP_SOURCE_ARX4 0x08000000
+#define CLOCK_CAP_SOURCE_INTERNAL 0x10000000
+
+/*
+ * Names of all clock sources; read-only. Quadlets are byte-swapped. Names
+ * are separated with one backslash, the list is terminated with two
+ * backslashes. Unused clock sources are included.
+ */
+#define GLOBAL_CLOCK_SOURCE_NAMES 0x068
+#define CLOCK_SOURCE_NAMES_SIZE 256
+
+/*
+ * Capture stream settings. This section includes the number/size registers
+ * and the registers of all streams.
+ */
+
+/*
+ * The number of supported capture streams; read-only.
+ */
+#define TX_NUMBER 0x000
+
+/*
+ * The size of one stream's register block, in quadlets; read-only. The
+ * registers of the first stream follow immediately afterwards; the registers
+ * of the following streams are offset by this register's value.
+ */
+#define TX_SIZE 0x004
+
+/*
+ * The isochronous channel number on which packets are sent, or -1 if the
+ * stream is not to be used; read/write.
+ */
+#define TX_ISOCHRONOUS 0x008
+
+/*
+ * The number of audio channels; read-only. There will be one quadlet per
+ * channel; the first channel is the first quadlet in a data block.
+ */
+#define TX_NUMBER_AUDIO 0x00c
+
+/*
+ * The number of MIDI ports, 0-8; read-only. If > 0, there will be one
+ * additional quadlet in each data block, following the audio quadlets.
+ */
+#define TX_NUMBER_MIDI 0x010
+
+/*
+ * The speed at which the packets are sent, SCODE_100-_400; read/write.
+ */
+#define TX_SPEED 0x014
+
+/*
+ * Names of all audio channels; read-only. Quadlets are byte-swapped. Names
+ * are separated with one backslash, the list is terminated with two
+ * backslashes.
+ */
+#define TX_NAMES 0x018
+#define TX_NAMES_SIZE 256
+
+/*
+ * Audio IEC60958 capabilities; read-only. Bitmask with one bit per audio
+ * channel.
+ */
+#define TX_AC3_CAPABILITIES 0x118
+
+/*
+ * Send audio data with IEC60958 label; read/write. Bitmask with one bit per
+ * audio channel. This register can be changed even while the stream is
+ * running.
+ */
+#define TX_AC3_ENABLE 0x11c
+
+/*
+ * Playback stream settings. This section includes the number/size registers
+ * and the registers of all streams.
+ */
+
+/*
+ * The number of supported playback streams; read-only.
+ */
+#define RX_NUMBER 0x000
+
+/*
+ * The size of one stream's register block, in quadlets; read-only. The
+ * registers of the first stream follow immediately afterwards; the registers
+ * of the following streams are offset by this register's value.
+ */
+#define RX_SIZE 0x004
+
+/*
+ * The isochronous channel number on which packets are received, or -1 if the
+ * stream is not to be used; read/write.
+ */
+#define RX_ISOCHRONOUS 0x008
+
+/*
+ * Index of first quadlet to be interpreted; read/write. If > 0, that many
+ * quadlets at the beginning of each data block will be ignored, and all the
+ * audio and MIDI quadlets will follow.
+ */
+#define RX_SEQ_START 0x00c
+
+/*
+ * The number of audio channels; read-only. There will be one quadlet per
+ * channel.
+ */
+#define RX_NUMBER_AUDIO 0x010
+
+/*
+ * The number of MIDI ports, 0-8; read-only. If > 0, there will be one
+ * additional quadlet in each data block, following the audio quadlets.
+ */
+#define RX_NUMBER_MIDI 0x014
+
+/*
+ * Names of all audio channels; read-only. Quadlets are byte-swapped. Names
+ * are separated with one backslash, the list is terminated with two
+ * backslashes.
+ */
+#define RX_NAMES 0x018
+#define RX_NAMES_SIZE 256
+
+/*
+ * Audio IEC60958 capabilities; read-only. Bitmask with one bit per audio
+ * channel.
+ */
+#define RX_AC3_CAPABILITIES 0x118
+
+/*
+ * Receive audio data with IEC60958 label; read/write. Bitmask with one bit
+ * per audio channel. This register can be changed even while the stream is
+ * running.
+ */
+#define RX_AC3_ENABLE 0x11c
+
+/*
+ * Extended synchronization information.
+ * This section can be read completely with a block read request.
+ */
+
+/*
+ * Current clock source; read-only.
+ */
+#define EXT_SYNC_CLOCK_SOURCE 0x000
+
+/*
+ * Clock source is locked (boolean); read-only.
+ */
+#define EXT_SYNC_LOCKED 0x004
+
+/*
+ * Current sample rate (CLOCK_RATE_* >> CLOCK_RATE_SHIFT), _32000-_192000 or
+ * _NONE; read-only.
+ */
+#define EXT_SYNC_RATE 0x008
+
+/*
+ * ADAT user data bits; read-only.
+ */
+#define EXT_SYNC_ADAT_USER_DATA 0x00c
+/* The data bits, if available. */
+#define ADAT_USER_DATA_MASK 0x0f
+/* The data bits are not available. */
+#define ADAT_USER_DATA_NO_DATA 0x10
+
+#endif
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
new file mode 100644
index 000000000000..c0aa64941cee
--- /dev/null
+++ b/sound/firewire/dice.c
@@ -0,0 +1,1494 @@
+/*
+ * TC Applied Technologies Digital Interface Communications Engine driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "amdtp.h"
+#include "iso-resources.h"
+#include "lib.h"
+#include "dice-interface.h"
+
+
+struct dice {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ spinlock_t lock;
+ struct mutex mutex;
+ unsigned int global_offset;
+ unsigned int rx_offset;
+ unsigned int clock_caps;
+ unsigned int rx_channels[3];
+ unsigned int rx_midi_ports[3];
+ struct fw_address_handler notification_handler;
+ int owner_generation;
+ int dev_lock_count; /* > 0 driver, < 0 userspace */
+ bool dev_lock_changed;
+ bool global_enabled;
+ struct completion clock_accepted;
+ wait_queue_head_t hwdep_wait;
+ u32 notification_bits;
+ struct fw_iso_resources resources;
+ struct amdtp_out_stream stream;
+};
+
+MODULE_DESCRIPTION("DICE driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+static const unsigned int dice_rates[] = {
+ /* mode 0 */
+ [0] = 32000,
+ [1] = 44100,
+ [2] = 48000,
+ /* mode 1 */
+ [3] = 88200,
+ [4] = 96000,
+ /* mode 2 */
+ [5] = 176400,
+ [6] = 192000,
+};
+
+static unsigned int rate_to_index(unsigned int rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
+ if (dice_rates[i] == rate)
+ return i;
+
+ return 0;
+}
+
+static unsigned int rate_index_to_mode(unsigned int rate_index)
+{
+ return ((int)rate_index - 1) / 2;
+}
+
+static void dice_lock_changed(struct dice *dice)
+{
+ dice->dev_lock_changed = true;
+ wake_up(&dice->hwdep_wait);
+}
+
+static int dice_try_lock(struct dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count < 0) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (dice->dev_lock_count++ == 0)
+ dice_lock_changed(dice);
+ err = 0;
+
+out:
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static void dice_unlock(struct dice *dice)
+{
+ spin_lock_irq(&dice->lock);
+
+ if (WARN_ON(dice->dev_lock_count <= 0))
+ goto out;
+
+ if (--dice->dev_lock_count == 0)
+ dice_lock_changed(dice);
+
+out:
+ spin_unlock_irq(&dice->lock);
+}
+
+static inline u64 global_address(struct dice *dice, unsigned int offset)
+{
+ return DICE_PRIVATE_SPACE + dice->global_offset + offset;
+}
+
+// TODO: rx index
+static inline u64 rx_address(struct dice *dice, unsigned int offset)
+{
+ return DICE_PRIVATE_SPACE + dice->rx_offset + offset;
+}
+
+static int dice_owner_set(struct dice *dice)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+ int err, errors = 0;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ for (;;) {
+ buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
+ buffer[1] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+
+ dice->owner_generation = device->generation;
+ smp_rmb(); /* node_id vs. generation */
+ err = snd_fw_transaction(dice->unit,
+ TCODE_LOCK_COMPARE_SWAP,
+ global_address(dice, GLOBAL_OWNER),
+ buffer, 2 * 8,
+ FW_FIXED_GENERATION |
+ dice->owner_generation);
+
+ if (err == 0) {
+ if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
+ dev_err(&dice->unit->device,
+ "device is already in use\n");
+ err = -EBUSY;
+ }
+ break;
+ }
+ if (err != -EAGAIN || ++errors >= 3)
+ break;
+
+ msleep(20);
+ }
+
+ kfree(buffer);
+
+ return err;
+}
+
+static int dice_owner_update(struct dice *dice)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+ int err;
+
+ if (dice->owner_generation == -1)
+ return 0;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
+ buffer[1] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+
+ dice->owner_generation = device->generation;
+ smp_rmb(); /* node_id vs. generation */
+ err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
+ global_address(dice, GLOBAL_OWNER),
+ buffer, 2 * 8,
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ if (err == 0) {
+ if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
+ dev_err(&dice->unit->device,
+ "device is already in use\n");
+ err = -EBUSY;
+ }
+ } else if (err == -EAGAIN) {
+ err = 0; /* try again later */
+ }
+
+ kfree(buffer);
+
+ if (err < 0)
+ dice->owner_generation = -1;
+
+ return err;
+}
+
+static void dice_owner_clear(struct dice *dice)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (!buffer)
+ return;
+
+ buffer[0] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+ buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
+ snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
+ global_address(dice, GLOBAL_OWNER),
+ buffer, 2 * 8, FW_QUIET |
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ kfree(buffer);
+
+ dice->owner_generation = -1;
+}
+
+static int dice_enable_set(struct dice *dice)
+{
+ __be32 value;
+ int err;
+
+ value = cpu_to_be32(1);
+ err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ global_address(dice, GLOBAL_ENABLE),
+ &value, 4,
+ FW_FIXED_GENERATION | dice->owner_generation);
+ if (err < 0)
+ return err;
+
+ dice->global_enabled = true;
+
+ return 0;
+}
+
+static void dice_enable_clear(struct dice *dice)
+{
+ __be32 value;
+
+ if (!dice->global_enabled)
+ return;
+
+ value = 0;
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ global_address(dice, GLOBAL_ENABLE),
+ &value, 4, FW_QUIET |
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ dice->global_enabled = false;
+}
+
+static void dice_notification(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, unsigned long long offset,
+ void *data, size_t length, void *callback_data)
+{
+ struct dice *dice = callback_data;
+ u32 bits;
+ unsigned long flags;
+
+ if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
+ fw_send_response(card, request, RCODE_TYPE_ERROR);
+ return;
+ }
+ if ((offset & 3) != 0) {
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ return;
+ }
+
+ bits = be32_to_cpup(data);
+
+ spin_lock_irqsave(&dice->lock, flags);
+ dice->notification_bits |= bits;
+ spin_unlock_irqrestore(&dice->lock, flags);
+
+ fw_send_response(card, request, RCODE_COMPLETE);
+
+ if (bits & NOTIFY_CLOCK_ACCEPTED)
+ complete(&dice->clock_accepted);
+ wake_up(&dice->hwdep_wait);
+}
+
+static int dice_rate_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct dice *dice = rule->private;
+ const struct snd_interval *channels =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *rate =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval allowed_rates = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, mode;
+
+ for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) {
+ mode = rate_index_to_mode(i);
+ if ((dice->clock_caps & (1 << i)) &&
+ snd_interval_test(channels, dice->rx_channels[mode])) {
+ allowed_rates.min = min(allowed_rates.min,
+ dice_rates[i]);
+ allowed_rates.max = max(allowed_rates.max,
+ dice_rates[i]);
+ }
+ }
+
+ return snd_interval_refine(rate, &allowed_rates);
+}
+
+static int dice_channels_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct dice *dice = rule->private;
+ const struct snd_interval *rate =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval allowed_channels = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, mode;
+
+ for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
+ if ((dice->clock_caps & (1 << i)) &&
+ snd_interval_test(rate, dice_rates[i])) {
+ mode = rate_index_to_mode(i);
+ allowed_channels.min = min(allowed_channels.min,
+ dice->rx_channels[mode]);
+ allowed_channels.max = max(allowed_channels.max,
+ dice->rx_channels[mode]);
+ }
+
+ return snd_interval_refine(channels, &allowed_channels);
+}
+
+static int dice_open(struct snd_pcm_substream *substream)
+{
+ static const struct snd_pcm_hardware hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+ .formats = AMDTP_OUT_PCM_FORMAT_BITS,
+ .channels_min = UINT_MAX,
+ .channels_max = 0,
+ .buffer_bytes_max = 16 * 1024 * 1024,
+ .period_bytes_min = 1,
+ .period_bytes_max = UINT_MAX,
+ .periods_min = 1,
+ .periods_max = UINT_MAX,
+ };
+ struct dice *dice = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned int i;
+ int err;
+
+ err = dice_try_lock(dice);
+ if (err < 0)
+ goto error;
+
+ runtime->hw = hardware;
+
+ for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
+ if (dice->clock_caps & (1 << i))
+ runtime->hw.rates |=
+ snd_pcm_rate_to_rate_bit(dice_rates[i]);
+ snd_pcm_limit_hw_rates(runtime);
+
+ for (i = 0; i < 3; ++i)
+ if (dice->rx_channels[i]) {
+ runtime->hw.channels_min = min(runtime->hw.channels_min,
+ dice->rx_channels[i]);
+ runtime->hw.channels_max = max(runtime->hw.channels_max,
+ dice->rx_channels[i]);
+ }
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ dice_rate_constraint, dice,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto err_lock;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ dice_channels_constraint, dice,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto err_lock;
+
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
+ if (err < 0)
+ goto err_lock;
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
+ if (err < 0)
+ goto err_lock;
+
+ err = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ 5000, UINT_MAX);
+ if (err < 0)
+ goto err_lock;
+
+ err = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+ if (err < 0)
+ goto err_lock;
+
+ return 0;
+
+err_lock:
+ dice_unlock(dice);
+error:
+ return err;
+}
+
+static int dice_close(struct snd_pcm_substream *substream)
+{
+ struct dice *dice = substream->private_data;
+
+ dice_unlock(dice);
+
+ return 0;
+}
+
+static int dice_stream_start_packets(struct dice *dice)
+{
+ int err;
+
+ if (amdtp_out_stream_running(&dice->stream))
+ return 0;
+
+ err = amdtp_out_stream_start(&dice->stream, dice->resources.channel,
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ return err;
+
+ err = dice_enable_set(dice);
+ if (err < 0) {
+ amdtp_out_stream_stop(&dice->stream);
+ return err;
+ }
+
+ return 0;
+}
+
+static int dice_stream_start(struct dice *dice)
+{
+ __be32 channel;
+ int err;
+
+ if (!dice->resources.allocated) {
+ err = fw_iso_resources_allocate(&dice->resources,
+ amdtp_out_stream_get_max_payload(&dice->stream),
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ goto error;
+
+ channel = cpu_to_be32(dice->resources.channel);
+ err = snd_fw_transaction(dice->unit,
+ TCODE_WRITE_QUADLET_REQUEST,
+ rx_address(dice, RX_ISOCHRONOUS),
+ &channel, 4, 0);
+ if (err < 0)
+ goto err_resources;
+ }
+
+ err = dice_stream_start_packets(dice);
+ if (err < 0)
+ goto err_rx_channel;
+
+ return 0;
+
+err_rx_channel:
+ channel = cpu_to_be32((u32)-1);
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
+err_resources:
+ fw_iso_resources_free(&dice->resources);
+error:
+ return err;
+}
+
+static void dice_stream_stop_packets(struct dice *dice)
+{
+ if (amdtp_out_stream_running(&dice->stream)) {
+ dice_enable_clear(dice);
+ amdtp_out_stream_stop(&dice->stream);
+ }
+}
+
+static void dice_stream_stop(struct dice *dice)
+{
+ __be32 channel;
+
+ dice_stream_stop_packets(dice);
+
+ if (!dice->resources.allocated)
+ return;
+
+ channel = cpu_to_be32((u32)-1);
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
+
+ fw_iso_resources_free(&dice->resources);
+}
+
+static int dice_change_rate(struct dice *dice, unsigned int clock_rate)
+{
+ __be32 value;
+ int err;
+
+ reinit_completion(&dice->clock_accepted);
+
+ value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1);
+ err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ global_address(dice, GLOBAL_CLOCK_SELECT),
+ &value, 4, 0);
+ if (err < 0)
+ return err;
+
+ if (!wait_for_completion_timeout(&dice->clock_accepted,
+ msecs_to_jiffies(100)))
+ dev_warn(&dice->unit->device, "clock change timed out\n");
+
+ return 0;
+}
+
+static int dice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct dice *dice = substream->private_data;
+ unsigned int rate_index, mode;
+ int err;
+
+ mutex_lock(&dice->mutex);
+ dice_stream_stop(dice);
+ mutex_unlock(&dice->mutex);
+
+ err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+ if (err < 0)
+ return err;
+
+ rate_index = rate_to_index(params_rate(hw_params));
+ err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
+ if (err < 0)
+ return err;
+
+ mode = rate_index_to_mode(rate_index);
+ amdtp_out_stream_set_parameters(&dice->stream,
+ params_rate(hw_params),
+ params_channels(hw_params),
+ dice->rx_midi_ports[mode]);
+ amdtp_out_stream_set_pcm_format(&dice->stream,
+ params_format(hw_params));
+
+ return 0;
+}
+
+static int dice_hw_free(struct snd_pcm_substream *substream)
+{
+ struct dice *dice = substream->private_data;
+
+ mutex_lock(&dice->mutex);
+ dice_stream_stop(dice);
+ mutex_unlock(&dice->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int dice_prepare(struct snd_pcm_substream *substream)
+{
+ struct dice *dice = substream->private_data;
+ int err;
+
+ mutex_lock(&dice->mutex);
+
+ if (amdtp_out_streaming_error(&dice->stream))
+ dice_stream_stop_packets(dice);
+
+ err = dice_stream_start(dice);
+ if (err < 0) {
+ mutex_unlock(&dice->mutex);
+ return err;
+ }
+
+ mutex_unlock(&dice->mutex);
+
+ amdtp_out_stream_pcm_prepare(&dice->stream);
+
+ return 0;
+}
+
+static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct dice *dice = substream->private_data;
+ struct snd_pcm_substream *pcm;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pcm = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pcm = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amdtp_out_stream_pcm_trigger(&dice->stream, pcm);
+
+ return 0;
+}
+
+static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream)
+{
+ struct dice *dice = substream->private_data;
+
+ return amdtp_out_stream_pcm_pointer(&dice->stream);
+}
+
+static int dice_create_pcm(struct dice *dice)
+{
+ static struct snd_pcm_ops ops = {
+ .open = dice_open,
+ .close = dice_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = dice_hw_params,
+ .hw_free = dice_hw_free,
+ .prepare = dice_prepare,
+ .trigger = dice_trigger,
+ .pointer = dice_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = dice;
+ strcpy(pcm->name, dice->card->shortname);
+ pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops;
+
+ return 0;
+}
+
+static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
+ long count, loff_t *offset)
+{
+ struct dice *dice = hwdep->private_data;
+ DEFINE_WAIT(wait);
+ union snd_firewire_event event;
+
+ spin_lock_irq(&dice->lock);
+
+ while (!dice->dev_lock_changed && dice->notification_bits == 0) {
+ prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&dice->lock);
+ schedule();
+ finish_wait(&dice->hwdep_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ spin_lock_irq(&dice->lock);
+ }
+
+ memset(&event, 0, sizeof(event));
+ if (dice->dev_lock_changed) {
+ event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+ event.lock_status.status = dice->dev_lock_count > 0;
+ dice->dev_lock_changed = false;
+
+ count = min(count, (long)sizeof(event.lock_status));
+ } else {
+ event.dice_notification.type = SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
+ event.dice_notification.notification = dice->notification_bits;
+ dice->notification_bits = 0;
+
+ count = min(count, (long)sizeof(event.dice_notification));
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+ poll_table *wait)
+{
+ struct dice *dice = hwdep->private_data;
+ unsigned int events;
+
+ poll_wait(file, &dice->hwdep_wait, wait);
+
+ spin_lock_irq(&dice->lock);
+ if (dice->dev_lock_changed || dice->notification_bits != 0)
+ events = POLLIN | POLLRDNORM;
+ else
+ events = 0;
+ spin_unlock_irq(&dice->lock);
+
+ return events;
+}
+
+static int dice_hwdep_get_info(struct dice *dice, void __user *arg)
+{
+ struct fw_device *dev = fw_parent_device(dice->unit);
+ struct snd_firewire_get_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.type = SNDRV_FIREWIRE_TYPE_DICE;
+ info.card = dev->card->index;
+ *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+ *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+ strlcpy(info.device_name, dev_name(&dev->device),
+ sizeof(info.device_name));
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int dice_hwdep_lock(struct dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count == 0) {
+ dice->dev_lock_count = -1;
+ err = 0;
+ } else {
+ err = -EBUSY;
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static int dice_hwdep_unlock(struct dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count == -1) {
+ dice->dev_lock_count = 0;
+ err = 0;
+ } else {
+ err = -EBADFD;
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+ struct dice *dice = hwdep->private_data;
+
+ spin_lock_irq(&dice->lock);
+ if (dice->dev_lock_count == -1)
+ dice->dev_lock_count = 0;
+ spin_unlock_irq(&dice->lock);
+
+ return 0;
+}
+
+static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct dice *dice = hwdep->private_data;
+
+ switch (cmd) {
+ case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+ return dice_hwdep_get_info(dice, (void __user *)arg);
+ case SNDRV_FIREWIRE_IOCTL_LOCK:
+ return dice_hwdep_lock(dice);
+ case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+ return dice_hwdep_unlock(dice);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return dice_hwdep_ioctl(hwdep, file, cmd,
+ (unsigned long)compat_ptr(arg));
+}
+#else
+#define dice_hwdep_compat_ioctl NULL
+#endif
+
+static int dice_create_hwdep(struct dice *dice)
+{
+ static const struct snd_hwdep_ops ops = {
+ .read = dice_hwdep_read,
+ .release = dice_hwdep_release,
+ .poll = dice_hwdep_poll,
+ .ioctl = dice_hwdep_ioctl,
+ .ioctl_compat = dice_hwdep_compat_ioctl,
+ };
+ struct snd_hwdep *hwdep;
+ int err;
+
+ err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
+ if (err < 0)
+ return err;
+ strcpy(hwdep->name, "DICE");
+ hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
+ hwdep->ops = ops;
+ hwdep->private_data = dice;
+ hwdep->exclusive = true;
+
+ return 0;
+}
+
+static int dice_proc_read_mem(struct dice *dice, void *buffer,
+ unsigned int offset_q, unsigned int quadlets)
+{
+ unsigned int i;
+ int err;
+
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE + 4 * offset_q,
+ buffer, 4 * quadlets, 0);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < quadlets; ++i)
+ be32_to_cpus(&((u32 *)buffer)[i]);
+
+ return 0;
+}
+
+static const char *str_from_array(const char *const strs[], unsigned int count,
+ unsigned int i)
+{
+ if (i < count)
+ return strs[i];
+ else
+ return "(unknown)";
+}
+
+static void dice_proc_fixup_string(char *s, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i += 4)
+ cpu_to_le32s((u32 *)(s + i));
+
+ for (i = 0; i < size - 2; ++i) {
+ if (s[i] == '\0')
+ return;
+ if (s[i] == '\\' && s[i + 1] == '\\') {
+ s[i + 2] = '\0';
+ return;
+ }
+ }
+ s[size - 1] = '\0';
+}
+
+static void dice_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ static const char *const section_names[5] = {
+ "global", "tx", "rx", "ext_sync", "unused2"
+ };
+ static const char *const clock_sources[] = {
+ "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
+ "wc", "arx1", "arx2", "arx3", "arx4", "internal"
+ };
+ static const char *const rates[] = {
+ "32000", "44100", "48000", "88200", "96000", "176400", "192000",
+ "any low", "any mid", "any high", "none"
+ };
+ struct dice *dice = entry->private_data;
+ u32 sections[ARRAY_SIZE(section_names) * 2];
+ struct {
+ u32 number;
+ u32 size;
+ } tx_rx_header;
+ union {
+ struct {
+ u32 owner_hi, owner_lo;
+ u32 notification;
+ char nick_name[NICK_NAME_SIZE];
+ u32 clock_select;
+ u32 enable;
+ u32 status;
+ u32 extended_status;
+ u32 sample_rate;
+ u32 version;
+ u32 clock_caps;
+ char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
+ } global;
+ struct {
+ u32 iso;
+ u32 number_audio;
+ u32 number_midi;
+ u32 speed;
+ char names[TX_NAMES_SIZE];
+ u32 ac3_caps;
+ u32 ac3_enable;
+ } tx;
+ struct {
+ u32 iso;
+ u32 seq_start;
+ u32 number_audio;
+ u32 number_midi;
+ char names[RX_NAMES_SIZE];
+ u32 ac3_caps;
+ u32 ac3_enable;
+ } rx;
+ struct {
+ u32 clock_source;
+ u32 locked;
+ u32 rate;
+ u32 adat_user_data;
+ } ext_sync;
+ } buf;
+ unsigned int quadlets, stream, i;
+
+ if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
+ return;
+ snd_iprintf(buffer, "sections:\n");
+ for (i = 0; i < ARRAY_SIZE(section_names); ++i)
+ snd_iprintf(buffer, " %s: offset %u, size %u\n",
+ section_names[i],
+ sections[i * 2], sections[i * 2 + 1]);
+
+ quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
+ if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
+ return;
+ snd_iprintf(buffer, "global:\n");
+ snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
+ buf.global.owner_hi >> 16,
+ buf.global.owner_hi & 0xffff, buf.global.owner_lo);
+ snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
+ dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
+ snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
+ snd_iprintf(buffer, " clock select: %s %s\n",
+ str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
+ buf.global.clock_select & CLOCK_SOURCE_MASK),
+ str_from_array(rates, ARRAY_SIZE(rates),
+ (buf.global.clock_select & CLOCK_RATE_MASK)
+ >> CLOCK_RATE_SHIFT));
+ snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
+ snd_iprintf(buffer, " status: %slocked %s\n",
+ buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
+ str_from_array(rates, ARRAY_SIZE(rates),
+ (buf.global.status &
+ STATUS_NOMINAL_RATE_MASK)
+ >> CLOCK_RATE_SHIFT));
+ snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
+ snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
+ snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
+ (buf.global.version >> 24) & 0xff,
+ (buf.global.version >> 16) & 0xff,
+ (buf.global.version >> 8) & 0xff,
+ (buf.global.version >> 0) & 0xff);
+ if (quadlets >= 90) {
+ snd_iprintf(buffer, " clock caps:");
+ for (i = 0; i <= 6; ++i)
+ if (buf.global.clock_caps & (1 << i))
+ snd_iprintf(buffer, " %s", rates[i]);
+ for (i = 0; i <= 12; ++i)
+ if (buf.global.clock_caps & (1 << (16 + i)))
+ snd_iprintf(buffer, " %s", clock_sources[i]);
+ snd_iprintf(buffer, "\n");
+ dice_proc_fixup_string(buf.global.clock_source_names,
+ CLOCK_SOURCE_NAMES_SIZE);
+ snd_iprintf(buffer, " clock source names: %s\n",
+ buf.global.clock_source_names);
+ }
+
+ if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
+ return;
+ quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
+ for (stream = 0; stream < tx_rx_header.number; ++stream) {
+ if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
+ stream * tx_rx_header.size,
+ quadlets) < 0)
+ break;
+ snd_iprintf(buffer, "tx %u:\n", stream);
+ snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
+ snd_iprintf(buffer, " audio channels: %u\n",
+ buf.tx.number_audio);
+ snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
+ snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
+ if (quadlets >= 68) {
+ dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
+ snd_iprintf(buffer, " names: %s\n", buf.tx.names);
+ }
+ if (quadlets >= 70) {
+ snd_iprintf(buffer, " ac3 caps: %08x\n",
+ buf.tx.ac3_caps);
+ snd_iprintf(buffer, " ac3 enable: %08x\n",
+ buf.tx.ac3_enable);
+ }
+ }
+
+ if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
+ return;
+ quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
+ for (stream = 0; stream < tx_rx_header.number; ++stream) {
+ if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
+ stream * tx_rx_header.size,
+ quadlets) < 0)
+ break;
+ snd_iprintf(buffer, "rx %u:\n", stream);
+ snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
+ snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start);
+ snd_iprintf(buffer, " audio channels: %u\n",
+ buf.rx.number_audio);
+ snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
+ if (quadlets >= 68) {
+ dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
+ snd_iprintf(buffer, " names: %s\n", buf.rx.names);
+ }
+ if (quadlets >= 70) {
+ snd_iprintf(buffer, " ac3 caps: %08x\n",
+ buf.rx.ac3_caps);
+ snd_iprintf(buffer, " ac3 enable: %08x\n",
+ buf.rx.ac3_enable);
+ }
+ }
+
+ quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
+ if (quadlets >= 4) {
+ if (dice_proc_read_mem(dice, &buf.ext_sync,
+ sections[6], 4) < 0)
+ return;
+ snd_iprintf(buffer, "ext status:\n");
+ snd_iprintf(buffer, " clock source: %s\n",
+ str_from_array(clock_sources,
+ ARRAY_SIZE(clock_sources),
+ buf.ext_sync.clock_source));
+ snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
+ snd_iprintf(buffer, " rate: %s\n",
+ str_from_array(rates, ARRAY_SIZE(rates),
+ buf.ext_sync.rate));
+ snd_iprintf(buffer, " adat user data: ");
+ if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
+ snd_iprintf(buffer, "-\n");
+ else
+ snd_iprintf(buffer, "%x\n",
+ buf.ext_sync.adat_user_data);
+ }
+}
+
+static void dice_create_proc(struct dice *dice)
+{
+ struct snd_info_entry *entry;
+
+ if (!snd_card_proc_new(dice->card, "dice", &entry))
+ snd_info_set_text_ops(entry, dice, dice_proc_read);
+}
+
+static void dice_card_free(struct snd_card *card)
+{
+ struct dice *dice = card->private_data;
+
+ amdtp_out_stream_destroy(&dice->stream);
+ fw_core_remove_address_handler(&dice->notification_handler);
+ mutex_destroy(&dice->mutex);
+}
+
+#define OUI_WEISS 0x001c6a
+
+#define DICE_CATEGORY_ID 0x04
+#define WEISS_CATEGORY_ID 0x00
+
+static int dice_interface_check(struct fw_unit *unit)
+{
+ static const int min_values[10] = {
+ 10, 0x64 / 4,
+ 10, 0x18 / 4,
+ 10, 0x18 / 4,
+ 0, 0,
+ 0, 0,
+ };
+ struct fw_device *device = fw_parent_device(unit);
+ struct fw_csr_iterator it;
+ int key, value, vendor = -1, model = -1, err;
+ unsigned int category, i;
+ __be32 pointers[ARRAY_SIZE(min_values)];
+ __be32 tx_data[4];
+ __be32 version;
+
+ /*
+ * Check that GUID and unit directory are constructed according to DICE
+ * rules, i.e., that the specifier ID is the GUID's OUI, and that the
+ * GUID chip ID consists of the 8-bit category ID, the 10-bit product
+ * ID, and a 22-bit serial number.
+ */
+ fw_csr_iterator_init(&it, unit->directory);
+ while (fw_csr_iterator_next(&it, &key, &value)) {
+ switch (key) {
+ case CSR_SPECIFIER_ID:
+ vendor = value;
+ break;
+ case CSR_MODEL:
+ model = value;
+ break;
+ }
+ }
+ if (vendor == OUI_WEISS)
+ category = WEISS_CATEGORY_ID;
+ else
+ category = DICE_CATEGORY_ID;
+ if (device->config_rom[3] != ((vendor << 8) | category) ||
+ device->config_rom[4] >> 22 != model)
+ return -ENODEV;
+
+ /*
+ * Check that the sub address spaces exist and are located inside the
+ * private address space. The minimum values are chosen so that all
+ * minimally required registers are included.
+ */
+ err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE,
+ pointers, sizeof(pointers), 0);
+ if (err < 0)
+ return -ENODEV;
+ for (i = 0; i < ARRAY_SIZE(pointers); ++i) {
+ value = be32_to_cpu(pointers[i]);
+ if (value < min_values[i] || value >= 0x40000)
+ return -ENODEV;
+ }
+
+ /* We support playback only. Let capture devices be handled by FFADO. */
+ err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE +
+ be32_to_cpu(pointers[2]) * 4,
+ tx_data, sizeof(tx_data), 0);
+ if (err < 0 || (tx_data[0] && tx_data[3]))
+ return -ENODEV;
+
+ /*
+ * Check that the implemented DICE driver specification major version
+ * number matches.
+ */
+ err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+ DICE_PRIVATE_SPACE +
+ be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
+ &version, 4, 0);
+ if (err < 0)
+ return -ENODEV;
+ if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
+ dev_err(&unit->device,
+ "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int highest_supported_mode_rate(struct dice *dice, unsigned int mode)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i)
+ if ((dice->clock_caps & (1 << i)) &&
+ rate_index_to_mode(i) == mode)
+ return i;
+
+ return -1;
+}
+
+static int dice_read_mode_params(struct dice *dice, unsigned int mode)
+{
+ __be32 values[2];
+ int rate_index, err;
+
+ rate_index = highest_supported_mode_rate(dice, mode);
+ if (rate_index < 0) {
+ dice->rx_channels[mode] = 0;
+ dice->rx_midi_ports[mode] = 0;
+ return 0;
+ }
+
+ err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
+ if (err < 0)
+ return err;
+
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ rx_address(dice, RX_NUMBER_AUDIO),
+ values, 2 * 4, 0);
+ if (err < 0)
+ return err;
+
+ dice->rx_channels[mode] = be32_to_cpu(values[0]);
+ dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
+
+ return 0;
+}
+
+static int dice_read_params(struct dice *dice)
+{
+ __be32 pointers[6];
+ __be32 value;
+ int mode, err;
+
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE,
+ pointers, sizeof(pointers), 0);
+ if (err < 0)
+ return err;
+
+ dice->global_offset = be32_to_cpu(pointers[0]) * 4;
+ dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
+
+ /* some very old firmwares don't tell about their clock support */
+ if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) {
+ err = snd_fw_transaction(
+ dice->unit, TCODE_READ_QUADLET_REQUEST,
+ global_address(dice, GLOBAL_CLOCK_CAPABILITIES),
+ &value, 4, 0);
+ if (err < 0)
+ return err;
+ dice->clock_caps = be32_to_cpu(value);
+ } else {
+ /* this should be supported by any device */
+ dice->clock_caps = CLOCK_CAP_RATE_44100 |
+ CLOCK_CAP_RATE_48000 |
+ CLOCK_CAP_SOURCE_ARX1 |
+ CLOCK_CAP_SOURCE_INTERNAL;
+ }
+
+ for (mode = 2; mode >= 0; --mode) {
+ err = dice_read_mode_params(dice, mode);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static void dice_card_strings(struct dice *dice)
+{
+ struct snd_card *card = dice->card;
+ struct fw_device *dev = fw_parent_device(dice->unit);
+ char vendor[32], model[32];
+ unsigned int i;
+ int err;
+
+ strcpy(card->driver, "DICE");
+
+ strcpy(card->shortname, "DICE");
+ BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ global_address(dice, GLOBAL_NICK_NAME),
+ card->shortname, sizeof(card->shortname), 0);
+ if (err >= 0) {
+ /* DICE strings are returned in "always-wrong" endianness */
+ BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
+ for (i = 0; i < sizeof(card->shortname); i += 4)
+ swab32s((u32 *)&card->shortname[i]);
+ card->shortname[sizeof(card->shortname) - 1] = '\0';
+ }
+
+ strcpy(vendor, "?");
+ fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
+ strcpy(model, "?");
+ fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s %s (serial %u) at %s, S%d",
+ vendor, model, dev->config_rom[4] & 0x3fffff,
+ dev_name(&dice->unit->device), 100 << dev->max_speed);
+
+ strcpy(card->mixername, "DICE");
+}
+
+static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+{
+ struct snd_card *card;
+ struct dice *dice;
+ __be32 clock_sel;
+ int err;
+
+ err = dice_interface_check(unit);
+ if (err < 0)
+ return err;
+
+ err = snd_card_create(-1, NULL, THIS_MODULE, sizeof(*dice), &card);
+ if (err < 0)
+ return err;
+ snd_card_set_dev(card, &unit->device);
+
+ dice = card->private_data;
+ dice->card = card;
+ spin_lock_init(&dice->lock);
+ mutex_init(&dice->mutex);
+ dice->unit = unit;
+ init_completion(&dice->clock_accepted);
+ init_waitqueue_head(&dice->hwdep_wait);
+
+ dice->notification_handler.length = 4;
+ dice->notification_handler.address_callback = dice_notification;
+ dice->notification_handler.callback_data = dice;
+ err = fw_core_add_address_handler(&dice->notification_handler,
+ &fw_high_memory_region);
+ if (err < 0)
+ goto err_mutex;
+
+ err = dice_owner_set(dice);
+ if (err < 0)
+ goto err_notification_handler;
+
+ err = dice_read_params(dice);
+ if (err < 0)
+ goto err_owner;
+
+ err = fw_iso_resources_init(&dice->resources, unit);
+ if (err < 0)
+ goto err_owner;
+ dice->resources.channels_mask = 0x00000000ffffffffuLL;
+
+ err = amdtp_out_stream_init(&dice->stream, unit,
+ CIP_BLOCKING | CIP_HI_DUALWIRE);
+ if (err < 0)
+ goto err_resources;
+
+ card->private_free = dice_card_free;
+
+ dice_card_strings(dice);
+
+ err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+ global_address(dice, GLOBAL_CLOCK_SELECT),
+ &clock_sel, 4, 0);
+ if (err < 0)
+ goto error;
+ clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK);
+ clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1);
+ err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST,
+ global_address(dice, GLOBAL_CLOCK_SELECT),
+ &clock_sel, 4, 0);
+ if (err < 0)
+ goto error;
+
+ err = dice_create_pcm(dice);
+ if (err < 0)
+ goto error;
+
+ err = dice_create_hwdep(dice);
+ if (err < 0)
+ goto error;
+
+ dice_create_proc(dice);
+
+ err = snd_card_register(card);
+ if (err < 0)
+ goto error;
+
+ dev_set_drvdata(&unit->device, dice);
+
+ return 0;
+
+err_resources:
+ fw_iso_resources_destroy(&dice->resources);
+err_owner:
+ dice_owner_clear(dice);
+err_notification_handler:
+ fw_core_remove_address_handler(&dice->notification_handler);
+err_mutex:
+ mutex_destroy(&dice->mutex);
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static void dice_remove(struct fw_unit *unit)
+{
+ struct dice *dice = dev_get_drvdata(&unit->device);
+
+ amdtp_out_stream_pcm_abort(&dice->stream);
+
+ snd_card_disconnect(dice->card);
+
+ mutex_lock(&dice->mutex);
+
+ dice_stream_stop(dice);
+ dice_owner_clear(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ snd_card_free_when_closed(dice->card);
+}
+
+static void dice_bus_reset(struct fw_unit *unit)
+{
+ struct dice *dice = dev_get_drvdata(&unit->device);
+
+ /*
+ * On a bus reset, the DICE firmware disables streaming and then goes
+ * off contemplating its own navel for hundreds of milliseconds before
+ * it can react to any of our attempts to reenable streaming. This
+ * means that we lose synchronization anyway, so we force our streams
+ * to stop so that the application can restart them in an orderly
+ * manner.
+ */
+ amdtp_out_stream_pcm_abort(&dice->stream);
+
+ mutex_lock(&dice->mutex);
+
+ dice->global_enabled = false;
+ dice_stream_stop_packets(dice);
+
+ dice_owner_update(dice);
+
+ fw_iso_resources_update(&dice->resources);
+
+ mutex_unlock(&dice->mutex);
+}
+
+#define DICE_INTERFACE 0x000001
+
+static const struct ieee1394_device_id dice_id_table[] = {
+ {
+ .match_flags = IEEE1394_MATCH_VERSION,
+ .version = DICE_INTERFACE,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
+
+static struct fw_driver dice_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ },
+ .probe = dice_probe,
+ .update = dice_bus_reset,
+ .remove = dice_remove,
+ .id_table = dice_id_table,
+};
+
+static int __init alsa_dice_init(void)
+{
+ return driver_register(&dice_driver.driver);
+}
+
+static void __exit alsa_dice_exit(void)
+{
+ driver_unregister(&dice_driver.driver);
+}
+
+module_init(alsa_dice_init);
+module_exit(alsa_dice_exit);
diff --git a/sound/firewire/fcp.c b/sound/firewire/fcp.c
index ec578b5ad8da..860c08073c59 100644
--- a/sound/firewire/fcp.c
+++ b/sound/firewire/fcp.c
@@ -90,7 +90,7 @@ int fcp_avc_transaction(struct fw_unit *unit,
: TCODE_WRITE_BLOCK_REQUEST;
ret = snd_fw_transaction(t.unit, tcode,
CSR_REGISTER_BASE + CSR_FCP_COMMAND,
- (void *)command, command_size);
+ (void *)command, command_size, 0);
if (ret < 0)
break;
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index 58a5afefdc69..fd42e6b315e6 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -217,7 +217,7 @@ static void isight_packet(struct fw_iso_context *context, u32 cycle,
static int isight_connect(struct isight *isight)
{
- int ch, err, rcode, errors = 0;
+ int ch, err;
__be32 value;
retry_after_bus_reset:
@@ -230,27 +230,19 @@ retry_after_bus_reset:
}
value = cpu_to_be32(ch | (isight->device->max_speed << SPEED_SHIFT));
- for (;;) {
- rcode = fw_run_transaction(
- isight->device->card,
- TCODE_WRITE_QUADLET_REQUEST,
- isight->device->node_id,
- isight->resources.generation,
- isight->device->max_speed,
- isight->audio_base + REG_ISO_TX_CONFIG,
- &value, 4);
- if (rcode == RCODE_COMPLETE) {
- return 0;
- } else if (rcode == RCODE_GENERATION) {
- fw_iso_resources_free(&isight->resources);
- goto retry_after_bus_reset;
- } else if (rcode_is_permanent_error(rcode) || ++errors >= 3) {
- err = -EIO;
- goto err_resources;
- }
- msleep(5);
+ err = snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
+ isight->audio_base + REG_ISO_TX_CONFIG,
+ &value, 4, FW_FIXED_GENERATION |
+ isight->resources.generation);
+ if (err == -EAGAIN) {
+ fw_iso_resources_free(&isight->resources);
+ goto retry_after_bus_reset;
+ } else if (err < 0) {
+ goto err_resources;
}
+ return 0;
+
err_resources:
fw_iso_resources_free(&isight->resources);
error:
@@ -315,17 +307,19 @@ static int isight_hw_params(struct snd_pcm_substream *substream,
static int reg_read(struct isight *isight, int offset, __be32 *value)
{
return snd_fw_transaction(isight->unit, TCODE_READ_QUADLET_REQUEST,
- isight->audio_base + offset, value, 4);
+ isight->audio_base + offset, value, 4, 0);
}
static int reg_write(struct isight *isight, int offset, __be32 value)
{
return snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
- isight->audio_base + offset, &value, 4);
+ isight->audio_base + offset, &value, 4, 0);
}
static void isight_stop_streaming(struct isight *isight)
{
+ __be32 value;
+
if (!isight->context)
return;
@@ -333,7 +327,10 @@ static void isight_stop_streaming(struct isight *isight)
fw_iso_context_destroy(isight->context);
isight->context = NULL;
fw_iso_resources_free(&isight->resources);
- reg_write(isight, REG_AUDIO_ENABLE, 0);
+ value = 0;
+ snd_fw_transaction(isight->unit, TCODE_WRITE_QUADLET_REQUEST,
+ isight->audio_base + REG_AUDIO_ENABLE,
+ &value, 4, FW_QUIET);
}
static int isight_hw_free(struct snd_pcm_substream *substream)
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
index 14eb41498372..7409edba9f06 100644
--- a/sound/firewire/lib.c
+++ b/sound/firewire/lib.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include "lib.h"
-#define ERROR_RETRY_DELAY_MS 5
+#define ERROR_RETRY_DELAY_MS 20
/**
* snd_fw_transaction - send a request and wait for its completion
@@ -20,6 +20,9 @@
* @offset: the address in the target's address space
* @buffer: input/output data
* @length: length of @buffer
+ * @flags: use %FW_FIXED_GENERATION and add the generation value to attempt the
+ * request only in that generation; use %FW_QUIET to suppress error
+ * messages
*
* Submits an asynchronous request to the target device, and waits for the
* response. The node ID and the current generation are derived from @unit.
@@ -27,14 +30,18 @@
* Returns zero on success, or a negative error code.
*/
int snd_fw_transaction(struct fw_unit *unit, int tcode,
- u64 offset, void *buffer, size_t length)
+ u64 offset, void *buffer, size_t length,
+ unsigned int flags)
{
struct fw_device *device = fw_parent_device(unit);
int generation, rcode, tries = 0;
+ generation = flags & FW_GENERATION_MASK;
for (;;) {
- generation = device->generation;
- smp_rmb(); /* node_id vs. generation */
+ if (!(flags & FW_FIXED_GENERATION)) {
+ generation = device->generation;
+ smp_rmb(); /* node_id vs. generation */
+ }
rcode = fw_run_transaction(device->card, tcode,
device->node_id, generation,
device->max_speed, offset,
@@ -43,9 +50,14 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode,
if (rcode == RCODE_COMPLETE)
return 0;
+ if (rcode == RCODE_GENERATION && (flags & FW_FIXED_GENERATION))
+ return -EAGAIN;
+
if (rcode_is_permanent_error(rcode) || ++tries >= 3) {
- dev_err(&unit->device, "transaction failed: %s\n",
- fw_rcode_string(rcode));
+ if (!(flags & FW_QUIET))
+ dev_err(&unit->device,
+ "transaction failed: %s\n",
+ fw_rcode_string(rcode));
return -EIO;
}
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h
index aef301476ea9..02cfabc9c3c4 100644
--- a/sound/firewire/lib.h
+++ b/sound/firewire/lib.h
@@ -6,8 +6,13 @@
struct fw_unit;
+#define FW_GENERATION_MASK 0x00ff
+#define FW_FIXED_GENERATION 0x0100
+#define FW_QUIET 0x0200
+
int snd_fw_transaction(struct fw_unit *unit, int tcode,
- u64 offset, void *buffer, size_t length);
+ u64 offset, void *buffer, size_t length,
+ unsigned int flags);
/* returns true if retrying the transaction would not make sense */
static inline bool rcode_is_permanent_error(int rcode)
diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c
index 505fc8123199..858023cf4298 100644
--- a/sound/firewire/scs1x.c
+++ b/sound/firewire/scs1x.c
@@ -369,7 +369,7 @@ static int scs_init_hss_address(struct scs *scs)
data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
scs->hss_handler.offset);
err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
- HSS1394_ADDRESS, &data, 8);
+ HSS1394_ADDRESS, &data, 8, 0);
if (err < 0)
dev_err(&scs->unit->device, "HSS1394 communication failed\n");
@@ -455,12 +455,16 @@ err_card:
static void scs_update(struct fw_unit *unit)
{
struct scs *scs = dev_get_drvdata(&unit->device);
+ int generation;
__be64 data;
data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) |
scs->hss_handler.offset);
+ generation = fw_parent_device(unit)->generation;
+ smp_rmb(); /* node_id vs. generation */
snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST,
- HSS1394_ADDRESS, &data, 8);
+ HSS1394_ADDRESS, &data, 8,
+ FW_FIXED_GENERATION | generation);
}
static void scs_remove(struct fw_unit *unit)
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
index fe9e6e2f2c5b..cc8bc3a51bc1 100644
--- a/sound/firewire/speakers.c
+++ b/sound/firewire/speakers.c
@@ -52,7 +52,6 @@ struct fwspk {
struct mutex mutex;
struct cmp_connection connection;
struct amdtp_out_stream stream;
- bool stream_running;
bool mute;
s16 volume[6];
s16 volume_min;
@@ -188,10 +187,9 @@ static int fwspk_close(struct snd_pcm_substream *substream)
static void fwspk_stop_stream(struct fwspk *fwspk)
{
- if (fwspk->stream_running) {
+ if (amdtp_out_stream_running(&fwspk->stream)) {
amdtp_out_stream_stop(&fwspk->stream);
cmp_connection_break(&fwspk->connection);
- fwspk->stream_running = false;
}
}
@@ -246,8 +244,10 @@ static int fwspk_hw_params(struct snd_pcm_substream *substream,
if (err < 0)
goto error;
- amdtp_out_stream_set_rate(&fwspk->stream, params_rate(hw_params));
- amdtp_out_stream_set_pcm(&fwspk->stream, params_channels(hw_params));
+ amdtp_out_stream_set_parameters(&fwspk->stream,
+ params_rate(hw_params),
+ params_channels(hw_params),
+ 0);
amdtp_out_stream_set_pcm_format(&fwspk->stream,
params_format(hw_params));
@@ -285,7 +285,7 @@ static int fwspk_prepare(struct snd_pcm_substream *substream)
if (amdtp_out_streaming_error(&fwspk->stream))
fwspk_stop_stream(fwspk);
- if (!fwspk->stream_running) {
+ if (!amdtp_out_stream_running(&fwspk->stream)) {
err = cmp_connection_establish(&fwspk->connection,
amdtp_out_stream_get_max_payload(&fwspk->stream));
if (err < 0)
@@ -296,8 +296,6 @@ static int fwspk_prepare(struct snd_pcm_substream *substream)
fwspk->connection.speed);
if (err < 0)
goto err_connection;
-
- fwspk->stream_running = true;
}
mutex_unlock(&fwspk->mutex);
@@ -647,7 +645,7 @@ static u32 fwspk_read_firmware_version(struct fw_unit *unit)
int err;
err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- OXFORD_FIRMWARE_ID_ADDRESS, &data, 4);
+ OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0);
return err >= 0 ? be32_to_cpu(data) : 0;
}
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index 5bf4fca19e48..15ae0250eace 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -60,7 +60,7 @@ static void reg_dump(struct ak4114 *ak4114)
printk(KERN_DEBUG "AK4114 REG DUMP:\n");
for (i = 0; i < 0x20; i++)
- printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < sizeof(ak4114->regmap) ? ak4114->regmap[i] : 0);
+ printk(KERN_DEBUG "reg[%02x] = %02x (%02x)\n", i, reg_read(ak4114, i), i < ARRAY_SIZE(ak4114->regmap) ? ak4114->regmap[i] : 0);
}
#endif
@@ -81,7 +81,7 @@ static int snd_ak4114_dev_free(struct snd_device *device)
int snd_ak4114_create(struct snd_card *card,
ak4114_read_t *read, ak4114_write_t *write,
- const unsigned char pgm[7], const unsigned char txcsb[5],
+ const unsigned char pgm[6], const unsigned char txcsb[5],
void *private_data, struct ak4114 **r_ak4114)
{
struct ak4114 *chip;
@@ -101,7 +101,7 @@ int snd_ak4114_create(struct snd_card *card,
chip->private_data = private_data;
INIT_DELAYED_WORK(&chip->work, ak4114_stats);
- for (reg = 0; reg < 7; reg++)
+ for (reg = 0; reg < 6; reg++)
chip->regmap[reg] = pgm[reg];
for (reg = 0; reg < 5; reg++)
chip->txcsb[reg] = txcsb[reg];
@@ -142,7 +142,7 @@ static void ak4114_init_regs(struct ak4114 *chip)
/* release reset, but leave powerdown */
reg_write(chip, AK4114_REG_PWRDN, (old | AK4114_RST) & ~AK4114_PWN);
udelay(200);
- for (reg = 1; reg < 7; reg++)
+ for (reg = 1; reg < 6; reg++)
reg_write(chip, reg, chip->regmap[reg]);
for (reg = 0; reg < 5; reg++)
reg_write(chip, reg + AK4114_REG_TXCSB0, chip->txcsb[reg]);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index ed726d1569e8..f3735e64791c 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -583,7 +583,7 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
if (idx >= num_names)
return -EINVAL;
input_names = ak->adc_info[mixer_ch].input_names;
- strncpy(uinfo->value.enumerated.name, input_names[idx],
+ strlcpy(uinfo->value.enumerated.name, input_names[idx],
sizeof(uinfo->value.enumerated.name));
return 0;
}
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c
index f84f073fc1e8..ab6b2dc043f1 100644
--- a/sound/isa/cmi8328.c
+++ b/sound/isa/cmi8328.c
@@ -126,6 +126,7 @@ static void snd_cmi8328_cfg_write(u16 port, u8 reg, u8 val)
outb(val, port + 3); /* yes, value goes to the same port as index */
}
+#ifdef CONFIG_PM
static void snd_cmi8328_cfg_save(u16 port, u8 cfg[])
{
cfg[0] = snd_cmi8328_cfg_read(port, CFG1);
@@ -139,6 +140,7 @@ static void snd_cmi8328_cfg_restore(u16 port, u8 cfg[])
snd_cmi8328_cfg_write(port, CFG2, cfg[1]);
snd_cmi8328_cfg_write(port, CFG3, cfg[2]);
}
+#endif /* CONFIG_PM */
static int snd_cmi8328_mixer(struct snd_wss *chip)
{
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 81aeb934261a..0a90bd6ae232 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -73,9 +73,11 @@
#ifdef MSND_CLASSIC
# include "msnd_classic.h"
# define LOGNAME "msnd_classic"
+# define DEV_NAME "msnd-classic"
#else
# include "msnd_pinnacle.h"
# define LOGNAME "snd_msnd_pinnacle"
+# define DEV_NAME "msnd-pinnacle"
#endif
static void set_default_audio_parameters(struct snd_msnd *chip)
@@ -1067,8 +1069,6 @@ static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
return 0;
}
-#define DEV_NAME "msnd-pinnacle"
-
static struct isa_driver snd_msnd_driver = {
.match = snd_msnd_isa_match,
.probe = snd_msnd_isa_probe,
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index c1aa21edcb65..48da2276683d 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -208,6 +208,7 @@ static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned i
switch (cmd) {
/* get information */
case SNDRV_SB_CSP_IOCTL_INFO:
+ memset(&info, 0, sizeof(info));
*info.codec_name = *p->codec_name;
info.func_nr = p->func_nr;
info.acc_format = p->acc_format;
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index a2f87f9488ee..e5db001363ee 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1196,7 +1196,7 @@ wavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header)
int num_samples;
unsigned char *msample_hdr;
- msample_hdr = kmalloc(sizeof(WF_MSAMPLE_BYTES), GFP_KERNEL);
+ msample_hdr = kmalloc(WF_MSAMPLE_BYTES, GFP_KERNEL);
if (! msample_hdr)
return -ENOMEM;
diff --git a/sound/mips/ad1843.c b/sound/mips/ad1843.c
index c624510ec374..586907500ca5 100644
--- a/sound/mips/ad1843.c
+++ b/sound/mips/ad1843.c
@@ -276,7 +276,7 @@ static void ad1843_write_multi(struct snd_ad1843 *ad1843, int argcount, ...)
if (reg == -1)
reg = fp->reg;
else
- BUG_ON(reg != fp->reg);
+ WARN_ON(reg != fp->reg);
m = ((1 << fp->nbits) - 1) << fp->lo_bit;
mask |= m;
bits |= (value << fp->lo_bit) & m;
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index 461d94cfecbe..e3f29132d3ac 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/gfp.h>
#include "sound_config.h"
+#include "sleep.h"
#define DMAP_FREE_ON_CLOSE 0
#define DMAP_KEEP_ON_CLOSE 1
@@ -351,8 +352,7 @@ static void dma_reset_output(int dev)
if (!signal_pending(current) && adev->dmap_out->qlen &&
adev->dmap_out->underrun_count == 0){
spin_unlock_irqrestore(&dmap->lock,flags);
- interruptible_sleep_on_timeout(&adev->out_sleeper,
- dmabuf_timeout(dmap));
+ oss_broken_sleep_on(&adev->out_sleeper, dmabuf_timeout(dmap));
spin_lock_irqsave(&dmap->lock,flags);
}
adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE);
@@ -446,7 +446,7 @@ int DMAbuf_sync(int dev)
long t = dmabuf_timeout(dmap);
spin_unlock_irqrestore(&dmap->lock,flags);
/* FIXME: not safe may miss events */
- t = interruptible_sleep_on_timeout(&adev->out_sleeper, t);
+ t = oss_broken_sleep_on(&adev->out_sleeper, t);
spin_lock_irqsave(&dmap->lock,flags);
if (!t) {
adev->dmap_out->flags &= ~DMA_SYNCING;
@@ -466,7 +466,7 @@ int DMAbuf_sync(int dev)
while (!signal_pending(current) &&
adev->d->local_qlen(dev)){
spin_unlock_irqrestore(&dmap->lock,flags);
- interruptible_sleep_on_timeout(&adev->out_sleeper,
+ oss_broken_sleep_on(&adev->out_sleeper,
dmabuf_timeout(dmap));
spin_lock_irqsave(&dmap->lock,flags);
}
@@ -587,8 +587,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock)
timeout = dmabuf_timeout(dmap);
spin_unlock_irqrestore(&dmap->lock,flags);
- timeout = interruptible_sleep_on_timeout(&adev->in_sleeper,
- timeout);
+ timeout = oss_broken_sleep_on(&adev->in_sleeper, timeout);
if (!timeout) {
/* FIXME: include device name */
err = -EIO;
@@ -768,8 +767,7 @@ static int output_sleep(int dev, int dontblock)
timeout_value = dmabuf_timeout(dmap);
else
timeout_value = MAX_SCHEDULE_TIMEOUT;
- timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper,
- timeout_value);
+ timeout_value = oss_broken_sleep_on(&adev->out_sleeper, timeout_value);
if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) {
printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n");
dma_reset_output(dev);
diff --git a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h
index 1308d8d34186..01019f06fa91 100644
--- a/sound/oss/dmasound/dmasound.h
+++ b/sound/oss/dmasound/dmasound.h
@@ -239,7 +239,6 @@ struct sound_queue {
int busy, syncing, xruns, died;
};
-#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
#define WAKE_UP(queue) (wake_up_interruptible(&queue))
extern struct sound_queue dmasound_write_sq;
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index bac43b5b6e95..f4ee85a4c42f 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -619,15 +619,27 @@ static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
}
while (uLeft) {
+ DEFINE_WAIT(wait);
+
while (write_sq.count >= write_sq.max_active) {
+ prepare_to_wait(&write_sq.action_queue, &wait, TASK_INTERRUPTIBLE);
sq_play();
- if (write_sq.non_blocking)
+ if (write_sq.non_blocking) {
+ finish_wait(&write_sq.action_queue, &wait);
return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(write_sq.action_queue);
- if (signal_pending(current))
+ }
+ if (write_sq.count < write_sq.max_active)
+ break;
+
+ schedule_timeout(HZ);
+ if (signal_pending(current)) {
+ finish_wait(&write_sq.action_queue, &wait);
return uWritten > 0 ? uWritten : -EINTR;
+ }
}
+ finish_wait(&write_sq.action_queue, &wait);
+
/* Here, we can avoid disabling the interrupt by first
* copying and translating the data, and then updating
* the write_sq variables. Until this is done, the interrupt
@@ -707,11 +719,8 @@ static int sq_open2(struct sound_queue *sq, struct file *file, fmode_t mode,
if (file->f_flags & O_NONBLOCK)
return rc;
rc = -EINTR;
- while (sq->busy) {
- SLEEP(sq->open_queue);
- if (signal_pending(current))
- return rc;
- }
+ if (wait_event_interruptible(sq->open_queue, !sq->busy))
+ return rc;
rc = 0;
#else
/* OSS manual says we will return EBUSY regardless
@@ -844,7 +853,8 @@ static int sq_fsync(void)
sq_play(); /* there may be an incomplete frame waiting */
while (write_sq.active) {
- SLEEP(write_sq.sync_queue);
+ wait_event_interruptible_timeout(write_sq.sync_queue,
+ !write_sq.active, HZ);
if (signal_pending(current)) {
/* While waiting for audio output to drain, an
* interrupt occurred. Stop audio output immediately
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index 8cdb2cfe65c8..8f45cd999965 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -86,9 +86,8 @@ static void drain_midi_queue(int dev)
*/
if (midi_devs[dev]->buffer_status != NULL)
- while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev))
- interruptible_sleep_on_timeout(&midi_sleeper[dev],
- HZ/10);
+ wait_event_interruptible_timeout(midi_sleeper[dev],
+ !midi_devs[dev]->buffer_status(dev), HZ/10);
}
static void midi_input_intr(int dev, unsigned char data)
@@ -233,8 +232,8 @@ void MIDIbuf_release(int dev, struct file *file)
* devices
*/
- while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev]))
- interruptible_sleep_on(&midi_sleeper[dev]);
+ wait_event_interruptible(midi_sleeper[dev],
+ !DATA_AVAIL(midi_out_buf[dev]));
/*
* Sync
*/
@@ -282,8 +281,8 @@ int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
goto out;
}
- interruptible_sleep_on(&midi_sleeper[dev]);
- if (signal_pending(current))
+ if (wait_event_interruptible(midi_sleeper[dev],
+ SPACE_AVAIL(midi_out_buf[dev])))
{
c = -EINTR;
goto out;
@@ -325,8 +324,9 @@ int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
c = -EAGAIN;
goto out;
}
- interruptible_sleep_on_timeout(&input_sleeper[dev],
- parms[dev].prech_timeout);
+ wait_event_interruptible_timeout(input_sleeper[dev],
+ DATA_AVAIL(midi_in_buf[dev]),
+ parms[dev].prech_timeout);
if (signal_pending(current))
c = -EINTR; /* The user is getting restless */
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index 11ff7c55240c..c23f9f95bfa5 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -664,12 +664,15 @@ static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static void dsp_write_flush(void)
{
+ int timeout = get_play_delay_jiffies(dev.DAPF.len);
+
if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags))
return;
set_bit(F_WRITEFLUSH, &dev.flags);
- interruptible_sleep_on_timeout(
- &dev.writeflush,
- get_play_delay_jiffies(dev.DAPF.len));
+ wait_event_interruptible_timeout(
+ dev.writeflush,
+ !test_bit(F_WRITEFLUSH, &dev.flags),
+ timeout);
clear_bit(F_WRITEFLUSH, &dev.flags);
if (!signal_pending(current)) {
current->state = TASK_INTERRUPTIBLE;
@@ -897,6 +900,7 @@ static int dsp_read(char __user *buf, size_t len)
{
int count = len;
char *page = (char *)__get_free_page(GFP_KERNEL);
+ int timeout = get_rec_delay_jiffies(DAR_BUFF_SIZE);
if (!page)
return -ENOMEM;
@@ -936,11 +940,11 @@ static int dsp_read(char __user *buf, size_t len)
if (count > 0) {
set_bit(F_READBLOCK, &dev.flags);
- if (!interruptible_sleep_on_timeout(
- &dev.readblock,
- get_rec_delay_jiffies(DAR_BUFF_SIZE)))
+ if (wait_event_interruptible_timeout(
+ dev.readblock,
+ test_bit(F_READBLOCK, &dev.flags),
+ timeout) <= 0)
clear_bit(F_READING, &dev.flags);
- clear_bit(F_READBLOCK, &dev.flags);
if (signal_pending(current)) {
free_page((unsigned long)page);
return -EINTR;
@@ -955,6 +959,7 @@ static int dsp_write(const char __user *buf, size_t len)
{
int count = len;
char *page = (char *)__get_free_page(GFP_KERNEL);
+ int timeout = get_play_delay_jiffies(DAP_BUFF_SIZE);
if (!page)
return -ENOMEM;
@@ -995,10 +1000,10 @@ static int dsp_write(const char __user *buf, size_t len)
if (count > 0) {
set_bit(F_WRITEBLOCK, &dev.flags);
- interruptible_sleep_on_timeout(
- &dev.writeblock,
- get_play_delay_jiffies(DAP_BUFF_SIZE));
- clear_bit(F_WRITEBLOCK, &dev.flags);
+ wait_event_interruptible_timeout(
+ dev.writeblock,
+ test_bit(F_WRITEBLOCK, &dev.flags),
+ timeout);
if (signal_pending(current)) {
free_page((unsigned long)page);
return -EINTR;
@@ -1044,7 +1049,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
clear_bit(F_WRITING, &dev.flags);
}
- if (test_bit(F_WRITEBLOCK, &dev.flags))
+ if (test_and_clear_bit(F_WRITEBLOCK, &dev.flags))
wake_up_interruptible(&dev.writeblock);
break;
@@ -1055,7 +1060,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
pack_DARQ_to_DARF(dev.last_recbank);
- if (test_bit(F_READBLOCK, &dev.flags))
+ if (test_and_clear_bit(F_READBLOCK, &dev.flags))
wake_up_interruptible(&dev.readblock);
break;
diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c
index c0be085e4a20..0e7254bde4c2 100644
--- a/sound/oss/sb_ess.c
+++ b/sound/oss/sb_ess.c
@@ -1544,7 +1544,7 @@ static int ess_has_rec_mixer (int submodel)
return 1;
default:
return 0;
- };
+ }
};
#ifdef FKS_LOGGING
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 4ff60a6427d9..9b9f7d385134 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -19,6 +19,7 @@
#include "sound_config.h"
#include "midi_ctrl.h"
+#include "sleep.h"
static int sequencer_ok;
static struct sound_timer_operations *tmr;
@@ -100,8 +101,7 @@ int sequencer_read(int dev, struct file *file, char __user *buf, int count)
return -EAGAIN;
}
- interruptible_sleep_on_timeout(&midi_sleeper,
- pre_event_timeout);
+ oss_broken_sleep_on(&midi_sleeper, pre_event_timeout);
spin_lock_irqsave(&lock,flags);
if (!iqlen)
{
@@ -343,7 +343,7 @@ static int seq_queue(unsigned char *note, char nonblock)
/*
* Sleep until there is enough space on the queue
*/
- interruptible_sleep_on(&seq_sleeper);
+ oss_broken_sleep_on(&seq_sleeper, MAX_SCHEDULE_TIMEOUT);
}
if (qlen >= SEQ_MAX_QUEUE)
{
@@ -1122,8 +1122,7 @@ static void seq_drain_midi_queues(void)
*/
if (n)
- interruptible_sleep_on_timeout(&seq_sleeper,
- HZ/10);
+ oss_broken_sleep_on(&seq_sleeper, HZ/10);
}
}
@@ -1145,8 +1144,7 @@ void sequencer_release(int dev, struct file *file)
while (!signal_pending(current) && qlen > 0)
{
seq_sync();
- interruptible_sleep_on_timeout(&seq_sleeper,
- 3*HZ);
+ oss_broken_sleep_on(&seq_sleeper, 3*HZ);
/* Extra delay */
}
}
@@ -1201,7 +1199,7 @@ static int seq_sync(void)
seq_startplay();
if (qlen > 0)
- interruptible_sleep_on_timeout(&seq_sleeper, HZ);
+ oss_broken_sleep_on(&seq_sleeper, HZ);
return qlen;
}
@@ -1224,7 +1222,7 @@ static void midi_outc(int dev, unsigned char data)
spin_lock_irqsave(&lock,flags);
while (n && !midi_devs[dev]->outputc(dev, data)) {
- interruptible_sleep_on_timeout(&seq_sleeper, HZ/25);
+ oss_broken_sleep_on(&seq_sleeper, HZ/25);
n--;
}
spin_unlock_irqrestore(&lock,flags);
diff --git a/sound/oss/sleep.h b/sound/oss/sleep.h
new file mode 100644
index 000000000000..a20fc925a5ce
--- /dev/null
+++ b/sound/oss/sleep.h
@@ -0,0 +1,18 @@
+#include <linux/wait.h>
+
+/*
+ * Do not use. This is a replacement for the old
+ * "interruptible_sleep_on_timeout" function that has been
+ * deprecated for ages. All users should instead try to use
+ * wait_event_interruptible_timeout.
+ */
+
+static inline long
+oss_broken_sleep_on(wait_queue_head_t *q, long timeout)
+{
+ DEFINE_WAIT(wait);
+ prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ finish_wait(q, &wait);
+ return timeout;
+}
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 7d8803a00b79..f851fd0e199c 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -90,6 +90,8 @@
#include <asm/sibyte/sb1250_mac.h>
#include <asm/sibyte/sb1250.h>
+#include "sleep.h"
+
struct cs4297a_state;
static DEFINE_MUTEX(swarm_cs4297a_mutex);
@@ -748,7 +750,7 @@ static int serdma_reg_access(struct cs4297a_state *s, u64 data)
/* Since a writer has the DSP open, we have to mux the
request in */
s->reg_request = data;
- interruptible_sleep_on(&s->dma_dac.reg_wait);
+ oss_broken_sleep_on(&s->dma_dac.reg_wait, MAX_SCHEDULE_TIMEOUT);
/* XXXKW how can I deal with the starvation case where
the opener isn't writing? */
} else {
@@ -790,7 +792,7 @@ static int cs4297a_read_ac97(struct cs4297a_state *s, u32 offset,
if (serdma_reg_access(s, (0xCLL << 60) | (1LL << 47) | ((u64)(offset & 0x7F) << 40)))
return -1;
- interruptible_sleep_on(&s->dma_adc.reg_wait);
+ oss_broken_sleep_on(&s->dma_adc.reg_wait, MAX_SCHEDULE_TIMEOUT);
*value = s->read_value;
CS_DBGOUT(CS_AC97, 2,
printk(KERN_INFO "cs4297a: rdr reg %x -> %x\n", s->read_reg, s->read_value));
@@ -1740,7 +1742,7 @@ static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count,
start_adc(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
+ oss_broken_sleep_on(&s->dma_adc.wait, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
@@ -1836,7 +1838,7 @@ static ssize_t cs4297a_write(struct file *file, const char *buffer,
start_dac(s);
if (file->f_flags & O_NONBLOCK)
return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&d->wait);
+ oss_broken_sleep_on(&d->wait, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current))
return ret ? ret : -ERESTARTSYS;
continue;
@@ -2452,7 +2454,7 @@ static int cs4297a_locked_open(struct inode *inode, struct file *file)
return -EBUSY;
}
mutex_unlock(&s->open_sem_dac);
- interruptible_sleep_on(&s->open_wait_dac);
+ oss_broken_sleep_on(&s->open_wait_dac, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current)) {
printk("open - sig pending\n");
@@ -2469,7 +2471,7 @@ static int cs4297a_locked_open(struct inode *inode, struct file *file)
return -EBUSY;
}
mutex_unlock(&s->open_sem_adc);
- interruptible_sleep_on(&s->open_wait_adc);
+ oss_broken_sleep_on(&s->open_wait_adc, MAX_SCHEDULE_TIMEOUT);
if (signal_pending(current)) {
printk("open - sig pending\n");
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index 4bbcc0fcd4eb..a077e9c69a5e 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -2921,6 +2921,7 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
vwsnd_dev_t *devc;
int minor = iminor(inode);
int sw_samplefmt;
+ DEFINE_WAIT(wait);
DBGE("(inode=0x%p, file=0x%p)\n", inode, file);
@@ -2937,21 +2938,26 @@ static int vwsnd_audio_open(struct inode *inode, struct file *file)
}
mutex_lock(&devc->open_mutex);
- while (devc->open_mode & file->f_mode) {
+ while (1) {
+ prepare_to_wait(&devc->open_wait, &wait, TASK_INTERRUPTIBLE);
+ if (!(devc->open_mode & file->f_mode))
+ break;
+
mutex_unlock(&devc->open_mutex);
+ mutex_unlock(&vwsnd_mutex);
if (file->f_flags & O_NONBLOCK) {
DEC_USE_COUNT;
- mutex_unlock(&vwsnd_mutex);
return -EBUSY;
}
- interruptible_sleep_on(&devc->open_wait);
+ schedule();
if (signal_pending(current)) {
DEC_USE_COUNT;
- mutex_unlock(&vwsnd_mutex);
return -ERESTARTSYS;
}
+ mutex_lock(&vwsnd_mutex);
mutex_lock(&devc->open_mutex);
}
+ finish_wait(&devc->open_wait, &wait);
devc->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
mutex_unlock(&devc->open_mutex);
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 46ed9e8ae0fd..8756c8e32922 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -25,6 +25,7 @@ config SND_ALS300
select SND_PCM
select SND_AC97_CODEC
select SND_OPL3_LIB
+ select ZONE_DMA
help
Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
@@ -49,6 +50,7 @@ config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for the integrated AC97 sound
device on motherboards using the ALi M5451 Audio Controller
@@ -153,6 +155,7 @@ config SND_AZT3328
select SND_PCM
select SND_RAWMIDI
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
@@ -254,6 +257,7 @@ config SND_CS46XX
tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x"
select SND_RAWMIDI
select SND_AC97_CODEC
+ select FW_LOADER
help
Say Y here to include support for Cirrus Logic CS4610/CS4612/
CS4614/CS4615/CS4622/CS4624/CS4630/CS4280 chips.
@@ -458,6 +462,7 @@ config SND_EMU10K1
select SND_HWDEP
select SND_RAWMIDI
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y to include support for Sound Blaster PCI 512, Live!,
Audigy and E-mu APS (partially supported) soundcards.
@@ -473,6 +478,7 @@ config SND_EMU10K1X
tristate "Emu10k1X (Dell OEM Version)"
select SND_AC97_CODEC
select SND_RAWMIDI
+ select ZONE_DMA
help
Say Y here to include support for the Dell OEM version of the
Sound Blaster Live!.
@@ -506,6 +512,7 @@ config SND_ES1938
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Solo-1
(ES1938, ES1946, ES1969) chips.
@@ -517,6 +524,7 @@ config SND_ES1968
tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Maestro
1/2/2E chips.
@@ -605,6 +613,7 @@ config SND_ICE1712
select SND_MPU401_UART
select SND_AC97_CODEC
select BITREVERSE
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on the
ICE1712 (Envy24) chip.
@@ -692,6 +701,7 @@ config SND_LX6464ES
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Maestro 3
(Allegro) chips.
@@ -788,6 +798,7 @@ config SND_SIS7019
tristate "SiS 7019 Audio Accelerator"
depends on X86 && !X86_64
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for the SiS 7019 Audio Accelerator.
@@ -799,6 +810,7 @@ config SND_SONICVIBES
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on the S3
SonicVibes chip.
@@ -810,6 +822,7 @@ config SND_TRIDENT
tristate "Trident 4D-Wave DX/NX; SiS 7018"
select SND_MPU401_UART
select SND_AC97_CODEC
+ select ZONE_DMA
help
Say Y here to include support for soundcards based on Trident
4D-Wave DX/NX or SiS 7018 chips.
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 445ca481d8d3..bf578ba2677e 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -175,6 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
{ 0x54524106, 0xffffffff, "TR28026", NULL, NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99]
{ 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
+{ 0x54584e03, 0xffffffff, "TLV320AIC27", NULL, NULL },
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL },
{ 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF
{ 0x56494170, 0xffffffff, "VIA1617A", patch_vt1617a, NULL }, // modified VT1616 with S/PDIF
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index d2b9d617aee5..b680d03e2419 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -739,7 +739,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
reg = ad1889_readw(chip, AD_DS_WADA);
snd_iprintf(buffer, "Right: %s, -%d dB\n",
(reg & AD_DS_WADA_RWAM) ? "mute" : "unmute",
- ((reg & AD_DS_WADA_RWAA) >> 8) * 3);
+ (reg & AD_DS_WADA_RWAA) * 3);
reg = ad1889_readw(chip, AD_DS_WAS);
snd_iprintf(buffer, "Wave samplerate: %u Hz\n", reg);
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 3dfa12b670eb..c6835a3d64fb 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -855,7 +855,6 @@ static void snd_ali_disable_spdif_out(struct snd_ali *codec)
static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
{
struct snd_ali_voice *pvoice;
- struct snd_pcm_runtime *runtime;
struct snd_ali_channel_control *pchregs;
unsigned int old, mask;
#ifdef ALI_DEBUG
@@ -872,7 +871,6 @@ static void snd_ali_update_ptr(struct snd_ali *codec, int channel)
return;
pvoice = &codec->synth.voices[channel];
- runtime = pvoice->substream->runtime;
udelay(100);
spin_lock(&codec->reg_lock);
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index dc632cdc3870..5f2acd35dcb9 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1913,6 +1913,7 @@ static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol);
*/
u32 h_control = kcontrol->private_value;
+ unsigned int idx;
u16 band;
u16 tuner_bands[HPI_TUNER_BAND_LAST];
u32 num_bands = 0;
@@ -1920,7 +1921,10 @@ static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol,
num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands,
HPI_TUNER_BAND_LAST);
- band = tuner_bands[ucontrol->value.enumerated.item[0]];
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= ARRAY_SIZE(tuner_bands))
+ idx = ARRAY_SIZE(tuner_bands) - 1;
+ band = tuner_bands[idx];
hpi_handle_error(hpi_tuner_set_band(h_control, band));
return 1;
@@ -2383,7 +2387,8 @@ static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol,
struct snd_card_asihpi *asihpi =
(struct snd_card_asihpi *)(kcontrol->private_data);
struct clk_cache *clkcache = &asihpi->cc;
- int change, item;
+ unsigned int item;
+ int change;
u32 h_control = kcontrol->private_value;
change = 1;
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index b46dc9b24dbd..9fb03b4ea925 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -671,7 +671,7 @@ static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
return err;
break;
#endif
- };
+ }
if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
index 8bef47311e45..922a84bba2ef 100644
--- a/sound/pci/au88x0/au88x0_synth.c
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -219,7 +219,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
*/
hwwrite(vortex->mmio, WT_RUN(wt), val);
return 0xc;
- break;
case 1: /* param 0 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
@@ -227,7 +226,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
*/
hwwrite(vortex->mmio, WT_PARM(wt, 0), val);
return 0xc;
- break;
case 2: /* param 1 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
@@ -235,7 +233,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
*/
hwwrite(vortex->mmio, WT_PARM(wt, 1), val);
return 0xc;
- break;
case 3: /* param 2 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
@@ -243,7 +240,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
*/
hwwrite(vortex->mmio, WT_PARM(wt, 2), val);
return 0xc;
- break;
case 4: /* param 3 */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
@@ -251,7 +247,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
*/
hwwrite(vortex->mmio, WT_PARM(wt, 3), val);
return 0xc;
- break;
case 6: /* mute */
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n",
@@ -259,20 +254,17 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
*/
hwwrite(vortex->mmio, WT_MUTE(wt), val);
return 0xc;
- break;
case 0xb:
- { /* delay */
- /*
- 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);
- hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
- return 0xc;
- }
- break;
+ /* delay */
+ /*
+ 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);
+ hwwrite(vortex->mmio, WT_DELAY(wt, 0), val);
+ return 0xc;
/* Global WT block parameters */
case 5: /* sramp */
ecx = WT_SRAMP(wt);
@@ -291,7 +283,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
break;
default:
return 0;
- break;
}
/*
printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val);
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index c8e121611593..1aef7128f7ca 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -715,14 +715,14 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
const struct snd_azf3328 *chip = ac97->private_data;
unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
unsigned short reg_val = 0;
- bool unsupported = 0;
+ bool unsupported = false;
snd_azf3328_dbgmixer(
"snd_azf3328_mixer_ac97_read reg_ac97 %u\n",
reg_ac97
);
if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
- unsupported = 1;
+ unsupported = true;
else {
if (reg_azf & AZF_AC97_REG_REAL_IO_READ)
reg_val = snd_azf3328_mixer_inw(chip,
@@ -759,7 +759,7 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97)
reg_val = azf_emulated_ac97_vendor_id & 0xffff;
break;
default:
- unsupported = 1;
+ unsupported = true;
break;
}
}
@@ -776,14 +776,14 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
{
const struct snd_azf3328 *chip = ac97->private_data;
unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97);
- bool unsupported = 0;
+ bool unsupported = false;
snd_azf3328_dbgmixer(
"snd_azf3328_mixer_ac97_write reg_ac97 %u val %u\n",
reg_ac97, val
);
if (reg_azf & AZF_AC97_REG_UNSUPPORTED)
- unsupported = 1;
+ unsupported = true;
else {
if (reg_azf & AZF_AC97_REG_REAL_IO_WRITE)
snd_azf3328_mixer_outw(
@@ -808,7 +808,7 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97,
*/
break;
default:
- unsupported = 1;
+ unsupported = true;
break;
}
}
@@ -1559,7 +1559,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_azf3328_codec_data *codec = runtime->private_data;
int result = 0;
u16 flags1;
- bool previously_muted = 0;
+ bool previously_muted = false;
bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type);
snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd);
diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h
index fc339ef0a0ae..c49a082c378b 100644
--- a/sound/pci/cs46xx/cs46xx.h
+++ b/sound/pci/cs46xx/cs46xx.h
@@ -1716,9 +1716,14 @@ struct snd_cs46xx {
struct snd_pcm *pcm_rear;
struct snd_pcm *pcm_center_lfe;
struct snd_pcm *pcm_iec958;
+
+#define CS46XX_DSP_MODULES 5
+ struct dsp_module_desc *modules[CS46XX_DSP_MODULES];
#else /* for compatibility */
struct snd_cs46xx_pcm *playback_pcm;
unsigned int play_ctl;
+
+ struct ba1_struct *ba1;
#endif
#ifdef CONFIG_PM_SLEEP
diff --git a/sound/pci/cs46xx/cs46xx_image.h b/sound/pci/cs46xx/cs46xx_image.h
deleted file mode 100644
index dc93f62db2c2..000000000000
--- a/sound/pci/cs46xx/cs46xx_image.h
+++ /dev/null
@@ -1,3468 +0,0 @@
-struct BA1struct {
- struct {
- unsigned long offset;
- unsigned long size;
- } memory[BA1_MEMORY_COUNT];
- u32 map[BA1_DWORD_SIZE];
-};
-
-
-static struct BA1struct BA1Struct = {
-{{ 0x00000000, 0x00003000 },{ 0x00010000, 0x00003800 },{ 0x00020000, 0x00007000 }},
-{0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000163,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00200040,0x00008010,0x00000000,
-0x00000000,0x80000001,0x00000001,0x00060000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00900080,0x00000173,0x00000000,
-0x00000000,0x00000010,0x00800000,0x00900000,
-0xf2c0000f,0x00000200,0x00000000,0x00010600,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000163,0x330300c2,
-0x06000000,0x00000000,0x80008000,0x80008000,
-0x3fc0000f,0x00000301,0x00010400,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00b00000,0x00d0806d,0x330480c3,
-0x04800000,0x00000001,0x00800001,0x0000ffff,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x066a0600,0x06350070,0x0000929d,0x929d929d,
-0x00000000,0x0000735a,0x00000600,0x00000000,
-0x929d735a,0x8734abfe,0x00010000,0x735a735a,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000804f,0x000000c3,
-0x05000000,0x00a00010,0x00000000,0x80008000,
-0x00000000,0x00000000,0x00000700,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000080,0x00a00000,0x0000809a,0x000000c2,
-0x07400000,0x00000000,0x80008000,0xffffffff,
-0x00c80028,0x00005555,0x00000000,0x000107a0,
-0x00c80028,0x000000c2,0x06800000,0x00000000,
-0x06e00080,0x00300000,0x000080bb,0x000000c9,
-0x07a00000,0x04000000,0x80008000,0xffffffff,
-0x00c80028,0x00005555,0x00000000,0x00000780,
-0x00c80028,0x000000c5,0xff800000,0x00000000,
-0x00640080,0x00c00000,0x00008197,0x000000c9,
-0x07800000,0x04000000,0x80008000,0xffffffff,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000805e,0x000000c1,
-0x00000000,0x00800000,0x80008000,0x80008000,
-0x00020000,0x0000ffff,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x929d0600,0x929d929d,0x929d929d,0x929d0000,
-0x929d929d,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0x00100635,0x060b013f,0x00000004,
-0x00000001,0x007a0002,0x00000000,0x066e0610,
-0x0105929d,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0xa431ac75,0x0001735a,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051,
-0x00000000,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0x929d929d,0x00000000,0x06400136,
-0x0000270f,0x00010000,0x007a0000,0x00000000,
-0x068e0645,0x0105929d,0x929d929d,0x929d929d,
-0x929d929d,0x929d929d,0xa431ac75,0x0001735a,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0x735a0100,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00010004,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00001705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00009705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00011705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00019705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00021705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00029705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00031705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00039705,0x00001400,0x000a411e,0x00001003,
-0x000fe19e,0x00001003,0x0009c730,0x00001003,
-0x0008e19c,0x00001003,0x000083c1,0x00093040,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00009705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00011705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00019705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00021705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00029705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00031705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00039705,0x00001400,0x000a211e,0x00001003,
-0x0000a730,0x00001008,0x000e2730,0x00001002,
-0x0000a731,0x00001002,0x0000a731,0x00001002,
-0x0000a731,0x00001002,0x0000a731,0x00001002,
-0x0000a731,0x00001002,0x0000a731,0x00001002,
-0x00000000,0x00000000,0x000f619c,0x00001003,
-0x0007f801,0x000c0000,0x00000037,0x00001000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x000c0000,0x00000000,0x00000000,
-0x0000373c,0x00001000,0x00000000,0x00000000,
-0x000ee19c,0x00001003,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000273c,0x00001000,
-0x00000033,0x00001000,0x000e679e,0x00001003,
-0x00007705,0x00001400,0x000ac71e,0x00001003,
-0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000a730,0x00001003,
-0x00000033,0x00001000,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x000c0000,
-0x00000032,0x00001000,0x0000273d,0x00001000,
-0x0004a730,0x00001003,0x00000f41,0x00097140,
-0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
-0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
-0x00000000,0x00000000,0x0001bf05,0x0003fc40,
-0x00002725,0x000aa400,0x00013705,0x00093a00,
-0x0000002e,0x0009d6c0,0x00038630,0x00001004,
-0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000,
-0x00000000,0x000c70e0,0x0007d182,0x0002c640,
-0x00000630,0x00001004,0x000799b8,0x0002c6c0,
-0x00031705,0x00092240,0x00039f05,0x000932c0,
-0x0003520a,0x00000000,0x00040731,0x0000100b,
-0x00010705,0x000b20c0,0x00000000,0x000eba44,
-0x00032108,0x000c60c4,0x00065208,0x000c2917,
-0x000406b0,0x00001007,0x00012f05,0x00036880,
-0x0002818e,0x000c0000,0x0004410a,0x00000000,
-0x00040630,0x00001007,0x00029705,0x000c0000,
-0x00000000,0x00000000,0x00003fc1,0x0003fc40,
-0x000037c1,0x00091b40,0x00003fc1,0x000911c0,
-0x000037c1,0x000957c0,0x00003fc1,0x000951c0,
-0x000037c1,0x00000000,0x00003fc1,0x000991c0,
-0x000037c1,0x00000000,0x00003fc1,0x0009d1c0,
-0x000037c1,0x00000000,0x0001ccc1,0x000915c0,
-0x0001c441,0x0009d800,0x0009cdc1,0x00091240,
-0x0001c541,0x00091d00,0x0009cfc1,0x00095240,
-0x0001c741,0x00095c80,0x000e8ca9,0x00099240,
-0x000e85ad,0x00095640,0x00069ca9,0x00099d80,
-0x000e952d,0x00099640,0x000eaca9,0x0009d6c0,
-0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80,
-0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0,
-0x000ec5ad,0x0009da40,0x000edca9,0x0009d300,
-0x000a6e0a,0x00001000,0x000ed52d,0x00091e40,
-0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40,
-0x0006fca9,0x00002500,0x000fb208,0x000c59a0,
-0x000ef52d,0x0009de40,0x00068ca9,0x000912c1,
-0x000683ad,0x00095241,0x00020f05,0x000991c1,
-0x00000000,0x00000000,0x00086f88,0x00001000,
-0x0009cf81,0x000b5340,0x0009c701,0x000b92c0,
-0x0009de81,0x000bd300,0x0009d601,0x000b1700,
-0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0,
-0x000a0f81,0x000bd740,0x00020701,0x000b5c80,
-0x000a1681,0x000b97c0,0x00021601,0x00002500,
-0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0,
-0x00021681,0x00002d00,0x00020f81,0x000bd800,
-0x000a0701,0x000b5bc0,0x00021601,0x00003500,
-0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0,
-0x00021681,0x00003d00,0x00020f81,0x000b1d00,
-0x000a0701,0x000b1fc0,0x00021601,0x00020500,
-0x00020f81,0x000b1341,0x000a0701,0x000b9fc0,
-0x00021681,0x00020d00,0x00020f81,0x000bde80,
-0x000a0701,0x000bdfc0,0x00021601,0x00021500,
-0x00020f81,0x000b9341,0x00020701,0x000b53c1,
-0x00021681,0x00021d00,0x000a0f81,0x000d0380,
-0x0000b601,0x000b15c0,0x00007b01,0x00000000,
-0x00007b81,0x000bd1c0,0x00007b01,0x00000000,
-0x00007b81,0x000b91c0,0x00007b01,0x000b57c0,
-0x00007b81,0x000b51c0,0x00007b01,0x000b1b40,
-0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0,
-0x0007e488,0x000d7e45,0x00000000,0x000d7a44,
-0x0007e48a,0x00000000,0x00011f05,0x00084080,
-0x00000000,0x00000000,0x00001705,0x000b3540,
-0x00008a01,0x000bf040,0x00007081,0x000bb5c0,
-0x00055488,0x00000000,0x0000d482,0x0003fc40,
-0x0003fc88,0x00000000,0x0001e401,0x000b3a00,
-0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784,
-0x000c86b0,0x00001007,0x00008281,0x000bb240,
-0x0000b801,0x000b7140,0x00007888,0x00000000,
-0x0000073c,0x00001000,0x0007f188,0x000c0000,
-0x00000000,0x00000000,0x00055288,0x000c555c,
-0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
-0x0000fa88,0x00000000,0x00000032,0x00001000,
-0x0000073d,0x00001000,0x0007f188,0x000c0000,
-0x00000000,0x00000000,0x0008c01c,0x00001003,
-0x00002705,0x00001008,0x0008b201,0x000c1392,
-0x0000ba01,0x00000000,0x00008731,0x00001400,
-0x0004c108,0x000fe0c4,0x00057488,0x00000000,
-0x000a6388,0x00001001,0x0008b334,0x000bc141,
-0x0003020e,0x00000000,0x000886b0,0x00001008,
-0x00003625,0x000c5dfa,0x000a638a,0x00001001,
-0x0008020e,0x00001002,0x0008a6b0,0x00001008,
-0x0007f301,0x00000000,0x00000000,0x00000000,
-0x00002725,0x000a8c40,0x000000ae,0x00000000,
-0x000d8630,0x00001008,0x00000000,0x000c74e0,
-0x0007d182,0x0002d640,0x000a8630,0x00001008,
-0x000799b8,0x0002d6c0,0x0000748a,0x000c3ec5,
-0x0007420a,0x000c0000,0x00062208,0x000c4117,
-0x00070630,0x00001009,0x00000000,0x000c0000,
-0x0001022e,0x00000000,0x0003a630,0x00001009,
-0x00000000,0x000c0000,0x00000036,0x00001000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x0002a730,0x00001008,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0002a730,0x00001008,
-0x00000033,0x00001000,0x0002a705,0x00001008,
-0x00007a01,0x000c0000,0x000e6288,0x000d550a,
-0x0006428a,0x00000000,0x00060730,0x0000100a,
-0x00000000,0x000c0000,0x00000000,0x00000000,
-0x0007aab0,0x00034880,0x00078fb0,0x0000100b,
-0x00057488,0x00000000,0x00033b94,0x00081140,
-0x000183ae,0x00000000,0x000786b0,0x0000100b,
-0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
-0x00042731,0x00001003,0x0007aab0,0x00034880,
-0x00048fb0,0x0000100a,0x00057488,0x00000000,
-0x00033b94,0x00081140,0x000183ae,0x00000000,
-0x000806b0,0x0000100b,0x00022f05,0x00000000,
-0x00007401,0x00091140,0x00048f05,0x000951c0,
-0x00042731,0x00001003,0x0000473d,0x00001000,
-0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
-0x000fe19e,0x00001003,0x00000000,0x00000000,
-0x0008e19c,0x00001003,0x000083c1,0x00093040,
-0x00000f41,0x00097140,0x0000a841,0x0009b240,
-0x0000a0c1,0x0009f040,0x0001c641,0x00093540,
-0x0001cec1,0x0009b5c0,0x00000000,0x000fdc44,
-0x00055208,0x00000000,0x00010705,0x000a2880,
-0x0000a23a,0x00093a00,0x0003fc8a,0x000df6c5,
-0x0004ef0a,0x000c0000,0x00012f05,0x00036880,
-0x00065308,0x000c2997,0x000d86b0,0x0000100a,
-0x0004410a,0x000d40c7,0x00000000,0x00000000,
-0x00080730,0x00001004,0x00056f0a,0x000ea105,
-0x00000000,0x00000000,0x0000473d,0x00001000,
-0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
-0x0000273d,0x00001000,0x00000000,0x000eba44,
-0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
-0x00000734,0x00001000,0x00010705,0x000a6880,
-0x00006a88,0x000c75c4,0x00000000,0x000e5084,
-0x00000000,0x000eba44,0x00087401,0x000e4782,
-0x00000734,0x00001000,0x00010705,0x000a6880,
-0x00006a88,0x000c75c4,0x0007c108,0x000c0000,
-0x0007e721,0x000bed40,0x00005f25,0x000badc0,
-0x0003ba97,0x000beb80,0x00065590,0x000b2e00,
-0x00033217,0x00003ec0,0x00065590,0x000b8e40,
-0x0003ed80,0x000491c0,0x00073fb0,0x00074c80,
-0x000283a0,0x0000100c,0x000ee388,0x00042970,
-0x00008301,0x00021ef2,0x000b8f14,0x0000000f,
-0x000c4d8d,0x0000001b,0x000d6dc2,0x000e06c6,
-0x000032ac,0x000c3916,0x0004edc2,0x00074c80,
-0x00078898,0x00001000,0x00038894,0x00000032,
-0x000c4d8d,0x00092e1b,0x000d6dc2,0x000e06c6,
-0x0004edc2,0x000c1956,0x0000722c,0x00034a00,
-0x00041705,0x0009ed40,0x00058730,0x00001400,
-0x000d7488,0x000c3a00,0x00048f05,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000}
- };
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 1b66efd9b728..062398ec5335 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -54,7 +54,9 @@
#include <linux/gameport.h>
#include <linux/mutex.h>
#include <linux/export.h>
-
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -330,13 +332,147 @@ int snd_cs46xx_download(struct snd_cs46xx *chip,
return 0;
}
+static inline void memcpy_le32(void *dst, const void *src, unsigned int len)
+{
+#ifdef __LITTLE_ENDIAN
+ memcpy(dst, src, len);
+#else
+ u32 *_dst = dst;
+ const __le32 *_src = src;
+ len /= 4;
+ while (len-- > 0)
+ *_dst++ = le32_to_cpu(*_src++);
+#endif
+}
+
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-#include "imgs/cwc4630.h"
-#include "imgs/cwcasync.h"
-#include "imgs/cwcsnoop.h"
-#include "imgs/cwcbinhack.h"
-#include "imgs/cwcdma.h"
+static const char *module_names[CS46XX_DSP_MODULES] = {
+ "cwc4630", "cwcasync", "cwcsnoop", "cwcbinhack", "cwcdma"
+};
+
+MODULE_FIRMWARE("cs46xx/cwc4630");
+MODULE_FIRMWARE("cs46xx/cwcasync");
+MODULE_FIRMWARE("cs46xx/cwcsnoop");
+MODULE_FIRMWARE("cs46xx/cwcbinhack");
+MODULE_FIRMWARE("cs46xx/cwcdma");
+
+static void free_module_desc(struct dsp_module_desc *module)
+{
+ if (!module)
+ return;
+ kfree(module->module_name);
+ kfree(module->symbol_table.symbols);
+ if (module->segments) {
+ int i;
+ for (i = 0; i < module->nsegments; i++)
+ kfree(module->segments[i].data);
+ kfree(module->segments);
+ }
+ kfree(module);
+}
+
+/* firmware binary format:
+ * le32 nsymbols;
+ * struct {
+ * le32 address;
+ * char symbol_name[DSP_MAX_SYMBOL_NAME];
+ * le32 symbol_type;
+ * } symbols[nsymbols];
+ * le32 nsegments;
+ * struct {
+ * le32 segment_type;
+ * le32 offset;
+ * le32 size;
+ * le32 data[size];
+ * } segments[nsegments];
+ */
+
+static int load_firmware(struct snd_cs46xx *chip,
+ struct dsp_module_desc **module_ret,
+ const char *fw_name)
+{
+ int i, err;
+ unsigned int nums, fwlen, fwsize;
+ const __le32 *fwdat;
+ struct dsp_module_desc *module = NULL;
+ const struct firmware *fw;
+ char fw_path[32];
+
+ sprintf(fw_path, "cs46xx/%s", fw_name);
+ err = request_firmware(&fw, fw_path, &chip->pci->dev);
+ if (err < 0)
+ return err;
+ fwsize = fw->size / 4;
+ if (fwsize < 2) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ err = -ENOMEM;
+ module = kzalloc(sizeof(*module), GFP_KERNEL);
+ if (!module)
+ goto error;
+ module->module_name = kstrdup(fw_name, GFP_KERNEL);
+ if (!module->module_name)
+ goto error;
+
+ fwlen = 0;
+ fwdat = (const __le32 *)fw->data;
+ nums = module->symbol_table.nsymbols = le32_to_cpu(fwdat[fwlen++]);
+ if (nums >= 40)
+ goto error_inval;
+ module->symbol_table.symbols =
+ kcalloc(nums, sizeof(struct dsp_symbol_entry), GFP_KERNEL);
+ if (!module->symbol_table.symbols)
+ goto error;
+ for (i = 0; i < nums; i++) {
+ struct dsp_symbol_entry *entry =
+ &module->symbol_table.symbols[i];
+ if (fwlen + 2 + DSP_MAX_SYMBOL_NAME / 4 > fwsize)
+ goto error_inval;
+ entry->address = le32_to_cpu(fwdat[fwlen++]);
+ memcpy(entry->symbol_name, &fwdat[fwlen], DSP_MAX_SYMBOL_NAME - 1);
+ fwlen += DSP_MAX_SYMBOL_NAME / 4;
+ entry->symbol_type = le32_to_cpu(fwdat[fwlen++]);
+ }
+
+ if (fwlen >= fwsize)
+ goto error_inval;
+ nums = module->nsegments = le32_to_cpu(fwdat[fwlen++]);
+ if (nums > 10)
+ goto error_inval;
+ module->segments =
+ kcalloc(nums, sizeof(struct dsp_segment_desc), GFP_KERNEL);
+ if (!module->segments)
+ goto error;
+ for (i = 0; i < nums; i++) {
+ struct dsp_segment_desc *entry = &module->segments[i];
+ if (fwlen + 3 > fwsize)
+ goto error_inval;
+ entry->segment_type = le32_to_cpu(fwdat[fwlen++]);
+ entry->offset = le32_to_cpu(fwdat[fwlen++]);
+ entry->size = le32_to_cpu(fwdat[fwlen++]);
+ if (fwlen + entry->size > fwsize)
+ goto error_inval;
+ entry->data = kmalloc(entry->size * 4, GFP_KERNEL);
+ if (!entry->data)
+ goto error;
+ memcpy_le32(entry->data, &fwdat[fwlen], entry->size * 4);
+ fwlen += entry->size;
+ }
+
+ *module_ret = module;
+ release_firmware(fw);
+ return 0;
+
+ error_inval:
+ err = -EINVAL;
+ error:
+ free_module_desc(module);
+ release_firmware(fw);
+ return err;
+}
int snd_cs46xx_clear_BA1(struct snd_cs46xx *chip,
unsigned long offset,
@@ -361,20 +497,63 @@ int snd_cs46xx_clear_BA1(struct snd_cs46xx *chip,
#else /* old DSP image */
-#include "cs46xx_image.h"
+struct ba1_struct {
+ struct {
+ u32 offset;
+ u32 size;
+ } memory[BA1_MEMORY_COUNT];
+ u32 map[BA1_DWORD_SIZE];
+};
+
+MODULE_FIRMWARE("cs46xx/ba1");
+
+static int load_firmware(struct snd_cs46xx *chip)
+{
+ const struct firmware *fw;
+ int i, size, err;
+
+ err = request_firmware(&fw, "cs46xx/ba1", &chip->pci->dev);
+ if (err < 0)
+ return err;
+ if (fw->size != sizeof(*chip->ba1)) {
+ err = -EINVAL;
+ goto error;
+ }
+
+ chip->ba1 = vmalloc(sizeof(*chip->ba1));
+ if (!chip->ba1) {
+ err = -ENOMEM;
+ goto error;
+ }
+
+ memcpy_le32(chip->ba1, fw->data, sizeof(*chip->ba1));
+
+ /* sanity check */
+ size = 0;
+ for (i = 0; i < BA1_MEMORY_COUNT; i++)
+ size += chip->ba1->memory[i].size;
+ if (size > BA1_DWORD_SIZE * 4)
+ err = -EINVAL;
+
+ error:
+ release_firmware(fw);
+ return err;
+}
int snd_cs46xx_download_image(struct snd_cs46xx *chip)
{
int idx, err;
- unsigned long offset = 0;
+ unsigned int offset = 0;
+ struct ba1_struct *ba1 = chip->ba1;
for (idx = 0; idx < BA1_MEMORY_COUNT; idx++) {
- if ((err = snd_cs46xx_download(chip,
- &BA1Struct.map[offset],
- BA1Struct.memory[idx].offset,
- BA1Struct.memory[idx].size)) < 0)
+ err = snd_cs46xx_download(chip,
+ &ba1->map[offset],
+ ba1->memory[idx].offset,
+ ba1->memory[idx].size);
+ if (err < 0)
return err;
- offset += BA1Struct.memory[idx].size >> 2;
+ offset += ba1->memory[idx].size >> 2;
}
return 0;
}
@@ -2798,6 +2977,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
cs46xx_dsp_spos_destroy(chip);
chip->dsp_spos_instance = NULL;
}
+ for (idx = 0; idx < CS46XX_DSP_MODULES; idx++)
+ free_module_desc(chip->modules[idx]);
+#else
+ vfree(chip->ba1);
#endif
#ifdef CONFIG_PM_SLEEP
@@ -3067,6 +3250,11 @@ static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
{
unsigned int tmp;
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ int i;
+#endif
+ int err;
+
/*
* Reset the processor.
*/
@@ -3075,45 +3263,33 @@ int snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
* Download the image to the processor.
*/
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-#if 0
- if (cs46xx_dsp_load_module(chip, &cwcemb80_module) < 0) {
- snd_printk(KERN_ERR "image download error\n");
- return -EIO;
- }
-#endif
-
- if (cs46xx_dsp_load_module(chip, &cwc4630_module) < 0) {
- snd_printk(KERN_ERR "image download error [cwc4630]\n");
- return -EIO;
- }
-
- if (cs46xx_dsp_load_module(chip, &cwcasync_module) < 0) {
- snd_printk(KERN_ERR "image download error [cwcasync]\n");
- return -EIO;
- }
-
- if (cs46xx_dsp_load_module(chip, &cwcsnoop_module) < 0) {
- snd_printk(KERN_ERR "image download error [cwcsnoop]\n");
- return -EIO;
- }
-
- if (cs46xx_dsp_load_module(chip, &cwcbinhack_module) < 0) {
- snd_printk(KERN_ERR "image download error [cwcbinhack]\n");
- return -EIO;
- }
-
- if (cs46xx_dsp_load_module(chip, &cwcdma_module) < 0) {
- snd_printk(KERN_ERR "image download error [cwcdma]\n");
- return -EIO;
+ for (i = 0; i < CS46XX_DSP_MODULES; i++) {
+ err = load_firmware(chip, &chip->modules[i], module_names[i]);
+ if (err < 0) {
+ snd_printk(KERN_ERR "firmware load error [%s]\n",
+ module_names[i]);
+ return err;
+ }
+ err = cs46xx_dsp_load_module(chip, chip->modules[i]);
+ if (err < 0) {
+ snd_printk(KERN_ERR "image download error [%s]\n",
+ module_names[i]);
+ return err;
+ }
}
if (cs46xx_dsp_scb_and_task_init(chip) < 0)
return -EIO;
#else
+ err = load_firmware(chip);
+ if (err < 0)
+ return err;
+
/* old image */
- if (snd_cs46xx_download_image(chip) < 0) {
+ err = snd_cs46xx_download_image(chip);
+ if (err < 0) {
snd_printk(KERN_ERR "image download error\n");
- return -EIO;
+ return err;
}
/*
diff --git a/sound/pci/cs46xx/imgs/cwc4630.h b/sound/pci/cs46xx/imgs/cwc4630.h
deleted file mode 100644
index 37c4f1318dc5..000000000000
--- a/sound/pci/cs46xx/imgs/cwc4630.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/* generated from cwc4630.osp DO NOT MODIFY */
-
-#ifndef __HEADER_cwc4630_H__
-#define __HEADER_cwc4630_H__
-
-static struct dsp_symbol_entry cwc4630_symbols[] = {
- { 0x0000, "BEGINADDRESS",0x00 },
- { 0x8000, "EXECCHILD",0x03 },
- { 0x8001, "EXECCHILD_98",0x03 },
- { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
- { 0x8008, "EXECSIBLING",0x03 },
- { 0x800a, "EXECSIBLING_298",0x03 },
- { 0x800b, "EXECSIBLING_2IND1",0x03 },
- { 0x8010, "TIMINGMASTER",0x03 },
- { 0x804f, "S16_CODECINPUTTASK",0x03 },
- { 0x805e, "PCMSERIALINPUTTASK",0x03 },
- { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
- { 0x809a, "S16_MIX",0x03 },
- { 0x80bb, "S16_UPSRC",0x03 },
- { 0x813b, "MIX3_EXP",0x03 },
- { 0x8164, "DECIMATEBYPOW2",0x03 },
- { 0x8197, "VARIDECIMATE",0x03 },
- { 0x81f2, "_3DINPUTTASK",0x03 },
- { 0x820a, "_3DPRLGCINPTASK",0x03 },
- { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
- { 0x8242, "_3DOUTPUTTASK",0x03 },
- { 0x82c4, "HRTF_MORPH_TASK",0x03 },
- { 0x82c6, "WAIT4DATA",0x03 },
- { 0x82fa, "PROLOGIC",0x03 },
- { 0x8496, "DECORRELATOR",0x03 },
- { 0x84a4, "STEREO2MONO",0x03 },
- { 0x0070, "SPOSCB",0x02 },
- { 0x0107, "TASKTREETHREAD",0x03 },
- { 0x013c, "TASKTREEHEADERCODE",0x03 },
- { 0x0145, "FGTASKTREEHEADERCODE",0x03 },
- { 0x0169, "NULLALGORITHM",0x03 },
- { 0x016d, "HFGEXECCHILD",0x03 },
- { 0x016e, "HFGEXECCHILD_98",0x03 },
- { 0x0170, "HFGEXECCHILD_PUSH1IND",0x03 },
- { 0x0173, "HFGEXECSIBLING",0x03 },
- { 0x0175, "HFGEXECSIBLING_298",0x03 },
- { 0x0176, "HFGEXECSIBLING_2IND1",0x03 },
- { 0x0179, "S16_CODECOUTPUTTASK",0x03 },
- { 0x0194, "#CODE_END",0x00 },
-}; /* cwc4630 symbols */
-
-static u32 cwc4630_code[] = {
-/* BEGINADDRESS */
-/* 0000 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 0002 */ 0x00001705,0x00001400,0x000a411e,0x00001003,
-/* 0004 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 0006 */ 0x00009705,0x00001400,0x000a411e,0x00001003,
-/* 0008 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 000A */ 0x00011705,0x00001400,0x000a411e,0x00001003,
-/* 000C */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 000E */ 0x00019705,0x00001400,0x000a411e,0x00001003,
-/* 0010 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 0012 */ 0x00021705,0x00001400,0x000a411e,0x00001003,
-/* 0014 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 0016 */ 0x00029705,0x00001400,0x000a411e,0x00001003,
-/* 0018 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 001A */ 0x00031705,0x00001400,0x000a411e,0x00001003,
-/* 001C */ 0x00040730,0x00001002,0x000f619e,0x00001003,
-/* 001E */ 0x00039705,0x00001400,0x000a411e,0x00001003,
-/* 0020 */ 0x000fe19e,0x00001003,0x0009c730,0x00001003,
-/* 0022 */ 0x0008e19c,0x00001003,0x000083c1,0x00093040,
-/* 0024 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 0026 */ 0x00009705,0x00001400,0x000a211e,0x00001003,
-/* 0028 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 002A */ 0x00011705,0x00001400,0x000a211e,0x00001003,
-/* 002C */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 002E */ 0x00019705,0x00001400,0x000a211e,0x00001003,
-/* 0030 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 0032 */ 0x00021705,0x00001400,0x000a211e,0x00001003,
-/* 0034 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 0036 */ 0x00029705,0x00001400,0x000a211e,0x00001003,
-/* 0038 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 003A */ 0x00031705,0x00001400,0x000a211e,0x00001003,
-/* 003C */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
-/* 003E */ 0x00039705,0x00001400,0x000a211e,0x00001003,
-/* 0040 */ 0x0001a730,0x00001008,0x000e2730,0x00001002,
-/* 0042 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
-/* 0044 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
-/* 0046 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
-/* 0048 */ 0x00000000,0x00000000,0x000f619c,0x00001003,
-/* 004A */ 0x0007f801,0x000c0000,0x00000037,0x00001000,
-/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 004E */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0050 */ 0x00000000,0x000c0000,0x00000000,0x00000000,
-/* 0052 */ 0x0000373c,0x00001000,0x00000000,0x00000000,
-/* 0054 */ 0x000ee19c,0x00001003,0x0007f801,0x000c0000,
-/* 0056 */ 0x00000037,0x00001000,0x00000000,0x00000000,
-/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 005A */ 0x00000000,0x00000000,0x0000273c,0x00001000,
-/* 005C */ 0x00000033,0x00001000,0x000e679e,0x00001003,
-/* 005E */ 0x00007705,0x00001400,0x000ac71e,0x00001003,
-/* 0060 */ 0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
-/* 0062 */ 0x00000037,0x00001000,0x00000000,0x00000000,
-/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0066 */ 0x00000000,0x00000000,0x0000a730,0x00001003,
-/* 0068 */ 0x00000033,0x00001000,0x0007f801,0x000c0000,
-/* 006A */ 0x00000037,0x00001000,0x00000000,0x00000000,
-/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 006E */ 0x00000000,0x00000000,0x00000000,0x000c0000,
-/* 0070 */ 0x00000032,0x00001000,0x0000273d,0x00001000,
-/* 0072 */ 0x0004a730,0x00001003,0x00000f41,0x00097140,
-/* 0074 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
-/* 0076 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
-/* 0078 */ 0x00000000,0x00000000,0x0001bf05,0x0003fc40,
-/* 007A */ 0x00002725,0x000aa400,0x00013705,0x00093a00,
-/* 007C */ 0x0000002e,0x0009d6c0,0x0002ef8a,0x00000000,
-/* 007E */ 0x00040630,0x00001004,0x0004ef0a,0x000eb785,
-/* 0080 */ 0x0003fc8a,0x00000000,0x00000000,0x000c70e0,
-/* 0082 */ 0x0007d182,0x0002c640,0x00008630,0x00001004,
-/* 0084 */ 0x000799b8,0x0002c6c0,0x00031705,0x00092240,
-/* 0086 */ 0x00039f05,0x000932c0,0x0003520a,0x00000000,
-/* 0088 */ 0x00070731,0x0000100b,0x00010705,0x000b20c0,
-/* 008A */ 0x00000000,0x000eba44,0x00032108,0x000c60c4,
-/* 008C */ 0x00065208,0x000c2917,0x000486b0,0x00001007,
-/* 008E */ 0x00012f05,0x00036880,0x0002818e,0x000c0000,
-/* 0090 */ 0x0004410a,0x00000000,0x00048630,0x00001007,
-/* 0092 */ 0x00029705,0x000c0000,0x00000000,0x00000000,
-/* 0094 */ 0x00003fc1,0x0003fc40,0x000037c1,0x00091b40,
-/* 0096 */ 0x00003fc1,0x000911c0,0x000037c1,0x000957c0,
-/* 0098 */ 0x00003fc1,0x000951c0,0x000037c1,0x00000000,
-/* 009A */ 0x00003fc1,0x000991c0,0x000037c1,0x00000000,
-/* 009C */ 0x00003fc1,0x0009d1c0,0x000037c1,0x00000000,
-/* 009E */ 0x0001ccc1,0x000915c0,0x0001c441,0x0009d800,
-/* 00A0 */ 0x0009cdc1,0x00091240,0x0001c541,0x00091d00,
-/* 00A2 */ 0x0009cfc1,0x00095240,0x0001c741,0x00095c80,
-/* 00A4 */ 0x000e8ca9,0x00099240,0x000e85ad,0x00095640,
-/* 00A6 */ 0x00069ca9,0x00099d80,0x000e952d,0x00099640,
-/* 00A8 */ 0x000eaca9,0x0009d6c0,0x000ea5ad,0x00091a40,
-/* 00AA */ 0x0006bca9,0x0009de80,0x000eb52d,0x00095a40,
-/* 00AC */ 0x000ecca9,0x00099ac0,0x000ec5ad,0x0009da40,
-/* 00AE */ 0x000edca9,0x0009d300,0x000a6e0a,0x00001000,
-/* 00B0 */ 0x000ed52d,0x00091e40,0x000eeca9,0x00095ec0,
-/* 00B2 */ 0x000ee5ad,0x00099e40,0x0006fca9,0x00002500,
-/* 00B4 */ 0x000fb208,0x000c59a0,0x000ef52d,0x0009de40,
-/* 00B6 */ 0x00068ca9,0x000912c1,0x000683ad,0x00095241,
-/* 00B8 */ 0x00020f05,0x000991c1,0x00000000,0x00000000,
-/* 00BA */ 0x00086f88,0x00001000,0x0009cf81,0x000b5340,
-/* 00BC */ 0x0009c701,0x000b92c0,0x0009de81,0x000bd300,
-/* 00BE */ 0x0009d601,0x000b1700,0x0001fd81,0x000b9d80,
-/* 00C0 */ 0x0009f501,0x000b57c0,0x000a0f81,0x000bd740,
-/* 00C2 */ 0x00020701,0x000b5c80,0x000a1681,0x000b97c0,
-/* 00C4 */ 0x00021601,0x00002500,0x000a0701,0x000b9b40,
-/* 00C6 */ 0x000a0f81,0x000b1bc0,0x00021681,0x00002d00,
-/* 00C8 */ 0x00020f81,0x000bd800,0x000a0701,0x000b5bc0,
-/* 00CA */ 0x00021601,0x00003500,0x000a0f81,0x000b5f40,
-/* 00CC */ 0x000a0701,0x000bdbc0,0x00021681,0x00003d00,
-/* 00CE */ 0x00020f81,0x000b1d00,0x000a0701,0x000b1fc0,
-/* 00D0 */ 0x00021601,0x00020500,0x00020f81,0x000b1341,
-/* 00D2 */ 0x000a0701,0x000b9fc0,0x00021681,0x00020d00,
-/* 00D4 */ 0x00020f81,0x000bde80,0x000a0701,0x000bdfc0,
-/* 00D6 */ 0x00021601,0x00021500,0x00020f81,0x000b9341,
-/* 00D8 */ 0x00020701,0x000b53c1,0x00021681,0x00021d00,
-/* 00DA */ 0x000a0f81,0x000d0380,0x0000b601,0x000b15c0,
-/* 00DC */ 0x00007b01,0x00000000,0x00007b81,0x000bd1c0,
-/* 00DE */ 0x00007b01,0x00000000,0x00007b81,0x000b91c0,
-/* 00E0 */ 0x00007b01,0x000b57c0,0x00007b81,0x000b51c0,
-/* 00E2 */ 0x00007b01,0x000b1b40,0x00007b81,0x000b11c0,
-/* 00E4 */ 0x00087b01,0x000c3dc0,0x0007e488,0x000d7e45,
-/* 00E6 */ 0x00000000,0x000d7a44,0x0007e48a,0x00000000,
-/* 00E8 */ 0x00011f05,0x00084080,0x00000000,0x00000000,
-/* 00EA */ 0x00001705,0x000b3540,0x00008a01,0x000bf040,
-/* 00EC */ 0x00007081,0x000bb5c0,0x00055488,0x00000000,
-/* 00EE */ 0x0000d482,0x0003fc40,0x0003fc88,0x00000000,
-/* 00F0 */ 0x0001e401,0x000b3a00,0x0001ec81,0x000bd6c0,
-/* 00F2 */ 0x0002ef88,0x000e7784,0x00056f08,0x00000000,
-/* 00F4 */ 0x000d86b0,0x00001007,0x00008281,0x000bb240,
-/* 00F6 */ 0x0000b801,0x000b7140,0x00007888,0x00000000,
-/* 00F8 */ 0x0000073c,0x00001000,0x0007f188,0x000c0000,
-/* 00FA */ 0x00000000,0x00000000,0x00055288,0x000c555c,
-/* 00FC */ 0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
-/* 00FE */ 0x0000fa88,0x00000000,0x00000032,0x00001000,
-/* 0100 */ 0x0000073d,0x00001000,0x0007f188,0x000c0000,
-/* 0102 */ 0x00000000,0x00000000,0x0008c01c,0x00001003,
-/* 0104 */ 0x00002705,0x00001008,0x0008b201,0x000c1392,
-/* 0106 */ 0x0000ba01,0x00000000,
-/* TASKTREETHREAD */
-/* 0107 */ 0x00008731,0x00001400,0x0004c108,0x000fe0c4,
-/* 0109 */ 0x00057488,0x00000000,0x000a6388,0x00001001,
-/* 010B */ 0x0008b334,0x000bc141,0x0003020e,0x00000000,
-/* 010D */ 0x000986b0,0x00001008,0x00003625,0x000c5dfa,
-/* 010F */ 0x000a638a,0x00001001,0x0008020e,0x00001002,
-/* 0111 */ 0x0009a6b0,0x00001008,0x0007f301,0x00000000,
-/* 0113 */ 0x00000000,0x00000000,0x00002725,0x000a8c40,
-/* 0115 */ 0x000000ae,0x00000000,0x000e8630,0x00001008,
-/* 0117 */ 0x00000000,0x000c74e0,0x0007d182,0x0002d640,
-/* 0119 */ 0x000b8630,0x00001008,0x000799b8,0x0002d6c0,
-/* 011B */ 0x0000748a,0x000c3ec5,0x0007420a,0x000c0000,
-/* 011D */ 0x00062208,0x000c4117,0x000a0630,0x00001009,
-/* 011F */ 0x00000000,0x000c0000,0x0001022e,0x00000000,
-/* 0121 */ 0x0006a630,0x00001009,0x00000032,0x00001000,
-/* 0123 */ 0x000ca21c,0x00001003,0x00005a02,0x00000000,
-/* 0125 */ 0x0001a630,0x00001009,0x00000000,0x000c0000,
-/* 0127 */ 0x00000036,0x00001000,0x00000000,0x00000000,
-/* 0129 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 012B */ 0x00000000,0x00000000,0x0003a730,0x00001008,
-/* 012D */ 0x0007f801,0x000c0000,0x00000037,0x00001000,
-/* 012F */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0131 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0133 */ 0x0003a730,0x00001008,0x00000033,0x00001000,
-/* 0135 */ 0x0003a705,0x00001008,0x00007a01,0x000c0000,
-/* 0137 */ 0x000e6288,0x000d550a,0x0006428a,0x00000000,
-/* 0139 */ 0x00090730,0x0000100a,0x00000000,0x000c0000,
-/* 013B */ 0x00000000,0x00000000,
-/* TASKTREEHEADERCODE */
-/* 013C */ 0x0007aab0,0x00034880,0x000a8fb0,0x0000100b,
-/* 013E */ 0x00057488,0x00000000,0x00033b94,0x00081140,
-/* 0140 */ 0x000183ae,0x00000000,0x000a86b0,0x0000100b,
-/* 0142 */ 0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
-/* 0144 */ 0x00042731,0x00001003,
-/* FGTASKTREEHEADERCODE */
-/* 0145 */ 0x0007aab0,0x00034880,0x00078fb0,0x0000100a,
-/* 0147 */ 0x00057488,0x00000000,0x00033b94,0x00081140,
-/* 0149 */ 0x000183ae,0x00000000,0x000b06b0,0x0000100b,
-/* 014B */ 0x00022f05,0x00000000,0x00007401,0x00091140,
-/* 014D */ 0x00048f05,0x000951c0,0x00042731,0x00001003,
-/* 014F */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47,
-/* 0151 */ 0x00080000,0x000bffc7,0x000fe19e,0x00001003,
-/* 0153 */ 0x00000000,0x00000000,0x0008e19c,0x00001003,
-/* 0155 */ 0x000083c1,0x00093040,0x00000f41,0x00097140,
-/* 0157 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
-/* 0159 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
-/* 015B */ 0x00000000,0x000fdc44,0x00055208,0x00000000,
-/* 015D */ 0x00010705,0x000a2880,0x0000a23a,0x00093a00,
-/* 015F */ 0x0003fc8a,0x000df6c5,0x0004ef0a,0x000c0000,
-/* 0161 */ 0x00012f05,0x00036880,0x00065308,0x000c2997,
-/* 0163 */ 0x000086b0,0x0000100b,0x0004410a,0x000d40c7,
-/* 0165 */ 0x00000000,0x00000000,0x00088730,0x00001004,
-/* 0167 */ 0x00056f0a,0x000ea105,0x00000000,0x00000000,
-/* NULLALGORITHM */
-/* 0169 */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47,
-/* 016B */ 0x00080000,0x000bffc7,0x0000273d,0x00001000,
-/* HFGEXECCHILD */
-/* 016D */ 0x00000000,0x000eba44,
-/* HFGEXECCHILD_98 */
-/* 016E */ 0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
-/* HFGEXECCHILD_PUSH1IND */
-/* 0170 */ 0x00000734,0x00001000,0x00010705,0x000a6880,
-/* 0172 */ 0x00006a88,0x000c75c4,
-/* HFGEXECSIBLING */
-/* 0173 */ 0x00000000,0x000e5084,0x00000000,0x000eba44,
-/* HFGEXECSIBLING_298 */
-/* 0175 */ 0x00087401,0x000e4782,
-/* HFGEXECSIBLING_2IND1 */
-/* 0176 */ 0x00000734,0x00001000,0x00010705,0x000a6880,
-/* 0178 */ 0x00006a88,0x000c75c4,
-/* S16_CODECOUTPUTTASK */
-/* 0179 */ 0x0007c108,0x000c0000,0x0007e721,0x000bed40,
-/* 017B */ 0x00005f25,0x000badc0,0x0003ba97,0x000beb80,
-/* 017D */ 0x00065590,0x000b2e00,0x00033217,0x00003ec0,
-/* 017F */ 0x00065590,0x000b8e40,0x0003ed80,0x000491c0,
-/* 0181 */ 0x00073fb0,0x00074c80,0x000583a0,0x0000100c,
-/* 0183 */ 0x000ee388,0x00042970,0x00008301,0x00021ef2,
-/* 0185 */ 0x000b8f14,0x0000000f,0x000c4d8d,0x0000001b,
-/* 0187 */ 0x000d6dc2,0x000e06c6,0x000032ac,0x000c3916,
-/* 0189 */ 0x0004edc2,0x00074c80,0x00078898,0x00001000,
-/* 018B */ 0x00038894,0x00000032,0x000c4d8d,0x00092e1b,
-/* 018D */ 0x000d6dc2,0x000e06c6,0x0004edc2,0x000c1956,
-/* 018F */ 0x0000722c,0x00034a00,0x00041705,0x0009ed40,
-/* 0191 */ 0x00058730,0x00001400,0x000d7488,0x000c3a00,
-/* 0193 */ 0x00048f05,0x00000000
-};
-/* #CODE_END */
-
-static u32 cwc4630_parameter[] = {
-/* 0000 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0004 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0008 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 000C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0010 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0014 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0018 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 001C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0020 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0024 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0028 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 002C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0030 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0034 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0038 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 003C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0040 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0044 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0048 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0050 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0054 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 005C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0060 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0068 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0070 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0074 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 0078 */ 0x00000000,0x00000000,0x00000000,0x00000000,
-/* 007C */ 0x00000000,0x00000000,0x00000000,0x00000000
-}; /* #PARAMETER_END */
-
-
-static struct dsp_segment_desc cwc4630_segments[] = {
- { SEGTYPE_SP_PROGRAM, 0x00000000, 0x00000328, cwc4630_code },
- { SEGTYPE_SP_PARAMETER, 0x00000000, 0x00000080, cwc4630_parameter },
-};
-
-static struct dsp_module_desc cwc4630_module = {
- "cwc4630",
- {
- 38,
- cwc4630_symbols
- },
- 2,
- cwc4630_segments,
-};
-
-#endif /* __HEADER_cwc4630_H__ */
diff --git a/sound/pci/cs46xx/imgs/cwcasync.h b/sound/pci/cs46xx/imgs/cwcasync.h
deleted file mode 100644
index 70e63e13c2b3..000000000000
--- a/sound/pci/cs46xx/imgs/cwcasync.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/* generated from cwcasync.osp DO NOT MODIFY */
-
-#ifndef __HEADER_cwcasync_H__
-#define __HEADER_cwcasync_H__
-
-static struct dsp_symbol_entry cwcasync_symbols[] = {
- { 0x8000, "EXECCHILD",0x03 },
- { 0x8001, "EXECCHILD_98",0x03 },
- { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
- { 0x8008, "EXECSIBLING",0x03 },
- { 0x800a, "EXECSIBLING_298",0x03 },
- { 0x800b, "EXECSIBLING_2IND1",0x03 },
- { 0x8010, "TIMINGMASTER",0x03 },
- { 0x804f, "S16_CODECINPUTTASK",0x03 },
- { 0x805e, "PCMSERIALINPUTTASK",0x03 },
- { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
- { 0x809a, "S16_MIX",0x03 },
- { 0x80bb, "S16_UPSRC",0x03 },
- { 0x813b, "MIX3_EXP",0x03 },
- { 0x8164, "DECIMATEBYPOW2",0x03 },
- { 0x8197, "VARIDECIMATE",0x03 },
- { 0x81f2, "_3DINPUTTASK",0x03 },
- { 0x820a, "_3DPRLGCINPTASK",0x03 },
- { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
- { 0x8242, "_3DOUTPUTTASK",0x03 },
- { 0x82c4, "HRTF_MORPH_TASK",0x03 },
- { 0x82c6, "WAIT4DATA",0x03 },
- { 0x82fa, "PROLOGIC",0x03 },
- { 0x8496, "DECORRELATOR",0x03 },
- { 0x84a4, "STEREO2MONO",0x03 },
- { 0x0000, "OVERLAYBEGINADDRESS",0x00 },
- { 0x0000, "SPIOWRITE",0x03 },
- { 0x000d, "S16_ASYNCCODECINPUTTASK",0x03 },
- { 0x0043, "SPDIFITASK",0x03 },
- { 0x007b, "SPDIFOTASK",0x03 },
- { 0x0097, "ASYNCHFGTXCODE",0x03 },
- { 0x00be, "ASYNCHFGRXCODE",0x03 },
- { 0x00db, "#CODE_END",0x00 },
-}; /* cwcasync symbols */
-
-static u32 cwcasync_code[] = {
-/* OVERLAYBEGINADDRESS */
-/* 0000 */ 0x00002731,0x00001400,0x00003725,0x000a8440,
-/* 0002 */ 0x000000ae,0x00000000,0x00060630,0x00001000,
-/* 0004 */ 0x00000000,0x000c7560,0x00075282,0x0002d640,
-/* 0006 */ 0x00021705,0x00000000,0x00072ab8,0x0002d6c0,
-/* 0008 */ 0x00020630,0x00001000,0x000c74c2,0x000d4b82,
-/* 000A */ 0x000475c2,0x00000000,0x0003430a,0x000c0000,
-/* 000C */ 0x00042730,0x00001400,
-/* S16_ASYNCCODECINPUTTASK */
-/* 000D */ 0x0006a108,0x000cf2c4,0x0004f4c0,0x00000000,
-/* 000F */ 0x000fa418,0x0000101f,0x0005d402,0x0001c500,
-/* 0011 */ 0x000f0630,0x00001000,0x00004418,0x00001380,
-/* 0013 */ 0x000e243d,0x000d394a,0x00049705,0x00000000,
-/* 0015 */ 0x0007d530,0x000b4240,0x000e00f2,0x00001000,
-/* 0017 */ 0x00009134,0x000ca20a,0x00004c90,0x00001000,
-/* 0019 */ 0x0005d705,0x00000000,0x00004f25,0x00098240,
-/* 001B */ 0x00004725,0x00000000,0x0000e48a,0x00000000,
-/* 001D */ 0x00027295,0x0009c2c0,0x0003df25,0x00000000,
-/* 001F */ 0x000e8030,0x00001001,0x0005f718,0x000ac600,
-/* 0021 */ 0x0007cf30,0x000c2a01,0x00082630,0x00001001,
-/* 0023 */ 0x000504a0,0x00001001,0x00029314,0x000bcb80,
-/* 0025 */ 0x0003cf25,0x000b0e00,0x0004f5c0,0x00000000,
-/* 0027 */ 0x00049118,0x000d888a,0x0007dd02,0x000c6efa,
-/* 0029 */ 0x00000000,0x00000000,0x0004f5c0,0x00069c80,
-/* 002B */ 0x0000d402,0x00000000,0x000e8630,0x00001001,
-/* 002D */ 0x00079130,0x00000000,0x00049118,0x00090e00,
-/* 002F */ 0x0006c10a,0x00000000,0x00000000,0x000c0000,
-/* 0031 */ 0x0007cf30,0x00030580,0x00005725,0x00000000,
-/* 0033 */ 0x000d84a0,0x00001001,0x00029314,0x000b4780,
-/* 0035 */ 0x0003cf25,0x000b8600,0x00000000,0x00000000,
-/* 0037 */ 0x00000000,0x000c0000,0x00000000,0x00042c80,
-/* 0039 */ 0x0001dec1,0x000e488c,0x00031114,0x00000000,
-/* 003B */ 0x0004f5c2,0x00000000,0x0003640a,0x00000000,
-/* 003D */ 0x00000000,0x000e5084,0x00000000,0x000eb844,
-/* 003F */ 0x00007001,0x00000000,0x00000734,0x00001000,
-/* 0041 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4,
-/* SPDIFITASK */
-/* 0043 */ 0x0006a108,0x000cf2c4,0x0004f4c0,0x000d5384,
-/* 0045 */ 0x0007e48a,0x00000000,0x00067718,0x00001000,
-/* 0047 */ 0x0007a418,0x00001000,0x0007221a,0x00000000,
-/* 0049 */ 0x0005d402,0x00014500,0x000b8630,0x00001002,
-/* 004B */ 0x00004418,0x00001780,0x000e243d,0x000d394a,
-/* 004D */ 0x00049705,0x00000000,0x0007d530,0x000b4240,
-/* 004F */ 0x000ac0f2,0x00001002,0x00014414,0x00000000,
-/* 0051 */ 0x00004c90,0x00001000,0x0005d705,0x00000000,
-/* 0053 */ 0x00004f25,0x00098240,0x00004725,0x00000000,
-/* 0055 */ 0x0000e48a,0x00000000,0x00027295,0x0009c2c0,
-/* 0057 */ 0x0007df25,0x00000000,0x000ac030,0x00001003,
-/* 0059 */ 0x0005f718,0x000fe798,0x00029314,0x000bcb80,
-/* 005B */ 0x00000930,0x000b0e00,0x0004f5c0,0x000de204,
-/* 005D */ 0x000884a0,0x00001003,0x0007cf25,0x000e3560,
-/* 005F */ 0x00049118,0x00000000,0x00049118,0x000d888a,
-/* 0061 */ 0x0007dd02,0x000c6efa,0x0000c434,0x00030040,
-/* 0063 */ 0x000fda82,0x000c2312,0x000fdc0e,0x00001001,
-/* 0065 */ 0x00083402,0x000c2b92,0x000706b0,0x00001003,
-/* 0067 */ 0x00075a82,0x00000000,0x0000d625,0x000b0940,
-/* 0069 */ 0x0000840e,0x00001002,0x0000aabc,0x000c511e,
-/* 006B */ 0x00078730,0x00001003,0x0000aaf4,0x000e910a,
-/* 006D */ 0x0004628a,0x00000000,0x00006aca,0x00000000,
-/* 006F */ 0x00000930,0x00000000,0x0004f5c0,0x00069c80,
-/* 0071 */ 0x00046ac0,0x00000000,0x0003c40a,0x000fc898,
-/* 0073 */ 0x00049118,0x00090e00,0x0006c10a,0x00000000,
-/* 0075 */ 0x00000000,0x000e5084,0x00000000,0x000eb844,
-/* 0077 */ 0x00007001,0x00000000,0x00000734,0x00001000,
-/* 0079 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4,
-/* SPDIFOTASK */
-/* 007B */ 0x0006a108,0x000c0000,0x0004f4c0,0x000c3245,
-/* 007D */ 0x0000a418,0x00001000,0x0003a20a,0x00000000,
-/* 007F */ 0x00004418,0x00001380,0x000e243d,0x000d394a,
-/* 0081 */ 0x000c9705,0x000def92,0x0008c030,0x00001004,
-/* 0083 */ 0x0005f718,0x000fe798,0x00000000,0x000c0000,
-/* 0085 */ 0x00005725,0x00000000,0x000704a0,0x00001004,
-/* 0087 */ 0x00029314,0x000b4780,0x0003cf25,0x000b8600,
-/* 0089 */ 0x00000000,0x00000000,0x00000000,0x000c0000,
-/* 008B */ 0x00000000,0x00042c80,0x0001dec1,0x000e488c,
-/* 008D */ 0x00031114,0x00000000,0x0004f5c2,0x00000000,
-/* 008F */ 0x0004a918,0x00098600,0x0006c28a,0x00000000,
-/* 0091 */ 0x00000000,0x000e5084,0x00000000,0x000eb844,
-/* 0093 */ 0x00007001,0x00000000,0x00000734,0x00001000,
-/* 0095 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4,
-/* ASYNCHFGTXCODE */
-/* 0097 */ 0x0002a880,0x000b4e40,0x00042214,0x000e5548,
-/* 0099 */ 0x000542bf,0x00000000,0x00000000,0x000481c0,
-/* 009B */ 0x00000000,0x00000000,0x00000000,0x00000030,
-/* 009D */ 0x0000072d,0x000fbf8a,0x00077f94,0x000ea7df,
-/* 009F */ 0x0002ac95,0x000d3145,0x00002731,0x00001400,
-/* 00A1 */ 0x00006288,0x000c71c4,0x00014108,0x000e6044,
-/* 00A3 */ 0x00035408,0x00000000,0x00025418,0x000a0ec0,
-/* 00A5 */ 0x0001443d,0x000ca21e,0x00046595,0x000d730c,
-/* 00A7 */ 0x0006538e,0x00000000,0x00064630,0x00001005,
-/* 00A9 */ 0x000e7b0e,0x000df782,0x000746b0,0x00001005,
-/* 00AB */ 0x00036f05,0x000c0000,0x00043695,0x000d598c,
-/* 00AD */ 0x0005331a,0x000f2185,0x00000000,0x00000000,
-/* 00AF */ 0x000007ae,0x000bdb00,0x00040630,0x00001400,
-/* 00B1 */ 0x0005e708,0x000c0000,0x0007ef30,0x000b1c00,
-/* 00B3 */ 0x000d86a0,0x00001005,0x00066408,0x000c0000,
-/* 00B5 */ 0x00000000,0x00000000,0x00021843,0x00000000,
-/* 00B7 */ 0x00000cac,0x00062c00,0x00001dac,0x00063400,
-/* 00B9 */ 0x00002cac,0x0006cc80,0x000db943,0x000e5ca1,
-/* 00BB */ 0x00000000,0x00000000,0x0006680a,0x000f3205,
-/* 00BD */ 0x00042730,0x00001400,
-/* ASYNCHFGRXCODE */
-/* 00BE */ 0x00014108,0x000f2204,0x00025418,0x000a2ec0,
-/* 00C0 */ 0x00015dbd,0x00038100,0x00015dbc,0x00000000,
-/* 00C2 */ 0x0005e415,0x00034880,0x0001258a,0x000d730c,
-/* 00C4 */ 0x0006538e,0x000baa40,0x00060630,0x00001006,
-/* 00C6 */ 0x00067b0e,0x000ac380,0x0003ef05,0x00000000,
-/* 00C8 */ 0x0000f734,0x0001c300,0x000586b0,0x00001400,
-/* 00CA */ 0x000b6f05,0x000c3a00,0x00048f05,0x00000000,
-/* 00CC */ 0x0005b695,0x0008c380,0x0002058e,0x00000000,
-/* 00CE */ 0x000500b0,0x00001400,0x0002b318,0x000e998d,
-/* 00D0 */ 0x0006430a,0x00000000,0x00000000,0x000ef384,
-/* 00D2 */ 0x00004725,0x000c0000,0x00000000,0x000f3204,
-/* 00D4 */ 0x00004f25,0x000c0000,0x00080000,0x000e5ca1,
-/* 00D6 */ 0x000cb943,0x000e5ca1,0x0004b943,0x00000000,
-/* 00D8 */ 0x00040730,0x00001400,0x000cb943,0x000e5ca1,
-/* 00DA */ 0x0004b943,0x00000000
-};
-/* #CODE_END */
-
-static struct dsp_segment_desc cwcasync_segments[] = {
- { SEGTYPE_SP_PROGRAM, 0x00000000, 0x000001b6, cwcasync_code },
-};
-
-static struct dsp_module_desc cwcasync_module = {
- "cwcasync",
- {
- 32,
- cwcasync_symbols
- },
- 1,
- cwcasync_segments,
-};
-
-#endif /* __HEADER_cwcasync_H__ */
diff --git a/sound/pci/cs46xx/imgs/cwcbinhack.h b/sound/pci/cs46xx/imgs/cwcbinhack.h
deleted file mode 100644
index f4d93689cd49..000000000000
--- a/sound/pci/cs46xx/imgs/cwcbinhack.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* generated by Benny
- MODIFY ON YOUR OWN RISK */
-
-#ifndef __HEADER_cwcbinhack_H__
-#define __HEADER_cwcbinhack_H__
-
-static struct dsp_symbol_entry cwcbinhack_symbols[] = {
- { 0x02c8, "OVERLAYBEGINADDRESS",0x00 },
- { 0x02c8, "MAGICSNOOPTASK",0x03 },
- { 0x0308, "#CODE_END",0x00 },
-}; /* cwcbinhack symbols */
-
-static u32 cwcbinhack_code[] = {
- /* 0x02c8 */
- 0x0007bfb0,0x000bc240,0x00000c2e,0x000c6084, /* 1 */
- 0x000b8630,0x00001016,0x00006408,0x000efb84, /* 2 */
- 0x00016008,0x00000000,0x0001c088,0x000c0000, /* 3 */
- 0x000fc908,0x000e3392,0x0005f488,0x000efb84, /* 4 */
- 0x0001d402,0x000b2e00,0x0003d418,0x00001000, /* 5 */
- 0x0008d574,0x000c4293,0x00065625,0x000ea30e, /* 6 */
- 0x00096c01,0x000c6f92,0x0001a58a,0x000c6085, /* 7 */
- 0x00002f43,0x00000000,0x000e03a0,0x00001016, /* 8 */
- 0x0005e608,0x000c0000,0x00000000,0x00000000, /* 9 */
- 0x000ca108,0x000dcca1,0x00003bac,0x000c3205, /* 10 */
- 0x00073843,0x00000000,0x00010730,0x00001017, /* 11 */
- 0x0001600a,0x000c0000,0x00057488,0x00000000, /* 12 */
- 0x00000000,0x000e5084,0x00000000,0x000eba44, /* 13 */
- 0x00087401,0x000e4782,0x00000734,0x00001000, /* 14 */
- 0x00010705,0x000a6880,0x00006a88,0x000c75c4, /* 15 */
- 0x00000000,0x00000000,0x00000000,0x00000000, /* 16 */
-};
-/* #CODE_END */
-
-static struct dsp_segment_desc cwcbinhack_segments[] = {
- { SEGTYPE_SP_PROGRAM, 0x00000000, 64, cwcbinhack_code },
-};
-
-static struct dsp_module_desc cwcbinhack_module = {
- "cwcbinhack",
- {
- 3,
- cwcbinhack_symbols
- },
- 1,
- cwcbinhack_segments,
-};
-
-#endif /* __HEADER_cwcbinhack_H__ */
diff --git a/sound/pci/cs46xx/imgs/cwcdma.asp b/sound/pci/cs46xx/imgs/cwcdma.asp
deleted file mode 100644
index a65e1193c89a..000000000000
--- a/sound/pci/cs46xx/imgs/cwcdma.asp
+++ /dev/null
@@ -1,170 +0,0 @@
-//
-// Copyright(c) by Benny Sjostrand (benny@hostmobility.com)
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-//
-
-
-//
-// This code runs inside the DSP (cs4610, cs4612, cs4624, or cs4630),
-// to compile it you need a tool named SPASM 3.0 and DSP code owned by
-// Cirrus Logic(R). The SPASM program will generate a object file (cwcdma.osp),
-// the "ospparser" tool will genereate the cwcdma.h file it's included from
-// the cs46xx_lib.c file.
-//
-//
-// The purpose of this code is very simple: make it possible to tranfser
-// the samples 'as they are' with no alteration from a PCMreader
-// SCB (DMA from host) to any other SCB. This is useful for AC3 through SPDIF.
-// SRC (source rate converters) task always alters the samples in somehow,
-// however it's from 48khz -> 48khz.
-// The alterations are not audible, but AC3 wont work.
-//
-// ...
-// |
-// +---------------+
-// | AsynchFGTxSCB |
-// +---------------+
-// |
-// subListPtr
-// |
-// +--------------+
-// | DMAReader |
-// +--------------+
-// |
-// subListPtr
-// |
-// +-------------+
-// | PCMReader |
-// +-------------+
-// (DMA from host)
-//
-
-struct dmaSCB
- {
- long dma_reserved1[3];
-
- short dma_reserved2:dma_outBufPtr;
-
- short dma_unused1:dma_unused2;
-
- long dma_reserved3[4];
-
- short dma_subListPtr:dma_nextSCB;
- short dma_SPBptr:dma_entryPoint;
-
- long dma_strmRsConfig;
- long dma_strmBufPtr;
-
- long dma_reserved4;
-
- VolumeControl s2m_volume;
- };
-
-#export DMAReader
-void DMAReader()
-{
- execChild();
- r2 = r0->dma_subListPtr;
- r1 = r0->nextSCB;
-
- rsConfig01 = r2->strmRsConfig;
- // Load rsConfig for input buffer
-
- rsDMA01 = r2->basicReq.daw, , tb = Z(0 - rf);
- // Load rsDMA in case input buffer is a DMA buffer Test to see if there is any data to transfer
-
- if (tb) goto execSibling_2ind1 after {
- r5 = rf + (-1);
- r6 = r1->dma_entryPoint; // r6 = entry point of sibling task
- r1 = r1->dma_SPBptr, // r1 = pointer to sibling task's SPB
- , ind = r6; // Load entry point of sibling task
- }
-
- rsConfig23 = r0->dma_strmRsConfig;
- // Load rsConfig for output buffer (never a DMA buffer)
-
- r4 = r0->dma_outBufPtr;
-
- rsa0 = r2->strmBufPtr;
- // rsa0 = input buffer pointer
-
- for (i = r5; i >= 0; --i)
- after {
- rsa2 = r4;
- // rsa2 = output buffer pointer
-
- nop;
- nop;
- }
- //*****************************
- // TODO: cycles to this point *
- //*****************************
- {
- acc0 = (rsd0 = *rsa0++1);
- // get sample
-
- nop; // Those "nop"'s are really uggly, but there's
- nop; // something with DSP's pipelines which I don't
- nop; // understand, resulting this code to fail without
- // having those "nop"'s (Benny)
-
- rsa0?reqDMA = r2;
- // Trigger DMA transfer on input stream,
- // if needed to replenish input buffer
-
- nop;
- // Yet another magic "nop" to make stuff work
-
- ,,r98 = acc0 $+>> 0;
- // store sample in ALU
-
- nop;
- // latency on load register.
- // (this one is understandable)
-
- *rsa2++1 = r98;
- // store sample in output buffer
-
- nop; // The same story
- nop; // as above again ...
- nop;
- }
- // TODO: cycles per loop iteration
-
- r2->strmBufPtr = rsa0,, ;
- // Update the modified buffer pointers
-
- r4 = rsa2;
- // Load output pointer position into r4
-
- r2 = r0->nextSCB;
- // Sibling task
-
- goto execSibling_2ind1 // takes 6 cycles
- after {
- r98 = r2->thisSPB:entryPoint;
- // Load child routine entry and data address
-
- r1 = r9;
- // r9 is r2->thisSPB
-
- r0->dma_outBufPtr = r4,,
- // Store updated output buffer pointer
-
- ind = r8;
- // r8 is r2->entryPoint
- }
-}
diff --git a/sound/pci/cs46xx/imgs/cwcdma.h b/sound/pci/cs46xx/imgs/cwcdma.h
deleted file mode 100644
index 7ff0d4587161..000000000000
--- a/sound/pci/cs46xx/imgs/cwcdma.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* generated from cwcdma.osp DO NOT MODIFY */
-
-#ifndef __HEADER_cwcdma_H__
-#define __HEADER_cwcdma_H__
-
-static struct dsp_symbol_entry cwcdma_symbols[] = {
- { 0x8000, "EXECCHILD",0x03 },
- { 0x8001, "EXECCHILD_98",0x03 },
- { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
- { 0x8008, "EXECSIBLING",0x03 },
- { 0x800a, "EXECSIBLING_298",0x03 },
- { 0x800b, "EXECSIBLING_2IND1",0x03 },
- { 0x8010, "TIMINGMASTER",0x03 },
- { 0x804f, "S16_CODECINPUTTASK",0x03 },
- { 0x805e, "PCMSERIALINPUTTASK",0x03 },
- { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
- { 0x809a, "S16_MIX",0x03 },
- { 0x80bb, "S16_UPSRC",0x03 },
- { 0x813b, "MIX3_EXP",0x03 },
- { 0x8164, "DECIMATEBYPOW2",0x03 },
- { 0x8197, "VARIDECIMATE",0x03 },
- { 0x81f2, "_3DINPUTTASK",0x03 },
- { 0x820a, "_3DPRLGCINPTASK",0x03 },
- { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
- { 0x8242, "_3DOUTPUTTASK",0x03 },
- { 0x82c4, "HRTF_MORPH_TASK",0x03 },
- { 0x82c6, "WAIT4DATA",0x03 },
- { 0x82fa, "PROLOGIC",0x03 },
- { 0x8496, "DECORRELATOR",0x03 },
- { 0x84a4, "STEREO2MONO",0x03 },
- { 0x0000, "OVERLAYBEGINADDRESS",0x00 },
- { 0x0000, "DMAREADER",0x03 },
- { 0x0018, "#CODE_END",0x00 },
-}; /* cwcdma symbols */
-
-static u32 cwcdma_code[] = {
-/* OVERLAYBEGINADDRESS */
-/* 0000 */ 0x00002731,0x00001400,0x0004c108,0x000e5044,
-/* 0002 */ 0x0005f608,0x00000000,0x000007ae,0x000be300,
-/* 0004 */ 0x00058630,0x00001400,0x0007afb0,0x000e9584,
-/* 0006 */ 0x00007301,0x000a9840,0x0005e708,0x000cd104,
-/* 0008 */ 0x00067008,0x00000000,0x000902a0,0x00001000,
-/* 000A */ 0x00012a01,0x000c0000,0x00000000,0x00000000,
-/* 000C */ 0x00021843,0x000c0000,0x00000000,0x000c0000,
-/* 000E */ 0x0000e101,0x000c0000,0x00000cac,0x00000000,
-/* 0010 */ 0x00080000,0x000e5ca1,0x00000000,0x000c0000,
-/* 0012 */ 0x00000000,0x00000000,0x00000000,0x00092c00,
-/* 0014 */ 0x000122c1,0x000e5084,0x00058730,0x00001400,
-/* 0016 */ 0x000d7488,0x000e4782,0x00007401,0x0001c100
-};
-
-/* #CODE_END */
-
-static struct dsp_segment_desc cwcdma_segments[] = {
- { SEGTYPE_SP_PROGRAM, 0x00000000, 0x00000030, cwcdma_code },
-};
-
-static struct dsp_module_desc cwcdma_module = {
- "cwcdma",
- {
- 27,
- cwcdma_symbols
- },
- 1,
- cwcdma_segments,
-};
-
-#endif /* __HEADER_cwcdma_H__ */
diff --git a/sound/pci/cs46xx/imgs/cwcsnoop.h b/sound/pci/cs46xx/imgs/cwcsnoop.h
deleted file mode 100644
index 6929d0a5a3f3..000000000000
--- a/sound/pci/cs46xx/imgs/cwcsnoop.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* generated from cwcsnoop.osp DO NOT MODIFY */
-
-#ifndef __HEADER_cwcsnoop_H__
-#define __HEADER_cwcsnoop_H__
-
-static struct dsp_symbol_entry cwcsnoop_symbols[] = {
- { 0x0500, "OVERLAYBEGINADDRESS",0x00 },
- { 0x0500, "OUTPUTSNOOP",0x03 },
- { 0x051f, "#CODE_END",0x00 },
-}; /* cwcsnoop symbols */
-
-static u32 cwcsnoop_code[] = {
-/* 0000 */ 0x0007bfb0,0x000b4e40,0x0007c088,0x000c0617,
-/* 0002 */ 0x00049705,0x00000000,0x00080630,0x00001028,
-/* 0004 */ 0x00076408,0x000efb84,0x00066008,0x00000000,
-/* 0006 */ 0x0007c908,0x000c0000,0x00046725,0x000efa44,
-/* 0008 */ 0x0005f708,0x00000000,0x0001d402,0x000b2e00,
-/* 000A */ 0x0003d418,0x00001000,0x0008d574,0x000c4293,
-/* 000C */ 0x00065625,0x000ea30e,0x00096c01,0x000c6f92,
-/* 000E */ 0x0006a58a,0x000f6085,0x00002f43,0x00000000,
-/* 0010 */ 0x000a83a0,0x00001028,0x0005e608,0x000c0000,
-/* 0012 */ 0x00000000,0x00000000,0x000ca108,0x000dcca1,
-/* 0014 */ 0x00003bac,0x000fb205,0x00073843,0x00000000,
-/* 0016 */ 0x000d8730,0x00001028,0x0006600a,0x000c0000,
-/* 0018 */ 0x00057488,0x00000000,0x00000000,0x000e5084,
-/* 001A */ 0x00000000,0x000eba44,0x00087401,0x000e4782,
-/* 001C */ 0x00000734,0x00001000,0x00010705,0x000a6880,
-/* 001E */ 0x00006a88,0x000c75c4
-};
-/* #CODE_END */
-
-static struct dsp_segment_desc cwcsnoop_segments[] = {
- { SEGTYPE_SP_PROGRAM, 0x00000000, 0x0000003e, cwcsnoop_code },
-};
-
-static struct dsp_module_desc cwcsnoop_module = {
- "cwcsnoop",
- {
- 3,
- cwcsnoop_symbols
- },
- 1,
- cwcsnoop_segments,
-};
-
-#endif /* __HEADER_cwcsnoop_H__ */
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 902bebd3b3fb..c0d2835344da 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -253,7 +253,7 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
static int snd_cs5535audio_free(struct cs5535audio *cs5535au)
{
synchronize_irq(cs5535au->irq);
- pci_set_power_state(cs5535au->pci, 3);
+ pci_set_power_state(cs5535au->pci, PCI_D3hot);
if (cs5535au->irq >= 0)
free_irq(cs5535au->irq, cs5535au);
diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c
index da1cb9c4c76c..e6a44507d557 100644
--- a/sound/pci/cs5535audio/cs5535audio_olpc.c
+++ b/sound/pci/cs5535audio/cs5535audio_olpc.c
@@ -161,13 +161,13 @@ int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97)
/* drop the original AD1888 HPF control */
memset(&elem, 0, sizeof(elem));
elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name));
+ strlcpy(elem.name, "High Pass Filter Enable", sizeof(elem.name));
snd_ctl_remove_id(card, &elem);
/* drop the original V_REFOUT control */
memset(&elem, 0, sizeof(elem));
elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strncpy(elem.name, "V_REFOUT Enable", sizeof(elem.name));
+ strlcpy(elem.name, "V_REFOUT Enable", sizeof(elem.name));
snd_ctl_remove_id(card, &elem);
/* add the OLPC-specific controls */
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index b5fa583a239a..eb86829529eb 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -435,6 +435,11 @@ atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
return 0;
position = src->ops->get_ca(src);
+ if (position < apcm->vm_block->addr) {
+ snd_printdd("ctxfi: bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", position, apcm->vm_block->addr, apcm->vm_block->size);
+ position = apcm->vm_block->addr;
+ }
+
size = apcm->vm_block->size;
max_cisz = src->multi * src->rsc.msr;
max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8);
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 0c00eb4088ef..84f86bf63b8f 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -33,7 +33,7 @@ struct daio_rsc_idx {
unsigned short right;
};
-struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
+static struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
[LINEO1] = {.left = 0x00, .right = 0x01},
[LINEO2] = {.left = 0x18, .right = 0x19},
[LINEO3] = {.left = 0x08, .right = 0x09},
@@ -44,7 +44,7 @@ struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = {
[SPDIFI1] = {.left = 0x95, .right = 0x9d},
};
-struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
+static struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
[LINEO1] = {.left = 0x40, .right = 0x41},
[LINEO2] = {.left = 0x60, .right = 0x61},
[LINEO3] = {.left = 0x50, .right = 0x51},
diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c
index 110b8ace6d8a..a689f2552706 100644
--- a/sound/pci/ctxfi/cthardware.c
+++ b/sound/pci/ctxfi/cthardware.c
@@ -69,7 +69,8 @@ unsigned int get_field(unsigned int data, unsigned int field)
{
int i;
- BUG_ON(!field);
+ if (WARN_ON(!field))
+ return 0;
/* @field should always be greater than 0 */
for (i = 0; !(field & (1 << i)); )
i++;
@@ -81,7 +82,8 @@ void set_field(unsigned int *data, unsigned int field, unsigned int value)
{
int i;
- BUG_ON(!field);
+ if (WARN_ON(!field))
+ return;
/* @field should always be greater than 0 */
for (i = 0; !(field & (1 << i)); )
i++;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 0275209ca82e..1f9c7c4bbcd8 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1182,15 +1182,20 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
u32 *gpr_map;
mm_segment_t seg;
- if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
- (icode->gpr_map = (u_int32_t __user *)
- kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
- GFP_KERNEL)) == NULL ||
- (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
- sizeof(*controls), GFP_KERNEL)) == NULL) {
- err = -ENOMEM;
- goto __err;
- }
+ err = -ENOMEM;
+ icode = kzalloc(sizeof(*icode), GFP_KERNEL);
+ if (!icode)
+ return err;
+
+ icode->gpr_map = (u_int32_t __user *) kcalloc(512 + 256 + 256 + 2 * 1024,
+ sizeof(u_int32_t), GFP_KERNEL);
+ if (!icode->gpr_map)
+ goto __err_gpr;
+ controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
+ sizeof(*controls), GFP_KERNEL);
+ if (!controls)
+ goto __err_ctrls;
+
gpr_map = (u32 __force *)icode->gpr_map;
icode->tram_data_map = icode->gpr_map + 512;
@@ -1741,12 +1746,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
emu->support_tlv = 0; /* clear again */
snd_leave_user(seg);
- __err:
+__err:
kfree(controls);
- if (icode != NULL) {
- kfree((void __force *)icode->gpr_map);
- kfree(icode);
- }
+__err_ctrls:
+ kfree((void __force *)icode->gpr_map);
+__err_gpr:
+ kfree(icode);
return err;
}
@@ -1813,18 +1818,26 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
u32 *gpr_map;
mm_segment_t seg;
- if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- if ((icode->gpr_map = (u_int32_t __user *)
- kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t),
- GFP_KERNEL)) == NULL ||
- (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
- sizeof(struct snd_emu10k1_fx8010_control_gpr),
- GFP_KERNEL)) == NULL ||
- (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) {
- err = -ENOMEM;
- goto __err;
- }
+ err = -ENOMEM;
+ icode = kzalloc(sizeof(*icode), GFP_KERNEL);
+ if (!icode)
+ return err;
+
+ icode->gpr_map = (u_int32_t __user *) kcalloc(256 + 160 + 160 + 2 * 512,
+ sizeof(u_int32_t), GFP_KERNEL);
+ if (!icode->gpr_map)
+ goto __err_gpr;
+
+ controls = kcalloc(SND_EMU10K1_GPR_CONTROLS,
+ sizeof(struct snd_emu10k1_fx8010_control_gpr),
+ GFP_KERNEL);
+ if (!controls)
+ goto __err_ctrls;
+
+ ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL);
+ if (!ipcm)
+ goto __err_ipcm;
+
gpr_map = (u32 __force *)icode->gpr_map;
icode->tram_data_map = icode->gpr_map + 256;
@@ -2363,13 +2376,14 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
snd_leave_user(seg);
if (err >= 0)
err = snd_emu10k1_ipcm_poke(emu, ipcm);
- __err:
+__err:
kfree(ipcm);
+__err_ipcm:
kfree(controls);
- if (icode != NULL) {
- kfree((void __force *)icode->gpr_map);
- kfree(icode);
- }
+__err_ctrls:
+ kfree((void __force *)icode->gpr_map);
+__err_gpr:
+ kfree(icode);
return err;
}
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index b0e3d92c4656..772cc36f951d 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1422,7 +1422,7 @@ static void snd_es1968_free_dmabuf(struct es1968 *chip)
if (! chip->dma.area)
return;
- snd_dma_reserve_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci));
+ snd_dma_free_pages(&chip->dma);
while ((p = chip->buf_list.next) != &chip->buf_list) {
struct esm_memory *chunk = list_entry(p, struct esm_memory, list);
list_del(p);
@@ -1438,20 +1438,18 @@ snd_es1968_init_dmabuf(struct es1968 *chip)
chip->dma.dev.type = SNDRV_DMA_TYPE_DEV;
chip->dma.dev.dev = snd_dma_pci_data(chip->pci);
- if (! snd_dma_get_reserved_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci))) {
- err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
- snd_dma_pci_data(chip->pci),
- chip->total_bufsize, &chip->dma);
- if (err < 0 || ! chip->dma.area) {
- snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n",
- chip->total_bufsize);
- return -ENOMEM;
- }
- if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) {
- snd_dma_free_pages(&chip->dma);
- snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n");
- return -ENOMEM;
- }
+ err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV,
+ snd_dma_pci_data(chip->pci),
+ chip->total_bufsize, &chip->dma);
+ if (err < 0 || ! chip->dma.area) {
+ snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n",
+ chip->total_bufsize);
+ return -ENOMEM;
+ }
+ if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) {
+ snd_dma_free_pages(&chip->dma);
+ snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n");
+ return -ENOMEM;
}
INIT_LIST_HEAD(&chip->buf_list);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 8de66ccd7279..0e53634dbbd8 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -87,69 +87,54 @@ config SND_HDA_PATCH_LOADER
This option turns on hwdep and reconfig features automatically.
config SND_HDA_CODEC_REALTEK
- bool "Build Realtek HD-audio codec support"
- default y
+ tristate "Build Realtek HD-audio codec support"
select SND_HDA_GENERIC
help
- Say Y here to include Realtek HD-audio codec support in
+ Say Y or M here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-realtek.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_REALTEK=m
config SND_HDA_CODEC_ANALOG
- bool "Build Analog Device HD-audio codec support"
- default y
+ tristate "Build Analog Device HD-audio codec support"
select SND_HDA_GENERIC
help
- Say Y here to include Analog Device HD-audio codec support in
+ Say Y or M here to include Analog Device HD-audio codec support in
snd-hda-intel driver, such as AD1986A.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-analog.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_ANALOG=m
config SND_HDA_CODEC_SIGMATEL
- bool "Build IDT/Sigmatel HD-audio codec support"
- default y
+ tristate "Build IDT/Sigmatel HD-audio codec support"
select SND_HDA_GENERIC
help
- Say Y here to include IDT (Sigmatel) HD-audio codec support in
+ Say Y or M here to include IDT (Sigmatel) HD-audio codec support in
snd-hda-intel driver, such as STAC9200.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-idt.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_SIGMATEL=m
config SND_HDA_CODEC_VIA
- bool "Build VIA HD-audio codec support"
- default y
+ tristate "Build VIA HD-audio codec support"
select SND_HDA_GENERIC
help
- Say Y here to include VIA HD-audio codec support in
+ Say Y or M here to include VIA HD-audio codec support in
snd-hda-intel driver, such as VT1708.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-via.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_VIA=m
config SND_HDA_CODEC_HDMI
- bool "Build HDMI/DisplayPort HD-audio codec support"
- default y
+ tristate "Build HDMI/DisplayPort HD-audio codec support"
help
- Say Y here to include HDMI and DisplayPort HD-audio codec
+ Say Y or M here to include HDMI and DisplayPort HD-audio codec
support in snd-hda-intel driver. This includes all AMD/ATI,
Intel and Nvidia HDMI/DisplayPort codecs.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-hdmi.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_HDMI=m
config SND_HDA_I915
bool
@@ -157,60 +142,49 @@ config SND_HDA_I915
depends on DRM_I915
config SND_HDA_CODEC_CIRRUS
- bool "Build Cirrus Logic codec support"
- default y
+ tristate "Build Cirrus Logic codec support"
select SND_HDA_GENERIC
help
- Say Y here to include Cirrus Logic codec support in
+ Say Y or M here to include Cirrus Logic codec support in
snd-hda-intel driver, such as CS4206.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-cirrus.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CIRRUS=m
config SND_HDA_CODEC_CONEXANT
- bool "Build Conexant HD-audio codec support"
- default y
+ tristate "Build Conexant HD-audio codec support"
select SND_HDA_GENERIC
help
- Say Y here to include Conexant HD-audio codec support in
+ Say Y or M here to include Conexant HD-audio codec support in
snd-hda-intel driver, such as CX20549.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-conexant.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CONEXANT=m
config SND_HDA_CODEC_CA0110
- bool "Build Creative CA0110-IBG codec support"
- default y
+ tristate "Build Creative CA0110-IBG codec support"
select SND_HDA_GENERIC
help
- Say Y here to include Creative CA0110-IBG codec support in
+ Say Y or M here to include Creative CA0110-IBG codec support in
snd-hda-intel driver, found on some Creative X-Fi cards.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-ca0110.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CA0110=m
config SND_HDA_CODEC_CA0132
- bool "Build Creative CA0132 codec support"
- default y
+ tristate "Build Creative CA0132 codec support"
help
- Say Y here to include Creative CA0132 codec support in
+ Say Y or M here to include Creative CA0132 codec support in
snd-hda-intel driver.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-ca0132.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CA0132=m
config SND_HDA_CODEC_CA0132_DSP
bool "Support new DSP code for CA0132 codec"
- depends on SND_HDA_CODEC_CA0132 && FW_LOADER
+ depends on SND_HDA_CODEC_CA0132
select SND_HDA_DSP_LOADER
+ select FW_LOADER
help
Say Y here to enable the DSP for Creative CA0132 for extended
features like equalizer or echo cancellation.
@@ -219,37 +193,33 @@ config SND_HDA_CODEC_CA0132_DSP
(ctefx.bin).
config SND_HDA_CODEC_CMEDIA
- bool "Build C-Media HD-audio codec support"
- default y
+ tristate "Build C-Media HD-audio codec support"
select SND_HDA_GENERIC
help
- Say Y here to include C-Media HD-audio codec support in
+ Say Y or M here to include C-Media HD-audio codec support in
snd-hda-intel driver, such as CMI9880.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-cmedia.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_CMEDIA=m
config SND_HDA_CODEC_SI3054
- bool "Build Silicon Labs 3054 HD-modem codec support"
- default y
+ tristate "Build Silicon Labs 3054 HD-modem codec support"
help
- Say Y here to include Silicon Labs 3054 HD-modem codec
+ Say Y or M here to include Silicon Labs 3054 HD-modem codec
(and compatibles) support in snd-hda-intel driver.
- When the HD-audio driver is built as a module, the codec
- support code is also built as another module,
- snd-hda-codec-si3054.
- This module is automatically loaded at probing.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_CODEC_SI3054=m
config SND_HDA_GENERIC
- bool "Enable generic HD-audio codec parser"
- default y
+ tristate "Enable generic HD-audio codec parser"
help
- Say Y here to enable the generic HD-audio codec parser
+ Say Y or M here to enable the generic HD-audio codec parser
in snd-hda-intel driver.
+comment "Set to Y if you want auto-loading the codec driver"
+ depends on SND_HDA_INTEL=y && SND_HDA_GENERIC=m
+
config SND_HDA_POWER_SAVE_DEFAULT
int "Default time-out for HD-audio power-save mode"
depends on PM
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index c091438286a3..1fcb118e480a 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -3,7 +3,6 @@ snd-hda-intel-objs := hda_intel.o
snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o
snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
-snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
@@ -12,6 +11,7 @@ snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o
CFLAGS_hda_codec.o := -I$(src)
CFLAGS_hda_intel.o := -I$(src)
+snd-hda-codec-generic-objs := hda_generic.o
snd-hda-codec-realtek-objs := patch_realtek.o
snd-hda-codec-cmedia-objs := patch_cmedia.o
snd-hda-codec-analog-objs := patch_analog.o
@@ -27,40 +27,19 @@ snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o
# common driver
obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o
-# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans)
-ifdef CONFIG_SND_HDA_CODEC_REALTEK
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_CMEDIA
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_ANALOG
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_SIGMATEL
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_SI3054
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_CIRRUS
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_CA0110
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_CA0132
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_CONEXANT
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_VIA
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o
-endif
-ifdef CONFIG_SND_HDA_CODEC_HDMI
-obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o
-endif
+# codec drivers
+obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
+obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
+obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
+obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
+obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
+obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
+obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
+obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
+obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
+obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
# this must be the last entry after codec drivers;
# otherwise the codec patches won't be hooked before the PCI probe
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 48a9d004d6d9..47ad31c6aa70 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -414,7 +414,7 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
+EXPORT_SYMBOL_GPL(snd_hda_parse_pin_defcfg);
int snd_hda_get_input_pin_attr(unsigned int def_conf)
{
@@ -435,7 +435,7 @@ int snd_hda_get_input_pin_attr(unsigned int def_conf)
return INPUT_PIN_ATTR_FRONT;
return INPUT_PIN_ATTR_NORMAL;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+EXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr);
/**
* hda_get_input_pin_label - Give a label for the given input pin
@@ -547,7 +547,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
cfg->inputs[input].pin,
has_multiple_pins);
}
-EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+EXPORT_SYMBOL_GPL(hda_get_autocfg_input_label);
/* return the position of NID in the list, or -1 if not found */
static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
@@ -638,7 +638,7 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
/* don't add channel suffix for Headphone controls */
int idx = get_hp_label_index(codec, nid, cfg->hp_pins,
cfg->hp_outs);
- if (idx >= 0)
+ if (idx >= 0 && indexp)
*indexp = idx;
sfx = "";
}
@@ -721,7 +721,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
strlcpy(label, name, maxlen);
return 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+EXPORT_SYMBOL_GPL(snd_hda_get_pin_label);
int snd_hda_add_verbs(struct hda_codec *codec,
const struct hda_verb *list)
@@ -733,7 +733,7 @@ int snd_hda_add_verbs(struct hda_codec *codec,
*v = list;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_verbs);
+EXPORT_SYMBOL_GPL(snd_hda_add_verbs);
void snd_hda_apply_verbs(struct hda_codec *codec)
{
@@ -743,7 +743,7 @@ void snd_hda_apply_verbs(struct hda_codec *codec)
snd_hda_sequence_write(codec, *v);
}
}
-EXPORT_SYMBOL_HDA(snd_hda_apply_verbs);
+EXPORT_SYMBOL_GPL(snd_hda_apply_verbs);
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg)
@@ -751,7 +751,7 @@ void snd_hda_apply_pincfgs(struct hda_codec *codec,
for (; cfg->nid; cfg++)
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
}
-EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
+EXPORT_SYMBOL_GPL(snd_hda_apply_pincfgs);
static void set_pin_targets(struct hda_codec *codec,
const struct hda_pintbl *cfg)
@@ -822,7 +822,7 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
if (codec->fixup_list)
apply_fixup(codec, codec->fixup_id, action, 0);
}
-EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
+EXPORT_SYMBOL_GPL(snd_hda_apply_fixup);
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
@@ -880,4 +880,4 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
codec->fixup_name = name;
}
}
-EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);
+EXPORT_SYMBOL_GPL(snd_hda_pick_fixup);
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 63c99090a4ec..0589b39cda6e 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -110,6 +110,7 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type,
case SND_BELL:
if (hz)
hz = 1000;
+ /* fallthru */
case SND_TONE:
if (beep->linear_tone)
beep->tone = beep_linear_tone(beep, hz);
@@ -151,10 +152,8 @@ static int snd_hda_do_attach(struct hda_beep *beep)
int err;
input_dev = input_allocate_device();
- if (!input_dev) {
- printk(KERN_INFO "hda_beep: unable to allocate input device\n");
+ if (!input_dev)
return -ENOMEM;
- }
/* setup digital beep device */
input_dev->name = "HDA Digital PCBeep";
@@ -195,7 +194,7 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device);
+EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device);
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
{
@@ -232,7 +231,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device);
+EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device);
void snd_hda_detach_beep_device(struct hda_codec *codec)
{
@@ -244,7 +243,7 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
kfree(beep);
}
}
-EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
+EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
{
@@ -266,7 +265,7 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
}
return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get_beep);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep);
int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -289,4 +288,4 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
return 0;
return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put_beep);
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 5b6c4e3c92ca..dafcf82139e2 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -26,6 +26,7 @@
#include <linux/pci.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/async.h>
#include <sound/core.h>
#include "hda_codec.h"
#include <sound/asoundef.h>
@@ -83,7 +84,7 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
mutex_unlock(&preset_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset);
+EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
{
@@ -92,23 +93,31 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
mutex_unlock(&preset_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
+EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset);
#ifdef CONFIG_PM
#define codec_in_pm(codec) ((codec)->in_pm)
static void hda_power_work(struct work_struct *work);
static void hda_keep_power_on(struct hda_codec *codec);
#define hda_codec_is_power_on(codec) ((codec)->power_on)
-static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up)
+
+static void hda_call_pm_notify(struct hda_codec *codec, bool power_up)
{
+ struct hda_bus *bus = codec->bus;
+
+ if ((power_up && codec->pm_up_notified) ||
+ (!power_up && !codec->pm_up_notified))
+ return;
if (bus->ops.pm_notify)
bus->ops.pm_notify(bus, power_up);
+ codec->pm_up_notified = power_up;
}
+
#else
#define codec_in_pm(codec) 0
static inline void hda_keep_power_on(struct hda_codec *codec) {}
#define hda_codec_is_power_on(codec) 1
-#define hda_call_pm_notify(bus, state) {}
+#define hda_call_pm_notify(codec, state) {}
#endif
/**
@@ -143,7 +152,7 @@ const char *snd_hda_get_jack_location(u32 cfg)
}
return "UNKNOWN";
}
-EXPORT_SYMBOL_HDA(snd_hda_get_jack_location);
+EXPORT_SYMBOL_GPL(snd_hda_get_jack_location);
/**
* snd_hda_get_jack_connectivity - Give a connectivity string of the jack
@@ -158,7 +167,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg)
return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3];
}
-EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity);
+EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity);
/**
* snd_hda_get_jack_type - Give a type string of the jack
@@ -179,7 +188,7 @@ const char *snd_hda_get_jack_type(u32 cfg)
return jack_types[(cfg & AC_DEFCFG_DEVICE)
>> AC_DEFCFG_DEVICE_SHIFT];
}
-EXPORT_SYMBOL_HDA(snd_hda_get_jack_type);
+EXPORT_SYMBOL_GPL(snd_hda_get_jack_type);
/*
* Compose a 32bit command word to be sent to the HD-audio controller
@@ -275,7 +284,7 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
return -1;
return res;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_read);
+EXPORT_SYMBOL_GPL(snd_hda_codec_read);
/**
* snd_hda_codec_write - send a single command without waiting for response
@@ -297,7 +306,7 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags,
return codec_exec_verb(codec, cmd, flags,
codec->bus->sync_write ? &res : NULL);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_write);
+EXPORT_SYMBOL_GPL(snd_hda_codec_write);
/**
* snd_hda_sequence_write - sequence writes
@@ -312,7 +321,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq)
for (; seq->nid; seq++)
snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param);
}
-EXPORT_SYMBOL_HDA(snd_hda_sequence_write);
+EXPORT_SYMBOL_GPL(snd_hda_sequence_write);
/**
* snd_hda_get_sub_nodes - get the range of sub nodes
@@ -334,7 +343,7 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
*start_id = (parm >> 16) & 0x7fff;
return (int)(parm & 0x7fff);
}
-EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes);
+EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes);
/* connection list element */
struct hda_conn_list {
@@ -444,7 +453,7 @@ int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
added = true;
}
}
-EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
+EXPORT_SYMBOL_GPL(snd_hda_get_conn_list);
/**
* snd_hda_get_connections - copy connection list
@@ -476,7 +485,7 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
return len;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_connections);
+EXPORT_SYMBOL_GPL(snd_hda_get_connections);
/* return CONNLIST_LEN parameter of the given widget */
static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid)
@@ -565,7 +574,7 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
range_val = !!(parm & (1 << (shift-1))); /* ranges */
val = parm & mask;
if (val == 0 && null_count++) { /* no second chance */
- snd_printk(KERN_WARNING "hda_codec: "
+ snd_printdd("hda_codec: "
"invalid CONNECT_LIST verb %x[%i]:%x\n",
nid, i, parm);
return 0;
@@ -625,7 +634,7 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
return add_conn_list(codec, nid, len, list);
}
-EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
+EXPORT_SYMBOL_GPL(snd_hda_override_conn_list);
/**
* snd_hda_get_conn_index - get the connection index of the given NID
@@ -664,7 +673,7 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
}
return -1;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_conn_index);
+EXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
/* return DEVLIST_LEN parameter of the given widget */
@@ -760,7 +769,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex)
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event);
+EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event);
/*
* process queued unsolicited events
@@ -831,6 +840,7 @@ static int snd_hda_bus_free(struct hda_bus *bus)
bus->ops.private_free(bus);
if (bus->workq)
destroy_workqueue(bus->workq);
+
kfree(bus);
return 0;
}
@@ -920,9 +930,9 @@ int snd_hda_bus_new(struct snd_card *card,
*busp = bus;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_bus_new);
+EXPORT_SYMBOL_GPL(snd_hda_bus_new);
-#ifdef CONFIG_SND_HDA_GENERIC
+#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
#define is_generic_config(codec) \
(codec->modelname && !strcmp(codec->modelname, "generic"))
#else
@@ -945,9 +955,6 @@ find_codec_preset(struct hda_codec *codec)
const struct hda_codec_preset *preset;
unsigned int mod_requested = 0;
- if (is_generic_config(codec))
- return NULL; /* use the generic parser */
-
again:
mutex_lock(&preset_mutex);
list_for_each_entry(tbl, &hda_preset_tables, list) {
@@ -1163,7 +1170,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec,
{
return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg);
+EXPORT_SYMBOL_GPL(snd_hda_codec_set_pincfg);
/**
* snd_hda_codec_get_pincfg - Obtain a pin-default configuration
@@ -1198,7 +1205,7 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
return pin->cfg;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg);
+EXPORT_SYMBOL_GPL(snd_hda_codec_get_pincfg);
/* remember the current pinctl target value */
int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
@@ -1212,7 +1219,7 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
pin->target = val;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_set_pin_target);
+EXPORT_SYMBOL_GPL(snd_hda_codec_set_pin_target);
/* return the current pinctl target value */
int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid)
@@ -1224,7 +1231,7 @@ int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid)
return 0;
return pin->target;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_get_pin_target);
+EXPORT_SYMBOL_GPL(snd_hda_codec_get_pin_target);
/**
* snd_hda_shutup_pins - Shut up all pins
@@ -1249,7 +1256,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec)
}
codec->pins_shutup = 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_shutup_pins);
+EXPORT_SYMBOL_GPL(snd_hda_shutup_pins);
#ifdef CONFIG_PM
/* Restore the pin controls cleared previously via snd_hda_shutup_pins() */
@@ -1330,6 +1337,20 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
}
/*
+ * Dynamic symbol binding for the codec parsers
+ */
+
+#define load_parser(codec, sym) \
+ ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym))
+
+static void unload_parser(struct hda_codec *codec)
+{
+ if (codec->parser)
+ symbol_put_addr(codec->parser);
+ codec->parser = NULL;
+}
+
+/*
* codec destructor
*/
static void snd_hda_codec_free(struct hda_codec *codec)
@@ -1352,10 +1373,8 @@ static void snd_hda_codec_free(struct hda_codec *codec)
codec->bus->caddr_tbl[codec->addr] = NULL;
if (codec->patch_ops.free)
codec->patch_ops.free(codec);
-#ifdef CONFIG_PM
- if (!codec->pm_down_notified) /* cancel leftover refcounts */
- hda_call_pm_notify(codec->bus, false);
-#endif
+ hda_call_pm_notify(codec, false); /* cancel leftover refcounts */
+ unload_parser(codec);
module_put(codec->owner);
free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache);
@@ -1363,6 +1382,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
kfree(codec->chip_name);
kfree(codec->modelname);
kfree(codec->wcaps);
+ codec->bus->num_codecs--;
kfree(codec);
}
@@ -1424,6 +1444,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
INIT_LIST_HEAD(&codec->conn_list);
INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work);
+ codec->depop_delay = -1;
#ifdef CONFIG_PM
spin_lock_init(&codec->power_lock);
@@ -1433,7 +1454,6 @@ int snd_hda_codec_new(struct hda_bus *bus,
* phase.
*/
hda_keep_power_on(codec);
- hda_call_pm_notify(bus, true);
#endif
if (codec->bus->modelname) {
@@ -1445,6 +1465,8 @@ int snd_hda_codec_new(struct hda_bus *bus,
}
list_add_tail(&codec->list, &bus->codec_list);
+ bus->num_codecs++;
+
bus->caddr_tbl[codec_addr] = codec;
codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT,
@@ -1486,11 +1508,14 @@ int snd_hda_codec_new(struct hda_bus *bus,
#ifdef CONFIG_PM
codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg,
AC_PWRST_CLKSTOP);
- if (!codec->d3_stop_clk)
- bus->power_keep_link_on = 1;
#endif
codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
AC_PWRST_EPSS);
+#ifdef CONFIG_PM
+ if (!codec->d3_stop_clk || !codec->epss)
+ bus->power_keep_link_on = 1;
+#endif
+
/* power-up all before initialization */
hda_set_power_state(codec, AC_PWRST_D0);
@@ -1511,7 +1536,7 @@ int snd_hda_codec_new(struct hda_bus *bus,
snd_hda_codec_free(codec);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_new);
+EXPORT_SYMBOL_GPL(snd_hda_codec_new);
int snd_hda_codec_update_widgets(struct hda_codec *codec)
{
@@ -1534,8 +1559,33 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets);
+EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets);
+
+#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
+/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
+static bool is_likely_hdmi_codec(struct hda_codec *codec)
+{
+ hda_nid_t nid = codec->start_nid;
+ int i;
+
+ for (i = 0; i < codec->num_nodes; i++, nid++) {
+ unsigned int wcaps = get_wcaps(codec, nid);
+ switch (get_wcaps_type(wcaps)) {
+ case AC_WID_AUD_IN:
+ return false; /* HDMI parser supports only HDMI out */
+ case AC_WID_AUD_OUT:
+ if (!(wcaps & AC_WCAP_DIGITAL))
+ return false;
+ break;
+ }
+ }
+ return true;
+}
+#else
+/* no HDMI codec parser support */
+#define is_likely_hdmi_codec(codec) false
+#endif /* CONFIG_SND_HDA_CODEC_HDMI */
/**
* snd_hda_codec_configure - (Re-)configure the HD-audio codec
@@ -1548,6 +1598,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_update_widgets);
*/
int snd_hda_codec_configure(struct hda_codec *codec)
{
+ int (*patch)(struct hda_codec *) = NULL;
int err;
codec->preset = find_codec_preset(codec);
@@ -1557,31 +1608,50 @@ int snd_hda_codec_configure(struct hda_codec *codec)
return err;
}
- if (is_generic_config(codec)) {
- err = snd_hda_parse_generic_codec(codec);
- goto patched;
- }
- if (codec->preset && codec->preset->patch) {
- err = codec->preset->patch(codec);
- goto patched;
+ if (!is_generic_config(codec) && codec->preset)
+ patch = codec->preset->patch;
+ if (!patch) {
+ unload_parser(codec); /* to be sure */
+ if (is_likely_hdmi_codec(codec)) {
+#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
+ patch = load_parser(codec, snd_hda_parse_hdmi_codec);
+#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI)
+ patch = snd_hda_parse_hdmi_codec;
+#endif
+ }
+ if (!patch) {
+#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
+ patch = load_parser(codec, snd_hda_parse_generic_codec);
+#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC)
+ patch = snd_hda_parse_generic_codec;
+#endif
+ }
+ if (!patch) {
+ printk(KERN_ERR "hda-codec: No codec parser is available\n");
+ return -ENODEV;
+ }
}
- /* call the default parser */
- err = snd_hda_parse_generic_codec(codec);
- if (err < 0)
- printk(KERN_ERR "hda-codec: No codec parser is available\n");
+ err = patch(codec);
+ if (err < 0) {
+ unload_parser(codec);
+ return err;
+ }
- patched:
- if (!err && codec->patch_ops.unsol_event)
+ if (codec->patch_ops.unsol_event) {
err = init_unsol_queue(codec->bus);
+ if (err < 0)
+ return err;
+ }
+
/* audio codec should override the mixer name */
- if (!err && (codec->afg || !*codec->bus->card->mixername))
+ if (codec->afg || !*codec->bus->card->mixername)
snprintf(codec->bus->card->mixername,
sizeof(codec->bus->card->mixername),
"%s %s", codec->vendor_name, codec->chip_name);
- return err;
+ return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_configure);
+EXPORT_SYMBOL_GPL(snd_hda_codec_configure);
/* update the stream-id if changed */
static void update_pcm_stream_id(struct hda_codec *codec,
@@ -1668,7 +1738,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
}
}
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream);
+EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream);
static void really_cleanup_stream(struct hda_codec *codec,
struct hda_cvt_setup *q);
@@ -1703,7 +1773,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid,
p->active = 0;
}
}
-EXPORT_SYMBOL_HDA(__snd_hda_codec_cleanup_stream);
+EXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream);
static void really_cleanup_stream(struct hda_codec *codec,
struct hda_cvt_setup *q)
@@ -1891,7 +1961,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
HDA_HASH_KEY(nid, direction, 0),
read_amp_cap);
}
-EXPORT_SYMBOL_HDA(query_amp_caps);
+EXPORT_SYMBOL_GPL(query_amp_caps);
/**
* snd_hda_override_amp_caps - Override the AMP capabilities
@@ -1911,7 +1981,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
{
return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps);
}
-EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
+EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
int dir)
@@ -1935,7 +2005,7 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
read_pin_cap);
}
-EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
+EXPORT_SYMBOL_GPL(snd_hda_query_pin_caps);
/**
* snd_hda_override_pin_caps - Override the pin capabilities
@@ -1952,7 +2022,7 @@ int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
{
return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
}
-EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
+EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps);
/* read or sync the hash value with the current value;
* call within hash_mutex
@@ -2033,7 +2103,7 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
mutex_unlock(&codec->hash_mutex);
return val;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read);
static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int idx, int mask, int val,
@@ -2085,7 +2155,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
{
return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update);
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
/**
* snd_hda_codec_amp_stereo - update the AMP stereo values
@@ -2111,7 +2181,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
idx, mask, val);
return ret;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo);
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo);
/* Works like snd_hda_codec_amp_update() but it writes the value only at
* the first access. If the amp was already initialized / updated beforehand,
@@ -2122,7 +2192,7 @@ int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
{
return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init);
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val)
@@ -2136,7 +2206,7 @@ int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
idx, mask, val);
return ret;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_amp_init_stereo);
+EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo);
/**
* snd_hda_codec_resume_amp - Resume all AMP commands from the cache
@@ -2179,7 +2249,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec)
}
mutex_unlock(&codec->hash_mutex);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp);
+EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp);
static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int ofs)
@@ -2219,7 +2289,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info);
static inline unsigned int
@@ -2276,7 +2346,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
*valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get);
/**
* snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume
@@ -2306,7 +2376,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
snd_hda_power_down(codec);
return change;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
/**
* snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume
@@ -2344,7 +2414,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
return -EFAULT;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv);
/**
* snd_hda_set_vmaster_tlv - Set TLV for a virtual master control
@@ -2372,7 +2442,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
tlv[2] = -nums * step;
tlv[3] = step;
}
-EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv);
+EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv);
/* find a mixer control element with the given name */
static struct snd_kcontrol *
@@ -2401,7 +2471,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec,
{
return find_mixer_ctl(codec, name, 0, 0);
}
-EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl);
+EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl);
static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name,
int start_idx)
@@ -2461,7 +2531,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid,
item->flags = flags;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_ctl_add);
+EXPORT_SYMBOL_GPL(snd_hda_ctl_add);
/**
* snd_hda_add_nid - Assign a NID to a control element
@@ -2492,7 +2562,7 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl,
kctl->id.name, kctl->id.index, index);
return -EINVAL;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_nid);
+EXPORT_SYMBOL_GPL(snd_hda_add_nid);
/**
* snd_hda_ctls_clear - Clear all controls assigned to the given codec
@@ -2543,7 +2613,7 @@ int snd_hda_lock_devices(struct hda_bus *bus)
spin_unlock(&card->files_lock);
return -EINVAL;
}
-EXPORT_SYMBOL_HDA(snd_hda_lock_devices);
+EXPORT_SYMBOL_GPL(snd_hda_lock_devices);
void snd_hda_unlock_devices(struct hda_bus *bus)
{
@@ -2554,7 +2624,7 @@ void snd_hda_unlock_devices(struct hda_bus *bus)
card->shutdown = 0;
spin_unlock(&card->files_lock);
}
-EXPORT_SYMBOL_HDA(snd_hda_unlock_devices);
+EXPORT_SYMBOL_GPL(snd_hda_unlock_devices);
/**
* snd_hda_codec_reset - Clear all objects assigned to the codec
@@ -2579,9 +2649,6 @@ int snd_hda_codec_reset(struct hda_codec *codec)
cancel_delayed_work_sync(&codec->jackpoll_work);
#ifdef CONFIG_PM
cancel_delayed_work_sync(&codec->power_work);
- codec->power_on = 0;
- codec->power_transition = 0;
- codec->power_jiffies = jiffies;
flush_workqueue(bus->workq);
#endif
snd_hda_ctls_clear(codec);
@@ -2613,6 +2680,7 @@ int snd_hda_codec_reset(struct hda_codec *codec)
codec->preset = NULL;
codec->slave_dig_outs = NULL;
codec->spdif_status_reset = 0;
+ unload_parser(codec);
module_put(codec->owner);
codec->owner = NULL;
@@ -2634,8 +2702,7 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves,
items = codec->mixers.list;
for (i = 0; i < codec->mixers.used; i++) {
struct snd_kcontrol *sctl = items[i].kctl;
- if (!sctl || !sctl->id.name ||
- sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
+ if (!sctl || sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER)
continue;
for (s = slaves; *s; s++) {
char tmpname[sizeof(sctl->id.name)];
@@ -2662,7 +2729,7 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl)
}
/* guess the value corresponding to 0dB */
-static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
+static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check)
{
int _tlv[4];
const int *tlv = NULL;
@@ -2677,8 +2744,19 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl)
set_fs(fs);
} else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ)
tlv = kctl->tlv.p;
- if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE)
- val = -tlv[2] / tlv[3];
+ if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) {
+ int step = tlv[3];
+ step &= ~TLV_DB_SCALE_MUTE;
+ if (!step)
+ return -1;
+ if (*step_to_check && *step_to_check != step) {
+ snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n",
+ *step_to_check, step);
+ return -1;
+ }
+ *step_to_check = step;
+ val = -tlv[2] / step;
+ }
return val;
}
@@ -2699,7 +2777,7 @@ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val)
/* initialize the slave volume with 0dB */
static int init_slave_0dB(void *data, struct snd_kcontrol *slave)
{
- int offset = get_kctl_0dB_offset(slave);
+ int offset = get_kctl_0dB_offset(slave, data);
if (offset > 0)
put_kctl_with_value(slave, offset);
return 0;
@@ -2760,15 +2838,17 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name,
/* init with master mute & zero volume */
put_kctl_with_value(kctl, 0);
- if (init_slave_vol)
+ if (init_slave_vol) {
+ int step = 0;
map_slaves(codec, slaves, suffix,
- tlv ? init_slave_0dB : init_slave_unmute, kctl);
+ tlv ? init_slave_0dB : init_slave_unmute, &step);
+ }
if (ctl_ret)
*ctl_ret = kctl;
return 0;
}
-EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster);
+EXPORT_SYMBOL_GPL(__snd_hda_add_vmaster);
/*
* mute-LED control using vmaster
@@ -2845,7 +2925,7 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec,
return -ENOMEM;
return snd_hda_ctl_add(codec, 0, kctl);
}
-EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook);
+EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);
/*
* Call the hook with the current value for synchronization
@@ -2869,7 +2949,7 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
break;
}
}
-EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook);
+EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook);
/**
@@ -2889,7 +2969,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 1;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info);
/**
* snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch
@@ -2915,7 +2995,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol,
HDA_AMP_MUTE) ? 0 : 1;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get);
/**
* snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch
@@ -2949,7 +3029,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol,
snd_hda_power_down(codec);
return change;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
/*
* bound volume controls
@@ -2981,7 +3061,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->control_mutex);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get);
/**
* snd_hda_mixer_bind_switch_put - Put callback for a bound volume control
@@ -3011,7 +3091,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put);
/**
* snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control
@@ -3034,7 +3114,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->control_mutex);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info);
/**
* snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control
@@ -3057,7 +3137,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->control_mutex);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get);
/**
* snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control
@@ -3086,7 +3166,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->control_mutex);
return err < 0 ? err : change;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put);
/**
* snd_hda_mixer_bind_tlv - TLV callback for a generic bound control
@@ -3109,7 +3189,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag,
mutex_unlock(&codec->control_mutex);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv);
+EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv);
struct hda_ctl_ops snd_hda_bind_vol = {
.info = snd_hda_mixer_amp_volume_info,
@@ -3117,7 +3197,7 @@ struct hda_ctl_ops snd_hda_bind_vol = {
.put = snd_hda_mixer_amp_volume_put,
.tlv = snd_hda_mixer_amp_tlv
};
-EXPORT_SYMBOL_HDA(snd_hda_bind_vol);
+EXPORT_SYMBOL_GPL(snd_hda_bind_vol);
struct hda_ctl_ops snd_hda_bind_sw = {
.info = snd_hda_mixer_amp_switch_info,
@@ -3125,7 +3205,7 @@ struct hda_ctl_ops snd_hda_bind_sw = {
.put = snd_hda_mixer_amp_switch_put,
.tlv = snd_hda_mixer_amp_tlv
};
-EXPORT_SYMBOL_HDA(snd_hda_bind_sw);
+EXPORT_SYMBOL_GPL(snd_hda_bind_sw);
/*
* SPDIF out controls
@@ -3429,7 +3509,7 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
spdif->status = convert_to_spdif_status(spdif->ctls);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_create_dig_out_ctls);
+EXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls);
/* get the hda_spdif_out entry from the given NID
* call within spdif_mutex lock
@@ -3446,7 +3526,7 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
}
return NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
+EXPORT_SYMBOL_GPL(snd_hda_spdif_out_of_nid);
void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
{
@@ -3457,7 +3537,7 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
spdif->nid = (u16)-1;
mutex_unlock(&codec->spdif_mutex);
}
-EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
+EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign);
void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
{
@@ -3473,7 +3553,7 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
}
mutex_unlock(&codec->spdif_mutex);
}
-EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign);
+EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign);
/*
* SPDIF sharing with analog output
@@ -3521,7 +3601,7 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec,
/* ATTENTION: here mout is passed as private_data, instead of codec */
return snd_hda_ctl_add(codec, mout->dig_out_nid, kctl);
}
-EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw);
+EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw);
/*
* SPDIF input
@@ -3629,7 +3709,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid)
AC_DIG1_ENABLE;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
+EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls);
/*
* command cache
@@ -3680,7 +3760,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
mutex_unlock(&codec->bus->cmd_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
+EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache);
/**
* snd_hda_codec_update_cache - check cache and write the cmd only when needed
@@ -3715,7 +3795,7 @@ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid,
mutex_unlock(&codec->bus->cmd_mutex);
return snd_hda_codec_write_cache(codec, nid, flags, verb, parm);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache);
+EXPORT_SYMBOL_GPL(snd_hda_codec_update_cache);
/**
* snd_hda_codec_resume_cache - Resume the all commands from the cache
@@ -3747,7 +3827,7 @@ void snd_hda_codec_resume_cache(struct hda_codec *codec)
}
mutex_unlock(&codec->hash_mutex);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache);
+EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache);
/**
* snd_hda_sequence_write_cache - sequence writes with caching
@@ -3765,7 +3845,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec,
snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb,
seq->param);
}
-EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache);
+EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache);
/**
* snd_hda_codec_flush_cache - Execute all pending (cached) amps / verbs
@@ -3776,7 +3856,7 @@ void snd_hda_codec_flush_cache(struct hda_codec *codec)
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_flush_cache);
+EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache);
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state)
@@ -3798,7 +3878,7 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
state);
}
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all);
+EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all);
/*
* supported power states check
@@ -3847,6 +3927,8 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
{
+ if (nid == codec->afg || nid == codec->mfg)
+ return power_state;
if (power_state == AC_PWRST_D3 &&
get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN &&
(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) {
@@ -3857,7 +3939,7 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
}
return power_state;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_eapd_power_filter);
+EXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter);
/*
* set power state of the codec, and return the power state
@@ -3872,8 +3954,10 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
/* this delay seems necessary to avoid click noise at power-down */
if (power_state == AC_PWRST_D3) {
- /* transition time less than 10ms for power down */
- msleep(codec->epss ? 10 : 100);
+ if (codec->depop_delay < 0)
+ msleep(codec->epss ? 10 : 100);
+ else if (codec->depop_delay > 0)
+ msleep(codec->depop_delay);
flags = HDA_RW_NO_RESPONSE_FALLBACK;
}
@@ -3883,9 +3967,13 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
codec->patch_ops.set_power_state(codec, fg,
power_state);
else {
- snd_hda_codec_read(codec, fg, flags,
- AC_VERB_SET_POWER_STATE,
- power_state);
+ state = power_state;
+ if (codec->power_filter)
+ state = codec->power_filter(codec, fg, state);
+ if (state == power_state || power_state != AC_PWRST_D3)
+ snd_hda_codec_read(codec, fg, flags,
+ AC_VERB_SET_POWER_STATE,
+ state);
snd_hda_codec_set_power_to_all(codec, fg, power_state);
}
state = hda_sync_power_state(codec, fg, power_state);
@@ -4042,7 +4130,7 @@ int snd_hda_build_controls(struct hda_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_build_controls);
+EXPORT_SYMBOL_GPL(snd_hda_build_controls);
/*
* add standard channel maps if not specified
@@ -4215,7 +4303,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
return val;
}
-EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
+EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format);
static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
int dir)
@@ -4361,7 +4449,7 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm);
+EXPORT_SYMBOL_GPL(snd_hda_query_supported_pcm);
/**
* snd_hda_is_supported_format - Check the validity of the format
@@ -4428,7 +4516,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid,
return 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_is_supported_format);
+EXPORT_SYMBOL_GPL(snd_hda_is_supported_format);
/*
* PCM stuff
@@ -4506,7 +4594,7 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
mutex_unlock(&codec->bus->prepare_mutex);
return ret;
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_prepare);
+EXPORT_SYMBOL_GPL(snd_hda_codec_prepare);
void snd_hda_codec_cleanup(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
@@ -4516,7 +4604,7 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,
hinfo->ops.cleanup(hinfo, codec, substream);
mutex_unlock(&codec->bus->prepare_mutex);
}
-EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup);
+EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup);
/* global */
const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = {
@@ -4674,7 +4762,7 @@ int snd_hda_build_pcms(struct hda_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_build_pcms);
+EXPORT_SYMBOL_GPL(snd_hda_build_pcms);
/**
* snd_hda_check_board_config - compare the current codec with the config table
@@ -4730,7 +4818,7 @@ int snd_hda_check_board_config(struct hda_codec *codec,
}
return -1;
}
-EXPORT_SYMBOL_HDA(snd_hda_check_board_config);
+EXPORT_SYMBOL_GPL(snd_hda_check_board_config);
/**
* snd_hda_check_board_codec_sid_config - compare the current codec
@@ -4791,7 +4879,7 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec,
}
return -1;
}
-EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config);
+EXPORT_SYMBOL_GPL(snd_hda_check_board_codec_sid_config);
/**
* snd_hda_add_new_ctls - create controls from the array
@@ -4841,7 +4929,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls);
+EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls);
#ifdef CONFIG_PM
static void hda_power_work(struct work_struct *work)
@@ -4864,11 +4952,8 @@ static void hda_power_work(struct work_struct *work)
spin_unlock(&codec->power_lock);
state = hda_call_codec_suspend(codec, true);
- codec->pm_down_notified = 0;
- if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) {
- codec->pm_down_notified = 1;
- hda_call_pm_notify(bus, false);
- }
+ if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK))
+ hda_call_pm_notify(codec, false);
}
static void hda_keep_power_on(struct hda_codec *codec)
@@ -4878,6 +4963,7 @@ static void hda_keep_power_on(struct hda_codec *codec)
codec->power_on = 1;
codec->power_jiffies = jiffies;
spin_unlock(&codec->power_lock);
+ hda_call_pm_notify(codec, true);
}
/* update the power on/off account with the current jiffies */
@@ -4897,8 +4983,6 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
/* call this with codec->power_lock held! */
static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
{
- struct hda_bus *bus = codec->bus;
-
/* Return if power_on or transitioning to power_on, unless currently
* powering down. */
if ((codec->power_on || codec->power_transition > 0) &&
@@ -4925,11 +5009,6 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
codec->power_transition = 1; /* avoid reentrance */
spin_unlock(&codec->power_lock);
- if (codec->pm_down_notified) {
- codec->pm_down_notified = 0;
- hda_call_pm_notify(bus, true);
- }
-
hda_call_codec_resume(codec);
spin_lock(&codec->power_lock);
@@ -4972,7 +5051,7 @@ void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
__snd_hda_power_down(codec);
spin_unlock(&codec->power_lock);
}
-EXPORT_SYMBOL_HDA(snd_hda_power_save);
+EXPORT_SYMBOL_GPL(snd_hda_power_save);
/**
* snd_hda_check_amp_list_power - Check the amp list and update the power
@@ -5022,7 +5101,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power);
+EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
#endif
/*
@@ -5046,7 +5125,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec,
chmode[uinfo->value.enumerated.item].channels);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info);
+EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
/**
* snd_hda_ch_mode_get - Get callback helper for the channel mode enum
@@ -5067,7 +5146,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec,
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get);
+EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
/**
* snd_hda_ch_mode_put - Put callback helper for the channel mode enum
@@ -5091,7 +5170,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec,
snd_hda_sequence_write_cache(codec, chmode[mode].sequence);
return 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put);
+EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
/*
* input MUX helper
@@ -5116,7 +5195,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux,
strcpy(uinfo->value.enumerated.name, imux->items[index].label);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_input_mux_info);
+EXPORT_SYMBOL_GPL(snd_hda_input_mux_info);
/**
* snd_hda_input_mux_info_put - Put callback helper for the input-mux enum
@@ -5141,7 +5220,7 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
*cur_val = idx;
return 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_input_mux_put);
+EXPORT_SYMBOL_GPL(snd_hda_input_mux_put);
/*
@@ -5170,7 +5249,7 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
texts[uinfo->value.enumerated.item]);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_enum_helper_info);
+EXPORT_SYMBOL_GPL(snd_hda_enum_helper_info);
/*
* Multi-channel / digital-out PCM helper functions
@@ -5236,7 +5315,7 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus)
codec->patch_ops.reboot_notify(codec);
}
}
-EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify);
+EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify);
/**
* snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
@@ -5252,7 +5331,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open);
/**
* snd_hda_multi_out_dig_prepare - prepare the digital out stream
@@ -5268,7 +5347,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
/**
* snd_hda_multi_out_dig_cleanup - clean-up the digital out stream
@@ -5281,7 +5360,7 @@ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);
/**
* snd_hda_multi_out_dig_close - release the digital out stream
@@ -5294,7 +5373,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close);
/**
* snd_hda_multi_out_analog_open - open analog outputs
@@ -5344,7 +5423,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,
return snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open);
/**
* snd_hda_multi_out_analog_prepare - Preapre the analog outputs.
@@ -5395,11 +5474,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
snd_hda_codec_setup_stream(codec,
mout->hp_out_nid[i],
stream_tag, 0, format);
- for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
- if (!mout->no_share_stream && mout->extra_out_nid[i])
- snd_hda_codec_setup_stream(codec,
- mout->extra_out_nid[i],
- stream_tag, 0, format);
/* surrounds */
for (i = 1; i < mout->num_dacs; i++) {
@@ -5410,9 +5484,23 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
snd_hda_codec_setup_stream(codec, nids[i], stream_tag,
0, format);
}
+
+ /* extra surrounds */
+ for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) {
+ int ch = 0;
+ if (!mout->extra_out_nid[i])
+ break;
+ if (chs >= (i + 1) * 2)
+ ch = i * 2;
+ else if (!mout->no_share_stream)
+ break;
+ snd_hda_codec_setup_stream(codec, mout->extra_out_nid[i],
+ stream_tag, ch, format);
+ }
+
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare);
/**
* snd_hda_multi_out_analog_cleanup - clean up the setting for analog out
@@ -5443,7 +5531,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
mutex_unlock(&codec->spdif_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
+EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup);
/**
* snd_hda_get_default_vref - Get the default (mic) VREF pin bits
@@ -5470,7 +5558,7 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
return AC_PINCTL_VREF_GRD;
return AC_PINCTL_VREF_HIZ;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
+EXPORT_SYMBOL_GPL(snd_hda_get_default_vref);
/* correct the pin ctl value for matching with the pin cap */
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
@@ -5521,7 +5609,7 @@ unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
return val;
}
-EXPORT_SYMBOL_HDA(snd_hda_correct_pin_ctl);
+EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl);
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
unsigned int val, bool cached)
@@ -5535,7 +5623,7 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
return snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
}
-EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl);
+EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl);
/**
* snd_hda_add_imux_item - Add an item to input_mux
@@ -5569,7 +5657,7 @@ int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
imux->num_items++;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
+EXPORT_SYMBOL_GPL(snd_hda_add_imux_item);
#ifdef CONFIG_PM
@@ -5577,6 +5665,17 @@ EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
* power management
*/
+
+static void hda_async_suspend(void *data, async_cookie_t cookie)
+{
+ hda_call_codec_suspend(data, false);
+}
+
+static void hda_async_resume(void *data, async_cookie_t cookie)
+{
+ hda_call_codec_resume(data);
+}
+
/**
* snd_hda_suspend - suspend the codecs
* @bus: the HDA bus
@@ -5586,15 +5685,25 @@ EXPORT_SYMBOL_HDA(snd_hda_add_imux_item);
int snd_hda_suspend(struct hda_bus *bus)
{
struct hda_codec *codec;
+ ASYNC_DOMAIN_EXCLUSIVE(domain);
list_for_each_entry(codec, &bus->codec_list, list) {
cancel_delayed_work_sync(&codec->jackpoll_work);
- if (hda_codec_is_power_on(codec))
- hda_call_codec_suspend(codec, false);
+ if (hda_codec_is_power_on(codec)) {
+ if (bus->num_codecs > 1)
+ async_schedule_domain(hda_async_suspend, codec,
+ &domain);
+ else
+ hda_call_codec_suspend(codec, false);
+ }
}
+
+ if (bus->num_codecs > 1)
+ async_synchronize_full_domain(&domain);
+
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_suspend);
+EXPORT_SYMBOL_GPL(snd_hda_suspend);
/**
* snd_hda_resume - resume the codecs
@@ -5605,13 +5714,21 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend);
int snd_hda_resume(struct hda_bus *bus)
{
struct hda_codec *codec;
+ ASYNC_DOMAIN_EXCLUSIVE(domain);
list_for_each_entry(codec, &bus->codec_list, list) {
- hda_call_codec_resume(codec);
+ if (bus->num_codecs > 1)
+ async_schedule_domain(hda_async_resume, codec, &domain);
+ else
+ hda_call_codec_resume(codec);
}
+
+ if (bus->num_codecs > 1)
+ async_synchronize_full_domain(&domain);
+
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_resume);
+EXPORT_SYMBOL_GPL(snd_hda_resume);
#endif /* CONFIG_PM */
/*
@@ -5645,7 +5762,7 @@ void *snd_array_new(struct snd_array *array)
}
return snd_array_elem(array, array->used++);
}
-EXPORT_SYMBOL_HDA(snd_array_new);
+EXPORT_SYMBOL_GPL(snd_array_new);
/**
* snd_array_free - free the given array elements
@@ -5658,7 +5775,7 @@ void snd_array_free(struct snd_array *array)
array->alloced = 0;
array->list = NULL;
}
-EXPORT_SYMBOL_HDA(snd_array_free);
+EXPORT_SYMBOL_GPL(snd_array_free);
/**
* snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer
@@ -5679,7 +5796,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
buf[j] = '\0'; /* necessary when j == 0 */
}
-EXPORT_SYMBOL_HDA(snd_print_pcm_bits);
+EXPORT_SYMBOL_GPL(snd_print_pcm_bits);
MODULE_DESCRIPTION("HDA codec core");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 7aa9870040c1..ab2a444ba501 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -25,552 +25,7 @@
#include <sound/control.h>
#include <sound/pcm.h>
#include <sound/hwdep.h>
-
-/*
- * nodes
- */
-#define AC_NODE_ROOT 0x00
-
-/*
- * function group types
- */
-enum {
- AC_GRP_AUDIO_FUNCTION = 0x01,
- AC_GRP_MODEM_FUNCTION = 0x02,
-};
-
-/*
- * widget types
- */
-enum {
- AC_WID_AUD_OUT, /* Audio Out */
- AC_WID_AUD_IN, /* Audio In */
- AC_WID_AUD_MIX, /* Audio Mixer */
- AC_WID_AUD_SEL, /* Audio Selector */
- AC_WID_PIN, /* Pin Complex */
- AC_WID_POWER, /* Power */
- AC_WID_VOL_KNB, /* Volume Knob */
- AC_WID_BEEP, /* Beep Generator */
- AC_WID_VENDOR = 0x0f /* Vendor specific */
-};
-
-/*
- * GET verbs
- */
-#define AC_VERB_GET_STREAM_FORMAT 0x0a00
-#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00
-#define AC_VERB_GET_PROC_COEF 0x0c00
-#define AC_VERB_GET_COEF_INDEX 0x0d00
-#define AC_VERB_PARAMETERS 0x0f00
-#define AC_VERB_GET_CONNECT_SEL 0x0f01
-#define AC_VERB_GET_CONNECT_LIST 0x0f02
-#define AC_VERB_GET_PROC_STATE 0x0f03
-#define AC_VERB_GET_SDI_SELECT 0x0f04
-#define AC_VERB_GET_POWER_STATE 0x0f05
-#define AC_VERB_GET_CONV 0x0f06
-#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07
-#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08
-#define AC_VERB_GET_PIN_SENSE 0x0f09
-#define AC_VERB_GET_BEEP_CONTROL 0x0f0a
-#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c
-#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d
-#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */
-#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f
-/* f10-f1a: GPIO */
-#define AC_VERB_GET_GPIO_DATA 0x0f15
-#define AC_VERB_GET_GPIO_MASK 0x0f16
-#define AC_VERB_GET_GPIO_DIRECTION 0x0f17
-#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18
-#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19
-#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a
-#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c
-/* f20: AFG/MFG */
-#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20
-#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d
-#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e
-#define AC_VERB_GET_HDMI_ELDD 0x0f2f
-#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30
-#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31
-#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32
-#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33
-#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34
-#define AC_VERB_GET_DEVICE_SEL 0xf35
-#define AC_VERB_GET_DEVICE_LIST 0xf36
-
-/*
- * SET verbs
- */
-#define AC_VERB_SET_STREAM_FORMAT 0x200
-#define AC_VERB_SET_AMP_GAIN_MUTE 0x300
-#define AC_VERB_SET_PROC_COEF 0x400
-#define AC_VERB_SET_COEF_INDEX 0x500
-#define AC_VERB_SET_CONNECT_SEL 0x701
-#define AC_VERB_SET_PROC_STATE 0x703
-#define AC_VERB_SET_SDI_SELECT 0x704
-#define AC_VERB_SET_POWER_STATE 0x705
-#define AC_VERB_SET_CHANNEL_STREAMID 0x706
-#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707
-#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708
-#define AC_VERB_SET_PIN_SENSE 0x709
-#define AC_VERB_SET_BEEP_CONTROL 0x70a
-#define AC_VERB_SET_EAPD_BTLENABLE 0x70c
-#define AC_VERB_SET_DIGI_CONVERT_1 0x70d
-#define AC_VERB_SET_DIGI_CONVERT_2 0x70e
-#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f
-#define AC_VERB_SET_GPIO_DATA 0x715
-#define AC_VERB_SET_GPIO_MASK 0x716
-#define AC_VERB_SET_GPIO_DIRECTION 0x717
-#define AC_VERB_SET_GPIO_WAKE_MASK 0x718
-#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719
-#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f
-#define AC_VERB_SET_EAPD 0x788
-#define AC_VERB_SET_CODEC_RESET 0x7ff
-#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d
-#define AC_VERB_SET_HDMI_DIP_INDEX 0x730
-#define AC_VERB_SET_HDMI_DIP_DATA 0x731
-#define AC_VERB_SET_HDMI_DIP_XMIT 0x732
-#define AC_VERB_SET_HDMI_CP_CTRL 0x733
-#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734
-#define AC_VERB_SET_DEVICE_SEL 0x735
-
-/*
- * Parameter IDs
- */
-#define AC_PAR_VENDOR_ID 0x00
-#define AC_PAR_SUBSYSTEM_ID 0x01
-#define AC_PAR_REV_ID 0x02
-#define AC_PAR_NODE_COUNT 0x04
-#define AC_PAR_FUNCTION_TYPE 0x05
-#define AC_PAR_AUDIO_FG_CAP 0x08
-#define AC_PAR_AUDIO_WIDGET_CAP 0x09
-#define AC_PAR_PCM 0x0a
-#define AC_PAR_STREAM 0x0b
-#define AC_PAR_PIN_CAP 0x0c
-#define AC_PAR_AMP_IN_CAP 0x0d
-#define AC_PAR_CONNLIST_LEN 0x0e
-#define AC_PAR_POWER_STATE 0x0f
-#define AC_PAR_PROC_CAP 0x10
-#define AC_PAR_GPIO_CAP 0x11
-#define AC_PAR_AMP_OUT_CAP 0x12
-#define AC_PAR_VOL_KNB_CAP 0x13
-#define AC_PAR_DEVLIST_LEN 0x15
-#define AC_PAR_HDMI_LPCM_CAP 0x20
-
-/*
- * AC_VERB_PARAMETERS results (32bit)
- */
-
-/* Function Group Type */
-#define AC_FGT_TYPE (0xff<<0)
-#define AC_FGT_TYPE_SHIFT 0
-#define AC_FGT_UNSOL_CAP (1<<8)
-
-/* Audio Function Group Capabilities */
-#define AC_AFG_OUT_DELAY (0xf<<0)
-#define AC_AFG_IN_DELAY (0xf<<8)
-#define AC_AFG_BEEP_GEN (1<<16)
-
-/* Audio Widget Capabilities */
-#define AC_WCAP_STEREO (1<<0) /* stereo I/O */
-#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */
-#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */
-#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */
-#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */
-#define AC_WCAP_STRIPE (1<<5) /* stripe */
-#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */
-#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */
-#define AC_WCAP_CONN_LIST (1<<8) /* connection list */
-#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */
-#define AC_WCAP_POWER (1<<10) /* power control */
-#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */
-#define AC_WCAP_CP_CAPS (1<<12) /* content protection */
-#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */
-#define AC_WCAP_DELAY (0xf<<16)
-#define AC_WCAP_DELAY_SHIFT 16
-#define AC_WCAP_TYPE (0xf<<20)
-#define AC_WCAP_TYPE_SHIFT 20
-
-/* supported PCM rates and bits */
-#define AC_SUPPCM_RATES (0xfff << 0)
-#define AC_SUPPCM_BITS_8 (1<<16)
-#define AC_SUPPCM_BITS_16 (1<<17)
-#define AC_SUPPCM_BITS_20 (1<<18)
-#define AC_SUPPCM_BITS_24 (1<<19)
-#define AC_SUPPCM_BITS_32 (1<<20)
-
-/* supported PCM stream format */
-#define AC_SUPFMT_PCM (1<<0)
-#define AC_SUPFMT_FLOAT32 (1<<1)
-#define AC_SUPFMT_AC3 (1<<2)
-
-/* GP I/O count */
-#define AC_GPIO_IO_COUNT (0xff<<0)
-#define AC_GPIO_O_COUNT (0xff<<8)
-#define AC_GPIO_O_COUNT_SHIFT 8
-#define AC_GPIO_I_COUNT (0xff<<16)
-#define AC_GPIO_I_COUNT_SHIFT 16
-#define AC_GPIO_UNSOLICITED (1<<30)
-#define AC_GPIO_WAKE (1<<31)
-
-/* Converter stream, channel */
-#define AC_CONV_CHANNEL (0xf<<0)
-#define AC_CONV_STREAM (0xf<<4)
-#define AC_CONV_STREAM_SHIFT 4
-
-/* Input converter SDI select */
-#define AC_SDI_SELECT (0xf<<0)
-
-/* stream format id */
-#define AC_FMT_CHAN_SHIFT 0
-#define AC_FMT_CHAN_MASK (0x0f << 0)
-#define AC_FMT_BITS_SHIFT 4
-#define AC_FMT_BITS_MASK (7 << 4)
-#define AC_FMT_BITS_8 (0 << 4)
-#define AC_FMT_BITS_16 (1 << 4)
-#define AC_FMT_BITS_20 (2 << 4)
-#define AC_FMT_BITS_24 (3 << 4)
-#define AC_FMT_BITS_32 (4 << 4)
-#define AC_FMT_DIV_SHIFT 8
-#define AC_FMT_DIV_MASK (7 << 8)
-#define AC_FMT_MULT_SHIFT 11
-#define AC_FMT_MULT_MASK (7 << 11)
-#define AC_FMT_BASE_SHIFT 14
-#define AC_FMT_BASE_48K (0 << 14)
-#define AC_FMT_BASE_44K (1 << 14)
-#define AC_FMT_TYPE_SHIFT 15
-#define AC_FMT_TYPE_PCM (0 << 15)
-#define AC_FMT_TYPE_NON_PCM (1 << 15)
-
-/* Unsolicited response control */
-#define AC_UNSOL_TAG (0x3f<<0)
-#define AC_UNSOL_ENABLED (1<<7)
-#define AC_USRSP_EN AC_UNSOL_ENABLED
-
-/* Unsolicited responses */
-#define AC_UNSOL_RES_TAG (0x3f<<26)
-#define AC_UNSOL_RES_TAG_SHIFT 26
-#define AC_UNSOL_RES_SUBTAG (0x1f<<21)
-#define AC_UNSOL_RES_SUBTAG_SHIFT 21
-#define AC_UNSOL_RES_DE (0x3f<<15) /* Device Entry
- * (for DP1.2 MST)
- */
-#define AC_UNSOL_RES_DE_SHIFT 15
-#define AC_UNSOL_RES_IA (1<<2) /* Inactive (for DP1.2 MST) */
-#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */
-#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */
-#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */
-#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */
-
-/* Pin widget capabilies */
-#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */
-#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */
-#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */
-#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */
-#define AC_PINCAP_OUT (1<<4) /* output capable */
-#define AC_PINCAP_IN (1<<5) /* input capable */
-#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */
-/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
- * but is marked reserved in the Intel HDA specification.
- */
-#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */
-/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
- * in HD-audio specification
- */
-#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */
-#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can
- * coexist with AC_PINCAP_HDMI
- */
-#define AC_PINCAP_VREF (0x37<<8)
-#define AC_PINCAP_VREF_SHIFT 8
-#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */
-#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */
-/* Vref status (used in pin cap) */
-#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */
-#define AC_PINCAP_VREF_50 (1<<1) /* 50% */
-#define AC_PINCAP_VREF_GRD (1<<2) /* ground */
-#define AC_PINCAP_VREF_80 (1<<4) /* 80% */
-#define AC_PINCAP_VREF_100 (1<<5) /* 100% */
-
-/* Amplifier capabilities */
-#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */
-#define AC_AMPCAP_OFFSET_SHIFT 0
-#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */
-#define AC_AMPCAP_NUM_STEPS_SHIFT 8
-#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB
- * in 0.25dB
- */
-#define AC_AMPCAP_STEP_SIZE_SHIFT 16
-#define AC_AMPCAP_MUTE (1<<31) /* mute capable */
-#define AC_AMPCAP_MUTE_SHIFT 31
-
-/* driver-specific amp-caps: using bits 24-30 */
-#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */
-
-/* Connection list */
-#define AC_CLIST_LENGTH (0x7f<<0)
-#define AC_CLIST_LONG (1<<7)
-
-/* Supported power status */
-#define AC_PWRST_D0SUP (1<<0)
-#define AC_PWRST_D1SUP (1<<1)
-#define AC_PWRST_D2SUP (1<<2)
-#define AC_PWRST_D3SUP (1<<3)
-#define AC_PWRST_D3COLDSUP (1<<4)
-#define AC_PWRST_S3D3COLDSUP (1<<29)
-#define AC_PWRST_CLKSTOP (1<<30)
-#define AC_PWRST_EPSS (1U<<31)
-
-/* Power state values */
-#define AC_PWRST_SETTING (0xf<<0)
-#define AC_PWRST_ACTUAL (0xf<<4)
-#define AC_PWRST_ACTUAL_SHIFT 4
-#define AC_PWRST_D0 0x00
-#define AC_PWRST_D1 0x01
-#define AC_PWRST_D2 0x02
-#define AC_PWRST_D3 0x03
-#define AC_PWRST_ERROR (1<<8)
-#define AC_PWRST_CLK_STOP_OK (1<<9)
-#define AC_PWRST_SETTING_RESET (1<<10)
-
-/* Processing capabilies */
-#define AC_PCAP_BENIGN (1<<0)
-#define AC_PCAP_NUM_COEF (0xff<<8)
-#define AC_PCAP_NUM_COEF_SHIFT 8
-
-/* Volume knobs capabilities */
-#define AC_KNBCAP_NUM_STEPS (0x7f<<0)
-#define AC_KNBCAP_DELTA (1<<7)
-
-/* HDMI LPCM capabilities */
-#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */
-#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */
-#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */
-#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */
-#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */
-#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */
-#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */
-#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */
-#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */
-#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */
-#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */
-#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */
-#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */
-#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */
-
-/* Display pin's device list length */
-#define AC_DEV_LIST_LEN_MASK 0x3f
-#define AC_MAX_DEV_LIST_LEN 64
-
-/*
- * Control Parameters
- */
-
-/* Amp gain/mute */
-#define AC_AMP_MUTE (1<<7)
-#define AC_AMP_GAIN (0x7f)
-#define AC_AMP_GET_INDEX (0xf<<0)
-
-#define AC_AMP_GET_LEFT (1<<13)
-#define AC_AMP_GET_RIGHT (0<<13)
-#define AC_AMP_GET_OUTPUT (1<<15)
-#define AC_AMP_GET_INPUT (0<<15)
-
-#define AC_AMP_SET_INDEX (0xf<<8)
-#define AC_AMP_SET_INDEX_SHIFT 8
-#define AC_AMP_SET_RIGHT (1<<12)
-#define AC_AMP_SET_LEFT (1<<13)
-#define AC_AMP_SET_INPUT (1<<14)
-#define AC_AMP_SET_OUTPUT (1<<15)
-
-/* DIGITAL1 bits */
-#define AC_DIG1_ENABLE (1<<0)
-#define AC_DIG1_V (1<<1)
-#define AC_DIG1_VCFG (1<<2)
-#define AC_DIG1_EMPHASIS (1<<3)
-#define AC_DIG1_COPYRIGHT (1<<4)
-#define AC_DIG1_NONAUDIO (1<<5)
-#define AC_DIG1_PROFESSIONAL (1<<6)
-#define AC_DIG1_LEVEL (1<<7)
-
-/* DIGITAL2 bits */
-#define AC_DIG2_CC (0x7f<<0)
-
-/* DIGITAL3 bits */
-#define AC_DIG3_ICT (0xf<<0)
-#define AC_DIG3_KAE (1<<7)
-
-/* Pin widget control - 8bit */
-#define AC_PINCTL_EPT (0x3<<0)
-#define AC_PINCTL_EPT_NATIVE 0
-#define AC_PINCTL_EPT_HBR 3
-#define AC_PINCTL_VREFEN (0x7<<0)
-#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */
-#define AC_PINCTL_VREF_50 1 /* 50% */
-#define AC_PINCTL_VREF_GRD 2 /* ground */
-#define AC_PINCTL_VREF_80 4 /* 80% */
-#define AC_PINCTL_VREF_100 5 /* 100% */
-#define AC_PINCTL_IN_EN (1<<5)
-#define AC_PINCTL_OUT_EN (1<<6)
-#define AC_PINCTL_HP_EN (1<<7)
-
-/* Pin sense - 32bit */
-#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff)
-#define AC_PINSENSE_PRESENCE (1<<31)
-#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */
-
-/* EAPD/BTL enable - 32bit */
-#define AC_EAPDBTL_BALANCED (1<<0)
-#define AC_EAPDBTL_EAPD (1<<1)
-#define AC_EAPDBTL_LR_SWAP (1<<2)
-
-/* HDMI ELD data */
-#define AC_ELDD_ELD_VALID (1<<31)
-#define AC_ELDD_ELD_DATA 0xff
-
-/* HDMI DIP size */
-#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */
-#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */
-
-/* HDMI DIP index */
-#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */
-#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */
-
-/* HDMI DIP xmit (transmit) control */
-#define AC_DIPXMIT_MASK (0x3<<6)
-#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */
-#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */
-#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */
-
-/* HDMI content protection (CP) control */
-#define AC_CPCTRL_CES (1<<9) /* current encryption state */
-#define AC_CPCTRL_READY (1<<8) /* ready bit */
-#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */
-#define AC_CPCTRL_STATE (3<<0) /* current CP request state */
-
-/* Converter channel <-> HDMI slot mapping */
-#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */
-#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */
-
-/* configuration default - 32bit */
-#define AC_DEFCFG_SEQUENCE (0xf<<0)
-#define AC_DEFCFG_DEF_ASSOC (0xf<<4)
-#define AC_DEFCFG_ASSOC_SHIFT 4
-#define AC_DEFCFG_MISC (0xf<<8)
-#define AC_DEFCFG_MISC_SHIFT 8
-#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0)
-#define AC_DEFCFG_COLOR (0xf<<12)
-#define AC_DEFCFG_COLOR_SHIFT 12
-#define AC_DEFCFG_CONN_TYPE (0xf<<16)
-#define AC_DEFCFG_CONN_TYPE_SHIFT 16
-#define AC_DEFCFG_DEVICE (0xf<<20)
-#define AC_DEFCFG_DEVICE_SHIFT 20
-#define AC_DEFCFG_LOCATION (0x3f<<24)
-#define AC_DEFCFG_LOCATION_SHIFT 24
-#define AC_DEFCFG_PORT_CONN (0x3<<30)
-#define AC_DEFCFG_PORT_CONN_SHIFT 30
-
-/* Display pin's device list entry */
-#define AC_DE_PD (1<<0)
-#define AC_DE_ELDV (1<<1)
-#define AC_DE_IA (1<<2)
-
-/* device device types (0x0-0xf) */
-enum {
- AC_JACK_LINE_OUT,
- AC_JACK_SPEAKER,
- AC_JACK_HP_OUT,
- AC_JACK_CD,
- AC_JACK_SPDIF_OUT,
- AC_JACK_DIG_OTHER_OUT,
- AC_JACK_MODEM_LINE_SIDE,
- AC_JACK_MODEM_HAND_SIDE,
- AC_JACK_LINE_IN,
- AC_JACK_AUX,
- AC_JACK_MIC_IN,
- AC_JACK_TELEPHONY,
- AC_JACK_SPDIF_IN,
- AC_JACK_DIG_OTHER_IN,
- AC_JACK_OTHER = 0xf,
-};
-
-/* jack connection types (0x0-0xf) */
-enum {
- AC_JACK_CONN_UNKNOWN,
- AC_JACK_CONN_1_8,
- AC_JACK_CONN_1_4,
- AC_JACK_CONN_ATAPI,
- AC_JACK_CONN_RCA,
- AC_JACK_CONN_OPTICAL,
- AC_JACK_CONN_OTHER_DIGITAL,
- AC_JACK_CONN_OTHER_ANALOG,
- AC_JACK_CONN_DIN,
- AC_JACK_CONN_XLR,
- AC_JACK_CONN_RJ11,
- AC_JACK_CONN_COMB,
- AC_JACK_CONN_OTHER = 0xf,
-};
-
-/* jack colors (0x0-0xf) */
-enum {
- AC_JACK_COLOR_UNKNOWN,
- AC_JACK_COLOR_BLACK,
- AC_JACK_COLOR_GREY,
- AC_JACK_COLOR_BLUE,
- AC_JACK_COLOR_GREEN,
- AC_JACK_COLOR_RED,
- AC_JACK_COLOR_ORANGE,
- AC_JACK_COLOR_YELLOW,
- AC_JACK_COLOR_PURPLE,
- AC_JACK_COLOR_PINK,
- AC_JACK_COLOR_WHITE = 0xe,
- AC_JACK_COLOR_OTHER,
-};
-
-/* Jack location (0x0-0x3f) */
-/* common case */
-enum {
- AC_JACK_LOC_NONE,
- AC_JACK_LOC_REAR,
- AC_JACK_LOC_FRONT,
- AC_JACK_LOC_LEFT,
- AC_JACK_LOC_RIGHT,
- AC_JACK_LOC_TOP,
- AC_JACK_LOC_BOTTOM,
-};
-/* bits 4-5 */
-enum {
- AC_JACK_LOC_EXTERNAL = 0x00,
- AC_JACK_LOC_INTERNAL = 0x10,
- AC_JACK_LOC_SEPARATE = 0x20,
- AC_JACK_LOC_OTHER = 0x30,
-};
-enum {
- /* external on primary chasis */
- AC_JACK_LOC_REAR_PANEL = 0x07,
- AC_JACK_LOC_DRIVE_BAY,
- /* internal */
- AC_JACK_LOC_RISER = 0x17,
- AC_JACK_LOC_HDMI,
- AC_JACK_LOC_ATAPI,
- /* others */
- AC_JACK_LOC_MOBILE_IN = 0x37,
- AC_JACK_LOC_MOBILE_OUT,
-};
-
-/* Port connectivity (0-3) */
-enum {
- AC_JACK_PORT_COMPLEX,
- AC_JACK_PORT_NONE,
- AC_JACK_PORT_FIXED,
- AC_JACK_PORT_BOTH,
-};
-
-/* max. codec address */
-#define HDA_MAX_CODEC_ADDRESS 0x0f
+#include <sound/hda_verbs.h>
/*
* generic arrays
@@ -673,6 +128,7 @@ struct hda_bus {
/* codec linked list */
struct list_head codec_list;
+ unsigned int num_codecs;
/* link caddr -> codec */
struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
@@ -834,6 +290,7 @@ struct hda_codec {
/* detected preset */
const struct hda_codec_preset *preset;
struct module *owner;
+ int (*parser)(struct hda_codec *codec);
const char *vendor_name; /* codec vendor name */
const char *chip_name; /* codec chip name */
const char *modelname; /* model name for preset */
@@ -904,10 +361,11 @@ struct hda_codec {
unsigned int epss:1; /* supporting EPSS? */
unsigned int cached_write:1; /* write only to caches */
unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
+ unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
#ifdef CONFIG_PM
unsigned int power_on :1; /* current (global) power-state */
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
- unsigned int pm_down_notified:1; /* PM notified to controller */
+ unsigned int pm_up_notified:1; /* PM notified to controller */
unsigned int in_pm:1; /* suspend/resume being performed */
int power_transition; /* power-state in transition */
int power_count; /* current (global) power refcount */
@@ -936,6 +394,8 @@ struct hda_codec {
struct snd_array jacks;
#endif
+ int depop_delay; /* depop delay in ms, -1 for default delay time */
+
/* fix-up list */
int fixup_id;
const struct hda_fixup *fixup_list;
@@ -1222,19 +682,6 @@ snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec,
struct snd_dma_buffer *dmab) {}
#endif
-/*
- * Codec modularization
- */
-
-/* Export symbols only for communication with codec drivers;
- * When built in kernel, all HD-audio drivers are supposed to be statically
- * linked to the kernel. Thus, the symbols don't have to (or shouldn't) be
- * exported unless it's built as a module.
- */
-#ifdef MODULE
#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym)
-#else
-#define EXPORT_SYMBOL_HDA(sym)
-#endif
#endif /* __SOUND_HDA_CODEC_H */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index d0d7ac1e99d2..79ca80f6c77a 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -2,6 +2,7 @@
* Generic routines and proc interface for ELD(EDID Like Data) information
*
* Copyright(c) 2008 Intel Corporation.
+ * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
*
* Authors:
* Wu Fengguang <wfg@linux.intel.com>
@@ -478,10 +479,9 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a,
snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
}
-static void hdmi_print_eld_info(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
+void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
+ struct snd_info_buffer *buffer)
{
- struct hdmi_eld *eld = entry->private_data;
struct parsed_hdmi_eld *e = &eld->info;
char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
int i;
@@ -500,13 +500,10 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
[4 ... 7] = "reserved"
};
- mutex_lock(&eld->lock);
snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
- if (!eld->eld_valid) {
- mutex_unlock(&eld->lock);
+ if (!eld->eld_valid)
return;
- }
snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
snd_iprintf(buffer, "connection_type\t\t%s\n",
eld_connection_type_names[e->conn_type]);
@@ -528,13 +525,11 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry,
for (i = 0; i < e->sad_count; i++)
hdmi_print_sad_info(i, e->sad + i, buffer);
- mutex_unlock(&eld->lock);
}
-static void hdmi_write_eld_info(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
+void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
+ struct snd_info_buffer *buffer)
{
- struct hdmi_eld *eld = entry->private_data;
struct parsed_hdmi_eld *e = &eld->info;
char line[64];
char name[64];
@@ -542,7 +537,6 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
long long val;
unsigned int n;
- mutex_lock(&eld->lock);
while (!snd_info_get_line(buffer, line, sizeof(line))) {
if (sscanf(line, "%s %llx", name, &val) != 2)
continue;
@@ -594,38 +588,7 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry,
e->sad_count = n + 1;
}
}
- mutex_unlock(&eld->lock);
-}
-
-
-int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
- int index)
-{
- char name[32];
- struct snd_info_entry *entry;
- int err;
-
- snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
- err = snd_card_proc_new(codec->bus->card, name, &entry);
- if (err < 0)
- return err;
-
- snd_info_set_text_ops(entry, eld, hdmi_print_eld_info);
- entry->c.text.write = hdmi_write_eld_info;
- entry->mode |= S_IWUSR;
- eld->proc_entry = entry;
-
- return 0;
-}
-
-void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld)
-{
- if (!codec->bus->shutdown && eld->proc_entry) {
- snd_device_free(codec->bus->card, eld->proc_entry);
- eld->proc_entry = NULL;
- }
}
-
#endif /* CONFIG_PROC_FS */
/* update PCM info based on ELD */
@@ -671,3 +634,174 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
hinfo->maxbps = min(hinfo->maxbps, maxbps);
hinfo->channels_max = min(hinfo->channels_max, channels_max);
}
+
+
+/* ATI/AMD specific stuff (ELD emulation) */
+
+#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776
+#define ATI_VERB_SET_SINK_INFO_INDEX 0x780
+#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70
+#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76
+#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
+#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80
+#define ATI_VERB_GET_SINK_INFO_DATA 0xf81
+
+#define ATI_SPKALLOC_SPKALLOC 0x007f
+#define ATI_SPKALLOC_TYPE_HDMI 0x0100
+#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200
+
+/* first three bytes are just standard SAD */
+#define ATI_AUDIODESC_CHANNELS 0x00000007
+#define ATI_AUDIODESC_RATES 0x0000ff00
+#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000
+
+/* in standard HDMI VSDB format */
+#define ATI_DELAY_VIDEO_LATENCY 0x000000ff
+#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00
+
+enum ati_sink_info_idx {
+ ATI_INFO_IDX_MANUFACTURER_ID = 0,
+ ATI_INFO_IDX_PRODUCT_ID = 1,
+ ATI_INFO_IDX_SINK_DESC_LEN = 2,
+ ATI_INFO_IDX_PORT_ID_LOW = 3,
+ ATI_INFO_IDX_PORT_ID_HIGH = 4,
+ ATI_INFO_IDX_SINK_DESC_FIRST = 5,
+ ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */
+};
+
+int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char *buf, int *eld_size, bool rev3_or_later)
+{
+ int spkalloc, ati_sad, aud_synch;
+ int sink_desc_len = 0;
+ int pos, i;
+
+ /* ATI/AMD does not have ELD, emulate it */
+
+ spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
+
+ if (spkalloc <= 0) {
+ snd_printd(KERN_INFO "HDMI ATI/AMD: no speaker allocation for ELD\n");
+ return -EINVAL;
+ }
+
+ memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
+
+ /* version */
+ buf[0] = ELD_VER_CEA_861D << 3;
+
+ /* speaker allocation from EDID */
+ buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
+
+ /* is DisplayPort? */
+ if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
+ buf[5] |= 0x04;
+
+ pos = ELD_FIXED_BYTES;
+
+ if (rev3_or_later) {
+ int sink_info;
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le32(sink_info, buf + 8);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le32(sink_info, buf + 12);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le16(sink_info, buf + 16);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
+ sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ put_unaligned_le16(sink_info, buf + 18);
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
+ sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+
+ if (sink_desc_len > ELD_MAX_MNL) {
+ snd_printd(KERN_INFO "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
+ sink_desc_len);
+ sink_desc_len = ELD_MAX_MNL;
+ }
+
+ buf[4] |= sink_desc_len;
+
+ for (i = 0; i < sink_desc_len; i++) {
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
+ buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+ }
+ }
+
+ for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
+ if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
+ continue; /* not handled by ATI/AMD */
+
+ snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
+ ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
+
+ if (ati_sad <= 0)
+ continue;
+
+ if (ati_sad & ATI_AUDIODESC_RATES) {
+ /* format is supported, copy SAD as-is */
+ buf[pos++] = (ati_sad & 0x0000ff) >> 0;
+ buf[pos++] = (ati_sad & 0x00ff00) >> 8;
+ buf[pos++] = (ati_sad & 0xff0000) >> 16;
+ }
+
+ if (i == AUDIO_CODING_TYPE_LPCM
+ && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
+ && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
+ /* for PCM there is a separate stereo rate mask */
+ buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
+ /* rates from the extra byte */
+ buf[pos++] = (ati_sad & 0xff000000) >> 24;
+ buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
+ }
+ }
+
+ if (pos == ELD_FIXED_BYTES + sink_desc_len) {
+ snd_printd(KERN_INFO "HDMI ATI/AMD: no audio descriptors for ELD\n");
+ return -EINVAL;
+ }
+
+ /*
+ * HDMI VSDB latency format:
+ * separately for both audio and video:
+ * 0 field not valid or unknown latency
+ * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb)
+ * 255 audio/video not supported
+ *
+ * HDA latency format:
+ * single value indicating video latency relative to audio:
+ * 0 unknown or 0ms
+ * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa)
+ * [251..255] reserved
+ */
+ aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
+ if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
+ int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
+ int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
+
+ if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
+ video_latency_hdmi > audio_latency_hdmi)
+ buf[6] = video_latency_hdmi - audio_latency_hdmi;
+ /* else unknown/invalid or 0ms or video ahead of audio, so use zero */
+ }
+
+ /* SAD count */
+ buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
+
+ /* Baseline ELD block length is 4-byte aligned */
+ pos = round_up(pos, 4);
+
+ /* Baseline ELD length (4-byte header is not counted in) */
+ buf[2] = (pos - 4) / 4;
+
+ *eld_size = pos;
+
+ return 0;
+}
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index ac41e9cdc976..d9a09bdd09db 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/bitops.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/jack.h>
#include "hda_codec.h"
@@ -47,7 +48,7 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
mutex_init(&spec->pcm_mutex);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_spec_init);
+EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
@@ -65,7 +66,7 @@ snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
return NULL;
return knew;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_add_kctl);
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl);
static void free_kctls(struct hda_gen_spec *spec)
{
@@ -86,7 +87,7 @@ void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
snd_array_free(&spec->paths);
snd_array_free(&spec->loopback_list);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_spec_free);
+EXPORT_SYMBOL_GPL(snd_hda_gen_spec_free);
/*
* store user hints
@@ -266,7 +267,7 @@ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
{
return get_nid_path(codec, from_nid, to_nid, 0);
}
-EXPORT_SYMBOL_HDA(snd_hda_get_nid_path);
+EXPORT_SYMBOL_GPL(snd_hda_get_nid_path);
/* get the index number corresponding to the path instance;
* the index starts from 1, for easier checking the invalid value
@@ -284,7 +285,7 @@ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
return 0;
return idx + 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_path_idx);
+EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
/* get the path instance corresponding to the given index number */
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
@@ -295,7 +296,7 @@ struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
return NULL;
return snd_array_elem(&spec->paths, idx - 1);
}
-EXPORT_SYMBOL_HDA(snd_hda_get_path_from_idx);
+EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx);
/* check whether the given DAC is already found in any existing paths */
static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
@@ -432,7 +433,7 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
}
return false;
}
-EXPORT_SYMBOL_HDA(snd_hda_parse_nid_path);
+EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path);
/*
* parse the path between the given NIDs and add to the path list.
@@ -463,7 +464,7 @@ snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
spec->paths.used--;
return NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_add_new_path);
+EXPORT_SYMBOL_GPL(snd_hda_add_new_path);
/* clear the given path as invalid so that it won't be picked up later */
static void invalidate_nid_path(struct hda_codec *codec, int idx)
@@ -474,6 +475,20 @@ static void invalidate_nid_path(struct hda_codec *codec, int idx)
memset(path, 0, sizeof(*path));
}
+/* return a DAC if paired to the given pin by codec driver */
+static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ const hda_nid_t *list = spec->preferred_dacs;
+
+ if (!list)
+ return 0;
+ for (; *list; list += 2)
+ if (*list == pin)
+ return list[1];
+ return 0;
+}
+
/* look for an empty DAC slot */
static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
bool is_digital)
@@ -549,11 +564,15 @@ static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
struct nid_path *path)
{
+ struct hda_gen_spec *spec = codec->spec;
int i;
for (i = path->depth - 1; i >= 0; i--) {
- if (nid_has_volume(codec, path->path[i], HDA_OUTPUT))
- return path->path[i];
+ hda_nid_t nid = path->path[i];
+ if ((spec->out_vol_mask >> nid) & 1)
+ continue;
+ if (nid_has_volume(codec, nid, HDA_OUTPUT))
+ return nid;
}
return 0;
}
@@ -755,7 +774,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
if (enable)
path->active = true;
}
-EXPORT_SYMBOL_HDA(snd_hda_activate_path);
+EXPORT_SYMBOL_GPL(snd_hda_activate_path);
/* if the given path is inactive, put widgets into D3 (only if suitable) */
static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
@@ -792,10 +811,10 @@ static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
if (spec->own_eapd_ctl ||
!(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
return;
- if (codec->inv_eapd)
- enable = !enable;
if (spec->keep_eapd_on && !enable)
return;
+ if (codec->inv_eapd)
+ enable = !enable;
snd_hda_codec_update_cache(codec, pin, 0,
AC_VERB_SET_EAPD_BTLENABLE,
enable ? 0x02 : 0x00);
@@ -1131,7 +1150,7 @@ const struct badness_table hda_main_out_badness = {
.shared_clfe = BAD_SHARED_CLFE,
.shared_surr_main = BAD_SHARED_SURROUND,
};
-EXPORT_SYMBOL_HDA(hda_main_out_badness);
+EXPORT_SYMBOL_GPL(hda_main_out_badness);
const struct badness_table hda_extra_out_badness = {
.no_primary_dac = BAD_NO_DAC,
@@ -1141,7 +1160,7 @@ const struct badness_table hda_extra_out_badness = {
.shared_clfe = BAD_SHARED_EXTRA_SURROUND,
.shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
};
-EXPORT_SYMBOL_HDA(hda_extra_out_badness);
+EXPORT_SYMBOL_GPL(hda_extra_out_badness);
/* get the DAC of the primary output corresponding to the given array index */
static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
@@ -1188,7 +1207,14 @@ static int try_assign_dacs(struct hda_codec *codec, int num_outs,
continue;
}
- dacs[i] = look_for_dac(codec, pin, false);
+ dacs[i] = get_preferred_dac(codec, pin);
+ if (dacs[i]) {
+ if (is_dac_already_used(codec, dacs[i]))
+ badness += bad->shared_primary;
+ }
+
+ if (!dacs[i])
+ dacs[i] = look_for_dac(codec, pin, false);
if (!dacs[i] && !i) {
/* try to steal the DAC of surrounds for the front */
for (j = 1; j < num_outs; j++) {
@@ -2502,12 +2528,8 @@ static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
for (i = 0; i < num_pins; i++) {
hda_nid_t pin = pins[i];
- if (pin == spec->hp_mic_pin) {
- int ret = create_hp_mic_jack_mode(codec, pin);
- if (ret < 0)
- return ret;
+ if (pin == spec->hp_mic_pin)
continue;
- }
if (get_out_jack_num_items(codec, pin) > 1) {
struct snd_kcontrol_new *knew;
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
@@ -2760,7 +2782,7 @@ static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
val &= ~(AC_PINCTL_VREFEN | PIN_HP);
val |= get_vref_idx(vref_caps, idx) | PIN_IN;
} else
- val = snd_hda_get_default_vref(codec, nid);
+ val = snd_hda_get_default_vref(codec, nid) | PIN_IN;
}
snd_hda_set_pin_ctl_cache(codec, nid, val);
call_hp_automute(codec, NULL);
@@ -2780,9 +2802,6 @@ static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
struct hda_gen_spec *spec = codec->spec;
struct snd_kcontrol_new *knew;
- if (get_out_jack_num_items(codec, pin) <= 1 &&
- get_in_jack_num_items(codec, pin) <= 1)
- return 0; /* no need */
knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
&hp_mic_jack_mode_enum);
if (!knew)
@@ -2811,6 +2830,44 @@ static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
return 0;
}
+/* return true if either a volume or a mute amp is found for the given
+ * aamix path; the amp has to be either in the mixer node or its direct leaf
+ */
+static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
+ hda_nid_t pin, unsigned int *mix_val,
+ unsigned int *mute_val)
+{
+ int idx, num_conns;
+ const hda_nid_t *list;
+ hda_nid_t nid;
+
+ idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
+ if (idx < 0)
+ return false;
+
+ *mix_val = *mute_val = 0;
+ if (nid_has_volume(codec, mix_nid, HDA_INPUT))
+ *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
+ if (nid_has_mute(codec, mix_nid, HDA_INPUT))
+ *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
+ if (*mix_val && *mute_val)
+ return true;
+
+ /* check leaf node */
+ num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
+ if (num_conns < idx)
+ return false;
+ nid = list[idx];
+ if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) &&
+ !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL))
+ *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+ if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) &&
+ !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL))
+ *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+
+ return *mix_val || *mute_val;
+}
+
/* create input playback/capture controls for the given pin */
static int new_analog_input(struct hda_codec *codec, int input_idx,
hda_nid_t pin, const char *ctlname, int ctlidx,
@@ -2818,12 +2875,11 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
{
struct hda_gen_spec *spec = codec->spec;
struct nid_path *path;
- unsigned int val;
+ unsigned int mix_val, mute_val;
int err, idx;
- if (!nid_has_volume(codec, mix_nid, HDA_INPUT) &&
- !nid_has_mute(codec, mix_nid, HDA_INPUT))
- return 0; /* no need for analog loopback */
+ if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
+ return 0;
path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
if (!path)
@@ -2832,20 +2888,18 @@ static int new_analog_input(struct hda_codec *codec, int input_idx,
spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
idx = path->idx[path->depth - 1];
- if (nid_has_volume(codec, mix_nid, HDA_INPUT)) {
- val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
- err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, val);
+ if (mix_val) {
+ err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
if (err < 0)
return err;
- path->ctls[NID_PATH_VOL_CTL] = val;
+ path->ctls[NID_PATH_VOL_CTL] = mix_val;
}
- if (nid_has_mute(codec, mix_nid, HDA_INPUT)) {
- val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
- err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, val);
+ if (mute_val) {
+ err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
if (err < 0)
return err;
- path->ctls[NID_PATH_MUTE_CTL] = val;
+ path->ctls[NID_PATH_MUTE_CTL] = mute_val;
}
path->active = true;
@@ -3002,6 +3056,8 @@ static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
spec->imux_pins[imux->num_items] = pin;
snd_hda_add_imux_item(imux, label, cfg_idx, NULL);
imux_added = true;
+ if (spec->dyn_adc_switch)
+ spec->dyn_adc_idx[imux_idx] = c;
}
}
@@ -3099,7 +3155,9 @@ static int create_input_ctls(struct hda_codec *codec)
}
}
- if (mixer && spec->add_stereo_mix_input) {
+ /* add stereo mix when explicitly enabled via hint */
+ if (mixer && spec->add_stereo_mix_input &&
+ snd_hda_get_bool_hint(codec, "add_stereo_mix_input") > 0) {
err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
"Stereo Mix", 0);
if (err < 0)
@@ -3211,7 +3269,7 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol,
mutex_unlock(&codec->control_mutex);
snd_hda_codec_flush_cache(codec); /* flush the updates */
if (err >= 0 && spec->cap_sync_hook)
- spec->cap_sync_hook(codec, ucontrol);
+ spec->cap_sync_hook(codec, kcontrol, ucontrol);
return err;
}
@@ -3332,7 +3390,7 @@ static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
return ret;
if (spec->cap_sync_hook)
- spec->cap_sync_hook(codec, ucontrol);
+ spec->cap_sync_hook(codec, kcontrol, ucontrol);
return ret;
}
@@ -3531,7 +3589,7 @@ static int create_capture_mixers(struct hda_codec *codec)
if (!multi)
err = create_single_cap_vol_ctl(codec, n, vol, sw,
inv_dmic);
- else if (!multi_cap_vol)
+ else if (!multi_cap_vol && !inv_dmic)
err = create_bind_cap_vol_ctl(codec, n, vol, sw);
else
err = create_multi_cap_vol_ctl(codec);
@@ -3737,7 +3795,7 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
return 0;
snd_hda_activate_path(codec, path, true, false);
if (spec->cap_sync_hook)
- spec->cap_sync_hook(codec, NULL);
+ spec->cap_sync_hook(codec, NULL, NULL);
path_power_down_sync(codec, old_path);
return 1;
}
@@ -3865,7 +3923,7 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec)
do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins, paths, on);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_update_outputs);
+EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs);
static void call_update_outputs(struct hda_codec *codec)
{
@@ -3898,7 +3956,7 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
return;
call_update_outputs(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_hp_automute);
+EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
/* standard line-out-automute helper */
void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
@@ -3918,7 +3976,7 @@ void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jac
return;
call_update_outputs(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_line_automute);
+EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
/* standard mic auto-switch helper */
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack)
@@ -3941,7 +3999,7 @@ void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *ja
}
mux_select(codec, 0, spec->am_entry[0].idx);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_mic_autoswitch);
+EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
/* call appropriate hooks */
static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack)
@@ -4254,11 +4312,11 @@ static int check_auto_mic_availability(struct hda_codec *codec)
}
/* power_filter hook; make inactive widgets into power down */
-static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
+unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
{
- if (power_state != AC_PWRST_D0)
+ if (power_state != AC_PWRST_D0 || nid == codec->afg)
return power_state;
if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
return power_state;
@@ -4266,7 +4324,28 @@ static unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
return power_state;
return AC_PWRST_D3;
}
+EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter);
+/* mute all aamix inputs initially; parse up to the first leaves */
+static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
+{
+ int i, nums;
+ const hda_nid_t *conn;
+ bool has_amp;
+
+ nums = snd_hda_get_conn_list(codec, mix, &conn);
+ has_amp = nid_has_mute(codec, mix, HDA_INPUT);
+ for (i = 0; i < nums; i++) {
+ if (has_amp)
+ snd_hda_codec_amp_stereo(codec, mix,
+ HDA_INPUT, i,
+ 0xff, HDA_AMP_MUTE);
+ else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
+ snd_hda_codec_amp_stereo(codec, conn[i],
+ HDA_OUTPUT, 0,
+ 0xff, HDA_AMP_MUTE);
+ }
+}
/*
* Parse the given BIOS configuration and set up the hda_gen_spec
@@ -4303,7 +4382,8 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
spec->no_analog = 1;
goto dig_only;
}
- return 0; /* can't find valid BIOS pin config */
+ if (!cfg->num_inputs && !cfg->dig_in_pin)
+ return 0; /* can't find valid BIOS pin config */
}
if (!spec->no_primary_hp &&
@@ -4371,6 +4451,19 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
if (err < 0)
return err;
+ /* add stereo mix if available and not enabled yet */
+ if (!spec->auto_mic && spec->mixer_nid &&
+ spec->add_stereo_mix_input &&
+ spec->input_mux.num_items > 1 &&
+ snd_hda_get_bool_hint(codec, "add_stereo_mix_input") < 0) {
+ err = parse_capture_source(codec, spec->mixer_nid,
+ CFG_IDX_MIX, spec->num_all_adcs,
+ "Stereo Mix", 0);
+ if (err < 0)
+ return err;
+ }
+
+
err = create_capture_mixers(codec);
if (err < 0)
return err;
@@ -4379,6 +4472,17 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
if (err < 0)
return err;
+ /* create "Headphone Mic Jack Mode" if no input selection is
+ * available (or user specifies add_jack_modes hint)
+ */
+ if (spec->hp_mic_pin &&
+ (spec->auto_mic || spec->input_mux.num_items == 1 ||
+ spec->add_jack_modes)) {
+ err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin);
+ if (err < 0)
+ return err;
+ }
+
if (spec->add_jack_modes) {
if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
err = create_out_jack_modes(codec, cfg->line_outs,
@@ -4394,6 +4498,10 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
}
}
+ /* mute all aamix input initially */
+ if (spec->mixer_nid)
+ mute_all_mixer_nid(codec, spec->mixer_nid);
+
dig_only:
parse_digital(codec);
@@ -4408,7 +4516,7 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
return 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_parse_auto_config);
+EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config);
/*
@@ -4475,9 +4583,11 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
true, &spec->vmaster_mute.sw_kctl);
if (err < 0)
return err;
- if (spec->vmaster_mute.hook)
+ if (spec->vmaster_mute.hook) {
snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute,
spec->vmaster_mute_enum);
+ snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+ }
}
free_kctls(spec); /* no longer needed */
@@ -4488,7 +4598,7 @@ int snd_hda_gen_build_controls(struct hda_codec *codec)
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_build_controls);
+EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls);
/*
@@ -5021,7 +5131,7 @@ int snd_hda_gen_build_pcms(struct hda_codec *codec)
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_build_pcms);
+EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms);
/*
@@ -5095,6 +5205,23 @@ static void init_multi_io(struct hda_codec *codec)
}
}
+static void init_aamix_paths(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ if (!spec->have_aamix_ctl)
+ return;
+ update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
+ spec->aamix_out_paths[0],
+ spec->autocfg.line_out_type);
+ update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0],
+ spec->aamix_out_paths[1],
+ AUTO_PIN_HP_OUT);
+ update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0],
+ spec->aamix_out_paths[2],
+ AUTO_PIN_SPEAKER_OUT);
+}
+
/* set up input pins and loopback paths */
static void init_analog_input(struct hda_codec *codec)
{
@@ -5143,7 +5270,7 @@ static void init_input_src(struct hda_codec *codec)
}
if (spec->cap_sync_hook)
- spec->cap_sync_hook(codec, NULL);
+ spec->cap_sync_hook(codec, NULL, NULL);
}
/* set right pin controls for digital I/O */
@@ -5197,6 +5324,7 @@ int snd_hda_gen_init(struct hda_codec *codec)
init_multi_out(codec);
init_extra_out(codec);
init_multi_io(codec);
+ init_aamix_paths(codec);
init_analog_input(codec);
init_input_src(codec);
init_digital(codec);
@@ -5214,7 +5342,7 @@ int snd_hda_gen_init(struct hda_codec *codec)
hda_call_check_power_status(codec, 0x01);
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_init);
+EXPORT_SYMBOL_GPL(snd_hda_gen_init);
/*
* free the generic spec;
@@ -5227,7 +5355,7 @@ void snd_hda_gen_free(struct hda_codec *codec)
kfree(codec->spec);
codec->spec = NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_free);
+EXPORT_SYMBOL_GPL(snd_hda_gen_free);
#ifdef CONFIG_PM
/*
@@ -5239,7 +5367,7 @@ int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
struct hda_gen_spec *spec = codec->spec;
return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
}
-EXPORT_SYMBOL_HDA(snd_hda_gen_check_power_status);
+EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
#endif
@@ -5284,4 +5412,7 @@ error:
snd_hda_gen_free(codec);
return err;
}
-EXPORT_SYMBOL_HDA(snd_hda_parse_generic_codec);
+EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic HD-audio codec parser");
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 48d44026705b..c908afbe4d94 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -242,10 +242,16 @@ struct hda_gen_spec {
/* additional mute flags (only effective with auto_mute_via_amp=1) */
u64 mute_bits;
+ /* bitmask for skipping volume controls */
+ u64 out_vol_mask;
+
/* badness tables for output path evaluations */
const struct badness_table *main_out_badness;
const struct badness_table *extra_out_badness;
+ /* preferred pin/DAC pairs; an array of paired NIDs */
+ const hda_nid_t *preferred_dacs;
+
/* loopback mixing mode */
bool aamix_mode;
@@ -268,6 +274,7 @@ struct hda_gen_spec {
void (*init_hook)(struct hda_codec *codec);
void (*automute_hook)(struct hda_codec *codec);
void (*cap_sync_hook)(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
/* PCM hooks */
@@ -329,5 +336,8 @@ void snd_hda_gen_update_outputs(struct hda_codec *codec);
#ifdef CONFIG_PM
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
#endif
+unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
+ hda_nid_t nid,
+ unsigned int power_state);
#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index fe0bda19de15..72d8389fb399 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -616,7 +616,7 @@ const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
struct hda_hint *hint = get_hint(codec, key);
return hint ? hint->val : NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_hint);
+EXPORT_SYMBOL_GPL(snd_hda_get_hint);
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
@@ -642,7 +642,7 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
mutex_unlock(&codec->user_mutex);
return ret;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint);
+EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
@@ -663,7 +663,7 @@ int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
mutex_unlock(&codec->user_mutex);
return ret;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_int_hint);
+EXPORT_SYMBOL_GPL(snd_hda_get_int_hint);
#endif /* CONFIG_SND_HDA_RECONFIG */
#ifdef CONFIG_SND_HDA_PATCH_LOADER
@@ -762,20 +762,50 @@ DEFINE_PARSE_ID_MODE(revision_id);
struct hda_patch_item {
const char *tag;
+ const char *alias;
void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc);
- int need_codec;
};
static struct hda_patch_item patch_items[NUM_LINE_MODES] = {
- [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 },
- [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 },
- [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 },
- [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 },
- [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 },
- [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 },
- [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 },
- [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 },
- [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 },
+ [LINE_MODE_CODEC] = {
+ .tag = "[codec]",
+ .parser = parse_codec_mode,
+ },
+ [LINE_MODE_MODEL] = {
+ .tag = "[model]",
+ .parser = parse_model_mode,
+ },
+ [LINE_MODE_VERB] = {
+ .tag = "[verb]",
+ .alias = "[init_verbs]",
+ .parser = parse_verb_mode,
+ },
+ [LINE_MODE_PINCFG] = {
+ .tag = "[pincfg]",
+ .alias = "[user_pin_configs]",
+ .parser = parse_pincfg_mode,
+ },
+ [LINE_MODE_HINT] = {
+ .tag = "[hint]",
+ .alias = "[hints]",
+ .parser = parse_hint_mode
+ },
+ [LINE_MODE_VENDOR_ID] = {
+ .tag = "[vendor_id]",
+ .parser = parse_vendor_id_mode,
+ },
+ [LINE_MODE_SUBSYSTEM_ID] = {
+ .tag = "[subsystem_id]",
+ .parser = parse_subsystem_id_mode,
+ },
+ [LINE_MODE_REVISION_ID] = {
+ .tag = "[revision_id]",
+ .parser = parse_revision_id_mode,
+ },
+ [LINE_MODE_CHIP_NAME] = {
+ .tag = "[chip_name]",
+ .parser = parse_chip_name_mode,
+ },
};
/* check the line starting with '[' -- change the parser mode accodingly */
@@ -787,6 +817,8 @@ static int parse_line_mode(char *buf, struct hda_bus *bus)
continue;
if (strmatch(buf, patch_items[i].tag))
return i;
+ if (patch_items[i].alias && strmatch(buf, patch_items[i].alias))
+ return i;
}
return LINE_MODE_NONE;
}
@@ -846,10 +878,10 @@ int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
if (*buf == '[')
line_mode = parse_line_mode(buf, bus);
else if (patch_items[line_mode].parser &&
- (codec || !patch_items[line_mode].need_codec))
+ (codec || line_mode <= LINE_MODE_CODEC))
patch_items[line_mode].parser(buf, bus, &codec);
}
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_load_patch);
+EXPORT_SYMBOL_GPL(snd_hda_load_patch);
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 6e61a019aa5e..e354ab1ec20f 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -169,6 +169,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, PPT},"
"{Intel, LPT},"
"{Intel, LPT_LP},"
+ "{Intel, WPT_LP},"
"{Intel, HPT},"
"{Intel, PBG},"
"{Intel, SCH},"
@@ -197,7 +198,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
#endif
#if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
-#ifdef CONFIG_SND_HDA_CODEC_HDMI
+#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
#define SUPPORT_VGA_SWITCHEROO
#endif
#endif
@@ -296,9 +297,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define ULI_NUM_CAPTURE 5
#define ULI_NUM_PLAYBACK 6
-/* ATI HDMI has 1 playback and 0 capture */
+/* ATI HDMI may have up to 8 playbacks and 0 capture */
#define ATIHDMI_NUM_CAPTURE 0
-#define ATIHDMI_NUM_PLAYBACK 1
+#define ATIHDMI_NUM_PLAYBACK 8
/* TERA has 4 playback and 3 capture */
#define TERA_NUM_CAPTURE 3
@@ -430,6 +431,8 @@ struct azx_dev {
struct timecounter azx_tc;
struct cyclecounter azx_cc;
+ int delay_negative_threshold;
+
#ifdef CONFIG_SND_HDA_DSP_LOADER
struct mutex dsp_mutex;
#endif
@@ -542,9 +545,7 @@ struct azx {
/* for pending irqs */
struct work_struct irq_pending_work;
-#ifdef CONFIG_SND_HDA_I915
struct work_struct probe_work;
-#endif
/* reboot notifier (for mysterious hangup problem at power-down) */
struct notifier_block reboot_notifier;
@@ -568,6 +569,7 @@ enum {
AZX_DRIVER_ICH,
AZX_DRIVER_PCH,
AZX_DRIVER_SCH,
+ AZX_DRIVER_HDMI,
AZX_DRIVER_ATI,
AZX_DRIVER_ATIHDMI,
AZX_DRIVER_ATIHDMI_NS,
@@ -612,6 +614,11 @@ enum {
#define AZX_DCAPS_INTEL_PCH \
(AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME)
+#define AZX_DCAPS_INTEL_HASWELL \
+ (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \
+ AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME | \
+ AZX_DCAPS_I915_POWERWELL)
+
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
(AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
@@ -642,6 +649,7 @@ static char *driver_short_names[] = {
[AZX_DRIVER_ICH] = "HDA Intel",
[AZX_DRIVER_PCH] = "HDA Intel PCH",
[AZX_DRIVER_SCH] = "HDA Intel MID",
+ [AZX_DRIVER_HDMI] = "HDA Intel HDMI",
[AZX_DRIVER_ATI] = "HDA ATI SB",
[AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI",
[AZX_DRIVER_ATIHDMI_NS] = "HDA ATI HDMI",
@@ -906,12 +914,12 @@ static void azx_update_rirb(struct azx *chip)
chip->rirb.res[addr] = res;
smp_wmb();
chip->rirb.cmds[addr]--;
- } else
- snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, "
- "last cmd=%#08x\n",
+ } else if (printk_ratelimit()) {
+ snd_printk(KERN_ERR SFX "%s: spurious response %#x:%#x, last cmd=%#08x\n",
pci_name(chip->pci),
res, res_ex,
chip->last_cmd[addr]);
+ }
}
}
@@ -2189,6 +2197,15 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
goto unlock;
}
+ /* when LPIB delay correction gives a small negative value,
+ * we ignore it; currently set the threshold statically to
+ * 64 frames
+ */
+ if (runtime->period_size > 64)
+ azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64);
+ else
+ azx_dev->delay_negative_threshold = 0;
+
/* wallclk has 24Mhz clock source */
azx_dev->period_wallclk = (((runtime->period_size * 24000) /
runtime->rate) * 1000);
@@ -2441,8 +2458,12 @@ static unsigned int azx_get_position(struct azx *chip,
delay = pos - lpib_pos;
else
delay = lpib_pos - pos;
- if (delay < 0)
- delay += azx_dev->bufsize;
+ if (delay < 0) {
+ if (delay >= azx_dev->delay_negative_threshold)
+ delay = 0;
+ else
+ delay += azx_dev->bufsize;
+ }
if (delay >= azx_dev->period_bytes) {
snd_printk(KERN_WARNING SFX
"%s: Unstable LPIB (%d >= %d); "
@@ -3425,6 +3446,10 @@ static void check_probe_mask(struct azx *chip, int dev)
* white/black-list for enable_msi
*/
static struct snd_pci_quirk msi_black_list[] = {
+ SND_PCI_QUIRK(0x103c, 0x2191, "HP", 0), /* AMD Hudson */
+ SND_PCI_QUIRK(0x103c, 0x2192, "HP", 0), /* AMD Hudson */
+ SND_PCI_QUIRK(0x103c, 0x21f7, "HP", 0), /* AMD Hudson */
+ SND_PCI_QUIRK(0x103c, 0x21fa, "HP", 0), /* AMD Hudson */
SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */
@@ -3492,12 +3517,10 @@ static void azx_check_snoop_available(struct azx *chip)
}
}
-#ifdef CONFIG_SND_HDA_I915
static void azx_probe_work(struct work_struct *work)
{
azx_probe_continue(container_of(work, struct azx, probe_work));
}
-#endif
/*
* constructor
@@ -3574,10 +3597,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
-#ifdef CONFIG_SND_HDA_I915
/* continue probing in work context as may trigger request module */
INIT_WORK(&chip->probe_work, azx_probe_work);
-#endif
*rchip = chip;
@@ -3797,7 +3818,7 @@ static int azx_probe(struct pci_dev *pci,
static int dev;
struct snd_card *card;
struct azx *chip;
- bool probe_now;
+ bool schedule_probe;
int err;
if (dev >= SNDRV_CARDS)
@@ -3836,7 +3857,7 @@ static int azx_probe(struct pci_dev *pci,
chip->disabled = true;
}
- probe_now = !chip->disabled;
+ schedule_probe = !chip->disabled;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
@@ -3847,28 +3868,21 @@ static int azx_probe(struct pci_dev *pci,
azx_firmware_cb);
if (err < 0)
goto out_free;
- probe_now = false; /* continued in azx_firmware_cb() */
+ schedule_probe = false; /* continued in azx_firmware_cb() */
}
#endif /* CONFIG_SND_HDA_PATCH_LOADER */
- /* continue probing in work context, avoid request_module deadlock */
- if (probe_now && (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)) {
-#ifdef CONFIG_SND_HDA_I915
- probe_now = false;
- schedule_work(&chip->probe_work);
-#else
+#ifndef CONFIG_SND_HDA_I915
+ if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
snd_printk(KERN_ERR SFX "Haswell must build in CONFIG_SND_HDA_I915\n");
#endif
- }
- if (probe_now) {
- err = azx_probe_continue(chip);
- if (err < 0)
- goto out_free;
- }
+ if (schedule_probe)
+ schedule_work(&chip->probe_work);
dev++;
- complete_all(&chip->probe_wait);
+ if (chip->disabled)
+ complete_all(&chip->probe_wait);
return 0;
out_free:
@@ -3945,10 +3959,10 @@ static int azx_probe_continue(struct azx *chip)
if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo)
pm_runtime_put_noidle(&pci->dev);
- return 0;
-
out_free:
- chip->init_failed = 1;
+ if (err < 0)
+ chip->init_failed = 1;
+ complete_all(&chip->probe_wait);
return err;
}
@@ -3970,7 +3984,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
/* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -3985,16 +3999,19 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c21),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ /* Wildcat Point-LP */
+ { PCI_DEVICE(0x8086, 0x9ca0),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
- AZX_DCAPS_I915_POWERWELL },
+ .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
{ PCI_DEVICE(0x8086, 0x0c0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
- AZX_DCAPS_I915_POWERWELL },
+ .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
{ PCI_DEVICE(0x8086, 0x0d0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH |
- AZX_DCAPS_I915_POWERWELL },
+ .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
+ /* Broadwell */
+ { PCI_DEVICE(0x8086, 0x160c),
+ .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM },
@@ -4074,6 +4091,22 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0xaa48),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa50),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa58),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa60),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa68),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa80),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa88),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa90),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
+ { PCI_DEVICE(0x1002, 0xaa98),
+ .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0x9902),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0xaaa0),
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 05b3e3e9108f..9746d73cec52 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -34,7 +34,7 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
return false;
return true;
}
-EXPORT_SYMBOL_HDA(is_jack_detectable);
+EXPORT_SYMBOL_GPL(is_jack_detectable);
/* execute pin sense measurement */
static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
@@ -71,7 +71,7 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
return jack;
return NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get);
+EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get);
/**
* snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
@@ -89,7 +89,7 @@ snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
return jack;
return NULL;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get_from_tag);
+EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag);
/**
* snd_hda_jack_tbl_new - create a jack-table entry for the given NID
@@ -108,7 +108,7 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
jack->tag = codec->jacktbl.used;
return jack;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_new);
+EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_new);
void snd_hda_jack_tbl_clear(struct hda_codec *codec)
{
@@ -172,7 +172,7 @@ void snd_hda_jack_set_dirty_all(struct hda_codec *codec)
if (jack->nid)
jack->jack_dirty = 1;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all);
+EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all);
/**
* snd_hda_pin_sense - execute pin sense measurement
@@ -191,7 +191,7 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
}
return read_pin_sense(codec, nid);
}
-EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
+EXPORT_SYMBOL_GPL(snd_hda_pin_sense);
/**
* snd_hda_jack_detect_state - query pin Presence Detect status
@@ -211,7 +211,7 @@ int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
else
return HDA_JACK_NOT_PRESENT;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_detect_state);
+EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state);
/**
* snd_hda_jack_detect_enable - enable the jack-detection
@@ -236,14 +236,14 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | jack->tag);
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable_callback);
+EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
unsigned char action)
{
return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL);
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
+EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable);
/**
* snd_hda_jack_set_gating_jack - Set gating jack.
@@ -264,7 +264,7 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack);
+EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack);
/**
* snd_hda_jack_report_sync - sync the states of all jacks and report if changed
@@ -286,7 +286,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
jack = codec->jacktbl.list;
for (i = 0; i < codec->jacktbl.used; i++, jack++)
if (jack->nid) {
- if (!jack->kctl)
+ if (!jack->kctl || jack->block_report)
continue;
state = get_jack_plug_state(jack->pin_sense);
snd_kctl_jack_report(codec->bus->card, jack->kctl, state);
@@ -297,7 +297,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
#endif
}
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync);
+EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync);
#ifdef CONFIG_SND_HDA_INPUT_JACK
/* guess the jack type from the pin-config */
@@ -377,7 +377,7 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
{
return __snd_hda_jack_add_kctl(codec, nid, name, idx, false);
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl);
+EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl);
/* get the unique index number for the given kctl name */
static int get_unique_index(struct hda_codec *codec, const char *name, int idx)
@@ -493,7 +493,7 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
return err;
return 0;
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);
+EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls);
static void call_jack_callback(struct hda_codec *codec,
struct hda_jack_tbl *jack)
@@ -521,7 +521,7 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
call_jack_callback(codec, event);
snd_hda_jack_report_sync(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event);
+EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event);
void snd_hda_jack_poll_all(struct hda_codec *codec)
{
@@ -542,5 +542,5 @@ void snd_hda_jack_poll_all(struct hda_codec *codec)
if (changes)
snd_hda_jack_report_sync(codec);
}
-EXPORT_SYMBOL_HDA(snd_hda_jack_poll_all);
+EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all);
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 379420c44eef..46e1ea83ce3c 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -28,6 +28,7 @@ struct hda_jack_tbl {
unsigned int jack_detect:1; /* capable of jack-detection? */
unsigned int jack_dirty:1; /* needs to update? */
unsigned int phantom_jack:1; /* a fixed, always present port? */
+ unsigned int block_report:1; /* in a transitional state - do not report to userspace */
hda_nid_t gating_jack; /* valid when gating jack plugged */
hda_nid_t gated_jack; /* gated is dependent on this jack */
struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 2e7493ef8ee0..da80c5bd7fd4 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -352,14 +352,8 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
/*
* generic codec parser
*/
-#ifdef CONFIG_SND_HDA_GENERIC
int snd_hda_parse_generic_codec(struct hda_codec *codec);
-#else
-static inline int snd_hda_parse_generic_codec(struct hda_codec *codec)
-{
- return -ENODEV;
-}
-#endif
+int snd_hda_parse_hdmi_codec(struct hda_codec *codec);
/*
* generic proc interface
@@ -428,6 +422,7 @@ enum {
HDA_FIXUP_ACT_PROBE,
HDA_FIXUP_ACT_INIT,
HDA_FIXUP_ACT_BUILD,
+ HDA_FIXUP_ACT_FREE,
};
int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list);
@@ -751,10 +746,6 @@ struct hdmi_eld {
int eld_size;
char eld_buffer[ELD_MAX_SIZE];
struct parsed_hdmi_eld info;
- struct mutex lock;
-#ifdef CONFIG_PROC_FS
- struct snd_info_entry *proc_entry;
-#endif
};
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
@@ -766,21 +757,15 @@ void snd_hdmi_show_eld(struct parsed_hdmi_eld *e);
void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo);
+int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char *buf, int *eld_size,
+ bool rev3_or_later);
+
#ifdef CONFIG_PROC_FS
-int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld,
- int index);
-void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld);
-#else
-static inline int snd_hda_eld_proc_new(struct hda_codec *codec,
- struct hdmi_eld *eld,
- int index)
-{
- return 0;
-}
-static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
- struct hdmi_eld *eld)
-{
-}
+void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
+ struct snd_info_buffer *buffer);
+void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
+ struct snd_info_buffer *buffer);
#endif
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index a8cb22eec89e..ce5a6da83419 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -24,9 +24,14 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/core.h>
+#include <linux/module.h>
#include "hda_codec.h"
#include "hda_local.h"
+static int dump_coef = -1;
+module_param(dump_coef, int, 0644);
+MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)");
+
static char *bits_names(unsigned int bits, char *names[], int size)
{
int i, n;
@@ -488,14 +493,39 @@ static void print_unsol_cap(struct snd_info_buffer *buffer,
(unsol & AC_UNSOL_ENABLED) ? 1 : 0);
}
+static inline bool can_dump_coef(struct hda_codec *codec)
+{
+ switch (dump_coef) {
+ case 0: return false;
+ case 1: return true;
+ default: return codec->dump_coef;
+ }
+}
+
static void print_proc_caps(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid)
{
+ unsigned int i, ncoeff, oldindex;
unsigned int proc_caps = snd_hda_param_read(codec, nid,
AC_PAR_PROC_CAP);
+ ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT;
snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n",
- proc_caps & AC_PCAP_BENIGN,
- (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT);
+ proc_caps & AC_PCAP_BENIGN, ncoeff);
+
+ if (!can_dump_coef(codec))
+ return;
+
+ /* Note: This is racy - another process could run in parallel and change
+ the coef index too. */
+ oldindex = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_COEF_INDEX, 0);
+ for (i = 0; i < ncoeff; i++) {
+ unsigned int val;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, i);
+ val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF,
+ 0);
+ snd_iprintf(buffer, " Coeff 0x%02x: 0x%04x\n", i, val);
+ }
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, oldindex);
}
static void print_conn_list(struct snd_info_buffer *buffer,
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 0cbdd87dde6d..df3652ad15ef 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -139,6 +139,20 @@ static int ad198x_suspend(struct hda_codec *codec)
}
#endif
+/* follow EAPD via vmaster hook */
+static void ad_vmaster_eapd_hook(void *private_data, int enabled)
+{
+ struct hda_codec *codec = private_data;
+ struct ad198x_spec *spec = codec->spec;
+
+ if (!spec->eapd_nid)
+ return;
+ if (codec->inv_eapd)
+ enabled = !enabled;
+ snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
+ AC_VERB_SET_EAPD_BTLENABLE,
+ enabled ? 0x02 : 0x00);
+}
/*
* Automatic parse of I/O pins from the BIOS configuration
@@ -171,7 +185,7 @@ static const struct hda_codec_ops ad198x_auto_patch_ops = {
};
-static int ad198x_parse_auto_config(struct hda_codec *codec)
+static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
{
struct ad198x_spec *spec = codec->spec;
struct auto_pin_cfg *cfg = &spec->gen.autocfg;
@@ -181,7 +195,8 @@ static int ad198x_parse_auto_config(struct hda_codec *codec)
codec->no_trigger_sense = 1;
codec->no_sticky_stream = 1;
- spec->gen.indep_hp = 1;
+ spec->gen.indep_hp = indep_hp;
+ spec->gen.add_stereo_mix_input = 1;
err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
if (err < 0)
@@ -219,8 +234,27 @@ static int alloc_ad_spec(struct hda_codec *codec)
static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ struct ad198x_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
codec->inv_jack_detect = 1;
+ spec->gen.keep_eapd_on = 1;
+ spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+ spec->eapd_nid = 0x1b;
+ }
+}
+
+/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */
+static void ad1986a_fixup_eapd(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct ad198x_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ codec->inv_eapd = 0;
+ spec->gen.keep_eapd_on = 1;
+ spec->eapd_nid = 0x1b;
+ }
}
enum {
@@ -230,6 +264,7 @@ enum {
AD1986A_FIXUP_3STACK,
AD1986A_FIXUP_LAPTOP,
AD1986A_FIXUP_LAPTOP_IMIC,
+ AD1986A_FIXUP_EAPD,
};
static const struct hda_fixup ad1986a_fixups[] = {
@@ -260,11 +295,11 @@ static const struct hda_fixup ad1986a_fixups[] = {
.v.pins = (const struct hda_pintbl[]) {
{ 0x1a, 0x02214021 }, /* headphone */
{ 0x1b, 0x01014011 }, /* front */
- { 0x1c, 0x01013012 }, /* surround */
- { 0x1d, 0x01019015 }, /* clfe */
+ { 0x1c, 0x01813030 }, /* line-in */
+ { 0x1d, 0x01a19020 }, /* rear mic */
{ 0x1e, 0x411111f0 }, /* N/A */
{ 0x1f, 0x02a190f0 }, /* mic */
- { 0x20, 0x018130f0 }, /* line-in */
+ { 0x20, 0x411111f0 }, /* N/A */
{}
},
},
@@ -290,6 +325,10 @@ static const struct hda_fixup ad1986a_fixups[] = {
.chained_before = 1,
.chain_id = AD1986A_FIXUP_LAPTOP,
},
+ [AD1986A_FIXUP_EAPD] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = ad1986a_fixup_eapd,
+ },
};
static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
@@ -297,6 +336,7 @@ static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
+ SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
@@ -320,6 +360,14 @@ static int patch_ad1986a(struct hda_codec *codec)
{
int err;
struct ad198x_spec *spec;
+ static hda_nid_t preferred_pairs[] = {
+ 0x1a, 0x03,
+ 0x1b, 0x03,
+ 0x1c, 0x04,
+ 0x1d, 0x05,
+ 0x1e, 0x03,
+ 0
+ };
err = alloc_ad_spec(codec);
if (err < 0)
@@ -340,12 +388,17 @@ static int patch_ad1986a(struct hda_codec *codec)
* So, let's disable the shared stream.
*/
spec->gen.multiout.no_share_stream = 1;
+ /* give fixed DAC/pin pairs */
+ spec->gen.preferred_dacs = preferred_pairs;
+
+ /* AD1986A can't manage the dynamic pin on/off smoothly */
+ spec->gen.auto_mute_via_amp = 1;
snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
ad1986a_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = ad198x_parse_auto_config(codec);
+ err = ad198x_parse_auto_config(codec, false);
if (err < 0) {
snd_hda_gen_free(codec);
return err;
@@ -438,6 +491,8 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
static int patch_ad1983(struct hda_codec *codec)
{
struct ad198x_spec *spec;
+ static hda_nid_t conn_0c[] = { 0x08 };
+ static hda_nid_t conn_0d[] = { 0x09 };
int err;
err = alloc_ad_spec(codec);
@@ -445,9 +500,15 @@ static int patch_ad1983(struct hda_codec *codec)
return err;
spec = codec->spec;
+ spec->gen.mixer_nid = 0x0e;
spec->gen.beep_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
- err = ad198x_parse_auto_config(codec);
+
+ /* limit the loopback routes not to confuse the parser */
+ snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
+ snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
+
+ err = ad198x_parse_auto_config(codec, false);
if (err < 0)
goto error;
err = ad1983_add_spdif_mux_ctl(codec);
@@ -465,19 +526,6 @@ static int patch_ad1983(struct hda_codec *codec)
* AD1981 HD specific
*/
-/* follow EAPD via vmaster hook */
-static void ad_vmaster_eapd_hook(void *private_data, int enabled)
-{
- struct hda_codec *codec = private_data;
- struct ad198x_spec *spec = codec->spec;
-
- if (!spec->eapd_nid)
- return;
- snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
- AC_VERB_SET_EAPD_BTLENABLE,
- enabled ? 0x02 : 0x00);
-}
-
static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -547,7 +595,7 @@ static int patch_ad1981(struct hda_codec *codec)
snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = ad198x_parse_auto_config(codec);
+ err = ad198x_parse_auto_config(codec, false);
if (err < 0)
goto error;
err = ad1983_add_spdif_mux_ctl(codec);
@@ -873,7 +921,7 @@ static int patch_ad1988(struct hda_codec *codec)
snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = ad198x_parse_auto_config(codec);
+ err = ad198x_parse_auto_config(codec, true);
if (err < 0)
goto error;
err = ad1988_add_spdif_mux_ctl(codec);
@@ -957,6 +1005,7 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
+ spec->gen.own_eapd_ctl = 1;
snd_hda_sequence_write_cache(codec, gpio_init_verbs);
break;
case HDA_FIXUP_ACT_PROBE:
@@ -968,6 +1017,18 @@ static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
}
}
+static void ad1884_fixup_thinkpad(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct ad198x_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gen.keep_eapd_on = 1;
+ spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+ spec->eapd_nid = 0x12;
+ }
+}
+
/* set magic COEFs for dmic */
static const struct hda_verb ad1884_dmic_init_verbs[] = {
{0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
@@ -979,6 +1040,7 @@ enum {
AD1884_FIXUP_AMP_OVERRIDE,
AD1884_FIXUP_HP_EAPD,
AD1884_FIXUP_DMIC_COEF,
+ AD1884_FIXUP_THINKPAD,
AD1884_FIXUP_HP_TOUCHSMART,
};
@@ -997,6 +1059,12 @@ static const struct hda_fixup ad1884_fixups[] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = ad1884_dmic_init_verbs,
},
+ [AD1884_FIXUP_THINKPAD] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = ad1884_fixup_thinkpad,
+ .chained = true,
+ .chain_id = AD1884_FIXUP_DMIC_COEF,
+ },
[AD1884_FIXUP_HP_TOUCHSMART] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = ad1884_dmic_init_verbs,
@@ -1008,7 +1076,7 @@ static const struct hda_fixup ad1884_fixups[] = {
static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
- SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_DMIC_COEF),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
{}
};
@@ -1030,7 +1098,7 @@ static int patch_ad1884(struct hda_codec *codec)
snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- err = ad198x_parse_auto_config(codec);
+ err = ad198x_parse_auto_config(codec, true);
if (err < 0)
goto error;
err = ad1983_add_spdif_mux_ctl(codec);
@@ -1072,7 +1140,7 @@ static int patch_ad1882(struct hda_codec *codec)
spec->gen.mixer_merge_nid = 0x21;
spec->gen.beep_nid = 0x10;
set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
- err = ad198x_parse_auto_config(codec);
+ err = ad198x_parse_auto_config(codec, true);
if (err < 0)
goto error;
err = ad1988_add_spdif_mux_ctl(codec);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 6e9876f27d95..54d14793725a 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -759,7 +759,7 @@ struct ca0132_spec {
/*
* CA0132 codec access
*/
-unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid,
+static unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid,
unsigned int verb, unsigned int parm, unsigned int *res)
{
unsigned int response;
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index b524f89a1f13..fc492ac24caa 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -47,6 +47,10 @@ struct cs_spec {
unsigned int spdif_present:1;
unsigned int sense_b:1;
hda_nid_t vendor_nid;
+
+ /* for MBP SPDIF control */
+ int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
};
/* available models with CS420x */
@@ -111,6 +115,9 @@ enum {
/* 0x0009 - 0x0014 -> 12 test regs */
/* 0x0015 - visibility reg */
+/* Cirrus Logic CS4208 */
+#define CS4208_VENDOR_NID 0x24
+
/*
* Cirrus Logic CS4210
*
@@ -223,6 +230,16 @@ static const struct hda_verb cs_coef_init_verbs[] = {
{} /* terminator */
};
+static const struct hda_verb cs4208_coef_init_verbs[] = {
+ {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
+ {0x24, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */
+ {0x24, AC_VERB_SET_COEF_INDEX, 0x0033},
+ {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */
+ {0x24, AC_VERB_SET_COEF_INDEX, 0x0034},
+ {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */
+ {} /* terminator */
+};
+
/* Errata: CS4207 rev C0/C1/C2 Silicon
*
* http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
@@ -295,6 +312,8 @@ static int cs_init(struct hda_codec *codec)
/* init_verb sequence for C0/C1/C2 errata*/
snd_hda_sequence_write(codec, cs_errata_init_verbs);
snd_hda_sequence_write(codec, cs_coef_init_verbs);
+ } else if (spec->vendor_nid == CS4208_VENDOR_NID) {
+ snd_hda_sequence_write(codec, cs4208_coef_init_verbs);
}
snd_hda_gen_init(codec);
@@ -316,10 +335,21 @@ static int cs_init(struct hda_codec *codec)
return 0;
}
+static int cs_build_controls(struct hda_codec *codec)
+{
+ int err;
+
+ err = snd_hda_gen_build_controls(codec);
+ if (err < 0)
+ return err;
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+ return 0;
+}
+
#define cs_free snd_hda_gen_free
static const struct hda_codec_ops cs_patch_ops = {
- .build_controls = snd_hda_gen_build_controls,
+ .build_controls = cs_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = cs_init,
.free = cs_free,
@@ -434,6 +464,29 @@ static const struct hda_pintbl mba42_pincfgs[] = {
{} /* terminator */
};
+static const struct hda_pintbl mba6_pincfgs[] = {
+ { 0x10, 0x032120f0 }, /* HP */
+ { 0x11, 0x500000f0 },
+ { 0x12, 0x90100010 }, /* Speaker */
+ { 0x13, 0x500000f0 },
+ { 0x14, 0x500000f0 },
+ { 0x15, 0x770000f0 },
+ { 0x16, 0x770000f0 },
+ { 0x17, 0x430000f0 },
+ { 0x18, 0x43ab9030 }, /* Mic */
+ { 0x19, 0x770000f0 },
+ { 0x1a, 0x770000f0 },
+ { 0x1b, 0x770000f0 },
+ { 0x1c, 0x90a00090 },
+ { 0x1d, 0x500000f0 },
+ { 0x1e, 0x500000f0 },
+ { 0x1f, 0x500000f0 },
+ { 0x20, 0x500000f0 },
+ { 0x21, 0x430000f0 },
+ { 0x22, 0x430000f0 },
+ {} /* terminator */
+};
+
static void cs420x_fixup_gpio_13(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -556,22 +609,32 @@ static int patch_cs420x(struct hda_codec *codec)
/*
* CS4208 support:
- * Its layout is no longer compatible with CS4206/CS4207, and the generic
- * parser seems working fairly well, except for trivial fixups.
+ * Its layout is no longer compatible with CS4206/CS4207
*/
enum {
+ CS4208_MAC_AUTO,
+ CS4208_MBA6,
+ CS4208_MBP11,
CS4208_GPIO0,
};
static const struct hda_model_fixup cs4208_models[] = {
{ .id = CS4208_GPIO0, .name = "gpio0" },
+ { .id = CS4208_MBA6, .name = "mba6" },
+ { .id = CS4208_MBP11, .name = "mbp11" },
{}
};
static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
- /* codec SSID */
- SND_PCI_QUIRK(0x106b, 0x7100, "MacBookPro 6,1", CS4208_GPIO0),
- SND_PCI_QUIRK(0x106b, 0x7200, "MacBookPro 6,2", CS4208_GPIO0),
+ SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
+ {} /* terminator */
+};
+
+/* codec SSID matching */
+static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
+ SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
+ SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
{} /* terminator */
};
@@ -587,28 +650,107 @@ static void cs4208_fixup_gpio0(struct hda_codec *codec,
}
}
+static const struct hda_fixup cs4208_fixups[];
+
+/* remap the fixup from codec SSID and apply it */
+static void cs4208_fixup_mac(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups);
+ if (codec->fixup_id < 0 || codec->fixup_id == CS4208_MAC_AUTO)
+ codec->fixup_id = CS4208_GPIO0; /* default fixup */
+ snd_hda_apply_fixup(codec, action);
+}
+
+static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cs_spec *spec = codec->spec;
+ hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0];
+ int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0;
+
+ snd_hda_set_pin_ctl_cache(codec, pin, pinctl);
+ return spec->spdif_sw_put(kcontrol, ucontrol);
+}
+
+/* hook the SPDIF switch */
+static void cs4208_fixup_spdif_switch(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_BUILD) {
+ struct cs_spec *spec = codec->spec;
+ struct snd_kcontrol *kctl;
+
+ if (!spec->gen.autocfg.dig_out_pins[0])
+ return;
+ kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
+ if (!kctl)
+ return;
+ spec->spdif_sw_put = kctl->put;
+ kctl->put = cs4208_spdif_sw_put;
+ }
+}
+
static const struct hda_fixup cs4208_fixups[] = {
+ [CS4208_MBA6] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = mba6_pincfgs,
+ .chained = true,
+ .chain_id = CS4208_GPIO0,
+ },
+ [CS4208_MBP11] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs4208_fixup_spdif_switch,
+ .chained = true,
+ .chain_id = CS4208_GPIO0,
+ },
[CS4208_GPIO0] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs4208_fixup_gpio0,
},
+ [CS4208_MAC_AUTO] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs4208_fixup_mac,
+ },
};
+/* correct the 0dB offset of input pins */
+static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
+{
+ unsigned int caps;
+
+ caps = query_amp_caps(codec, adc, HDA_INPUT);
+ caps &= ~(AC_AMPCAP_OFFSET);
+ caps |= 0x02;
+ snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
+}
+
static int patch_cs4208(struct hda_codec *codec)
{
struct cs_spec *spec;
int err;
- spec = cs_alloc_spec(codec, 0); /* no specific w/a */
+ spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
if (!spec)
return -ENOMEM;
spec->gen.automute_hook = cs_automute;
+ /* exclude NID 0x10 (HP) from output volumes due to different steps */
+ spec->gen.out_vol_mask = 1ULL << 0x10;
snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
cs4208_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+ snd_hda_override_wcaps(codec, 0x18,
+ get_wcaps(codec, 0x18) | AC_WCAP_STEREO);
+ cs4208_fix_amp_caps(codec, 0x18);
+ cs4208_fix_amp_caps(codec, 0x1b);
+ cs4208_fix_amp_caps(codec, 0x1c);
+
err = cs_parse_auto_config(codec);
if (err < 0)
goto error;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 4edd2d0f9a3c..bcf91bea3317 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -2936,7 +2936,6 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD),
- SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD),
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS),
SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
@@ -3208,11 +3207,17 @@ static int cx_auto_init(struct hda_codec *codec)
return 0;
}
+static void cx_auto_free(struct hda_codec *codec)
+{
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
+ snd_hda_gen_free(codec);
+}
+
static const struct hda_codec_ops cx_auto_patch_ops = {
.build_controls = cx_auto_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = cx_auto_init,
- .free = snd_hda_gen_free,
+ .free = cx_auto_free,
.unsol_event = snd_hda_jack_unsol_event,
#ifdef CONFIG_PM
.check_power_status = snd_hda_gen_check_power_status,
@@ -3231,8 +3236,13 @@ enum {
CXT_FIXUP_INC_MIC_BOOST,
CXT_FIXUP_HEADPHONE_MIC_PIN,
CXT_FIXUP_HEADPHONE_MIC,
+ CXT_FIXUP_GPIO1,
+ CXT_FIXUP_THINKPAD_ACPI,
};
+/* for hda_fixup_thinkpad_acpi() */
+#include "thinkpad_helper.c"
+
static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3281,7 +3291,8 @@ static void cxt_update_headset_mode(struct hda_codec *codec)
}
static void cxt_update_headset_mode_hook(struct hda_codec *codec,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
cxt_update_headset_mode(codec);
}
@@ -3343,6 +3354,8 @@ static const struct hda_fixup cxt_fixups[] = {
[CXT_PINCFG_LENOVO_TP410] = {
.type = HDA_FIXUP_PINS,
.v.pins = cxt_pincfg_lenovo_tp410,
+ .chained = true,
+ .chain_id = CXT_FIXUP_THINKPAD_ACPI,
},
[CXT_PINCFG_LEMOTE_A1004] = {
.type = HDA_FIXUP_PINS,
@@ -3375,6 +3388,19 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_headphone_mic,
},
+ [CXT_FIXUP_GPIO1] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
+ { 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
+ { }
+ },
+ },
+ [CXT_FIXUP_THINKPAD_ACPI] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = hda_fixup_thinkpad_acpi,
+ },
};
static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -3384,6 +3410,7 @@ static const struct snd_pci_quirk cxt5051_fixups[] = {
static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
@@ -3395,6 +3422,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
{}
@@ -3496,7 +3524,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
return 0;
error:
- snd_hda_gen_free(codec);
+ cx_auto_free(codec);
return err;
}
@@ -3557,6 +3585,8 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_conexant_auto },
{ .id = 0x14f15115, .name = "CX20757",
.patch = patch_conexant_auto },
+ { .id = 0x14f151d7, .name = "CX20952",
+ .patch = patch_conexant_auto },
{} /* terminator */
};
@@ -3583,6 +3613,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15111");
MODULE_ALIAS("snd-hda-codec-id:14f15113");
MODULE_ALIAS("snd-hda-codec-id:14f15114");
MODULE_ALIAS("snd-hda-codec-id:14f15115");
+MODULE_ALIAS("snd-hda-codec-id:14f151d7");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Conexant HD-audio codec");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 3d8cd04455a6..5ef95034d041 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -6,6 +6,7 @@
* Copyright (c) 2006 ATI Technologies Inc.
* Copyright (c) 2008 NVIDIA Corp. All rights reserved.
* Copyright (c) 2008 Wei Ni <wni@nvidia.com>
+ * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
*
* Authors:
* Wu Fengguang <wfg@linux.intel.com>
@@ -45,6 +46,10 @@ module_param(static_hdmi_pcm, bool, 0644);
MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
#define is_haswell(codec) ((codec)->vendor_id == 0x80862807)
+#define is_broadwell(codec) ((codec)->vendor_id == 0x80862808)
+#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec))
+
+#define is_valleyview(codec) ((codec)->vendor_id == 0x80862882)
struct hdmi_spec_per_cvt {
hda_nid_t cvt_nid;
@@ -63,9 +68,11 @@ struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+ hda_nid_t cvt_nid;
struct hda_codec *codec;
struct hdmi_eld sink_eld;
+ struct mutex lock;
struct delayed_work work;
struct snd_kcontrol *eld_ctl;
int repoll_count;
@@ -75,6 +82,42 @@ struct hdmi_spec_per_pin {
bool chmap_set; /* channel-map override by ALSA API? */
unsigned char chmap[8]; /* ALSA API channel-map */
char pcm_name[8]; /* filled in build_pcm callbacks */
+#ifdef CONFIG_PROC_FS
+ struct snd_info_entry *proc_entry;
+#endif
+};
+
+struct cea_channel_speaker_allocation;
+
+/* operations used by generic code that can be overridden by patches */
+struct hdmi_ops {
+ int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
+ unsigned char *buf, int *eld_size);
+
+ /* get and set channel assigned to each HDMI ASP (audio sample packet) slot */
+ int (*pin_get_slot_channel)(struct hda_codec *codec, hda_nid_t pin_nid,
+ int asp_slot);
+ int (*pin_set_slot_channel)(struct hda_codec *codec, hda_nid_t pin_nid,
+ int asp_slot, int channel);
+
+ void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
+ int ca, int active_channels, int conn_type);
+
+ /* enable/disable HBR (HD passthrough) */
+ int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, bool hbr);
+
+ int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, u32 stream_tag, int format);
+
+ /* Helpers for producing the channel map TLVs. These can be overridden
+ * for devices that have non-standard mapping requirements. */
+ int (*chmap_cea_alloc_validate_get_type)(struct cea_channel_speaker_allocation *cap,
+ int channels);
+ void (*cea_alloc_to_tlv_chmap)(struct cea_channel_speaker_allocation *cap,
+ unsigned int *chmap, int channels);
+
+ /* check that the user-given chmap is supported */
+ int (*chmap_validate)(int ca, int channels, unsigned char *chmap);
};
struct hdmi_spec {
@@ -88,8 +131,12 @@ struct hdmi_spec {
unsigned int channels_max; /* max over all cvts */
struct hdmi_eld temp_eld;
+ struct hdmi_ops ops;
+
+ bool dyn_pin_out;
+
/*
- * Non-generic ATI/NVIDIA specific
+ * Non-generic VIA/NVIDIA specific
*/
struct hda_multi_out multiout;
struct hda_pcm_stream pcm_playback;
@@ -348,17 +395,19 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
struct hdmi_eld *eld;
int pin_idx;
uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
pin_idx = kcontrol->private_value;
- eld = &get_pin(spec, pin_idx)->sink_eld;
+ per_pin = get_pin(spec, pin_idx);
+ eld = &per_pin->sink_eld;
- mutex_lock(&eld->lock);
+ mutex_lock(&per_pin->lock);
uinfo->count = eld->eld_valid ? eld->eld_size : 0;
- mutex_unlock(&eld->lock);
+ mutex_unlock(&per_pin->lock);
return 0;
}
@@ -368,15 +417,17 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
struct hdmi_eld *eld;
int pin_idx;
pin_idx = kcontrol->private_value;
- eld = &get_pin(spec, pin_idx)->sink_eld;
+ per_pin = get_pin(spec, pin_idx);
+ eld = &per_pin->sink_eld;
- mutex_lock(&eld->lock);
+ mutex_lock(&per_pin->lock);
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
- mutex_unlock(&eld->lock);
+ mutex_unlock(&per_pin->lock);
snd_BUG();
return -EINVAL;
}
@@ -386,7 +437,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
if (eld->eld_valid)
memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
eld->eld_size);
- mutex_unlock(&eld->lock);
+ mutex_unlock(&per_pin->lock);
return 0;
}
@@ -452,15 +503,25 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
{
+ struct hdmi_spec *spec = codec->spec;
+ int pin_out;
+
/* Unmute */
if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- /* Enable pin out: some machines with GM965 gets broken output when
- * the pin is disabled or changed while using with HDMI
- */
+
+ if (spec->dyn_pin_out)
+ /* Disable pin out until stream is active */
+ pin_out = 0;
+ else
+ /* Enable pin out: some machines with GM965 gets broken output
+ * when the pin is disabled or changed while using with HDMI
+ */
+ pin_out = PIN_OUT;
+
snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
}
static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
@@ -477,6 +538,68 @@ static void hdmi_set_channel_count(struct hda_codec *codec,
AC_VERB_SET_CVT_CHAN_COUNT, chs - 1);
}
+/*
+ * ELD proc files
+ */
+
+#ifdef CONFIG_PROC_FS
+static void print_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_spec_per_pin *per_pin = entry->private_data;
+
+ mutex_lock(&per_pin->lock);
+ snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer);
+ mutex_unlock(&per_pin->lock);
+}
+
+static void write_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_spec_per_pin *per_pin = entry->private_data;
+
+ mutex_lock(&per_pin->lock);
+ snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
+ mutex_unlock(&per_pin->lock);
+}
+
+static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
+{
+ char name[32];
+ struct hda_codec *codec = per_pin->codec;
+ struct snd_info_entry *entry;
+ int err;
+
+ snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
+ err = snd_card_proc_new(codec->bus->card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, per_pin, print_eld_info);
+ entry->c.text.write = write_eld_info;
+ entry->mode |= S_IWUSR;
+ per_pin->proc_entry = entry;
+
+ return 0;
+}
+
+static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
+{
+ if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) {
+ snd_device_free(per_pin->codec->bus->card, per_pin->proc_entry);
+ per_pin->proc_entry = NULL;
+ }
+}
+#else
+static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
+ int index)
+{
+ return 0;
+}
+static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
+{
+}
+#endif
/*
* Channel mapping routines
@@ -577,74 +700,91 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid)
{
#ifdef CONFIG_SND_DEBUG_VERBOSE
+ struct hdmi_spec *spec = codec->spec;
int i;
- int slot;
+ int channel;
for (i = 0; i < 8; i++) {
- slot = snd_hda_codec_read(codec, pin_nid, 0,
- AC_VERB_GET_HDMI_CHAN_SLOT, i);
+ channel = spec->ops.pin_get_slot_channel(codec, pin_nid, i);
printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n",
- slot >> 4, slot & 0xf);
+ channel, i);
}
#endif
}
-
static void hdmi_std_setup_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid,
bool non_pcm,
int ca)
{
+ struct hdmi_spec *spec = codec->spec;
+ struct cea_channel_speaker_allocation *ch_alloc;
int i;
int err;
int order;
int non_pcm_mapping[8];
order = get_channel_allocation_order(ca);
+ ch_alloc = &channel_allocations[order];
if (hdmi_channel_mapping[ca][1] == 0) {
- for (i = 0; i < channel_allocations[order].channels; i++)
- hdmi_channel_mapping[ca][i] = i | (i << 4);
- for (; i < 8; i++)
- hdmi_channel_mapping[ca][i] = 0xf | (i << 4);
+ int hdmi_slot = 0;
+ /* fill actual channel mappings in ALSA channel (i) order */
+ for (i = 0; i < ch_alloc->channels; i++) {
+ while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8))
+ hdmi_slot++; /* skip zero slots */
+
+ hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++;
+ }
+ /* fill the rest of the slots with ALSA channel 0xf */
+ for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++)
+ if (!ch_alloc->speakers[7 - hdmi_slot])
+ hdmi_channel_mapping[ca][i++] = (0xf << 4) | hdmi_slot;
}
if (non_pcm) {
- for (i = 0; i < channel_allocations[order].channels; i++)
- non_pcm_mapping[i] = i | (i << 4);
+ for (i = 0; i < ch_alloc->channels; i++)
+ non_pcm_mapping[i] = (i << 4) | i;
for (; i < 8; i++)
- non_pcm_mapping[i] = 0xf | (i << 4);
+ non_pcm_mapping[i] = (0xf << 4) | i;
}
for (i = 0; i < 8; i++) {
- err = snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_HDMI_CHAN_SLOT,
- non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]);
+ int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i];
+ int hdmi_slot = slotsetup & 0x0f;
+ int channel = (slotsetup & 0xf0) >> 4;
+ err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, channel);
if (err) {
snd_printdd(KERN_NOTICE
"HDMI: channel mapping failed\n");
break;
}
}
-
- hdmi_debug_channel_mapping(codec, pin_nid);
}
struct channel_map_table {
unsigned char map; /* ALSA API channel map position */
- unsigned char cea_slot; /* CEA slot value */
int spk_mask; /* speaker position bit mask */
};
static struct channel_map_table map_tables[] = {
- { SNDRV_CHMAP_FL, 0x00, FL },
- { SNDRV_CHMAP_FR, 0x01, FR },
- { SNDRV_CHMAP_RL, 0x04, RL },
- { SNDRV_CHMAP_RR, 0x05, RR },
- { SNDRV_CHMAP_LFE, 0x02, LFE },
- { SNDRV_CHMAP_FC, 0x03, FC },
- { SNDRV_CHMAP_RLC, 0x06, RLC },
- { SNDRV_CHMAP_RRC, 0x07, RRC },
+ { SNDRV_CHMAP_FL, FL },
+ { SNDRV_CHMAP_FR, FR },
+ { SNDRV_CHMAP_RL, RL },
+ { SNDRV_CHMAP_RR, RR },
+ { SNDRV_CHMAP_LFE, LFE },
+ { SNDRV_CHMAP_FC, FC },
+ { SNDRV_CHMAP_RLC, RLC },
+ { SNDRV_CHMAP_RRC, RRC },
+ { SNDRV_CHMAP_RC, RC },
+ { SNDRV_CHMAP_FLC, FLC },
+ { SNDRV_CHMAP_FRC, FRC },
+ { SNDRV_CHMAP_TFL, FLH },
+ { SNDRV_CHMAP_TFR, FRH },
+ { SNDRV_CHMAP_FLW, FLW },
+ { SNDRV_CHMAP_FRW, FRW },
+ { SNDRV_CHMAP_TC, TC },
+ { SNDRV_CHMAP_TFC, FCH },
{} /* terminator */
};
@@ -660,25 +800,19 @@ static int to_spk_mask(unsigned char c)
}
/* from ALSA API channel position to CEA slot */
-static int to_cea_slot(unsigned char c)
+static int to_cea_slot(int ordered_ca, unsigned char pos)
{
- struct channel_map_table *t = map_tables;
- for (; t->map; t++) {
- if (t->map == c)
- return t->cea_slot;
- }
- return 0x0f;
-}
+ int mask = to_spk_mask(pos);
+ int i;
-/* from CEA slot to ALSA API channel position */
-static int from_cea_slot(unsigned char c)
-{
- struct channel_map_table *t = map_tables;
- for (; t->map; t++) {
- if (t->cea_slot == c)
- return t->map;
+ if (mask) {
+ for (i = 0; i < 8; i++) {
+ if (channel_allocations[ordered_ca].speakers[7 - i] == mask)
+ return i;
+ }
}
- return 0;
+
+ return -1;
}
/* from speaker bit mask to ALSA API channel position */
@@ -692,6 +826,14 @@ static int spk_to_chmap(int spk)
return 0;
}
+/* from CEA slot to ALSA API channel position */
+static int from_cea_slot(int ordered_ca, unsigned char slot)
+{
+ int mask = channel_allocations[ordered_ca].speakers[7 - slot];
+
+ return spk_to_chmap(mask);
+}
+
/* get the CA index corresponding to the given ALSA API channel map */
static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
{
@@ -718,18 +860,29 @@ static int hdmi_manual_channel_allocation(int chs, unsigned char *map)
/* set up the channel slots for the given ALSA API channel map */
static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
hda_nid_t pin_nid,
- int chs, unsigned char *map)
+ int chs, unsigned char *map,
+ int ca)
{
- int i;
- for (i = 0; i < 8; i++) {
- int val, err;
- if (i < chs)
- val = to_cea_slot(map[i]);
- else
- val = 0xf;
- val |= (i << 4);
- err = snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_HDMI_CHAN_SLOT, val);
+ struct hdmi_spec *spec = codec->spec;
+ int ordered_ca = get_channel_allocation_order(ca);
+ int alsa_pos, hdmi_slot;
+ int assignments[8] = {[0 ... 7] = 0xf};
+
+ for (alsa_pos = 0; alsa_pos < chs; alsa_pos++) {
+
+ hdmi_slot = to_cea_slot(ordered_ca, map[alsa_pos]);
+
+ if (hdmi_slot < 0)
+ continue; /* unassigned channel */
+
+ assignments[hdmi_slot] = alsa_pos;
+ }
+
+ for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) {
+ int err;
+
+ err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot,
+ assignments[hdmi_slot]);
if (err)
return -EINVAL;
}
@@ -740,9 +893,10 @@ static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec,
static void hdmi_setup_fake_chmap(unsigned char *map, int ca)
{
int i;
+ int ordered_ca = get_channel_allocation_order(ca);
for (i = 0; i < 8; i++) {
- if (i < channel_allocations[ca].channels)
- map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f);
+ if (i < channel_allocations[ordered_ca].channels)
+ map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f);
else
map[i] = 0;
}
@@ -755,11 +909,29 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec,
{
if (!non_pcm && chmap_set) {
hdmi_manual_setup_channel_mapping(codec, pin_nid,
- channels, map);
+ channels, map, ca);
} else {
hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca);
hdmi_setup_fake_chmap(map, ca);
}
+
+ hdmi_debug_channel_mapping(codec, pin_nid);
+}
+
+static int hdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid,
+ int asp_slot, int channel)
+{
+ return snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_HDMI_CHAN_SLOT,
+ (channel << 4) | asp_slot);
+}
+
+static int hdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid,
+ int asp_slot)
+{
+ return (snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_HDMI_CHAN_SLOT,
+ asp_slot) & 0xf0) >> 4;
}
/*
@@ -883,52 +1055,29 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
return true;
}
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
- struct hdmi_spec_per_pin *per_pin,
- bool non_pcm)
+static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
+ hda_nid_t pin_nid,
+ int ca, int active_channels,
+ int conn_type)
{
- hda_nid_t pin_nid = per_pin->pin_nid;
- int channels = per_pin->channels;
- struct hdmi_eld *eld;
- int ca;
union audio_infoframe ai;
- if (!channels)
- return;
-
- if (is_haswell(codec))
- snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
-
- eld = &per_pin->sink_eld;
- if (!eld->monitor_present)
- return;
-
- if (!non_pcm && per_pin->chmap_set)
- ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
- else
- ca = hdmi_channel_allocation(eld, channels);
- if (ca < 0)
- ca = 0;
-
- memset(&ai, 0, sizeof(ai));
- if (eld->info.conn_type == 0) { /* HDMI */
+ if (conn_type == 0) { /* HDMI */
struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
hdmi_ai->type = 0x84;
hdmi_ai->ver = 0x01;
hdmi_ai->len = 0x0a;
- hdmi_ai->CC02_CT47 = channels - 1;
+ hdmi_ai->CC02_CT47 = active_channels - 1;
hdmi_ai->CA = ca;
hdmi_checksum_audio_infoframe(hdmi_ai);
- } else if (eld->info.conn_type == 1) { /* DisplayPort */
+ } else if (conn_type == 1) { /* DisplayPort */
struct dp_audio_infoframe *dp_ai = &ai.dp;
dp_ai->type = 0x84;
dp_ai->len = 0x1b;
dp_ai->ver = 0x11 << 2;
- dp_ai->CC02_CT47 = channels - 1;
+ dp_ai->CC02_CT47 = active_channels - 1;
dp_ai->CA = ca;
} else {
snd_printd("HDMI: unknown connection type at pin %d\n",
@@ -943,62 +1092,100 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
*/
if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
sizeof(ai))) {
- snd_printdd("hdmi_setup_audio_infoframe: "
- "pin=%d channels=%d\n",
+ snd_printdd("hdmi_pin_setup_infoframe: "
+ "pin=%d channels=%d ca=0x%02x\n",
pin_nid,
- channels);
- hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
- channels, per_pin->chmap,
- per_pin->chmap_set);
+ active_channels, ca);
hdmi_stop_infoframe_trans(codec, pin_nid);
hdmi_fill_audio_infoframe(codec, pin_nid,
ai.bytes, sizeof(ai));
hdmi_start_infoframe_trans(codec, pin_nid);
- } else {
- /* For non-pcm audio switch, setup new channel mapping
- * accordingly */
- if (per_pin->non_pcm != non_pcm)
- hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
- channels, per_pin->chmap,
- per_pin->chmap_set);
}
+}
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+ struct hdmi_spec_per_pin *per_pin,
+ bool non_pcm)
+{
+ struct hdmi_spec *spec = codec->spec;
+ hda_nid_t pin_nid = per_pin->pin_nid;
+ int channels = per_pin->channels;
+ int active_channels;
+ struct hdmi_eld *eld;
+ int ca, ordered_ca;
+
+ if (!channels)
+ return;
+
+ if (is_haswell_plus(codec))
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+
+ eld = &per_pin->sink_eld;
+ if (!eld->monitor_present)
+ return;
+
+ if (!non_pcm && per_pin->chmap_set)
+ ca = hdmi_manual_channel_allocation(channels, per_pin->chmap);
+ else
+ ca = hdmi_channel_allocation(eld, channels);
+ if (ca < 0)
+ ca = 0;
+
+ ordered_ca = get_channel_allocation_order(ca);
+ active_channels = channel_allocations[ordered_ca].channels;
+
+ hdmi_set_channel_count(codec, per_pin->cvt_nid, active_channels);
+
+ /*
+ * always configure channel mapping, it may have been changed by the
+ * user in the meantime
+ */
+ hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca,
+ channels, per_pin->chmap,
+ per_pin->chmap_set);
+
+ spec->ops.pin_setup_infoframe(codec, pin_nid, ca, active_channels,
+ eld->info.conn_type);
per_pin->non_pcm = non_pcm;
}
-
/*
* Unsolicited events
*/
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
+static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
-static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack)
{
struct hdmi_spec *spec = codec->spec;
+ int pin_idx = pin_nid_to_pin_index(spec, jack->nid);
+ if (pin_idx < 0)
+ return;
+
+ if (hdmi_present_sense(get_pin(spec, pin_idx), 1))
+ snd_hda_jack_report_sync(codec);
+}
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
- int pin_nid;
- int pin_idx;
struct hda_jack_tbl *jack;
int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (!jack)
return;
- pin_nid = jack->nid;
jack->jack_dirty = 1;
_snd_printd(SND_PR_VERBOSE,
"HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
- codec->addr, pin_nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
+ codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
- pin_idx = pin_nid_to_pin_index(spec, pin_nid);
- if (pin_idx < 0)
- return;
-
- hdmi_present_sense(get_pin(spec, pin_idx), 1);
- snd_hda_jack_report_sync(codec);
+ jack_callback(codec, jack);
}
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -1069,26 +1256,25 @@ static void haswell_verify_D0(struct hda_codec *codec,
#define is_hbr_format(format) \
((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
- hda_nid_t pin_nid, u32 stream_tag, int format)
+static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+ bool hbr)
{
- int pinctl;
- int new_pinctl = 0;
-
- if (is_haswell(codec))
- haswell_verify_D0(codec, cvt_nid, pin_nid);
+ int pinctl, new_pinctl;
if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ if (pinctl < 0)
+ return hbr ? -EINVAL : 0;
+
new_pinctl = pinctl & ~AC_PINCTL_EPT;
- if (is_hbr_format(format))
+ if (hbr)
new_pinctl |= AC_PINCTL_EPT_HBR;
else
new_pinctl |= AC_PINCTL_EPT_NATIVE;
- snd_printdd("hdmi_setup_stream: "
+ snd_printdd("hdmi_pin_hbr_setup: "
"NID=0x%x, %spinctl=0x%x\n",
pin_nid,
pinctl == new_pinctl ? "" : "new-",
@@ -1098,11 +1284,26 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
snd_hda_codec_write(codec, pin_nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL,
new_pinctl);
+ } else if (hbr)
+ return -EINVAL;
- }
- if (is_hbr_format(format) && !new_pinctl) {
+ return 0;
+}
+
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, u32 stream_tag, int format)
+{
+ struct hdmi_spec *spec = codec->spec;
+ int err;
+
+ if (is_haswell_plus(codec))
+ haswell_verify_D0(codec, cvt_nid, pin_nid);
+
+ err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format));
+
+ if (err) {
snd_printdd("hdmi_setup_stream: HBR is not supported\n");
- return -EINVAL;
+ return err;
}
snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
@@ -1148,33 +1349,53 @@ static int hdmi_choose_cvt(struct hda_codec *codec,
return 0;
}
-static void haswell_config_cvts(struct hda_codec *codec,
- int pin_id, int mux_id)
+/* Intel HDMI workaround to fix audio routing issue:
+ * For some Intel display codecs, pins share the same connection list.
+ * So a conveter can be selected by multiple pins and playback on any of these
+ * pins will generate sound on the external display, because audio flows from
+ * the same converter to the display pipeline. Also muting one pin may make
+ * other pins have no sound output.
+ * So this function assures that an assigned converter for a pin is not selected
+ * by any other pins.
+ */
+static void intel_not_share_assigned_cvt(struct hda_codec *codec,
+ hda_nid_t pin_nid, int mux_idx)
{
struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_pin *per_pin;
- int pin_idx, mux_idx;
- int curr;
- int err;
+ hda_nid_t nid, end_nid;
+ int cvt_idx, curr;
+ struct hdmi_spec_per_cvt *per_cvt;
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
- per_pin = get_pin(spec, pin_idx);
+ /* configure all pins, including "no physical connection" ones */
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ unsigned int wid_caps = get_wcaps(codec, nid);
+ unsigned int wid_type = get_wcaps_type(wid_caps);
+
+ if (wid_type != AC_WID_PIN)
+ continue;
- if (pin_idx == pin_id)
+ if (nid == pin_nid)
continue;
- curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+ curr = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_SEL, 0);
+ if (curr != mux_idx)
+ continue;
- /* Choose another unused converter */
- if (curr == mux_id) {
- err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx);
- if (err < 0)
- return;
- snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx);
- snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ /* choose an unassigned converter. The conveters in the
+ * connection list are in the same order as in the codec.
+ */
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+ per_cvt = get_cvt(spec, cvt_idx);
+ if (!per_cvt->assigned) {
+ snd_printdd("choose cvt %d for pin nid %d\n",
+ cvt_idx, nid);
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
- mux_idx);
+ cvt_idx);
+ break;
+ }
}
}
}
@@ -1208,6 +1429,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
per_cvt = get_cvt(spec, cvt_idx);
/* Claim converter */
per_cvt->assigned = 1;
+ per_pin->cvt_nid = per_cvt->cvt_nid;
hinfo->nid = per_cvt->cvt_nid;
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
@@ -1215,8 +1437,8 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
mux_idx);
/* configure unused pins to choose other converters */
- if (is_haswell(codec))
- haswell_config_cvts(codec, pin_idx, mux_idx);
+ if (is_haswell_plus(codec) || is_valleyview(codec))
+ intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx);
snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
@@ -1274,8 +1496,9 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
return 0;
}
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
{
+ struct hda_jack_tbl *jack;
struct hda_codec *codec = per_pin->codec;
struct hdmi_spec *spec = codec->spec;
struct hdmi_eld *eld = &spec->temp_eld;
@@ -1289,10 +1512,15 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
* specification worked this way. Hence, we just ignore the data in
* the unsolicited response to avoid custom WARs.
*/
- int present = snd_hda_pin_sense(codec, pin_nid);
+ int present;
bool update_eld = false;
bool eld_changed = false;
+ bool ret;
+
+ snd_hda_power_up(codec);
+ present = snd_hda_pin_sense(codec, pin_nid);
+ mutex_lock(&per_pin->lock);
pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
if (pin_eld->monitor_present)
eld->eld_valid = !!(present & AC_PINSENSE_ELDV);
@@ -1304,7 +1532,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid);
if (eld->eld_valid) {
- if (snd_hdmi_get_eld(codec, pin_nid, eld->eld_buffer,
+ if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer,
&eld->eld_size) < 0)
eld->eld_valid = false;
else {
@@ -1322,11 +1550,10 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
queue_delayed_work(codec->bus->workq,
&per_pin->work,
msecs_to_jiffies(300));
- return;
+ goto unlock;
}
}
- mutex_lock(&pin_eld->lock);
if (pin_eld->eld_valid && !eld->eld_valid) {
update_eld = true;
eld_changed = true;
@@ -1343,20 +1570,30 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
pin_eld->eld_size = eld->eld_size;
pin_eld->info = eld->info;
- /* Haswell-specific workaround: re-setup when the transcoder is
- * changed during the stream playback
+ /*
+ * Re-setup pin and infoframe. This is needed e.g. when
+ * - sink is first plugged-in (infoframe is not set up if !monitor_present)
+ * - transcoder can change during stream playback on Haswell
*/
- if (is_haswell(codec) &&
- eld->eld_valid && !old_eld_valid && per_pin->setup)
+ if (eld->eld_valid && !old_eld_valid && per_pin->setup)
hdmi_setup_audio_infoframe(codec, per_pin,
per_pin->non_pcm);
}
- mutex_unlock(&pin_eld->lock);
if (eld_changed)
snd_ctl_notify(codec->bus->card,
SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO,
&per_pin->eld_ctl->id);
+ unlock:
+ ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid;
+
+ jack = snd_hda_jack_tbl_get(codec, pin_nid);
+ if (jack)
+ jack->block_report = !ret;
+
+ mutex_unlock(&per_pin->lock);
+ snd_hda_power_down(codec);
+ return ret;
}
static void hdmi_repoll_eld(struct work_struct *work)
@@ -1367,7 +1604,8 @@ static void hdmi_repoll_eld(struct work_struct *work)
if (per_pin->repoll_count++ > 6)
per_pin->repoll_count = 0;
- hdmi_present_sense(per_pin, per_pin->repoll_count);
+ if (hdmi_present_sense(per_pin, per_pin->repoll_count))
+ snd_hda_jack_report_sync(per_pin->codec);
}
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
@@ -1389,7 +1627,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
return 0;
- if (is_haswell(codec))
+ if (is_haswell_plus(codec))
intel_haswell_fixup_connect_list(codec, pin_nid);
pin_idx = spec->num_pins;
@@ -1476,21 +1714,6 @@ static int hdmi_parse_codec(struct hda_codec *codec)
}
}
-#ifdef CONFIG_PM
- /* We're seeing some problems with unsolicited hot plug events on
- * PantherPoint after S3, if this is not enabled */
- if (codec->vendor_id == 0x80862806)
- codec->bus->power_keep_link_on = 1;
- /*
- * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event
- * can be lost and presence sense verb will become inaccurate if the
- * HDA link is powered off at hot plug or hw initialization time.
- */
- else if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) &
- AC_PWRST_EPSS))
- codec->bus->power_keep_link_on = 1;
-#endif
-
return 0;
}
@@ -1525,16 +1748,25 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
hda_nid_t pin_nid = per_pin->pin_nid;
bool non_pcm;
+ int pinctl;
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
+ mutex_lock(&per_pin->lock);
per_pin->channels = substream->runtime->channels;
per_pin->setup = true;
- hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels);
-
hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+ mutex_unlock(&per_pin->lock);
- return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
+ if (spec->dyn_pin_out) {
+ pinctl = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl | PIN_OUT);
+ }
+
+ return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
}
static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
@@ -1553,6 +1785,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
int cvt_idx, pin_idx;
struct hdmi_spec_per_cvt *per_cvt;
struct hdmi_spec_per_pin *per_pin;
+ int pinctl;
if (hinfo->nid) {
cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
@@ -1569,12 +1802,23 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
return -EINVAL;
per_pin = get_pin(spec, pin_idx);
+ if (spec->dyn_pin_out) {
+ pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL,
+ pinctl & ~PIN_OUT);
+ }
+
snd_hda_spdif_ctls_unassign(codec, pin_idx);
+
+ mutex_lock(&per_pin->lock);
per_pin->chmap_set = false;
memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
per_pin->setup = false;
per_pin->channels = 0;
+ mutex_unlock(&per_pin->lock);
}
return 0;
@@ -1603,14 +1847,40 @@ static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol,
return 0;
}
+static int hdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap,
+ int channels)
+{
+ /* If the speaker allocation matches the channel count, it is OK.*/
+ if (cap->channels != channels)
+ return -1;
+
+ /* all channels are remappable freely */
+ return SNDRV_CTL_TLVT_CHMAP_VAR;
+}
+
+static void hdmi_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *cap,
+ unsigned int *chmap, int channels)
+{
+ int count = 0;
+ int c;
+
+ for (c = 7; c >= 0; c--) {
+ int spk = cap->speakers[c];
+ if (!spk)
+ continue;
+
+ chmap[count++] = spk_to_chmap(spk);
+ }
+
+ WARN_ON(count != channels);
+}
+
static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *tlv)
{
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
struct hda_codec *codec = info->private_data;
struct hdmi_spec *spec = codec->spec;
- const unsigned int valid_mask =
- FL | FR | RL | RR | LFE | FC | RLC | RRC;
unsigned int __user *dst;
int chs, count = 0;
@@ -1621,18 +1891,19 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
size -= 8;
dst = tlv + 2;
for (chs = 2; chs <= spec->channels_max; chs++) {
- int i, c;
+ int i;
struct cea_channel_speaker_allocation *cap;
cap = channel_allocations;
for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) {
int chs_bytes = chs * 4;
- if (cap->channels != chs)
- continue;
- if (cap->spk_mask & ~valid_mask)
+ int type = spec->ops.chmap_cea_alloc_validate_get_type(cap, chs);
+ unsigned int tlv_chmap[8];
+
+ if (type < 0)
continue;
if (size < 8)
return -ENOMEM;
- if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) ||
+ if (put_user(type, dst) ||
put_user(chs_bytes, dst + 1))
return -EFAULT;
dst += 2;
@@ -1642,14 +1913,10 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
return -ENOMEM;
size -= chs_bytes;
count += chs_bytes;
- for (c = 7; c >= 0; c--) {
- int spk = cap->speakers[c];
- if (!spk)
- continue;
- if (put_user(spk_to_chmap(spk), dst))
- return -EFAULT;
- dst++;
- }
+ spec->ops.cea_alloc_to_tlv_chmap(cap, tlv_chmap, chs);
+ if (copy_to_user(dst, tlv_chmap, chs_bytes))
+ return -EFAULT;
+ dst += chs;
}
}
if (put_user(count, tlv + 1))
@@ -1683,7 +1950,7 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
unsigned int ctl_idx;
struct snd_pcm_substream *substream;
unsigned char chmap[8];
- int i, ca, prepared = 0;
+ int i, err, ca, prepared = 0;
ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
substream = snd_pcm_chmap_substream(info, ctl_idx);
@@ -1707,10 +1974,17 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol,
ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap);
if (ca < 0)
return -EINVAL;
+ if (spec->ops.chmap_validate) {
+ err = spec->ops.chmap_validate(ca, ARRAY_SIZE(chmap), chmap);
+ if (err)
+ return err;
+ }
+ mutex_lock(&per_pin->lock);
per_pin->chmap_set = true;
memcpy(per_pin->chmap, chmap, sizeof(chmap));
if (prepared)
hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+ mutex_unlock(&per_pin->lock);
return 0;
}
@@ -1827,12 +2101,11 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec)
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- struct hdmi_eld *eld = &per_pin->sink_eld;
per_pin->codec = codec;
- mutex_init(&eld->lock);
+ mutex_init(&per_pin->lock);
INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
- snd_hda_eld_proc_new(codec, eld, pin_idx);
+ eld_proc_new(per_pin, pin_idx);
}
return 0;
}
@@ -1847,7 +2120,8 @@ static int generic_hdmi_init(struct hda_codec *codec)
hda_nid_t pin_nid = per_pin->pin_nid;
hdmi_init_pin(codec, pin_nid);
- snd_hda_jack_detect_enable(codec, pin_nid, pin_nid);
+ snd_hda_jack_detect_enable_callback(codec, pin_nid, pin_nid,
+ codec->jackpoll_interval > 0 ? jack_callback : NULL);
}
return 0;
}
@@ -1873,10 +2147,9 @@ static void generic_hdmi_free(struct hda_codec *codec)
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
- struct hdmi_eld *eld = &per_pin->sink_eld;
cancel_delayed_work(&per_pin->work);
- snd_hda_eld_proc_free(codec, eld);
+ eld_proc_free(per_pin);
}
flush_workqueue(codec->bus->workq);
@@ -1913,6 +2186,17 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
#endif
};
+static const struct hdmi_ops generic_standard_hdmi_ops = {
+ .pin_get_eld = snd_hdmi_get_eld,
+ .pin_get_slot_channel = hdmi_pin_get_slot_channel,
+ .pin_set_slot_channel = hdmi_pin_set_slot_channel,
+ .pin_setup_infoframe = hdmi_pin_setup_infoframe,
+ .pin_hbr_setup = hdmi_pin_hbr_setup,
+ .setup_stream = hdmi_setup_stream,
+ .chmap_cea_alloc_validate_get_type = hdmi_chmap_cea_alloc_validate_get_type,
+ .cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap,
+};
+
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
hda_nid_t nid)
@@ -1995,21 +2279,26 @@ static int patch_generic_hdmi(struct hda_codec *codec)
if (spec == NULL)
return -ENOMEM;
+ spec->ops = generic_standard_hdmi_ops;
codec->spec = spec;
hdmi_array_init(spec, 4);
- if (is_haswell(codec)) {
+ if (is_haswell_plus(codec)) {
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
}
+ if (is_haswell(codec) || is_valleyview(codec)) {
+ codec->depop_delay = 0;
+ }
+
if (hdmi_parse_codec(codec) < 0) {
codec->spec = NULL;
kfree(spec);
return -EINVAL;
}
codec->patch_ops = generic_hdmi_patch_ops;
- if (is_haswell(codec)) {
+ if (is_haswell_plus(codec)) {
codec->patch_ops.set_power_state = haswell_set_power_state;
codec->dp_mst = true;
}
@@ -2075,8 +2364,9 @@ static int simple_playback_build_controls(struct hda_codec *codec)
int err;
per_cvt = get_cvt(spec, 0);
- err = snd_hda_create_spdif_out_ctls(codec, per_cvt->cvt_nid,
- per_cvt->cvt_nid);
+ err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
+ per_cvt->cvt_nid,
+ HDA_PCM_TYPE_HDMI);
if (err < 0)
return err;
return simple_hdmi_build_jack(codec, 0);
@@ -2550,49 +2840,399 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
}
/*
- * ATI-specific implementations
- *
- * FIXME: we may omit the whole this and use the generic code once after
- * it's confirmed to work.
+ * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
+ * - 0x10de0015
+ * - 0x10de0040
*/
+static int nvhdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap,
+ int channels)
+{
+ if (cap->ca_index == 0x00 && channels == 2)
+ return SNDRV_CTL_TLVT_CHMAP_FIXED;
-#define ATIHDMI_CVT_NID 0x02 /* audio converter */
-#define ATIHDMI_PIN_NID 0x03 /* HDMI output pin */
+ return hdmi_chmap_cea_alloc_validate_get_type(cap, channels);
+}
+
+static int nvhdmi_chmap_validate(int ca, int chs, unsigned char *map)
+{
+ if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int patch_nvhdmi(struct hda_codec *codec)
+{
+ struct hdmi_spec *spec;
+ int err;
+
+ err = patch_generic_hdmi(codec);
+ if (err)
+ return err;
+
+ spec = codec->spec;
+ spec->dyn_pin_out = true;
+
+ spec->ops.chmap_cea_alloc_validate_get_type =
+ nvhdmi_chmap_cea_alloc_validate_get_type;
+ spec->ops.chmap_validate = nvhdmi_chmap_validate;
+
+ return 0;
+}
+
+/*
+ * ATI/AMD-specific implementations
+ */
+
+#define is_amdhdmi_rev3_or_later(codec) \
+ ((codec)->vendor_id == 0x1002aa01 && ((codec)->revision_id & 0xff00) >= 0x0300)
+#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
+
+/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
+#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771
+#define ATI_VERB_SET_DOWNMIX_INFO 0x772
+#define ATI_VERB_SET_MULTICHANNEL_01 0x777
+#define ATI_VERB_SET_MULTICHANNEL_23 0x778
+#define ATI_VERB_SET_MULTICHANNEL_45 0x779
+#define ATI_VERB_SET_MULTICHANNEL_67 0x77a
+#define ATI_VERB_SET_HBR_CONTROL 0x77c
+#define ATI_VERB_SET_MULTICHANNEL_1 0x785
+#define ATI_VERB_SET_MULTICHANNEL_3 0x786
+#define ATI_VERB_SET_MULTICHANNEL_5 0x787
+#define ATI_VERB_SET_MULTICHANNEL_7 0x788
+#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
+#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71
+#define ATI_VERB_GET_DOWNMIX_INFO 0xf72
+#define ATI_VERB_GET_MULTICHANNEL_01 0xf77
+#define ATI_VERB_GET_MULTICHANNEL_23 0xf78
+#define ATI_VERB_GET_MULTICHANNEL_45 0xf79
+#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a
+#define ATI_VERB_GET_HBR_CONTROL 0xf7c
+#define ATI_VERB_GET_MULTICHANNEL_1 0xf85
+#define ATI_VERB_GET_MULTICHANNEL_3 0xf86
+#define ATI_VERB_GET_MULTICHANNEL_5 0xf87
+#define ATI_VERB_GET_MULTICHANNEL_7 0xf88
+#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89
+
+/* AMD specific HDA cvt verbs */
+#define ATI_VERB_SET_RAMP_RATE 0x770
+#define ATI_VERB_GET_RAMP_RATE 0xf70
+
+#define ATI_OUT_ENABLE 0x1
-static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- unsigned int stream_tag,
- unsigned int format,
- struct snd_pcm_substream *substream)
+#define ATI_MULTICHANNEL_MODE_PAIRED 0
+#define ATI_MULTICHANNEL_MODE_SINGLE 1
+
+#define ATI_HBR_CAPABLE 0x01
+#define ATI_HBR_ENABLE 0x10
+
+static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+ unsigned char *buf, int *eld_size)
+{
+ /* call hda_eld.c ATI/AMD-specific function */
+ return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
+ is_amdhdmi_rev3_or_later(codec));
+}
+
+static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, int ca,
+ int active_channels, int conn_type)
+{
+ snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
+}
+
+static int atihdmi_paired_swap_fc_lfe(int pos)
+{
+ /*
+ * ATI/AMD have automatic FC/LFE swap built-in
+ * when in pairwise mapping mode.
+ */
+
+ switch (pos) {
+ /* see channel_allocations[].speakers[] */
+ case 2: return 3;
+ case 3: return 2;
+ default: break;
+ }
+
+ return pos;
+}
+
+static int atihdmi_paired_chmap_validate(int ca, int chs, unsigned char *map)
+{
+ struct cea_channel_speaker_allocation *cap;
+ int i, j;
+
+ /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
+
+ cap = &channel_allocations[get_channel_allocation_order(ca)];
+ for (i = 0; i < chs; ++i) {
+ int mask = to_spk_mask(map[i]);
+ bool ok = false;
+ bool companion_ok = false;
+
+ if (!mask)
+ continue;
+
+ for (j = 0 + i % 2; j < 8; j += 2) {
+ int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
+ if (cap->speakers[chan_idx] == mask) {
+ /* channel is in a supported position */
+ ok = true;
+
+ if (i % 2 == 0 && i + 1 < chs) {
+ /* even channel, check the odd companion */
+ int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
+ int comp_mask_req = to_spk_mask(map[i+1]);
+ int comp_mask_act = cap->speakers[comp_chan_idx];
+
+ if (comp_mask_req == comp_mask_act)
+ companion_ok = true;
+ else
+ return -EINVAL;
+ }
+ break;
+ }
+ }
+
+ if (!ok)
+ return -EINVAL;
+
+ if (companion_ok)
+ i++; /* companion channel already checked */
+ }
+
+ return 0;
+}
+
+static int atihdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid,
+ int hdmi_slot, int stream_channel)
+{
+ int verb;
+ int ati_channel_setup = 0;
+
+ if (hdmi_slot > 7)
+ return -EINVAL;
+
+ if (!has_amd_full_remap_support(codec)) {
+ hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
+
+ /* In case this is an odd slot but without stream channel, do not
+ * disable the slot since the corresponding even slot could have a
+ * channel. In case neither have a channel, the slot pair will be
+ * disabled when this function is called for the even slot. */
+ if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
+ return 0;
+
+ hdmi_slot -= hdmi_slot % 2;
+
+ if (stream_channel != 0xf)
+ stream_channel -= stream_channel % 2;
+ }
+
+ verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
+
+ /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
+
+ if (stream_channel != 0xf)
+ ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
+
+ return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
+}
+
+static int atihdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid,
+ int asp_slot)
+{
+ bool was_odd = false;
+ int ati_asp_slot = asp_slot;
+ int verb;
+ int ati_channel_setup;
+
+ if (asp_slot > 7)
+ return -EINVAL;
+
+ if (!has_amd_full_remap_support(codec)) {
+ ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
+ if (ati_asp_slot % 2 != 0) {
+ ati_asp_slot -= 1;
+ was_odd = true;
+ }
+ }
+
+ verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
+
+ ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
+
+ if (!(ati_channel_setup & ATI_OUT_ENABLE))
+ return 0xf;
+
+ return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
+}
+
+static int atihdmi_paired_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap,
+ int channels)
+{
+ int c;
+
+ /*
+ * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
+ * we need to take that into account (a single channel may take 2
+ * channel slots if we need to carry a silent channel next to it).
+ * On Rev3+ AMD codecs this function is not used.
+ */
+ int chanpairs = 0;
+
+ /* We only produce even-numbered channel count TLVs */
+ if ((channels % 2) != 0)
+ return -1;
+
+ for (c = 0; c < 7; c += 2) {
+ if (cap->speakers[c] || cap->speakers[c+1])
+ chanpairs++;
+ }
+
+ if (chanpairs * 2 != channels)
+ return -1;
+
+ return SNDRV_CTL_TLVT_CHMAP_PAIRED;
+}
+
+static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *cap,
+ unsigned int *chmap, int channels)
+{
+ /* produce paired maps for pre-rev3 ATI/AMD codecs */
+ int count = 0;
+ int c;
+
+ for (c = 7; c >= 0; c--) {
+ int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
+ int spk = cap->speakers[chan];
+ if (!spk) {
+ /* add N/A channel if the companion channel is occupied */
+ if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
+ chmap[count++] = SNDRV_CHMAP_NA;
+
+ continue;
+ }
+
+ chmap[count++] = spk_to_chmap(spk);
+ }
+
+ WARN_ON(count != channels);
+}
+
+static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+ bool hbr)
+{
+ int hbr_ctl, hbr_ctl_new;
+
+ hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
+ if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
+ if (hbr)
+ hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
+ else
+ hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
+
+ snd_printdd("atihdmi_pin_hbr_setup: "
+ "NID=0x%x, %shbr-ctl=0x%x\n",
+ pin_nid,
+ hbr_ctl == hbr_ctl_new ? "" : "new-",
+ hbr_ctl_new);
+
+ if (hbr_ctl != hbr_ctl_new)
+ snd_hda_codec_write(codec, pin_nid, 0,
+ ATI_VERB_SET_HBR_CONTROL,
+ hbr_ctl_new);
+
+ } else if (hbr)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+ hda_nid_t pin_nid, u32 stream_tag, int format)
+{
+
+ if (is_amdhdmi_rev3_or_later(codec)) {
+ int ramp_rate = 180; /* default as per AMD spec */
+ /* disable ramp-up/down for non-pcm as per AMD spec */
+ if (format & AC_FMT_TYPE_NON_PCM)
+ ramp_rate = 0;
+
+ snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
+ }
+
+ return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
+}
+
+
+static int atihdmi_init(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
- struct hdmi_spec_per_cvt *per_cvt = get_cvt(spec, 0);
- int chans = substream->runtime->channels;
- int i, err;
+ int pin_idx, err;
- err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format,
- substream);
- if (err < 0)
+ err = generic_hdmi_init(codec);
+
+ if (err)
return err;
- snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
- AC_VERB_SET_CVT_CHAN_COUNT, chans - 1);
- /* FIXME: XXX */
- for (i = 0; i < chans; i++) {
- snd_hda_codec_write(codec, per_cvt->cvt_nid, 0,
- AC_VERB_SET_HDMI_CHAN_SLOT,
- (i << 4) | i);
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+ /* make sure downmix information in infoframe is zero */
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
+
+ /* enable channel-wise remap mode if supported */
+ if (has_amd_full_remap_support(codec))
+ snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ ATI_VERB_SET_MULTICHANNEL_MODE,
+ ATI_MULTICHANNEL_MODE_SINGLE);
}
+
return 0;
}
static int patch_atihdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
- int err = patch_simple_hdmi(codec, ATIHDMI_CVT_NID, ATIHDMI_PIN_NID);
- if (err < 0)
+ struct hdmi_spec_per_cvt *per_cvt;
+ int err, cvt_idx;
+
+ err = patch_generic_hdmi(codec);
+
+ if (err)
return err;
+
+ codec->patch_ops.init = atihdmi_init;
+
spec = codec->spec;
- spec->pcm_playback.ops.prepare = atihdmi_playback_pcm_prepare;
+
+ spec->ops.pin_get_eld = atihdmi_pin_get_eld;
+ spec->ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
+ spec->ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
+ spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
+ spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
+ spec->ops.setup_stream = atihdmi_setup_stream;
+
+ if (!has_amd_full_remap_support(codec)) {
+ /* override to ATI/AMD-specific versions with pairwise mapping */
+ spec->ops.chmap_cea_alloc_validate_get_type =
+ atihdmi_paired_chmap_cea_alloc_validate_get_type;
+ spec->ops.cea_alloc_to_tlv_chmap = atihdmi_paired_cea_alloc_to_tlv_chmap;
+ spec->ops.chmap_validate = atihdmi_paired_chmap_validate;
+ }
+
+ /* ATI/AMD converters do not advertise all of their capabilities */
+ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+ per_cvt = get_cvt(spec, cvt_idx);
+ per_cvt->channels_max = max(per_cvt->channels_max, 8u);
+ per_cvt->rates |= SUPPORTED_RATES;
+ per_cvt->formats |= SUPPORTED_FORMATS;
+ per_cvt->maxbps = max(per_cvt->maxbps, 24u);
+ }
+
+ spec->channels_max = max(spec->channels_max, 8u);
+
return 0;
}
@@ -2606,13 +3246,22 @@ static int patch_via_hdmi(struct hda_codec *codec)
}
/*
+ * called from hda_codec.c for generic HDMI support
+ */
+int snd_hda_parse_hdmi_codec(struct hda_codec *codec)
+{
+ return patch_generic_hdmi(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hda_parse_hdmi_codec);
+
+/*
* patch entries
*/
static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi },
-{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi },
{ .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi },
@@ -2621,30 +3270,30 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
-{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi },
-{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi },
+{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi },
+{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi },
/* 17 is known to be absent */
-{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_generic_hdmi },
-{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_generic_hdmi },
+{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi },
+{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi },
@@ -2659,7 +3308,9 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862807, .name = "Haswell HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862808, .name = "Broadwell HDMI", .patch = patch_generic_hdmi },
{ .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi },
+{ .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi },
{ .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi },
{} /* terminator */
};
@@ -2713,7 +3364,9 @@ MODULE_ALIAS("snd-hda-codec-id:80862804");
MODULE_ALIAS("snd-hda-codec-id:80862805");
MODULE_ALIAS("snd-hda-codec-id:80862806");
MODULE_ALIAS("snd-hda-codec-id:80862807");
+MODULE_ALIAS("snd-hda-codec-id:80862808");
MODULE_ALIAS("snd-hda-codec-id:80862880");
+MODULE_ALIAS("snd-hda-codec-id:80862882");
MODULE_ALIAS("snd-hda-codec-id:808629fb");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bc07d369fac4..a9a83b85517a 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -118,7 +118,8 @@ struct alc_spec {
int init_amp;
int codec_variant; /* flag for other variants */
- bool has_alc5505_dsp;
+ unsigned int has_alc5505_dsp:1;
+ unsigned int no_depop_delay:1;
/* for PLL fix */
hda_nid_t pll_nid;
@@ -280,8 +281,11 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
*/
static void alc_eapd_shutup(struct hda_codec *codec)
{
+ struct alc_spec *spec = codec->spec;
+
alc_auto_setup_eapd(codec, false);
- msleep(200);
+ if (!spec->no_depop_delay)
+ msleep(200);
snd_hda_shutup_pins(codec);
}
@@ -365,6 +369,17 @@ static void alc_fixup_sku_ignore(struct hda_codec *codec,
}
}
+static void alc_fixup_no_depop_delay(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PROBE) {
+ spec->no_depop_delay = 1;
+ codec->depop_delay = 0;
+ }
+}
+
static int alc_auto_parse_customize_define(struct hda_codec *codec)
{
unsigned int ass, tmp, i;
@@ -454,9 +469,7 @@ static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
* 7 ~ 0 : Assembly ID
* port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
*/
-static int alc_subsystem_id(struct hda_codec *codec,
- hda_nid_t porta, hda_nid_t porte,
- hda_nid_t portd, hda_nid_t porti)
+static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
{
unsigned int ass, tmp, i;
unsigned nid;
@@ -546,16 +559,7 @@ do_sku:
spec->gen.autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
hda_nid_t nid;
tmp = (ass >> 11) & 0x3; /* HP to chassis */
- if (tmp == 0)
- nid = porta;
- else if (tmp == 1)
- nid = porte;
- else if (tmp == 2)
- nid = portd;
- else if (tmp == 3)
- nid = porti;
- else
- return 1;
+ nid = ports[tmp];
if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
spec->gen.autocfg.line_outs))
return 1;
@@ -568,7 +572,7 @@ do_sku:
* ports contains an array of 4 pin NIDs for port-A, E, D and I */
static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
{
- if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
+ if (!alc_subsystem_id(codec, ports)) {
struct alc_spec *spec = codec->spec;
snd_printd("realtek: "
"Enable default setup for auto mode as fallback\n");
@@ -579,26 +583,35 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
/*
* COEF access helper functions
*/
-static int alc_read_coef_idx(struct hda_codec *codec,
- unsigned int coef_idx)
+
+static int alc_read_coefex_idx(struct hda_codec *codec,
+ hda_nid_t nid,
+ unsigned int coef_idx)
{
unsigned int val;
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX,
coef_idx);
- val = snd_hda_codec_read(codec, 0x20, 0,
+ val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PROC_COEF, 0);
return val;
}
-static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
+#define alc_read_coef_idx(codec, coef_idx) \
+ alc_read_coefex_idx(codec, 0x20, coef_idx)
+
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+ unsigned int coef_idx,
unsigned int coef_val)
{
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX,
coef_idx);
- snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF,
coef_val);
}
+#define alc_write_coef_idx(codec, coef_idx, coef_val) \
+ alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
+
/* a special bypass for COEF 0; read the cached value at the second time */
static unsigned int alc_get_coef0(struct hda_codec *codec)
{
@@ -695,7 +708,8 @@ static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
}
static void alc_inv_dmic_hook(struct hda_codec *codec,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
alc_inv_dmic_sync(codec, false);
}
@@ -831,7 +845,11 @@ static inline void alc_shutup(struct hda_codec *codec)
snd_hda_shutup_pins(codec);
}
-#define alc_free snd_hda_gen_free
+static void alc_free(struct hda_codec *codec)
+{
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
+ snd_hda_gen_free(codec);
+}
#ifdef CONFIG_PM
static void alc_power_eapd(struct hda_codec *codec)
@@ -852,7 +870,10 @@ static int alc_suspend(struct hda_codec *codec)
#ifdef CONFIG_PM
static int alc_resume(struct hda_codec *codec)
{
- msleep(150); /* to avoid pop noise */
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->no_depop_delay)
+ msleep(150); /* to avoid pop noise */
codec->patch_ops.init(codec);
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
@@ -892,7 +913,7 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name)
}
/*
- * Rename codecs appropriately from COEF value
+ * Rename codecs appropriately from COEF value or subvendor id
*/
struct alc_codec_rename_table {
unsigned int vendor_id;
@@ -901,6 +922,13 @@ struct alc_codec_rename_table {
const char *name;
};
+struct alc_codec_rename_pci_table {
+ unsigned int codec_vendor_id;
+ unsigned short pci_subvendor;
+ unsigned short pci_subdevice;
+ const char *name;
+};
+
static struct alc_codec_rename_table rename_tbl[] = {
{ 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
{ 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
@@ -920,9 +948,20 @@ static struct alc_codec_rename_table rename_tbl[] = {
{ } /* terminator */
};
+static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
+ { 0x10ec0280, 0x1028, 0, "ALC3220" },
+ { 0x10ec0282, 0x1028, 0, "ALC3221" },
+ { 0x10ec0283, 0x1028, 0, "ALC3223" },
+ { 0x10ec0292, 0x1028, 0, "ALC3226" },
+ { 0x10ec0255, 0x1028, 0, "ALC3234" },
+ { 0x10ec0668, 0x1028, 0, "ALC3661" },
+ { } /* terminator */
+};
+
static int alc_codec_rename_from_preset(struct hda_codec *codec)
{
const struct alc_codec_rename_table *p;
+ const struct alc_codec_rename_pci_table *q;
for (p = rename_tbl; p->vendor_id; p++) {
if (p->vendor_id != codec->vendor_id)
@@ -930,6 +969,17 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
return alc_codec_rename(codec, p->name);
}
+
+ for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
+ if (q->codec_vendor_id != codec->vendor_id)
+ continue;
+ if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
+ continue;
+ if (!q->pci_subdevice ||
+ q->pci_subdevice == codec->bus->pci->subsystem_device)
+ return alc_codec_rename(codec, q->name);
+ }
+
return 0;
}
@@ -1043,6 +1093,7 @@ enum {
ALC880_FIXUP_UNIWILL,
ALC880_FIXUP_UNIWILL_DIG,
ALC880_FIXUP_Z71V,
+ ALC880_FIXUP_ASUS_W5A,
ALC880_FIXUP_3ST_BASE,
ALC880_FIXUP_3ST,
ALC880_FIXUP_3ST_DIG,
@@ -1213,6 +1264,26 @@ static const struct hda_fixup alc880_fixups[] = {
{ }
}
},
+ [ALC880_FIXUP_ASUS_W5A] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* set up the whole pins as BIOS is utterly broken */
+ { 0x14, 0x0121411f }, /* HP */
+ { 0x15, 0x411111f0 }, /* N/A */
+ { 0x16, 0x411111f0 }, /* N/A */
+ { 0x17, 0x411111f0 }, /* N/A */
+ { 0x18, 0x90a60160 }, /* mic */
+ { 0x19, 0x411111f0 }, /* N/A */
+ { 0x1a, 0x411111f0 }, /* N/A */
+ { 0x1b, 0x411111f0 }, /* N/A */
+ { 0x1c, 0x411111f0 }, /* N/A */
+ { 0x1d, 0x411111f0 }, /* N/A */
+ { 0x1e, 0xb743111e }, /* SPDIF out */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC880_FIXUP_GPIO1,
+ },
[ALC880_FIXUP_3ST_BASE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -1334,6 +1405,7 @@ static const struct hda_fixup alc880_fixups[] = {
static const struct snd_pci_quirk alc880_fixup_tbl[] = {
SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
+ SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
@@ -1479,6 +1551,7 @@ enum {
ALC260_FIXUP_KN1,
ALC260_FIXUP_FSC_S7020,
ALC260_FIXUP_FSC_S7020_JWSE,
+ ALC260_FIXUP_VAIO_PINS,
};
static void alc260_gpio1_automute(struct hda_codec *codec)
@@ -1619,6 +1692,24 @@ static const struct hda_fixup alc260_fixups[] = {
.chained = true,
.chain_id = ALC260_FIXUP_FSC_S7020,
},
+ [ALC260_FIXUP_VAIO_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ /* Pin configs are missing completely on some VAIOs */
+ { 0x0f, 0x01211020 },
+ { 0x10, 0x0001003f },
+ { 0x11, 0x411111f0 },
+ { 0x12, 0x01a15930 },
+ { 0x13, 0x411111f0 },
+ { 0x14, 0x411111f0 },
+ { 0x15, 0x411111f0 },
+ { 0x16, 0x411111f0 },
+ { 0x17, 0x411111f0 },
+ { 0x18, 0x411111f0 },
+ { 0x19, 0x411111f0 },
+ { }
+ }
+ },
};
static const struct snd_pci_quirk alc260_fixup_tbl[] = {
@@ -1627,6 +1718,8 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
+ SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
+ SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
@@ -1709,6 +1802,7 @@ enum {
ALC882_FIXUP_ACER_ASPIRE_7736,
ALC882_FIXUP_ASUS_W90V,
ALC889_FIXUP_CD,
+ ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
ALC889_FIXUP_VAIO_TT,
ALC888_FIXUP_EEE1601,
ALC882_FIXUP_EAPD,
@@ -1726,8 +1820,13 @@ enum {
ALC889_FIXUP_DAC_ROUTE,
ALC889_FIXUP_MBP_VREF,
ALC889_FIXUP_IMAC91_VREF,
+ ALC889_FIXUP_MBA11_VREF,
+ ALC889_FIXUP_MBA21_VREF,
+ ALC889_FIXUP_MP11_VREF,
ALC882_FIXUP_INV_DMIC,
ALC882_FIXUP_NO_PRIMARY_HP,
+ ALC887_FIXUP_ASUS_BASS,
+ ALC887_FIXUP_BASS_CHMAP,
};
static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1828,17 +1927,13 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
}
}
-/* Set VREF on speaker pins on imac91 */
-static void alc889_fixup_imac91_vref(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+static void alc889_fixup_mac_pins(struct hda_codec *codec,
+ const hda_nid_t *nids, int num_nids)
{
struct alc_spec *spec = codec->spec;
- static hda_nid_t nids[2] = { 0x18, 0x1a };
int i;
- if (action != HDA_FIXUP_ACT_INIT)
- return;
- for (i = 0; i < ARRAY_SIZE(nids); i++) {
+ for (i = 0; i < num_nids; i++) {
unsigned int val;
val = snd_hda_codec_get_pin_target(codec, nids[i]);
val |= AC_PINCTL_VREF_50;
@@ -1847,6 +1942,36 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
spec->gen.keep_vref_in_automute = 1;
}
+/* Set VREF on speaker pins on imac91 */
+static void alc889_fixup_imac91_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static hda_nid_t nids[2] = { 0x18, 0x1a };
+
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba11 */
+static void alc889_fixup_mba11_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static hda_nid_t nids[1] = { 0x18 };
+
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba21 */
+static void alc889_fixup_mba21_vref(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ static hda_nid_t nids[2] = { 0x18, 0x19 };
+
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
/* Don't take HP output as primary
* Strangely, the speaker output doesn't work on Vaio Z and some Vaio
* all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
@@ -1861,6 +1986,9 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
}
}
+static void alc_fixup_bass_chmap(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
+
static const struct hda_fixup alc882_fixups[] = {
[ALC882_FIXUP_ABIT_AW9D_MAX] = {
.type = HDA_FIXUP_PINS,
@@ -1904,6 +2032,15 @@ static const struct hda_fixup alc882_fixups[] = {
{ }
}
},
+ [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC889_FIXUP_CD,
+ },
[ALC889_FIXUP_VAIO_TT] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -2043,6 +2180,24 @@ static const struct hda_fixup alc882_fixups[] = {
.chained = true,
.chain_id = ALC882_FIXUP_GPIO1,
},
+ [ALC889_FIXUP_MBA11_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mba11_vref,
+ .chained = true,
+ .chain_id = ALC889_FIXUP_MBP_VREF,
+ },
+ [ALC889_FIXUP_MBA21_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mba21_vref,
+ .chained = true,
+ .chain_id = ALC889_FIXUP_MBP_VREF,
+ },
+ [ALC889_FIXUP_MP11_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mba11_vref,
+ .chained = true,
+ .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+ },
[ALC882_FIXUP_INV_DMIC] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic_0x12,
@@ -2051,6 +2206,19 @@ static const struct hda_fixup alc882_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc882_fixup_no_primary_hp,
},
+ [ALC887_FIXUP_ASUS_BASS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x16, 0x99130130}, /* bass speaker */
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC887_FIXUP_BASS_CHMAP,
+ },
+ [ALC887_FIXUP_BASS_CHMAP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_bass_chmap,
+ },
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2084,6 +2252,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
+ SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
@@ -2092,14 +2261,14 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
+ SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
- SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF),
- SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
+ SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
@@ -2115,7 +2284,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
- SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3", ALC889_FIXUP_CD),
+ SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -2218,6 +2387,7 @@ enum {
ALC262_FIXUP_BENQ,
ALC262_FIXUP_BENQ_T31,
ALC262_FIXUP_INV_DMIC,
+ ALC262_FIXUP_INTEL_BAYLEYBAY,
};
static const struct hda_fixup alc262_fixups[] = {
@@ -2282,6 +2452,10 @@ static const struct hda_fixup alc262_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic_0x12,
},
+ [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_no_depop_delay,
+ },
};
static const struct snd_pci_quirk alc262_fixup_tbl[] = {
@@ -2293,6 +2467,7 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
+ SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
{}
};
@@ -2388,6 +2563,7 @@ static const struct hda_verb alc268_beep_init_verbs[] = {
enum {
ALC268_FIXUP_INV_DMIC,
ALC268_FIXUP_HP_EAPD,
+ ALC268_FIXUP_SPDIF,
};
static const struct hda_fixup alc268_fixups[] = {
@@ -2402,6 +2578,13 @@ static const struct hda_fixup alc268_fixups[] = {
{}
}
},
+ [ALC268_FIXUP_SPDIF] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1e, 0x014b1180 }, /* enable SPDIF out */
+ {}
+ }
+ },
};
static const struct hda_model_fixup alc268_fixup_models[] = {
@@ -2411,6 +2594,7 @@ static const struct hda_model_fixup alc268_fixup_models[] = {
};
static const struct snd_pci_quirk alc268_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
/* below is codec SSID since multiple Toshiba laptops have the
* same PCI SSID 1179:ff00
@@ -2539,7 +2723,9 @@ enum {
ALC269_TYPE_ALC282,
ALC269_TYPE_ALC283,
ALC269_TYPE_ALC284,
+ ALC269_TYPE_ALC285,
ALC269_TYPE_ALC286,
+ ALC269_TYPE_ALC255,
};
/*
@@ -2558,6 +2744,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
case ALC269_TYPE_ALC269VC:
case ALC269_TYPE_ALC280:
case ALC269_TYPE_ALC284:
+ case ALC269_TYPE_ALC285:
ssids = alc269va_ssids;
break;
case ALC269_TYPE_ALC269VB:
@@ -2565,6 +2752,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
case ALC269_TYPE_ALC282:
case ALC269_TYPE_ALC283:
case ALC269_TYPE_ALC286:
+ case ALC269_TYPE_ALC255:
ssids = alc269_ssids;
break;
default:
@@ -2652,7 +2840,7 @@ static void alc283_shutup(struct hda_codec *codec)
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
if (hp_pin_sense)
- msleep(85);
+ msleep(100);
snd_hda_codec_write(codec, hp_pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
@@ -2661,7 +2849,7 @@ static void alc283_shutup(struct hda_codec *codec)
alc_write_coef_idx(codec, 0x46, val | (3 << 12));
if (hp_pin_sense)
- msleep(85);
+ msleep(100);
snd_hda_shutup_pins(codec);
alc_write_coef_idx(codec, 0x43, 0x9614);
}
@@ -2819,6 +3007,15 @@ static void alc269_fixup_hweq(struct hda_codec *codec,
alc_write_coef_idx(codec, 0x1e, coef | 0x80);
}
+static void alc269_fixup_headset_mic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+}
+
static void alc271_fixup_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -2935,6 +3132,23 @@ static void alc269_fixup_mic_mute_hook(void *private_data, int enabled)
snd_hda_set_pin_ctl_cache(codec, spec->mute_led_nid, pinval);
}
+/* Make sure the led works even in runtime suspend */
+static unsigned int led_power_filter(struct hda_codec *codec,
+ hda_nid_t nid,
+ unsigned int power_state)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (power_state != AC_PWRST_D3 || nid != spec->mute_led_nid)
+ return power_state;
+
+ /* Set pin ctl again, it might have just been set to 0 */
+ snd_hda_set_pin_ctl(codec, nid,
+ snd_hda_codec_get_pin_target(codec, nid));
+
+ return AC_PWRST_D0;
+}
+
static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -2954,6 +3168,7 @@ static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
spec->mute_led_nid = pin - 0x0a + 0x18;
spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
spec->gen.vmaster_mute_enum = 1;
+ codec->power_filter = led_power_filter;
snd_printd("Detected mute LED for %x:%d\n", spec->mute_led_nid,
spec->mute_led_polarity);
break;
@@ -2969,6 +3184,7 @@ static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec,
spec->mute_led_nid = 0x18;
spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
spec->gen.vmaster_mute_enum = 1;
+ codec->power_filter = led_power_filter;
}
}
@@ -2981,6 +3197,7 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
spec->mute_led_nid = 0x19;
spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
spec->gen.vmaster_mute_enum = 1;
+ codec->power_filter = led_power_filter;
}
}
@@ -3002,7 +3219,8 @@ static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
/* turn on/off mic-mute LED per capture hook */
static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct alc_spec *spec = codec->spec;
unsigned int oldval = spec->gpio_led;
@@ -3043,6 +3261,19 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
int val;
switch (codec->vendor_id) {
+ case 0x10ec0255:
+ /* LDO and MISC control */
+ alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+ /* UAJ function set to menual mode */
+ alc_write_coef_idx(codec, 0x45, 0xd089);
+ /* Direct Drive HP Amp control(Set to verb control)*/
+ val = alc_read_coefex_idx(codec, 0x57, 0x05);
+ alc_write_coefex_idx(codec, 0x57, 0x05, val & ~(1<<14));
+ /* Set MIC2 Vref gate with HP */
+ alc_write_coef_idx(codec, 0x06, 0x6104);
+ /* Direct Drive HP Amp control */
+ alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6);
+ break;
case 0x10ec0283:
alc_write_coef_idx(codec, 0x1b, 0x0c0b);
alc_write_coef_idx(codec, 0x45, 0xc429);
@@ -3074,6 +3305,14 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
int val;
switch (codec->vendor_id) {
+ case 0x10ec0255:
+ alc_write_coef_idx(codec, 0x45, 0xc489);
+ snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+ alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6);
+ /* Set MIC2 Vref gate to normal */
+ alc_write_coef_idx(codec, 0x06, 0x6100);
+ snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+ break;
case 0x10ec0283:
alc_write_coef_idx(codec, 0x45, 0xc429);
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
@@ -3105,6 +3344,12 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
static void alc_headset_mode_default(struct hda_codec *codec)
{
switch (codec->vendor_id) {
+ case 0x10ec0255:
+ alc_write_coef_idx(codec, 0x45, 0xc089);
+ alc_write_coef_idx(codec, 0x45, 0xc489);
+ alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+ alc_write_coef_idx(codec, 0x49, 0x0049);
+ break;
case 0x10ec0283:
alc_write_coef_idx(codec, 0x06, 0x2100);
alc_write_coef_idx(codec, 0x32, 0x4ea3);
@@ -3128,6 +3373,12 @@ static void alc_headset_mode_default(struct hda_codec *codec)
static void alc_headset_mode_ctia(struct hda_codec *codec)
{
switch (codec->vendor_id) {
+ case 0x10ec0255:
+ /* Set to CTIA type */
+ alc_write_coef_idx(codec, 0x45, 0xd489);
+ alc_write_coef_idx(codec, 0x1b, 0x0c2b);
+ alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+ break;
case 0x10ec0283:
alc_write_coef_idx(codec, 0x45, 0xd429);
alc_write_coef_idx(codec, 0x1b, 0x0c2b);
@@ -3139,6 +3390,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
alc_write_coef_idx(codec, 0x18, 0x7388);
break;
case 0x10ec0668:
+ alc_write_coef_idx(codec, 0x11, 0x0001);
alc_write_coef_idx(codec, 0x15, 0x0d60);
alc_write_coef_idx(codec, 0xc3, 0x0000);
break;
@@ -3150,6 +3402,12 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
static void alc_headset_mode_omtp(struct hda_codec *codec)
{
switch (codec->vendor_id) {
+ case 0x10ec0255:
+ /* Set to OMTP Type */
+ alc_write_coef_idx(codec, 0x45, 0xe489);
+ alc_write_coef_idx(codec, 0x1b, 0x0c2b);
+ alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6);
+ break;
case 0x10ec0283:
alc_write_coef_idx(codec, 0x45, 0xe429);
alc_write_coef_idx(codec, 0x1b, 0x0c2b);
@@ -3161,6 +3419,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
alc_write_coef_idx(codec, 0x18, 0x7388);
break;
case 0x10ec0668:
+ alc_write_coef_idx(codec, 0x11, 0x0001);
alc_write_coef_idx(codec, 0x15, 0x0d50);
alc_write_coef_idx(codec, 0xc3, 0x0000);
break;
@@ -3175,6 +3434,15 @@ static void alc_determine_headset_type(struct hda_codec *codec)
struct alc_spec *spec = codec->spec;
switch (codec->vendor_id) {
+ case 0x10ec0255:
+ /* combo jack auto switch control(Check type)*/
+ alc_write_coef_idx(codec, 0x45, 0xd089);
+ /* combo jack auto switch control(Vref conteol) */
+ alc_write_coef_idx(codec, 0x49, 0x0149);
+ msleep(300);
+ val = alc_read_coef_idx(codec, 0x46);
+ is_ctia = (val & 0x0070) == 0x0070;
+ break;
case 0x10ec0283:
alc_write_coef_idx(codec, 0x45, 0xd029);
msleep(300);
@@ -3221,8 +3489,10 @@ static void alc_update_headset_mode(struct hda_codec *codec)
else
new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
- if (new_headset_mode == spec->current_headset_mode)
+ if (new_headset_mode == spec->current_headset_mode) {
+ snd_hda_gen_update_outputs(codec);
return;
+ }
switch (new_headset_mode) {
case ALC_HEADSET_MODE_UNPLUGGED:
@@ -3260,7 +3530,8 @@ static void alc_update_headset_mode(struct hda_codec *codec)
}
static void alc_update_headset_mode_hook(struct hda_codec *codec,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
alc_update_headset_mode(codec);
}
@@ -3268,7 +3539,7 @@ static void alc_update_headset_mode_hook(struct hda_codec *codec,
static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack)
{
struct alc_spec *spec = codec->spec;
- spec->current_headset_type = ALC_HEADSET_MODE_UNKNOWN;
+ spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
snd_hda_gen_hp_automute(codec, jack);
}
@@ -3321,6 +3592,30 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
alc_fixup_headset_mode(codec, fix, action);
}
+static void alc_fixup_headset_mode_alc255(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ /* Set to iphone type */
+ alc_write_coef_idx(codec, 0x1b, 0x880b);
+ alc_write_coef_idx(codec, 0x45, 0xd089);
+ alc_write_coef_idx(codec, 0x1b, 0x080b);
+ alc_write_coef_idx(codec, 0x46, 0x0004);
+ alc_write_coef_idx(codec, 0x1b, 0x0c0b);
+ msleep(30);
+ }
+ alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct alc_spec *spec = codec->spec;
+ spec->gen.auto_mute_via_amp = 1;
+ }
+}
+
static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3420,12 +3715,27 @@ static void alc283_hp_automute_hook(struct hda_codec *codec,
vref);
}
-static void alc283_chromebook_caps(struct hda_codec *codec)
+static void alc283_fixup_chromebook(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
{
- snd_hda_override_wcaps(codec, 0x03, 0);
+ struct alc_spec *spec = codec->spec;
+ int val;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_override_wcaps(codec, 0x03, 0);
+ /* Disable AA-loopback as it causes white noise */
+ spec->gen.mixer_nid = 0;
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /* Enable Line1 input control by verb */
+ val = alc_read_coef_idx(codec, 0x1a);
+ alc_write_coef_idx(codec, 0x1a, val | (1 << 4));
+ break;
+ }
}
-static void alc283_fixup_chromebook(struct hda_codec *codec,
+static void alc283_fixup_sense_combo_jack(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
@@ -3433,8 +3743,9 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
- alc283_chromebook_caps(codec);
spec->gen.hp_automute_hook = alc283_hp_automute_hook;
+ break;
+ case HDA_FIXUP_ACT_INIT:
/* MIC2-VREF control */
/* Set to manual mode */
val = alc_read_coef_idx(codec, 0x06);
@@ -3493,6 +3804,22 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
}
}
+static void alc290_fixup_mono_speakers(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ /* DAC node 0x03 is giving mono output. We therefore want to
+ make sure 0x14 (front speaker) and 0x15 (headphones) use the
+ stereo DAC, while leaving 0x17 (bass speaker) for node 0x03. */
+ hda_nid_t conn1[2] = { 0x0c };
+ snd_hda_override_conn_list(codec, 0x14, 1, conn1);
+ snd_hda_override_conn_list(codec, 0x15, 1, conn1);
+ }
+}
+
+/* for hda_fixup_thinkpad_acpi() */
+#include "thinkpad_helper.c"
+
enum {
ALC269_FIXUP_SONY_VAIO,
ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -3504,6 +3831,7 @@ enum {
ALC271_FIXUP_DMIC,
ALC269_FIXUP_PCM_44K,
ALC269_FIXUP_STEREO_DMIC,
+ ALC269_FIXUP_HEADSET_MIC,
ALC269_FIXUP_QUANTA_MUTE,
ALC269_FIXUP_LIFEBOOK,
ALC269_FIXUP_AMIC,
@@ -3516,9 +3844,11 @@ enum {
ALC269_FIXUP_HP_GPIO_LED,
ALC269_FIXUP_INV_DMIC,
ALC269_FIXUP_LENOVO_DOCK,
+ ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+ ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
ALC269_FIXUP_HEADSET_MODE,
ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
ALC269_FIXUP_ASUS_X101_FUNC,
@@ -3526,11 +3856,24 @@ enum {
ALC269_FIXUP_ASUS_X101,
ALC271_FIXUP_AMIC_MIC2,
ALC271_FIXUP_HP_GATE_MIC_JACK,
+ ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572,
ALC269_FIXUP_ACER_AC700,
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+ ALC269VB_FIXUP_ASUS_ZENBOOK,
+ ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
+ ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED,
ALC269VB_FIXUP_ORDISSIMO_EVE2,
ALC283_FIXUP_CHROME_BOOK,
+ ALC283_FIXUP_SENSE_COMBO_JACK,
ALC282_FIXUP_ASUS_TX300,
+ ALC283_FIXUP_INT_MIC,
+ ALC290_FIXUP_MONO_SPEAKERS,
+ ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
+ ALC290_FIXUP_SUBWOOFER,
+ ALC290_FIXUP_SUBWOOFER_HSJACK,
+ ALC269_FIXUP_THINKPAD_ACPI,
+ ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC255_FIXUP_HEADSET_MODE,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -3599,6 +3942,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_stereo_dmic,
},
+ [ALC269_FIXUP_HEADSET_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_headset_mic,
+ },
[ALC269_FIXUP_QUANTA_MUTE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_quanta_mute,
@@ -3686,6 +4033,8 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_pincfg_no_hp_to_lineout,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
},
[ALC269_FIXUP_DELL1_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
@@ -3708,6 +4057,15 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
},
+ [ALC269_FIXUP_DELL3_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+ },
[ALC269_FIXUP_HEADSET_MODE] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode,
@@ -3716,6 +4074,15 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_no_hp_mic,
},
+ [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HEADSET_MIC
+ },
[ALC269_FIXUP_ASUS_X101_FUNC] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_x101_headset_mic,
@@ -3756,6 +4123,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC271_FIXUP_AMIC_MIC2,
},
+ [ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC271_FIXUP_HP_GATE_MIC_JACK,
+ },
[ALC269_FIXUP_ACER_AC700] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -3772,6 +4145,31 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+ },
+ [ALC269VB_FIXUP_ASUS_ZENBOOK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC269VB_FIXUP_DMIC,
+ },
+ [ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* class-D output amp +5dB */
+ { 0x20, AC_VERB_SET_COEF_INDEX, 0x12 },
+ { 0x20, AC_VERB_SET_PROC_COEF, 0x2800 },
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK,
+ },
+ [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC1,
},
[ALC269VB_FIXUP_ORDISSIMO_EVE2] = {
.type = HDA_FIXUP_PINS,
@@ -3786,10 +4184,72 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc283_fixup_chromebook,
},
+ [ALC283_FIXUP_SENSE_COMBO_JACK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc283_fixup_sense_combo_jack,
+ .chained = true,
+ .chain_id = ALC283_FIXUP_CHROME_BOOK,
+ },
[ALC282_FIXUP_ASUS_TX300] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc282_fixup_asus_tx300,
},
+ [ALC283_FIXUP_INT_MIC] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x1a},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x0011},
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+ },
+ [ALC290_FIXUP_SUBWOOFER_HSJACK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170112 }, /* subwoofer */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
+ },
+ [ALC290_FIXUP_SUBWOOFER] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x17, 0x90170112 }, /* subwoofer */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC290_FIXUP_MONO_SPEAKERS,
+ },
+ [ALC290_FIXUP_MONO_SPEAKERS] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc290_fixup_mono_speakers,
+ },
+ [ALC290_FIXUP_MONO_SPEAKERS_HSJACK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc290_fixup_mono_speakers,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+ },
+ [ALC269_FIXUP_THINKPAD_ACPI] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = hda_fixup_thinkpad_acpi,
+ },
+ [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+ { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_HEADSET_MODE
+ },
+ [ALC255_FIXUP_HEADSET_MODE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_mode_alc255,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3799,6 +4259,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
@@ -3812,6 +4273,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -3830,20 +4292,37 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x060f, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0610, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
+ SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
+ SND_PCI_QUIRK(0x1028, 0x061f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0629, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
+ SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
- SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
- SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
- SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
+ SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
@@ -3853,6 +4332,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
+ SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -3874,11 +4355,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
- SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI),
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
#if 0
@@ -3938,10 +4420,13 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
{.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
{.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"},
{.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
{.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
{.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
{.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
+ {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-chrome"},
+ {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
{}
};
@@ -4058,13 +4543,20 @@ static int patch_alc269(struct hda_codec *codec)
case 0x10ec0292:
spec->codec_variant = ALC269_TYPE_ALC284;
break;
+ case 0x10ec0285:
+ case 0x10ec0293:
+ spec->codec_variant = ALC269_TYPE_ALC285;
+ break;
case 0x10ec0286:
spec->codec_variant = ALC269_TYPE_ALC286;
break;
+ case 0x10ec0255:
+ spec->codec_variant = ALC269_TYPE_ALC255;
+ break;
}
if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
- spec->has_alc5505_dsp = true;
+ spec->has_alc5505_dsp = 1;
spec->init_hook = alc5505_dsp_init;
}
@@ -4110,6 +4602,7 @@ enum {
ALC861_FIXUP_AMP_VREF_0F,
ALC861_FIXUP_NO_JACK_DETECT,
ALC861_FIXUP_ASUS_A6RP,
+ ALC660_FIXUP_ASUS_W7J,
};
/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
@@ -4159,10 +4652,22 @@ static const struct hda_fixup alc861_fixups[] = {
.v.func = alc861_fixup_asus_amp_vref_0f,
.chained = true,
.chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+ },
+ [ALC660_FIXUP_ASUS_W7J] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* ASUS W7J needs a magic pin setup on unused NID 0x10
+ * for enabling outputs
+ */
+ {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ { }
+ },
}
};
static const struct snd_pci_quirk alc861_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
+ SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
@@ -4348,6 +4853,25 @@ static void alc272_fixup_mario(struct hda_codec *codec,
"hda_codec: failed to override amp caps for NID 0x2\n");
}
+static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
+ { }
+};
+
+/* override the 2.1 chmap */
+static void alc_fixup_bass_chmap(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_BUILD) {
+ struct alc_spec *spec = codec->spec;
+ spec->gen.pcm_rec[0].stream[0].chmap = asus_pcm_2_1_chmaps;
+ }
+}
+
enum {
ALC662_FIXUP_ASPIRE,
ALC662_FIXUP_IDEAPAD,
@@ -4368,6 +4892,10 @@ enum {
ALC662_FIXUP_INV_DMIC,
ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
ALC668_FIXUP_HEADSET_MODE,
+ ALC662_FIXUP_BASS_CHMAP,
+ ALC662_FIXUP_BASS_1A,
+ ALC662_FIXUP_BASS_1A_CHMAP,
+ ALC668_FIXUP_AUTO_MUTE,
};
static const struct hda_fixup alc662_fixups[] = {
@@ -4528,6 +5056,12 @@ static const struct hda_fixup alc662_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic_0x12,
},
+ [ALC668_FIXUP_AUTO_MUTE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_auto_mute_via_amp,
+ .chained = true,
+ .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+ },
[ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -4542,6 +5076,25 @@ static const struct hda_fixup alc662_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_headset_mode_alc668,
},
+ [ALC662_FIXUP_BASS_CHMAP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_bass_chmap,
+ .chained = true,
+ .chain_id = ALC662_FIXUP_ASUS_MODE4
+ },
+ [ALC662_FIXUP_BASS_1A] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ {0x1a, 0x80106111}, /* bass speaker */
+ {}
+ },
+ },
+ [ALC662_FIXUP_BASS_1A_CHMAP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_bass_chmap,
+ .chained = true,
+ .chain_id = ALC662_FIXUP_BASS_1A,
+ },
};
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -4554,7 +5107,17 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_AUTO_MUTE),
+ SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_AUTO_MUTE),
+ SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE),
+ SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+ SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP),
+ SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP),
+ SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_CHMAP),
SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
@@ -4715,6 +5278,7 @@ static int patch_alc662(struct hda_codec *codec)
case 0x10ec0272:
case 0x10ec0663:
case 0x10ec0665:
+ case 0x10ec0668:
set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
break;
case 0x10ec0273:
@@ -4772,7 +5336,9 @@ static int patch_alc680(struct hda_codec *codec)
*/
static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
+ { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 },
{ .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 },
+ { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 },
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
@@ -4786,9 +5352,11 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
{ .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
{ .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 },
+ { .id = 0x10ec0285, .name = "ALC285", .patch = patch_alc269 },
{ .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 },
{ .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
{ .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
+ { .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 },
{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
.patch = patch_alc861 },
{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index fba0cef1c47f..7311badf6a94 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -100,6 +100,7 @@ enum {
STAC_92HD83XXX_HEADSET_JACK,
STAC_92HD83XXX_HP,
STAC_HP_ENVY_BASS,
+ STAC_HP_BNB13_EQ,
STAC_92HD83XXX_MODELS
};
@@ -193,7 +194,7 @@ struct sigmatel_spec {
int default_polarity;
unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
- bool mic_mute_led_on; /* current mic mute state */
+ unsigned int mic_enabled; /* current mic mute state (bitmask) */
/* stream */
unsigned int stream_delay;
@@ -323,19 +324,26 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
/* hook for controlling mic-mute LED GPIO */
static void stac_capture_led_hook(struct hda_codec *codec,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct sigmatel_spec *spec = codec->spec;
- bool mute;
+ unsigned int mask;
+ bool cur_mute, prev_mute;
- if (!ucontrol)
+ if (!kcontrol || !ucontrol)
return;
- mute = !(ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
- if (spec->mic_mute_led_on != mute) {
- spec->mic_mute_led_on = mute;
- if (mute)
+ mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ prev_mute = !spec->mic_enabled;
+ if (ucontrol->value.integer.value[0] ||
+ ucontrol->value.integer.value[1])
+ spec->mic_enabled |= mask;
+ else
+ spec->mic_enabled &= ~mask;
+ cur_mute = !spec->mic_enabled;
+ if (cur_mute != prev_mute) {
+ if (cur_mute)
spec->gpio_data |= spec->mic_mute_led_gpio;
else
spec->gpio_data &= ~spec->mic_mute_led_gpio;
@@ -367,6 +375,17 @@ static int stac_vrefout_set(struct hda_codec *codec,
return 1;
}
+/* prevent codec AFG to D3 state when vref-out pin is used for mute LED */
+/* this hook is set in stac_setup_gpio() */
+static unsigned int stac_vref_led_power_filter(struct hda_codec *codec,
+ hda_nid_t nid,
+ unsigned int power_state)
+{
+ if (nid == codec->afg && power_state == AC_PWRST_D3)
+ return AC_PWRST_D1;
+ return snd_hda_gen_path_power_filter(codec, nid, power_state);
+}
+
/* update mute-LED accoring to the master switch */
static void stac_update_led_status(struct hda_codec *codec, int enabled)
{
@@ -2091,8 +2110,11 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
{
struct sigmatel_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+ /* resetting controller clears GPIO, so we need to keep on */
+ codec->bus->power_keep_link_on = 1;
+ }
}
static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
@@ -2104,6 +2126,434 @@ static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
spec->headset_jack = 1;
}
+static const struct hda_verb hp_bnb13_eq_verbs[] = {
+ /* 44.1KHz base */
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0x68 },
+ { 0x22, 0x7A8, 0x17 },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0x68 },
+ { 0x22, 0x7AB, 0x17 },
+ { 0x22, 0x7AC, 0x00 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x83 },
+ { 0x22, 0x7A7, 0x2F },
+ { 0x22, 0x7A8, 0xD1 },
+ { 0x22, 0x7A9, 0x83 },
+ { 0x22, 0x7AA, 0x2F },
+ { 0x22, 0x7AB, 0xD1 },
+ { 0x22, 0x7AC, 0x01 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0x68 },
+ { 0x22, 0x7A8, 0x17 },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0x68 },
+ { 0x22, 0x7AB, 0x17 },
+ { 0x22, 0x7AC, 0x02 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x7C },
+ { 0x22, 0x7A7, 0xC6 },
+ { 0x22, 0x7A8, 0x0C },
+ { 0x22, 0x7A9, 0x7C },
+ { 0x22, 0x7AA, 0xC6 },
+ { 0x22, 0x7AB, 0x0C },
+ { 0x22, 0x7AC, 0x03 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xC3 },
+ { 0x22, 0x7A7, 0x25 },
+ { 0x22, 0x7A8, 0xAF },
+ { 0x22, 0x7A9, 0xC3 },
+ { 0x22, 0x7AA, 0x25 },
+ { 0x22, 0x7AB, 0xAF },
+ { 0x22, 0x7AC, 0x04 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0x85 },
+ { 0x22, 0x7A8, 0x73 },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0x85 },
+ { 0x22, 0x7AB, 0x73 },
+ { 0x22, 0x7AC, 0x05 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x85 },
+ { 0x22, 0x7A7, 0x39 },
+ { 0x22, 0x7A8, 0xC7 },
+ { 0x22, 0x7A9, 0x85 },
+ { 0x22, 0x7AA, 0x39 },
+ { 0x22, 0x7AB, 0xC7 },
+ { 0x22, 0x7AC, 0x06 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3C },
+ { 0x22, 0x7A7, 0x90 },
+ { 0x22, 0x7A8, 0xB0 },
+ { 0x22, 0x7A9, 0x3C },
+ { 0x22, 0x7AA, 0x90 },
+ { 0x22, 0x7AB, 0xB0 },
+ { 0x22, 0x7AC, 0x07 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x7A },
+ { 0x22, 0x7A7, 0xC6 },
+ { 0x22, 0x7A8, 0x39 },
+ { 0x22, 0x7A9, 0x7A },
+ { 0x22, 0x7AA, 0xC6 },
+ { 0x22, 0x7AB, 0x39 },
+ { 0x22, 0x7AC, 0x08 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xC4 },
+ { 0x22, 0x7A7, 0xE9 },
+ { 0x22, 0x7A8, 0xDC },
+ { 0x22, 0x7A9, 0xC4 },
+ { 0x22, 0x7AA, 0xE9 },
+ { 0x22, 0x7AB, 0xDC },
+ { 0x22, 0x7AC, 0x09 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3D },
+ { 0x22, 0x7A7, 0xE1 },
+ { 0x22, 0x7A8, 0x0D },
+ { 0x22, 0x7A9, 0x3D },
+ { 0x22, 0x7AA, 0xE1 },
+ { 0x22, 0x7AB, 0x0D },
+ { 0x22, 0x7AC, 0x0A },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x89 },
+ { 0x22, 0x7A7, 0xB6 },
+ { 0x22, 0x7A8, 0xEB },
+ { 0x22, 0x7A9, 0x89 },
+ { 0x22, 0x7AA, 0xB6 },
+ { 0x22, 0x7AB, 0xEB },
+ { 0x22, 0x7AC, 0x0B },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x39 },
+ { 0x22, 0x7A7, 0x9D },
+ { 0x22, 0x7A8, 0xFE },
+ { 0x22, 0x7A9, 0x39 },
+ { 0x22, 0x7AA, 0x9D },
+ { 0x22, 0x7AB, 0xFE },
+ { 0x22, 0x7AC, 0x0C },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x76 },
+ { 0x22, 0x7A7, 0x49 },
+ { 0x22, 0x7A8, 0x15 },
+ { 0x22, 0x7A9, 0x76 },
+ { 0x22, 0x7AA, 0x49 },
+ { 0x22, 0x7AB, 0x15 },
+ { 0x22, 0x7AC, 0x0D },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xC8 },
+ { 0x22, 0x7A7, 0x80 },
+ { 0x22, 0x7A8, 0xF5 },
+ { 0x22, 0x7A9, 0xC8 },
+ { 0x22, 0x7AA, 0x80 },
+ { 0x22, 0x7AB, 0xF5 },
+ { 0x22, 0x7AC, 0x0E },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x40 },
+ { 0x22, 0x7A7, 0x00 },
+ { 0x22, 0x7A8, 0x00 },
+ { 0x22, 0x7A9, 0x40 },
+ { 0x22, 0x7AA, 0x00 },
+ { 0x22, 0x7AB, 0x00 },
+ { 0x22, 0x7AC, 0x0F },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x90 },
+ { 0x22, 0x7A7, 0x68 },
+ { 0x22, 0x7A8, 0xF1 },
+ { 0x22, 0x7A9, 0x90 },
+ { 0x22, 0x7AA, 0x68 },
+ { 0x22, 0x7AB, 0xF1 },
+ { 0x22, 0x7AC, 0x10 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x34 },
+ { 0x22, 0x7A7, 0x47 },
+ { 0x22, 0x7A8, 0x6C },
+ { 0x22, 0x7A9, 0x34 },
+ { 0x22, 0x7AA, 0x47 },
+ { 0x22, 0x7AB, 0x6C },
+ { 0x22, 0x7AC, 0x11 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x6F },
+ { 0x22, 0x7A7, 0x97 },
+ { 0x22, 0x7A8, 0x0F },
+ { 0x22, 0x7A9, 0x6F },
+ { 0x22, 0x7AA, 0x97 },
+ { 0x22, 0x7AB, 0x0F },
+ { 0x22, 0x7AC, 0x12 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xCB },
+ { 0x22, 0x7A7, 0xB8 },
+ { 0x22, 0x7A8, 0x94 },
+ { 0x22, 0x7A9, 0xCB },
+ { 0x22, 0x7AA, 0xB8 },
+ { 0x22, 0x7AB, 0x94 },
+ { 0x22, 0x7AC, 0x13 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x40 },
+ { 0x22, 0x7A7, 0x00 },
+ { 0x22, 0x7A8, 0x00 },
+ { 0x22, 0x7A9, 0x40 },
+ { 0x22, 0x7AA, 0x00 },
+ { 0x22, 0x7AB, 0x00 },
+ { 0x22, 0x7AC, 0x14 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x95 },
+ { 0x22, 0x7A7, 0x76 },
+ { 0x22, 0x7A8, 0x5B },
+ { 0x22, 0x7A9, 0x95 },
+ { 0x22, 0x7AA, 0x76 },
+ { 0x22, 0x7AB, 0x5B },
+ { 0x22, 0x7AC, 0x15 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x31 },
+ { 0x22, 0x7A7, 0xAC },
+ { 0x22, 0x7A8, 0x31 },
+ { 0x22, 0x7A9, 0x31 },
+ { 0x22, 0x7AA, 0xAC },
+ { 0x22, 0x7AB, 0x31 },
+ { 0x22, 0x7AC, 0x16 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x6A },
+ { 0x22, 0x7A7, 0x89 },
+ { 0x22, 0x7A8, 0xA5 },
+ { 0x22, 0x7A9, 0x6A },
+ { 0x22, 0x7AA, 0x89 },
+ { 0x22, 0x7AB, 0xA5 },
+ { 0x22, 0x7AC, 0x17 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xCE },
+ { 0x22, 0x7A7, 0x53 },
+ { 0x22, 0x7A8, 0xCF },
+ { 0x22, 0x7A9, 0xCE },
+ { 0x22, 0x7AA, 0x53 },
+ { 0x22, 0x7AB, 0xCF },
+ { 0x22, 0x7AC, 0x18 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x40 },
+ { 0x22, 0x7A7, 0x00 },
+ { 0x22, 0x7A8, 0x00 },
+ { 0x22, 0x7A9, 0x40 },
+ { 0x22, 0x7AA, 0x00 },
+ { 0x22, 0x7AB, 0x00 },
+ { 0x22, 0x7AC, 0x19 },
+ { 0x22, 0x7AD, 0x80 },
+ /* 48KHz base */
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0x88 },
+ { 0x22, 0x7A8, 0xDC },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0x88 },
+ { 0x22, 0x7AB, 0xDC },
+ { 0x22, 0x7AC, 0x1A },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x82 },
+ { 0x22, 0x7A7, 0xEE },
+ { 0x22, 0x7A8, 0x46 },
+ { 0x22, 0x7A9, 0x82 },
+ { 0x22, 0x7AA, 0xEE },
+ { 0x22, 0x7AB, 0x46 },
+ { 0x22, 0x7AC, 0x1B },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0x88 },
+ { 0x22, 0x7A8, 0xDC },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0x88 },
+ { 0x22, 0x7AB, 0xDC },
+ { 0x22, 0x7AC, 0x1C },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x7D },
+ { 0x22, 0x7A7, 0x09 },
+ { 0x22, 0x7A8, 0x28 },
+ { 0x22, 0x7A9, 0x7D },
+ { 0x22, 0x7AA, 0x09 },
+ { 0x22, 0x7AB, 0x28 },
+ { 0x22, 0x7AC, 0x1D },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xC2 },
+ { 0x22, 0x7A7, 0xE5 },
+ { 0x22, 0x7A8, 0xB4 },
+ { 0x22, 0x7A9, 0xC2 },
+ { 0x22, 0x7AA, 0xE5 },
+ { 0x22, 0x7AB, 0xB4 },
+ { 0x22, 0x7AC, 0x1E },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0xA3 },
+ { 0x22, 0x7A8, 0x1F },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0xA3 },
+ { 0x22, 0x7AB, 0x1F },
+ { 0x22, 0x7AC, 0x1F },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x84 },
+ { 0x22, 0x7A7, 0xCA },
+ { 0x22, 0x7A8, 0xF1 },
+ { 0x22, 0x7A9, 0x84 },
+ { 0x22, 0x7AA, 0xCA },
+ { 0x22, 0x7AB, 0xF1 },
+ { 0x22, 0x7AC, 0x20 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3C },
+ { 0x22, 0x7A7, 0xD5 },
+ { 0x22, 0x7A8, 0x9C },
+ { 0x22, 0x7A9, 0x3C },
+ { 0x22, 0x7AA, 0xD5 },
+ { 0x22, 0x7AB, 0x9C },
+ { 0x22, 0x7AC, 0x21 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x7B },
+ { 0x22, 0x7A7, 0x35 },
+ { 0x22, 0x7A8, 0x0F },
+ { 0x22, 0x7A9, 0x7B },
+ { 0x22, 0x7AA, 0x35 },
+ { 0x22, 0x7AB, 0x0F },
+ { 0x22, 0x7AC, 0x22 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xC4 },
+ { 0x22, 0x7A7, 0x87 },
+ { 0x22, 0x7A8, 0x45 },
+ { 0x22, 0x7A9, 0xC4 },
+ { 0x22, 0x7AA, 0x87 },
+ { 0x22, 0x7AB, 0x45 },
+ { 0x22, 0x7AC, 0x23 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3E },
+ { 0x22, 0x7A7, 0x0A },
+ { 0x22, 0x7A8, 0x78 },
+ { 0x22, 0x7A9, 0x3E },
+ { 0x22, 0x7AA, 0x0A },
+ { 0x22, 0x7AB, 0x78 },
+ { 0x22, 0x7AC, 0x24 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x88 },
+ { 0x22, 0x7A7, 0xE2 },
+ { 0x22, 0x7A8, 0x05 },
+ { 0x22, 0x7A9, 0x88 },
+ { 0x22, 0x7AA, 0xE2 },
+ { 0x22, 0x7AB, 0x05 },
+ { 0x22, 0x7AC, 0x25 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x3A },
+ { 0x22, 0x7A7, 0x1A },
+ { 0x22, 0x7A8, 0xA3 },
+ { 0x22, 0x7A9, 0x3A },
+ { 0x22, 0x7AA, 0x1A },
+ { 0x22, 0x7AB, 0xA3 },
+ { 0x22, 0x7AC, 0x26 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x77 },
+ { 0x22, 0x7A7, 0x1D },
+ { 0x22, 0x7A8, 0xFB },
+ { 0x22, 0x7A9, 0x77 },
+ { 0x22, 0x7AA, 0x1D },
+ { 0x22, 0x7AB, 0xFB },
+ { 0x22, 0x7AC, 0x27 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xC7 },
+ { 0x22, 0x7A7, 0xDA },
+ { 0x22, 0x7A8, 0xE5 },
+ { 0x22, 0x7A9, 0xC7 },
+ { 0x22, 0x7AA, 0xDA },
+ { 0x22, 0x7AB, 0xE5 },
+ { 0x22, 0x7AC, 0x28 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x40 },
+ { 0x22, 0x7A7, 0x00 },
+ { 0x22, 0x7A8, 0x00 },
+ { 0x22, 0x7A9, 0x40 },
+ { 0x22, 0x7AA, 0x00 },
+ { 0x22, 0x7AB, 0x00 },
+ { 0x22, 0x7AC, 0x29 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x8E },
+ { 0x22, 0x7A7, 0xD7 },
+ { 0x22, 0x7A8, 0x22 },
+ { 0x22, 0x7A9, 0x8E },
+ { 0x22, 0x7AA, 0xD7 },
+ { 0x22, 0x7AB, 0x22 },
+ { 0x22, 0x7AC, 0x2A },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x35 },
+ { 0x22, 0x7A7, 0x26 },
+ { 0x22, 0x7A8, 0xC6 },
+ { 0x22, 0x7A9, 0x35 },
+ { 0x22, 0x7AA, 0x26 },
+ { 0x22, 0x7AB, 0xC6 },
+ { 0x22, 0x7AC, 0x2B },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x71 },
+ { 0x22, 0x7A7, 0x28 },
+ { 0x22, 0x7A8, 0xDE },
+ { 0x22, 0x7A9, 0x71 },
+ { 0x22, 0x7AA, 0x28 },
+ { 0x22, 0x7AB, 0xDE },
+ { 0x22, 0x7AC, 0x2C },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xCA },
+ { 0x22, 0x7A7, 0xD9 },
+ { 0x22, 0x7A8, 0x3A },
+ { 0x22, 0x7A9, 0xCA },
+ { 0x22, 0x7AA, 0xD9 },
+ { 0x22, 0x7AB, 0x3A },
+ { 0x22, 0x7AC, 0x2D },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x40 },
+ { 0x22, 0x7A7, 0x00 },
+ { 0x22, 0x7A8, 0x00 },
+ { 0x22, 0x7A9, 0x40 },
+ { 0x22, 0x7AA, 0x00 },
+ { 0x22, 0x7AB, 0x00 },
+ { 0x22, 0x7AC, 0x2E },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x93 },
+ { 0x22, 0x7A7, 0x5E },
+ { 0x22, 0x7A8, 0xD8 },
+ { 0x22, 0x7A9, 0x93 },
+ { 0x22, 0x7AA, 0x5E },
+ { 0x22, 0x7AB, 0xD8 },
+ { 0x22, 0x7AC, 0x2F },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x32 },
+ { 0x22, 0x7A7, 0xB7 },
+ { 0x22, 0x7A8, 0xB1 },
+ { 0x22, 0x7A9, 0x32 },
+ { 0x22, 0x7AA, 0xB7 },
+ { 0x22, 0x7AB, 0xB1 },
+ { 0x22, 0x7AC, 0x30 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x6C },
+ { 0x22, 0x7A7, 0xA1 },
+ { 0x22, 0x7A8, 0x28 },
+ { 0x22, 0x7A9, 0x6C },
+ { 0x22, 0x7AA, 0xA1 },
+ { 0x22, 0x7AB, 0x28 },
+ { 0x22, 0x7AC, 0x31 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0xCD },
+ { 0x22, 0x7A7, 0x48 },
+ { 0x22, 0x7A8, 0x4F },
+ { 0x22, 0x7A9, 0xCD },
+ { 0x22, 0x7AA, 0x48 },
+ { 0x22, 0x7AB, 0x4F },
+ { 0x22, 0x7AC, 0x32 },
+ { 0x22, 0x7AD, 0x80 },
+ { 0x22, 0x7A6, 0x40 },
+ { 0x22, 0x7A7, 0x00 },
+ { 0x22, 0x7A8, 0x00 },
+ { 0x22, 0x7A9, 0x40 },
+ { 0x22, 0x7AA, 0x00 },
+ { 0x22, 0x7AB, 0x00 },
+ { 0x22, 0x7AC, 0x33 },
+ { 0x22, 0x7AD, 0x80 },
+ /* common */
+ { 0x22, 0x782, 0xC1 },
+ { 0x22, 0x771, 0x2C },
+ { 0x22, 0x772, 0x2C },
+ { 0x22, 0x788, 0x04 },
+ { 0x01, 0x7B0, 0x08 },
+ {}
+};
+
static const struct hda_fixup stac92hd83xxx_fixups[] = {
[STAC_92HD83XXX_REF] = {
.type = HDA_FIXUP_PINS,
@@ -2172,6 +2622,12 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = {
{}
},
},
+ [STAC_HP_BNB13_EQ] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = hp_bnb13_eq_verbs,
+ .chained = true,
+ .chain_id = STAC_92HD83XXX_HP_MIC_LED,
+ },
};
static const struct hda_model_fixup stac92hd83xxx_models[] = {
@@ -2187,6 +2643,7 @@ static const struct hda_model_fixup stac92hd83xxx_models[] = {
{ .id = STAC_92HD83XXX_HP_MIC_LED, .name = "hp-mic-led" },
{ .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" },
{ .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" },
+ { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" },
{}
};
@@ -2233,7 +2690,101 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888,
"HP Envy Spectre", STAC_HP_ENVY_BASS),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
- "HP Folio", STAC_92HD83XXX_HP_MIC_LED),
+ "HP Folio", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1909,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1942,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1943,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1944,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1945,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1946,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1948,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1949,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194A,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194B,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194C,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194E,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194F,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1950,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1951,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195A,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195B,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195C,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1991,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2103,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2104,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2105,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2106,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2107,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2108,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2109,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210A,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210B,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211C,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211D,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211E,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211F,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2120,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2121,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2122,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2123,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213E,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213F,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2140,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B2,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B3,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B5,
+ "HP bNB13", STAC_HP_BNB13_EQ),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B6,
+ "HP bNB13", STAC_HP_BNB13_EQ),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900,
"HP", STAC_92HD83XXX_HP_MIC_LED),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000,
@@ -3727,30 +4278,8 @@ static int stac_suspend(struct hda_codec *codec)
stac_shutup(codec);
return 0;
}
-
-static void stac_set_power_state(struct hda_codec *codec, hda_nid_t fg,
- unsigned int power_state)
-{
- unsigned int afg_power_state = power_state;
- struct sigmatel_spec *spec = codec->spec;
-
- if (power_state == AC_PWRST_D3) {
- if (spec->vref_mute_led_nid) {
- /* with vref-out pin used for mute led control
- * codec AFG is prevented from D3 state
- */
- afg_power_state = AC_PWRST_D1;
- }
- /* this delay seems necessary to avoid click noise at power-down */
- msleep(100);
- }
- snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
- afg_power_state);
- snd_hda_codec_set_power_to_all(codec, fg, power_state);
-}
#else
#define stac_suspend NULL
-#define stac_set_power_state NULL
#endif /* CONFIG_PM */
static const struct hda_codec_ops stac_patch_ops = {
@@ -3933,15 +4462,14 @@ static void stac_setup_gpio(struct hda_codec *codec)
spec->gpio_dir |= spec->gpio_led;
spec->gpio_data |= spec->gpio_led;
} else {
- codec->patch_ops.set_power_state =
- stac_set_power_state;
+ codec->power_filter = stac_vref_led_power_filter;
}
}
if (spec->mic_mute_led_gpio) {
spec->gpio_mask |= spec->mic_mute_led_gpio;
spec->gpio_dir |= spec->mic_mute_led_gpio;
- spec->mic_mute_led_on = true;
+ spec->mic_enabled = 0;
spec->gpio_data |= spec->mic_mute_led_gpio;
spec->gen.cap_sync_hook = stac_capture_led_hook;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 0bc20ef5687a..f84195f3ea31 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -138,6 +138,7 @@ static struct via_spec *via_new_spec(struct hda_codec *codec)
spec->gen.indep_hp = 1;
spec->gen.keep_eapd_on = 1;
spec->gen.pcm_playback_hook = via_playback_pcm_hook;
+ spec->gen.add_stereo_mix_input = 1;
return spec;
}
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
new file mode 100644
index 000000000000..8fe3b8c18ed4
--- /dev/null
+++ b/sound/pci/hda/thinkpad_helper.c
@@ -0,0 +1,100 @@
+/* Helper functions for Thinkpad LED control;
+ * to be included from codec driver
+ */
+
+#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
+
+#include <linux/acpi.h>
+#include <linux/thinkpad_acpi.h>
+
+static int (*led_set_func)(int, bool);
+static void (*old_vmaster_hook)(void *, int);
+
+static acpi_status acpi_check_cb(acpi_handle handle, u32 lvl, void *context,
+ void **rv)
+{
+ bool *found = context;
+ *found = true;
+ return AE_OK;
+}
+
+static bool is_thinkpad(struct hda_codec *codec)
+{
+ bool found = false;
+ if (codec->subsystem_id >> 16 != 0x17aa)
+ return false;
+ if (ACPI_SUCCESS(acpi_get_devices("LEN0068", acpi_check_cb, &found, NULL)) && found)
+ return true;
+ found = false;
+ return ACPI_SUCCESS(acpi_get_devices("IBM0068", acpi_check_cb, &found, NULL)) && found;
+}
+
+static void update_tpacpi_mute_led(void *private_data, int enabled)
+{
+ if (old_vmaster_hook)
+ old_vmaster_hook(private_data, enabled);
+
+ if (led_set_func)
+ led_set_func(TPACPI_LED_MUTE, !enabled);
+}
+
+static void update_tpacpi_micmute_led(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (!ucontrol || !led_set_func)
+ return;
+ if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
+ /* TODO: How do I verify if it's a mono or stereo here? */
+ bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
+ led_set_func(TPACPI_LED_MICMUTE, !val);
+ }
+}
+
+static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ bool removefunc = false;
+
+ if (action == HDA_FIXUP_ACT_PROBE) {
+ if (!is_thinkpad(codec))
+ return;
+ if (!led_set_func)
+ led_set_func = symbol_request(tpacpi_led_set);
+ if (!led_set_func) {
+ snd_printk(KERN_WARNING "Failed to find thinkpad-acpi symbol tpacpi_led_set\n");
+ return;
+ }
+
+ removefunc = true;
+ if (led_set_func(TPACPI_LED_MUTE, false) >= 0) {
+ old_vmaster_hook = spec->vmaster_mute.hook;
+ spec->vmaster_mute.hook = update_tpacpi_mute_led;
+ removefunc = false;
+ }
+ if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
+ if (spec->num_adc_nids > 1)
+ snd_printdd("Skipping micmute LED control due to several ADCs");
+ else {
+ spec->cap_sync_hook = update_tpacpi_micmute_led;
+ removefunc = false;
+ }
+ }
+ }
+
+ if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
+ symbol_put(tpacpi_led_set);
+ led_set_func = NULL;
+ old_vmaster_hook = NULL;
+ }
+}
+
+#else /* CONFIG_THINKPAD_ACPI */
+
+static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+}
+
+#endif /* CONFIG_THINKPAD_ACPI */
diff --git a/sound/pci/ice1712/psc724.c b/sound/pci/ice1712/psc724.c
index 302ac6ddd545..4019cf27d117 100644
--- a/sound/pci/ice1712/psc724.c
+++ b/sound/pci/ice1712/psc724.c
@@ -203,12 +203,12 @@ static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected)
/* notify about master speaker mute change */
memset(&elem_id, 0, sizeof(elem_id));
elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- strncpy(elem_id.name, "Master Speakers Playback Switch",
+ strlcpy(elem_id.name, "Master Speakers Playback Switch",
sizeof(elem_id.name));
kctl = snd_ctl_find_id(ice->card, &elem_id);
snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
/* and headphone mute change */
- strncpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name,
+ strlcpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name,
sizeof(elem_id.name));
kctl = snd_ctl_find_id(ice->card, &elem_id);
snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
index 975e0357bd5a..71c6003ef338 100644
--- a/sound/pci/ice1712/quartet.c
+++ b/sound/pci/ice1712/quartet.c
@@ -203,6 +203,7 @@ static const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS",
#define AK4620_DEEMVOL_REG 0x03
#define AK4620_SMUTE (1<<7)
+#ifdef CONFIG_PROC_FS
/*
* Conversion from int value to its binary form. Used for debugging.
* The output buffer must be allocated prior to calling the function.
@@ -227,6 +228,7 @@ static char *get_binary(char *buffer, int value)
buffer[pos] = '\0';
return buffer;
}
+#endif /* CONFIG_PROC_FS */
/*
* Initial setup of the conversion array GPIO <-> rate
diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c
index e473f8a88f9c..21b373b2e260 100644
--- a/sound/pci/ice1712/wm8766.c
+++ b/sound/pci/ice1712/wm8766.c
@@ -253,7 +253,8 @@ static int snd_wm8766_ctl_get(struct snd_kcontrol *kcontrol,
}
if (wm->ctl[n].flags & WM8766_FLAG_INVERT) {
val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min);
- val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min);
+ if (wm->ctl[n].flags & WM8766_FLAG_STEREO)
+ val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min);
}
ucontrol->value.integer.value[0] = val1;
if (wm->ctl[n].flags & WM8766_FLAG_STEREO)
diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c
index a3c05fe5daf9..e66c0da62014 100644
--- a/sound/pci/ice1712/wm8776.c
+++ b/sound/pci/ice1712/wm8776.c
@@ -52,7 +52,7 @@ static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm,
unsigned int index_offset;
memset(&elem_id, 0, sizeof(elem_id));
- strncpy(elem_id.name, ctl_name, sizeof(elem_id.name));
+ strlcpy(elem_id.name, ctl_name, sizeof(elem_id.name));
elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
kctl = snd_ctl_find_id(card, &elem_id);
if (!kctl)
@@ -526,7 +526,8 @@ static int snd_wm8776_ctl_get(struct snd_kcontrol *kcontrol,
}
if (wm->ctl[n].flags & WM8776_FLAG_INVERT) {
val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min);
- val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min);
+ if (wm->ctl[n].flags & WM8776_FLAG_STEREO)
+ val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min);
}
ucontrol->value.integer.value[0] = val1;
if (wm->ctl[n].flags & WM8776_FLAG_STEREO)
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 59c8aaebb91e..08d8733604a2 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -1541,17 +1541,16 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
snd_dma_pci_data(chip->pci),
rec->prealloc_size, rec->prealloc_max_size);
- if (rec->ac97_idx == ICHD_PCMOUT && rec->playback_ops) {
+ if (rec->playback_ops &&
+ rec->playback_ops->open == snd_intel8x0_playback_open) {
struct snd_pcm_chmap *chmap;
int chs = 2;
- if (rec->ac97_idx == ICHD_PCMOUT) {
- if (chip->multi8)
- chs = 8;
- else if (chip->multi6)
- chs = 6;
- else if (chip->multi4)
- chs = 4;
- }
+ if (chip->multi8)
+ chs = 8;
+ else if (chip->multi6)
+ chs = 6;
+ else if (chip->multi4)
+ chs = 4;
err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
snd_pcm_alt_chmaps, chs, 0,
&chmap);
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 7307d97186cb..0568540dc8d3 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -463,7 +463,7 @@ static int lola_parse_tree(struct lola *chip)
err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val);
if (err < 0) {
- printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid);
+ printk(KERN_ERR SFX "Can't read FUNCTION_TYPE\n");
return err;
}
if (val != 1) {
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 3230e57f246c..5fcaaa6da4a8 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -453,8 +453,8 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream)
lower_32_bits(buf), upper_32_bits(buf),
&buffer_index);
- snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n",
- buffer_index, (void *)buf, period_bytes);
+ snd_printdd(LXP "starting: buffer index %x on 0x%lx (%d bytes)\n",
+ buffer_index, (unsigned long)buf, period_bytes);
buf += period_bytes;
}
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c
index 633c8607d053..626ecad4dae7 100644
--- a/sound/pci/lx6464es/lx_core.c
+++ b/sound/pci/lx6464es/lx_core.c
@@ -1191,8 +1191,8 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip,
unpack_pointer(buf, &buf_lo, &buf_hi);
err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi,
&buffer_index);
- snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n",
- buffer_index, (void *)buf, period_bytes);
+ snd_printdd(LXP "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n",
+ buffer_index, (unsigned long)buf, period_bytes);
lx_stream->frame_pos = next_pos;
spin_unlock_irqrestore(&chip->lock, flags);
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile
index 0f8726551fde..8f4c409f7e45 100644
--- a/sound/pci/oxygen/Makefile
+++ b/sound/pci/oxygen/Makefile
@@ -1,5 +1,5 @@
snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-oxygen-objs := oxygen.o xonar_dg.o
+snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
snd-virtuoso-objs := virtuoso.o xonar_lib.o \
xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h
index 5e0197e07dd1..99098657695a 100644
--- a/sound/pci/oxygen/cs4245.h
+++ b/sound/pci/oxygen/cs4245.h
@@ -102,6 +102,9 @@
#define CS4245_ADC_OVFL 0x02
#define CS4245_ADC_UNDRFL 0x01
+#define CS4245_SPI_ADDRESS_S (0x9e << 16)
+#define CS4245_SPI_WRITE_S (0 << 16)
-#define CS4245_SPI_ADDRESS (0x9e << 16)
-#define CS4245_SPI_WRITE (0 << 16)
+#define CS4245_SPI_ADDRESS 0x9e
+#define CS4245_SPI_WRITE 0
+#define CS4245_SPI_READ 1
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 09a24b24958b..c10ab077afd8 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -198,7 +198,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
unsigned int index, u16 data, u16 mask);
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
void oxygen_reset_uart(struct oxygen *chip);
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c
index 521eae458348..3274907189fe 100644
--- a/sound/pci/oxygen/oxygen_io.c
+++ b/sound/pci/oxygen/oxygen_io.c
@@ -194,23 +194,36 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
}
EXPORT_SYMBOL(oxygen_write_ac97_masked);
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+static int oxygen_wait_spi(struct oxygen *chip)
{
unsigned int count;
- /* should not need more than 30.72 us (24 * 1.28 us) */
- count = 10;
- while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
- && count > 0) {
+ /*
+ * Higher timeout to be sure: 200 us;
+ * actual transaction should not need more than 40 us.
+ */
+ for (count = 50; count > 0; count--) {
udelay(4);
- --count;
+ if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
+ OXYGEN_SPI_BUSY) == 0)
+ return 0;
}
+ snd_printk(KERN_ERR "oxygen: SPI wait timeout\n");
+ return -EIO;
+}
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+{
+ /*
+ * We need to wait AFTER initiating the SPI transaction,
+ * otherwise read operations will not work.
+ */
oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
if (control & OXYGEN_SPI_DATA_LENGTH_3)
oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
+ return oxygen_wait_spi(chip);
}
EXPORT_SYMBOL(oxygen_write_spi);
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c
index c0dbb52d45be..5988e044c519 100644
--- a/sound/pci/oxygen/oxygen_mixer.c
+++ b/sound/pci/oxygen/oxygen_mixer.c
@@ -190,6 +190,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
if (chip->model.update_center_lfe_mix)
chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
}
+EXPORT_SYMBOL(oxygen_update_dac_routing);
static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
{
diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h
index 63dc7a0ab555..8c191badaae8 100644
--- a/sound/pci/oxygen/oxygen_regs.h
+++ b/sound/pci/oxygen/oxygen_regs.h
@@ -318,6 +318,7 @@
#define OXYGEN_PLAY_MUTE23 0x0002
#define OXYGEN_PLAY_MUTE45 0x0004
#define OXYGEN_PLAY_MUTE67 0x0008
+#define OXYGEN_PLAY_MUTE_MASK 0x000f
#define OXYGEN_PLAY_MULTICH_MASK 0x0010
#define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000
#define OXYGEN_PLAY_MULTICH_AC97 0x0010
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 77acd790ea47..ed6f199f8a38 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -2,7 +2,7 @@
* card driver for the Xonar DG/DGX
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- *
+ * Copyright (c) Roman Volkov <v1ron@mail.ru>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.
@@ -20,27 +20,35 @@
* Xonar DG/DGX
* ------------
*
+ * CS4245 and CS4361 both will mute all outputs if any clock ratio
+ * is invalid.
+ *
* CMI8788:
*
* SPI 0 -> CS4245
*
+ * Playback:
* I²S 1 -> CS4245
* I²S 2 -> CS4361 (center/LFE)
* I²S 3 -> CS4361 (surround)
* I²S 4 -> CS4361 (front)
+ * Capture:
+ * I²S ADC 1 <- CS4245
*
* GPIO 3 <- ?
* GPIO 4 <- headphone detect
- * GPIO 5 -> route input jack to line-in (0) or mic-in (1)
- * GPIO 6 -> route input jack to line-in (0) or mic-in (1)
- * GPIO 7 -> enable rear headphone amp
+ * GPIO 5 -> enable ADC analog circuit for the left channel
+ * GPIO 6 -> enable ADC analog circuit for the right channel
+ * GPIO 7 -> switch green rear output jack between CS4245 and and the first
+ * channel of CS4361 (mechanical relay)
* GPIO 8 -> enable output to speakers
*
* CS4245:
*
+ * input 0 <- mic
* input 1 <- aux
* input 2 <- front mic
- * input 4 <- line/mic
+ * input 4 <- line
* DAC out -> headphones
* aux out -> front panel headphones
*/
@@ -56,553 +64,214 @@
#include "xonar_dg.h"
#include "cs4245.h"
-#define GPIO_MAGIC 0x0008
-#define GPIO_HP_DETECT 0x0010
-#define GPIO_INPUT_ROUTE 0x0060
-#define GPIO_HP_REAR 0x0080
-#define GPIO_OUTPUT_ENABLE 0x0100
-
-struct dg {
- unsigned int output_sel;
- s8 input_vol[4][2];
- unsigned int input_sel;
- u8 hp_vol_att;
- u8 cs4245_regs[0x11];
-};
-
-static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
+int cs4245_write_spi(struct oxygen *chip, u8 reg)
{
struct dg *data = chip->model_data;
+ unsigned int packet;
- oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
- OXYGEN_SPI_DATA_LENGTH_3 |
- OXYGEN_SPI_CLOCK_1280 |
- (0 << OXYGEN_SPI_CODEC_SHIFT) |
- OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
- CS4245_SPI_ADDRESS |
- CS4245_SPI_WRITE |
- (reg << 8) | value);
- data->cs4245_regs[reg] = value;
+ packet = reg << 8;
+ packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
+ packet |= data->cs4245_shadow[reg];
+
+ return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_3 |
+ OXYGEN_SPI_CLOCK_1280 |
+ (0 << OXYGEN_SPI_CODEC_SHIFT) |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+ packet);
}
-static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
+int cs4245_read_spi(struct oxygen *chip, u8 addr)
{
struct dg *data = chip->model_data;
+ int ret;
+
+ ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+ OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+ ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr);
+ if (ret < 0)
+ return ret;
+
+ ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+ OXYGEN_SPI_DATA_LENGTH_2 |
+ OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+ OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+ (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
+ if (ret < 0)
+ return ret;
+
+ data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
- if (value != data->cs4245_regs[reg])
- cs4245_write(chip, reg, value);
+ return 0;
}
-static void cs4245_registers_init(struct oxygen *chip)
+int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
{
struct dg *data = chip->model_data;
-
- cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
- cs4245_write(chip, CS4245_DAC_CTRL_1,
- data->cs4245_regs[CS4245_DAC_CTRL_1]);
- cs4245_write(chip, CS4245_ADC_CTRL,
- data->cs4245_regs[CS4245_ADC_CTRL]);
- cs4245_write(chip, CS4245_SIGNAL_SEL,
- data->cs4245_regs[CS4245_SIGNAL_SEL]);
- cs4245_write(chip, CS4245_PGA_B_CTRL,
- data->cs4245_regs[CS4245_PGA_B_CTRL]);
- cs4245_write(chip, CS4245_PGA_A_CTRL,
- data->cs4245_regs[CS4245_PGA_A_CTRL]);
- cs4245_write(chip, CS4245_ANALOG_IN,
- data->cs4245_regs[CS4245_ANALOG_IN]);
- cs4245_write(chip, CS4245_DAC_A_CTRL,
- data->cs4245_regs[CS4245_DAC_A_CTRL]);
- cs4245_write(chip, CS4245_DAC_B_CTRL,
- data->cs4245_regs[CS4245_DAC_B_CTRL]);
- cs4245_write(chip, CS4245_DAC_CTRL_2,
- CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
- cs4245_write(chip, CS4245_INT_MASK, 0);
- cs4245_write(chip, CS4245_POWER_CTRL, 0);
+ unsigned char addr;
+ int ret;
+
+ for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) {
+ ret = (op == CS4245_SAVE_TO_SHADOW ?
+ cs4245_read_spi(chip, addr) :
+ cs4245_write_spi(chip, addr));
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
}
static void cs4245_init(struct oxygen *chip)
{
struct dg *data = chip->model_data;
- data->cs4245_regs[CS4245_DAC_CTRL_1] =
+ /* save the initial state: codec version, registers */
+ cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
+
+ /*
+ * Power up the CODEC internals, enable soft ramp & zero cross, work in
+ * async. mode, enable aux output from DAC. Invert DAC output as in the
+ * Windows driver.
+ */
+ data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] =
+ CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] =
CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
- data->cs4245_regs[CS4245_ADC_CTRL] =
+ data->cs4245_shadow[CS4245_DAC_CTRL_2] =
+ CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC;
+ data->cs4245_shadow[CS4245_ADC_CTRL] =
CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
- data->cs4245_regs[CS4245_SIGNAL_SEL] =
- CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
- data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
- data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
- data->cs4245_regs[CS4245_ANALOG_IN] =
- CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
- data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
- data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
- cs4245_registers_init(chip);
+ data->cs4245_shadow[CS4245_ANALOG_IN] =
+ CS4245_PGA_SOFT | CS4245_PGA_ZERO;
+ data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0;
+ data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0;
+ data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8;
+ data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8;
+
+ cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
snd_component_add(chip->card, "CS4245");
}
-static void dg_output_enable(struct oxygen *chip)
-{
- msleep(2500);
- oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
-}
-
-static void dg_init(struct oxygen *chip)
+void dg_init(struct oxygen *chip)
{
struct dg *data = chip->model_data;
- data->output_sel = 0;
- data->input_sel = 3;
- data->hp_vol_att = 2 * 16;
+ data->output_sel = PLAYBACK_DST_HP_FP;
+ data->input_sel = CAPTURE_SRC_MIC;
cs4245_init(chip);
-
- oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_MAGIC | GPIO_HP_DETECT);
- oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
- GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
- oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
- GPIO_INPUT_ROUTE | GPIO_HP_REAR);
- dg_output_enable(chip);
+ oxygen_write16(chip, OXYGEN_GPIO_CONTROL,
+ GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE);
+ /* anti-pop delay, wait some time before enabling the output */
+ msleep(2500);
+ oxygen_write16(chip, OXYGEN_GPIO_DATA,
+ GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE);
}
-static void dg_cleanup(struct oxygen *chip)
+void dg_cleanup(struct oxygen *chip)
{
oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
}
-static void dg_suspend(struct oxygen *chip)
+void dg_suspend(struct oxygen *chip)
{
dg_cleanup(chip);
}
-static void dg_resume(struct oxygen *chip)
+void dg_resume(struct oxygen *chip)
{
- cs4245_registers_init(chip);
- dg_output_enable(chip);
-}
-
-static void set_cs4245_dac_params(struct oxygen *chip,
- struct snd_pcm_hw_params *params)
-{
- struct dg *data = chip->model_data;
- u8 value;
-
- value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
- if (params_rate(params) <= 50000)
- value |= CS4245_DAC_FM_SINGLE;
- else if (params_rate(params) <= 100000)
- value |= CS4245_DAC_FM_DOUBLE;
- else
- value |= CS4245_DAC_FM_QUAD;
- cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
+ cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
+ msleep(2500);
+ oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
}
-static void set_cs4245_adc_params(struct oxygen *chip,
+void set_cs4245_dac_params(struct oxygen *chip,
struct snd_pcm_hw_params *params)
{
struct dg *data = chip->model_data;
- u8 value;
-
- value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
- if (params_rate(params) <= 50000)
- value |= CS4245_ADC_FM_SINGLE;
- else if (params_rate(params) <= 100000)
- value |= CS4245_ADC_FM_DOUBLE;
- else
- value |= CS4245_ADC_FM_QUAD;
- cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
-}
-
-static inline unsigned int shift_bits(unsigned int value,
- unsigned int shift_from,
- unsigned int shift_to,
- unsigned int mask)
-{
- if (shift_from < shift_to)
- return (value << (shift_to - shift_from)) & mask;
- else
- return (value >> (shift_from - shift_to)) & mask;
-}
-
-static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
- unsigned int play_routing)
-{
- return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC1_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC2_SOURCE_MASK) |
- shift_bits(play_routing,
- OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
- OXYGEN_PLAY_DAC3_SOURCE_MASK);
-}
-
-static int output_switch_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "Speakers", "Headphones", "FP Headphones"
- };
-
- return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int output_switch_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- value->value.enumerated.item[0] = data->output_sel;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int output_switch_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- u8 reg;
- int changed;
-
- if (value->value.enumerated.item[0] > 2)
- return -EINVAL;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->output_sel;
- if (changed) {
- data->output_sel = value->value.enumerated.item[0];
-
- reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
- ~CS4245_A_OUT_SEL_MASK;
- reg |= data->output_sel == 2 ?
- CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
- cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
-
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
- data->output_sel ? data->hp_vol_att : 0);
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
- data->output_sel ? data->hp_vol_att : 0);
-
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- data->output_sel == 1 ? GPIO_HP_REAR : 0,
- GPIO_HP_REAR);
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int hp_volume_offset_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[3] = {
- "< 64 ohms", "64-150 ohms", "150-300 ohms"
- };
-
- return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int hp_volume_offset_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- if (data->hp_vol_att > 2 * 7)
- value->value.enumerated.item[0] = 0;
- else if (data->hp_vol_att > 0)
- value->value.enumerated.item[0] = 1;
- else
- value->value.enumerated.item[0] = 2;
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int hp_volume_offset_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- s8 att;
- int changed;
-
- if (value->value.enumerated.item[0] > 2)
- return -EINVAL;
- att = atts[value->value.enumerated.item[0]];
- mutex_lock(&chip->mutex);
- changed = att != data->hp_vol_att;
- if (changed) {
- data->hp_vol_att = att;
- if (data->output_sel) {
- cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
- cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
- }
+ unsigned char dac_ctrl;
+ unsigned char mclk_freq;
+
+ dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
+ mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
+ if (params_rate(params) <= 50000) {
+ dac_ctrl |= CS4245_DAC_FM_SINGLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+ } else if (params_rate(params) <= 100000) {
+ dac_ctrl |= CS4245_DAC_FM_DOUBLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+ } else {
+ dac_ctrl |= CS4245_DAC_FM_QUAD;
+ mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
}
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int input_vol_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 2;
- info->value.integer.min = 2 * -12;
- info->value.integer.max = 2 * 12;
- return 0;
-}
-
-static int input_vol_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- unsigned int idx = ctl->private_value;
-
- mutex_lock(&chip->mutex);
- value->value.integer.value[0] = data->input_vol[idx][0];
- value->value.integer.value[1] = data->input_vol[idx][1];
- mutex_unlock(&chip->mutex);
- return 0;
-}
-
-static int input_vol_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
- unsigned int idx = ctl->private_value;
- int changed = 0;
-
- if (value->value.integer.value[0] < 2 * -12 ||
- value->value.integer.value[0] > 2 * 12 ||
- value->value.integer.value[1] < 2 * -12 ||
- value->value.integer.value[1] > 2 * 12)
- return -EINVAL;
- mutex_lock(&chip->mutex);
- changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
- data->input_vol[idx][1] != value->value.integer.value[1];
- if (changed) {
- data->input_vol[idx][0] = value->value.integer.value[0];
- data->input_vol[idx][1] = value->value.integer.value[1];
- if (idx == data->input_sel) {
- cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
- data->input_vol[idx][0]);
- cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
- data->input_vol[idx][1]);
- }
- }
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
-
-static int input_sel_info(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_info *info)
-{
- static const char *const names[4] = {
- "Mic", "Aux", "Front Mic", "Line"
- };
-
- return snd_ctl_enum_info(info, 1, 4, names);
-}
-
-static int input_sel_get(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- mutex_lock(&chip->mutex);
- value->value.enumerated.item[0] = data->input_sel;
- mutex_unlock(&chip->mutex);
- return 0;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
+ cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
-static int input_sel_put(struct snd_kcontrol *ctl,
- struct snd_ctl_elem_value *value)
+void set_cs4245_adc_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params)
{
- static const u8 sel_values[4] = {
- CS4245_SEL_MIC,
- CS4245_SEL_INPUT_1,
- CS4245_SEL_INPUT_2,
- CS4245_SEL_INPUT_4
- };
- struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- int changed;
-
- if (value->value.enumerated.item[0] > 3)
- return -EINVAL;
-
- mutex_lock(&chip->mutex);
- changed = value->value.enumerated.item[0] != data->input_sel;
- if (changed) {
- data->input_sel = value->value.enumerated.item[0];
-
- cs4245_write(chip, CS4245_ANALOG_IN,
- (data->cs4245_regs[CS4245_ANALOG_IN] &
- ~CS4245_SEL_MASK) |
- sel_values[data->input_sel]);
-
- cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
- data->input_vol[data->input_sel][0]);
- cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
- data->input_vol[data->input_sel][1]);
-
- oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
- data->input_sel ? 0 : GPIO_INPUT_ROUTE,
- GPIO_INPUT_ROUTE);
+ unsigned char adc_ctrl;
+ unsigned char mclk_freq;
+
+ adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
+ mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
+ if (params_rate(params) <= 50000) {
+ adc_ctrl |= CS4245_ADC_FM_SINGLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+ } else if (params_rate(params) <= 100000) {
+ adc_ctrl |= CS4245_ADC_FM_DOUBLE;
+ mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+ } else {
+ adc_ctrl |= CS4245_ADC_FM_QUAD;
+ mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
}
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
-{
- static const char *const names[2] = { "Active", "Frozen" };
-
- return snd_ctl_enum_info(info, 1, 2, names);
+ data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
+ data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
+ cs4245_write_spi(chip, CS4245_ADC_CTRL);
+ cs4245_write_spi(chip, CS4245_MCLK_FREQ);
}
-static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
-{
- struct oxygen *chip = ctl->private_data;
- struct dg *data = chip->model_data;
-
- value->value.enumerated.item[0] =
- !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
- return 0;
-}
-
-static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+ unsigned int play_routing)
{
- struct oxygen *chip = ctl->private_data;
struct dg *data = chip->model_data;
- u8 reg;
- int changed;
-
- mutex_lock(&chip->mutex);
- reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
- if (value->value.enumerated.item[0])
- reg |= CS4245_HPF_FREEZE;
- changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
- if (changed)
- cs4245_write(chip, CS4245_ADC_CTRL, reg);
- mutex_unlock(&chip->mutex);
- return changed;
-}
-
-#define INPUT_VOLUME(xname, index) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
- .name = xname, \
- .info = input_vol_info, \
- .get = input_vol_get, \
- .put = input_vol_put, \
- .tlv = { .p = cs4245_pga_db_scale }, \
- .private_value = index, \
-}
-static const struct snd_kcontrol_new dg_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Analog Output Playback Enum",
- .info = output_switch_info,
- .get = output_switch_get,
- .put = output_switch_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Headphones Impedance Playback Enum",
- .info = hp_volume_offset_info,
- .get = hp_volume_offset_get,
- .put = hp_volume_offset_put,
- },
- INPUT_VOLUME("Mic Capture Volume", 0),
- INPUT_VOLUME("Aux Capture Volume", 1),
- INPUT_VOLUME("Front Mic Capture Volume", 2),
- INPUT_VOLUME("Line Capture Volume", 3),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Source",
- .info = input_sel_info,
- .get = input_sel_get,
- .put = input_sel_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "ADC High-pass Filter Capture Enum",
- .info = hpf_info,
- .get = hpf_get,
- .put = hpf_put,
- },
-};
-
-static int dg_control_filter(struct snd_kcontrol_new *template)
-{
- if (!strncmp(template->name, "Master Playback ", 16))
- return 1;
- return 0;
-}
-
-static int dg_mixer_init(struct oxygen *chip)
-{
- unsigned int i;
- int err;
-
- for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
- err = snd_ctl_add(chip->card,
- snd_ctl_new1(&dg_controls[i], chip));
- if (err < 0)
- return err;
+ unsigned int routing = 0;
+
+ switch (data->output_sel) {
+ case PLAYBACK_DST_HP:
+ case PLAYBACK_DST_HP_FP:
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
+ OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
+ break;
+ case PLAYBACK_DST_MULTICH:
+ routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+ (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+ (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+ (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+ oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+ OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
+ break;
}
- return 0;
+ return routing;
}
-static void dump_cs4245_registers(struct oxygen *chip,
+void dump_cs4245_registers(struct oxygen *chip,
struct snd_info_buffer *buffer)
{
struct dg *data = chip->model_data;
- unsigned int i;
+ unsigned int addr;
snd_iprintf(buffer, "\nCS4245:");
- for (i = 1; i <= 0x10; ++i)
- snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
+ cs4245_read_spi(chip, CS4245_INT_STATUS);
+ for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++)
+ snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
snd_iprintf(buffer, "\n");
}
-
-struct oxygen_model model_xonar_dg = {
- .longname = "C-Media Oxygen HD Audio",
- .chip = "CMI8786",
- .init = dg_init,
- .control_filter = dg_control_filter,
- .mixer_init = dg_mixer_init,
- .cleanup = dg_cleanup,
- .suspend = dg_suspend,
- .resume = dg_resume,
- .set_dac_params = set_cs4245_dac_params,
- .set_adc_params = set_cs4245_adc_params,
- .adjust_dac_routing = adjust_dg_dac_routing,
- .dump_registers = dump_cs4245_registers,
- .model_data_size = sizeof(struct dg),
- .device_config = PLAYBACK_0_TO_I2S |
- PLAYBACK_1_TO_SPDIF |
- CAPTURE_0_FROM_I2S_2 |
- CAPTURE_1_FROM_SPDIF,
- .dac_channels_pcm = 6,
- .dac_channels_mixer = 0,
- .function_flags = OXYGEN_FUNCTION_SPI,
- .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
- .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
- .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
- .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h
index 5688d78609a9..d461df357aa1 100644
--- a/sound/pci/oxygen/xonar_dg.h
+++ b/sound/pci/oxygen/xonar_dg.h
@@ -3,6 +3,54 @@
#include "oxygen.h"
+#define GPIO_MAGIC 0x0008
+#define GPIO_HP_DETECT 0x0010
+#define GPIO_INPUT_ROUTE 0x0060
+#define GPIO_HP_REAR 0x0080
+#define GPIO_OUTPUT_ENABLE 0x0100
+
+#define CAPTURE_SRC_MIC 0
+#define CAPTURE_SRC_FP_MIC 1
+#define CAPTURE_SRC_LINE 2
+#define CAPTURE_SRC_AUX 3
+
+#define PLAYBACK_DST_HP 0
+#define PLAYBACK_DST_HP_FP 1
+#define PLAYBACK_DST_MULTICH 2
+
+enum cs4245_shadow_operation {
+ CS4245_SAVE_TO_SHADOW,
+ CS4245_LOAD_FROM_SHADOW
+};
+
+struct dg {
+ /* shadow copy of the CS4245 register space */
+ unsigned char cs4245_shadow[17];
+ /* output select: headphone/speakers */
+ unsigned char output_sel;
+ /* volumes for all capture sources */
+ char input_vol[4][2];
+ /* input select: mic/fp mic/line/aux */
+ unsigned char input_sel;
+};
+
+/* Xonar DG control routines */
+int cs4245_write_spi(struct oxygen *chip, u8 reg);
+int cs4245_read_spi(struct oxygen *chip, u8 reg);
+int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op);
+void dg_init(struct oxygen *chip);
+void set_cs4245_dac_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params);
+void set_cs4245_adc_params(struct oxygen *chip,
+ struct snd_pcm_hw_params *params);
+unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+ unsigned int play_routing);
+void dump_cs4245_registers(struct oxygen *chip,
+ struct snd_info_buffer *buffer);
+void dg_suspend(struct oxygen *chip);
+void dg_resume(struct oxygen *chip);
+void dg_cleanup(struct oxygen *chip);
+
extern struct oxygen_model model_xonar_dg;
#endif
diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c
new file mode 100644
index 000000000000..b885dac28a09
--- /dev/null
+++ b/sound/pci/oxygen/xonar_dg_mixer.c
@@ -0,0 +1,477 @@
+/*
+ * Mixer controls for the Xonar DG/DGX
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) Roman Volkov <v1ron@mail.ru>
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2.
+ *
+ * This driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "xonar_dg.h"
+#include "cs4245.h"
+
+/* analog output select */
+
+static int output_select_apply(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK;
+ if (data->output_sel == PLAYBACK_DST_HP) {
+ /* mute FP (aux output) amplifier, switch rear jack to CS4245 */
+ oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+ } else if (data->output_sel == PLAYBACK_DST_HP_FP) {
+ /*
+ * Unmute FP amplifier, switch rear jack to CS4361;
+ * I2S channels 2,3,4 should be inactive.
+ */
+ oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+ data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
+ } else {
+ /*
+ * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
+ * and change playback routing.
+ */
+ oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+ }
+ return cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
+}
+
+static int output_select_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[3] = {
+ "Stereo Headphones",
+ "Stereo Headphones FP",
+ "Multichannel",
+ };
+
+ return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_select_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ value->value.enumerated.item[0] = data->output_sel;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int output_select_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int new = value->value.enumerated.item[0];
+ int changed = 0;
+ int ret;
+
+ mutex_lock(&chip->mutex);
+ if (data->output_sel != new) {
+ data->output_sel = new;
+ ret = output_select_apply(chip);
+ changed = ret >= 0 ? 1 : ret;
+ oxygen_update_dac_routing(chip);
+ }
+ mutex_unlock(&chip->mutex);
+
+ return changed;
+}
+
+/* CS4245 Headphone Channels A&B Volume Control */
+
+static int hp_stereo_volume_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 0;
+ info->value.integer.max = 255;
+ return 0;
+}
+
+static int hp_stereo_volume_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int tmp;
+
+ mutex_lock(&chip->mutex);
+ tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
+ val->value.integer.value[0] = tmp;
+ tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
+ val->value.integer.value[1] = tmp;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ int ret;
+ int changed = 0;
+ long new1 = val->value.integer.value[0];
+ long new2 = val->value.integer.value[1];
+
+ if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) ||
+ (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) {
+ data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1;
+ data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2;
+ ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
+ if (ret >= 0)
+ ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
+ changed = ret >= 0 ? 1 : ret;
+ }
+ mutex_unlock(&chip->mutex);
+
+ return changed;
+}
+
+/* Headphone Mute */
+
+static int hp_mute_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ val->value.integer.value[0] =
+ !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC);
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int hp_mute_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *val)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ int ret;
+ int changed;
+
+ if (val->value.integer.value[0] > 1)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
+ data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
+ (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
+ ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+ changed = ret >= 0 ? 1 : ret;
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+/* capture volume for all sources */
+
+static int input_volume_apply(struct oxygen *chip, char left, char right)
+{
+ struct dg *data = chip->model_data;
+ int ret;
+
+ data->cs4245_shadow[CS4245_PGA_A_CTRL] = left;
+ data->cs4245_shadow[CS4245_PGA_B_CTRL] = right;
+ ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL);
+ if (ret < 0)
+ return ret;
+ return cs4245_write_spi(chip, CS4245_PGA_B_CTRL);
+}
+
+static int input_vol_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 2;
+ info->value.integer.min = 2 * -12;
+ info->value.integer.max = 2 * 12;
+ return 0;
+}
+
+static int input_vol_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int idx = ctl->private_value;
+
+ mutex_lock(&chip->mutex);
+ value->value.integer.value[0] = data->input_vol[idx][0];
+ value->value.integer.value[1] = data->input_vol[idx][1];
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int input_vol_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ unsigned int idx = ctl->private_value;
+ int changed = 0;
+ int ret = 0;
+
+ if (value->value.integer.value[0] < 2 * -12 ||
+ value->value.integer.value[0] > 2 * 12 ||
+ value->value.integer.value[1] < 2 * -12 ||
+ value->value.integer.value[1] > 2 * 12)
+ return -EINVAL;
+ mutex_lock(&chip->mutex);
+ changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
+ data->input_vol[idx][1] != value->value.integer.value[1];
+ if (changed) {
+ data->input_vol[idx][0] = value->value.integer.value[0];
+ data->input_vol[idx][1] = value->value.integer.value[1];
+ if (idx == data->input_sel) {
+ ret = input_volume_apply(chip,
+ data->input_vol[idx][0],
+ data->input_vol[idx][1]);
+ }
+ changed = ret >= 0 ? 1 : ret;
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+/* Capture Source */
+
+static int input_source_apply(struct oxygen *chip)
+{
+ struct dg *data = chip->model_data;
+
+ data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK;
+ if (data->input_sel == CAPTURE_SRC_FP_MIC)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2;
+ else if (data->input_sel == CAPTURE_SRC_LINE)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4;
+ else if (data->input_sel != CAPTURE_SRC_MIC)
+ data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1;
+ return cs4245_write_spi(chip, CS4245_ANALOG_IN);
+}
+
+static int input_sel_info(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_info *info)
+{
+ static const char *const names[4] = {
+ "Mic", "Front Mic", "Line", "Aux"
+ };
+
+ return snd_ctl_enum_info(info, 1, 4, names);
+}
+
+static int input_sel_get(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ mutex_lock(&chip->mutex);
+ value->value.enumerated.item[0] = data->input_sel;
+ mutex_unlock(&chip->mutex);
+ return 0;
+}
+
+static int input_sel_put(struct snd_kcontrol *ctl,
+ struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ int changed;
+ int ret;
+
+ if (value->value.enumerated.item[0] > 3)
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ changed = value->value.enumerated.item[0] != data->input_sel;
+ if (changed) {
+ data->input_sel = value->value.enumerated.item[0];
+
+ ret = input_source_apply(chip);
+ if (ret >= 0)
+ ret = input_volume_apply(chip,
+ data->input_vol[data->input_sel][0],
+ data->input_vol[data->input_sel][1]);
+ changed = ret >= 0 ? 1 : ret;
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+/* ADC high-pass filter */
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+ static const char *const names[2] = { "Active", "Frozen" };
+
+ return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+
+ value->value.enumerated.item[0] =
+ !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
+ return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+ struct oxygen *chip = ctl->private_data;
+ struct dg *data = chip->model_data;
+ u8 reg;
+ int changed;
+
+ mutex_lock(&chip->mutex);
+ reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
+ if (value->value.enumerated.item[0])
+ reg |= CS4245_HPF_FREEZE;
+ changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL];
+ if (changed) {
+ data->cs4245_shadow[CS4245_ADC_CTRL] = reg;
+ cs4245_write_spi(chip, CS4245_ADC_CTRL);
+ }
+ mutex_unlock(&chip->mutex);
+ return changed;
+}
+
+#define INPUT_VOLUME(xname, index) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+ .info = input_vol_info, \
+ .get = input_vol_get, \
+ .put = input_vol_put, \
+ .tlv = { .p = pga_db_scale }, \
+ .private_value = index, \
+}
+static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0);
+static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200);
+static const struct snd_kcontrol_new dg_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Analog Output Playback Enum",
+ .info = output_select_info,
+ .get = output_select_get,
+ .put = output_select_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = hp_stereo_volume_info,
+ .get = hp_stereo_volume_get,
+ .put = hp_stereo_volume_put,
+ .tlv = { .p = hp_db_scale, },
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Headphone Playback Switch",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ctl_boolean_mono_info,
+ .get = hp_mute_get,
+ .put = hp_mute_put,
+ },
+ INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC),
+ INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC),
+ INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE),
+ INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = input_sel_info,
+ .get = input_sel_get,
+ .put = input_sel_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "ADC High-pass Filter Capture Enum",
+ .info = hpf_info,
+ .get = hpf_get,
+ .put = hpf_put,
+ },
+};
+
+static int dg_control_filter(struct snd_kcontrol_new *template)
+{
+ if (!strncmp(template->name, "Master Playback ", 16))
+ return 1;
+ return 0;
+}
+
+static int dg_mixer_init(struct oxygen *chip)
+{
+ unsigned int i;
+ int err;
+
+ output_select_apply(chip);
+ input_source_apply(chip);
+ oxygen_update_dac_routing(chip);
+
+ for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&dg_controls[i], chip));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+struct oxygen_model model_xonar_dg = {
+ .longname = "C-Media Oxygen HD Audio",
+ .chip = "CMI8786",
+ .init = dg_init,
+ .control_filter = dg_control_filter,
+ .mixer_init = dg_mixer_init,
+ .cleanup = dg_cleanup,
+ .suspend = dg_suspend,
+ .resume = dg_resume,
+ .set_dac_params = set_cs4245_dac_params,
+ .set_adc_params = set_cs4245_adc_params,
+ .adjust_dac_routing = adjust_dg_dac_routing,
+ .dump_registers = dump_cs4245_registers,
+ .model_data_size = sizeof(struct dg),
+ .device_config = PLAYBACK_0_TO_I2S |
+ PLAYBACK_1_TO_SPDIF |
+ CAPTURE_0_FROM_I2S_1 |
+ CAPTURE_1_FROM_SPDIF,
+ .dac_channels_pcm = 6,
+ .dac_channels_mixer = 0,
+ .function_flags = OXYGEN_FUNCTION_SPI,
+ .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+ .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+ .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index bb9ebc5543d7..0236363c301f 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -350,9 +350,8 @@ snd_rme96_playback_copy(struct snd_pcm_substream *substream,
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
count <<= rme96->playback_frlog;
pos <<= rme96->playback_frlog;
- copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src,
- count);
- return 0;
+ return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src,
+ count);
}
static int
@@ -365,9 +364,8 @@ snd_rme96_capture_copy(struct snd_pcm_substream *substream,
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
count <<= rme96->capture_frlog;
pos <<= rme96->capture_frlog;
- copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos,
- count);
- return 0;
+ return copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos,
+ count);
}
/*
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 4f255dfee450..bd90c80bb494 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -584,10 +584,6 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
{
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
dmab->dev.dev = snd_dma_pci_data(pci);
- if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
- if (dmab->bytes >= size)
- return 0;
- }
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
size, dmab) < 0)
return -ENOMEM;
@@ -596,10 +592,8 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
{
- if (dmab->area) {
- dmab->dev.dev = NULL; /* make it anonymous */
- snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
- }
+ if (dmab->area)
+ snd_dma_free_pages(dmab);
}
@@ -4845,6 +4839,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne
if ((err = hdsp_get_iobox_version(hdsp)) < 0)
return err;
}
+ memset(&hdsp_version, 0, sizeof(hdsp_version));
hdsp_version.io_type = hdsp->io_type;
hdsp_version.firmware_rev = hdsp->firmware_rev;
if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version))))
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 3cde55b753e2..e98dc008de0b 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -3996,7 +3996,6 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
return 1;
}
return 0;
- break;
case AES32:
status = hdspm_read(hdspm, HDSPM_statusRegister);
if (status & HDSPM_tcoLockAes) {
@@ -4006,9 +4005,6 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
return 1;
}
return 0;
-
- break;
-
case RayDAT:
case AIO:
status = hdspm_read(hdspm, HDSPM_RD_STATUS_1);
@@ -4018,7 +4014,6 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm)
if (status & 0x4000000)
return 1; /* Lock */
return 0; /* No signal */
- break;
default:
break;
@@ -6405,7 +6400,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
memset(&hdspm_version, 0, sizeof(hdspm_version));
hdspm_version.card_type = hdspm->io_type;
- strncpy(hdspm_version.cardname, hdspm->card_name,
+ strlcpy(hdspm_version.cardname, hdspm->card_name,
sizeof(hdspm_version.cardname));
hdspm_version.serial = hdspm->serial;
hdspm_version.firmware_rev = hdspm->firmware_rev;
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index b96d9e1adf6d..1503ee3585fd 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -285,7 +285,7 @@ static char channel_map_9636_ds[26] = {
/* ADAT channels are remapped */
1, 3, 5, 7, 9, 11, 13, 15,
/* channels 8 and 9 are S/PDIF */
- 24, 25
+ 24, 25,
/* others don't exist */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
@@ -294,10 +294,6 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
{
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
dmab->dev.dev = snd_dma_pci_data(pci);
- if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) {
- if (dmab->bytes >= size)
- return 0;
- }
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
size, dmab) < 0)
return -ENOMEM;
@@ -306,10 +302,8 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer
static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci)
{
- if (dmab->area) {
- dmab->dev.dev = NULL; /* make it anonymous */
- snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci));
- }
+ if (dmab->area)
+ snd_dma_free_pages(dmab);
}
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 01aecc2b5073..0d1c27e911b8 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -65,7 +65,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
* already bound. If not it means binding failed, and then there
* is no point in keeping the device instantiated.
*/
- if (!keywest_ctx->client->driver) {
+ if (!keywest_ctx->client->dev.driver) {
i2c_unregister_device(keywest_ctx->client);
keywest_ctx->client = NULL;
return -ENODEV;
@@ -76,7 +76,7 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
* This is safe because i2c-core holds the core_lock mutex for us.
*/
list_add_tail(&keywest_ctx->client->detected,
- &keywest_ctx->client->driver->clients);
+ &to_i2c_driver(keywest_ctx->client->dev.driver)->clients);
return 0;
}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index c93fbbb201fe..7a43c0c38316 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -28,6 +28,8 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <sound/core.h>
#include "pmac.h"
#include <sound/pcm_params.h>
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 8c7dcbe0118d..ebb76f2d90d7 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -933,8 +933,10 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
int i, ret;
u64 lpar_addr, lpar_size;
- BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
- BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND);
+ if (WARN_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)))
+ return -ENODEV;
+ if (WARN_ON(dev->match_id != PS3_MATCH_ID_SOUND))
+ return -ENODEV;
the_card.ps3_dev = dev;
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index b23354a4ceca..b9ffc17a4799 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/string.h>
+#include <linux/of_irq.h>
#include <sound/core.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 5138b8493051..d62ce483a443 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -31,8 +31,10 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
select SND_DMAENGINE_PCM
# All the supported SoCs
+source "sound/soc/adi/Kconfig"
source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
+source "sound/soc/bcm/Kconfig"
source "sound/soc/blackfin/Kconfig"
source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig"
@@ -42,7 +44,7 @@ source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
-source "sound/soc/mid-x86/Kconfig"
+source "sound/soc/intel/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/samsung/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 61a64d281905..62a1822e77bf 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,5 +1,5 @@
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
-snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
+snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
@@ -8,15 +8,17 @@ endif
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
+obj-$(CONFIG_SND_SOC) += adi/
obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
+obj-$(CONFIG_SND_SOC) += bcm/
obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += jz4740/
-obj-$(CONFIG_SND_SOC) += mid-x86/
+obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
diff --git a/sound/soc/adi/Kconfig b/sound/soc/adi/Kconfig
new file mode 100644
index 000000000000..dd763f55edac
--- /dev/null
+++ b/sound/soc/adi/Kconfig
@@ -0,0 +1,21 @@
+config SND_SOC_ADI
+ tristate "Audio support for Analog Devices reference designs"
+ depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST
+ help
+ Audio support for various reference designs by Analog Devices.
+
+config SND_SOC_ADI_AXI_I2S
+ tristate "AXI-I2S support"
+ depends on SND_SOC_ADI
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ ASoC driver for the Analog Devices AXI-I2S softcore peripheral.
+
+config SND_SOC_ADI_AXI_SPDIF
+ tristate "AXI-SPDIF support"
+ depends on SND_SOC_ADI
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ ASoC driver for the Analog Devices AXI-SPDIF softcore peripheral.
diff --git a/sound/soc/adi/Makefile b/sound/soc/adi/Makefile
new file mode 100644
index 000000000000..64456c1e5347
--- /dev/null
+++ b/sound/soc/adi/Makefile
@@ -0,0 +1,5 @@
+snd-soc-adi-axi-i2s-objs := axi-i2s.o
+snd-soc-adi-axi-spdif-objs := axi-spdif.o
+
+obj-$(CONFIG_SND_SOC_ADI_AXI_I2S) += snd-soc-adi-axi-i2s.o
+obj-$(CONFIG_SND_SOC_ADI_AXI_SPDIF) += snd-soc-adi-axi-spdif.o
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c
new file mode 100644
index 000000000000..6058c1fd5070
--- /dev/null
+++ b/sound/soc/adi/axi-i2s.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2012-2013, Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#define AXI_I2S_REG_RESET 0x00
+#define AXI_I2S_REG_CTRL 0x04
+#define AXI_I2S_REG_CLK_CTRL 0x08
+#define AXI_I2S_REG_STATUS 0x10
+
+#define AXI_I2S_REG_RX_FIFO 0x28
+#define AXI_I2S_REG_TX_FIFO 0x2C
+
+#define AXI_I2S_RESET_GLOBAL BIT(0)
+#define AXI_I2S_RESET_TX_FIFO BIT(1)
+#define AXI_I2S_RESET_RX_FIFO BIT(2)
+
+#define AXI_I2S_CTRL_TX_EN BIT(0)
+#define AXI_I2S_CTRL_RX_EN BIT(1)
+
+/* The frame size is configurable, but for now we always set it 64 bit */
+#define AXI_I2S_BITS_PER_FRAME 64
+
+struct axi_i2s {
+ struct regmap *regmap;
+ struct clk *clk;
+ struct clk *clk_ref;
+
+ struct snd_soc_dai_driver dai_driver;
+
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+
+ struct snd_ratnum ratnum;
+ struct snd_pcm_hw_constraint_ratnums rate_constraints;
+};
+
+static int axi_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int mask, val;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mask = AXI_I2S_CTRL_RX_EN;
+ else
+ mask = AXI_I2S_CTRL_TX_EN;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ val = mask;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(i2s->regmap, AXI_I2S_REG_CTRL, mask, val);
+
+ return 0;
+}
+
+static int axi_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ unsigned int bclk_div, word_size;
+ unsigned int bclk_rate;
+
+ bclk_rate = params_rate(params) * AXI_I2S_BITS_PER_FRAME;
+
+ word_size = AXI_I2S_BITS_PER_FRAME / 2 - 1;
+ bclk_div = DIV_ROUND_UP(clk_get_rate(i2s->clk_ref), bclk_rate) / 2 - 1;
+
+ regmap_write(i2s->regmap, AXI_I2S_REG_CLK_CTRL, (word_size << 16) |
+ bclk_div);
+
+ return 0;
+}
+
+static int axi_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ uint32_t mask;
+ int ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mask = AXI_I2S_RESET_RX_FIFO;
+ else
+ mask = AXI_I2S_RESET_TX_FIFO;
+
+ regmap_write(i2s->regmap, AXI_I2S_REG_RESET, mask);
+
+ ret = snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &i2s->rate_constraints);
+ if (ret)
+ return ret;
+
+ return clk_prepare_enable(i2s->clk_ref);
+}
+
+static void axi_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(i2s->clk_ref);
+}
+
+static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
+ &i2s->capture_dma_data);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops axi_i2s_dai_ops = {
+ .startup = axi_i2s_startup,
+ .shutdown = axi_i2s_shutdown,
+ .trigger = axi_i2s_trigger,
+ .hw_params = axi_i2s_hw_params,
+};
+
+static struct snd_soc_dai_driver axi_i2s_dai = {
+ .probe = axi_i2s_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
+ },
+ .ops = &axi_i2s_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver axi_i2s_component = {
+ .name = "axi-i2s",
+};
+
+static const struct regmap_config axi_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = AXI_I2S_REG_STATUS,
+};
+
+static int axi_i2s_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct axi_i2s *i2s;
+ void __iomem *base;
+ int ret;
+
+ i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
+ if (!i2s)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, i2s);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ i2s->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &axi_i2s_regmap_config);
+ if (IS_ERR(i2s->regmap))
+ return PTR_ERR(i2s->regmap);
+
+ i2s->clk = devm_clk_get(&pdev->dev, "axi");
+ if (IS_ERR(i2s->clk))
+ return PTR_ERR(i2s->clk);
+
+ i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");
+ if (IS_ERR(i2s->clk_ref))
+ return PTR_ERR(i2s->clk_ref);
+
+ ret = clk_prepare_enable(i2s->clk);
+ if (ret)
+ return ret;
+
+ i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO;
+ i2s->playback_dma_data.addr_width = 4;
+ i2s->playback_dma_data.maxburst = 1;
+
+ i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO;
+ i2s->capture_dma_data.addr_width = 4;
+ i2s->capture_dma_data.maxburst = 1;
+
+ i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME;
+ i2s->ratnum.den_step = 1;
+ i2s->ratnum.den_min = 1;
+ i2s->ratnum.den_max = 64;
+
+ i2s->rate_constraints.rats = &i2s->ratnum;
+ i2s->rate_constraints.nrats = 1;
+
+ regmap_write(i2s->regmap, AXI_I2S_REG_RESET, AXI_I2S_RESET_GLOBAL);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &axi_i2s_component,
+ &axi_i2s_dai, 1);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_clk_disable;
+
+err_clk_disable:
+ clk_disable_unprepare(i2s->clk);
+ return ret;
+}
+
+static int axi_i2s_dev_remove(struct platform_device *pdev)
+{
+ struct axi_i2s *i2s = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2s->clk);
+
+ return 0;
+}
+
+static const struct of_device_id axi_i2s_of_match[] = {
+ { .compatible = "adi,axi-i2s-1.00.a", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, axi_i2s_of_match);
+
+static struct platform_driver axi_i2s_driver = {
+ .driver = {
+ .name = "axi-i2s",
+ .owner = THIS_MODULE,
+ .of_match_table = axi_i2s_of_match,
+ },
+ .probe = axi_i2s_probe,
+ .remove = axi_i2s_dev_remove,
+};
+module_platform_driver(axi_i2s_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("AXI I2S driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c
new file mode 100644
index 000000000000..198e3a4640f6
--- /dev/null
+++ b/sound/soc/adi/axi-spdif.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012-2013, Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+#define AXI_SPDIF_REG_CTRL 0x0
+#define AXI_SPDIF_REG_STAT 0x4
+#define AXI_SPDIF_REG_TX_FIFO 0xc
+
+#define AXI_SPDIF_CTRL_TXDATA BIT(1)
+#define AXI_SPDIF_CTRL_TXEN BIT(0)
+#define AXI_SPDIF_CTRL_CLKDIV_OFFSET 8
+#define AXI_SPDIF_CTRL_CLKDIV_MASK (0xff << 8)
+
+#define AXI_SPDIF_FREQ_44100 (0x0 << 6)
+#define AXI_SPDIF_FREQ_48000 (0x1 << 6)
+#define AXI_SPDIF_FREQ_32000 (0x2 << 6)
+#define AXI_SPDIF_FREQ_NA (0x3 << 6)
+
+struct axi_spdif {
+ struct regmap *regmap;
+ struct clk *clk;
+ struct clk *clk_ref;
+
+ struct snd_dmaengine_dai_dma_data dma_data;
+
+ struct snd_ratnum ratnum;
+ struct snd_pcm_hw_constraint_ratnums rate_constraints;
+};
+
+static int axi_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+ unsigned int val;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ val = AXI_SPDIF_CTRL_TXDATA;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+ AXI_SPDIF_CTRL_TXDATA, val);
+
+ return 0;
+}
+
+static int axi_spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ unsigned int clkdiv, stat;
+
+ switch (params_rate(params)) {
+ case 32000:
+ stat = AXI_SPDIF_FREQ_32000;
+ break;
+ case 44100:
+ stat = AXI_SPDIF_FREQ_44100;
+ break;
+ case 48000:
+ stat = AXI_SPDIF_FREQ_48000;
+ break;
+ default:
+ stat = AXI_SPDIF_FREQ_NA;
+ break;
+ }
+
+ clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(spdif->clk_ref),
+ rate * 64 * 2) - 1;
+ clkdiv <<= AXI_SPDIF_CTRL_CLKDIV_OFFSET;
+
+ regmap_write(spdif->regmap, AXI_SPDIF_REG_STAT, stat);
+ regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+ AXI_SPDIF_CTRL_CLKDIV_MASK, clkdiv);
+
+ return 0;
+}
+
+static int axi_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+ struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL);
+
+ return 0;
+}
+
+static int axi_spdif_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &spdif->rate_constraints);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(spdif->clk_ref);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+ AXI_SPDIF_CTRL_TXEN, AXI_SPDIF_CTRL_TXEN);
+
+ return 0;
+}
+
+static void axi_spdif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axi_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+ regmap_update_bits(spdif->regmap, AXI_SPDIF_REG_CTRL,
+ AXI_SPDIF_CTRL_TXEN, 0);
+
+ clk_disable_unprepare(spdif->clk_ref);
+}
+
+static const struct snd_soc_dai_ops axi_spdif_dai_ops = {
+ .startup = axi_spdif_startup,
+ .shutdown = axi_spdif_shutdown,
+ .trigger = axi_spdif_trigger,
+ .hw_params = axi_spdif_hw_params,
+};
+
+static struct snd_soc_dai_driver axi_spdif_dai = {
+ .probe = axi_spdif_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &axi_spdif_dai_ops,
+};
+
+static const struct snd_soc_component_driver axi_spdif_component = {
+ .name = "axi-spdif",
+};
+
+static const struct regmap_config axi_spdif_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = AXI_SPDIF_REG_STAT,
+};
+
+static int axi_spdif_probe(struct platform_device *pdev)
+{
+ struct axi_spdif *spdif;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+
+ spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL);
+ if (!spdif)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, spdif);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ spdif->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &axi_spdif_regmap_config);
+ if (IS_ERR(spdif->regmap))
+ return PTR_ERR(spdif->regmap);
+
+ spdif->clk = devm_clk_get(&pdev->dev, "axi");
+ if (IS_ERR(spdif->clk))
+ return PTR_ERR(spdif->clk);
+
+ spdif->clk_ref = devm_clk_get(&pdev->dev, "ref");
+ if (IS_ERR(spdif->clk_ref))
+ return PTR_ERR(spdif->clk_ref);
+
+ ret = clk_prepare_enable(spdif->clk);
+ if (ret)
+ return ret;
+
+ spdif->dma_data.addr = res->start + AXI_SPDIF_REG_TX_FIFO;
+ spdif->dma_data.addr_width = 4;
+ spdif->dma_data.maxburst = 1;
+
+ spdif->ratnum.num = clk_get_rate(spdif->clk_ref) / 128;
+ spdif->ratnum.den_step = 1;
+ spdif->ratnum.den_min = 1;
+ spdif->ratnum.den_max = 64;
+
+ spdif->rate_constraints.rats = &spdif->ratnum;
+ spdif->rate_constraints.nrats = 1;
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &axi_spdif_component,
+ &axi_spdif_dai, 1);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_clk_disable;
+
+ return 0;
+
+err_clk_disable:
+ clk_disable_unprepare(spdif->clk);
+ return ret;
+}
+
+static int axi_spdif_dev_remove(struct platform_device *pdev)
+{
+ struct axi_spdif *spdif = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(spdif->clk);
+
+ return 0;
+}
+
+static const struct of_device_id axi_spdif_of_match[] = {
+ { .compatible = "adi,axi-spdif-tx-1.00.a", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, axi_spdif_of_match);
+
+static struct platform_driver axi_spdif_driver = {
+ .driver = {
+ .name = "axi-spdif",
+ .owner = THIS_MODULE,
+ .of_match_table = axi_spdif_of_match,
+ },
+ .probe = axi_spdif_probe,
+ .remove = axi_spdif_dev_remove,
+};
+module_platform_driver(axi_spdif_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("AXI SPDIF driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index e48d38a1b95c..e634eb78ed03 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -25,7 +25,7 @@ config SND_ATMEL_SOC_SSC
config SND_AT91_SOC_SAM9G20_WM8731
tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board"
- depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS
+ depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
select SND_ATMEL_SOC_PDC
select SND_ATMEL_SOC_SSC
select SND_SOC_WM8731
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index 06082e5e5dcb..b79a2a864513 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -50,7 +50,6 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
.period_bytes_min = 256, /* lighting DMA overhead */
.period_bytes_max = 2 * 0xffff, /* if 2 bytes format */
.periods_min = 8,
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c
index 054ea4d9326a..33ec592ecd75 100644
--- a/sound/soc/atmel/atmel-pcm-pdc.c
+++ b/sound/soc/atmel/atmel-pcm-pdc.c
@@ -58,7 +58,6 @@ static const struct snd_pcm_hardware atmel_pcm_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
.period_bytes_min = 32,
.period_bytes_max = 8192,
.periods_min = 2,
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index 3109db7b9017..8ae3fa5ac60a 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -50,7 +50,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
buf->area = dma_alloc_coherent(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%zu\n",
- (void *)buf->area, (void *)buf->addr, size);
+ (void *)buf->area, (void *)(long)buf->addr, size);
if (!buf->area)
return -ENOMEM;
@@ -68,18 +68,15 @@ int atmel_pcm_mmap(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL_GPL(atmel_pcm_mmap);
-static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32);
-
int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &atmel_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n");
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index bb53dea85b17..1ead3c977a51 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -648,7 +648,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
dma_params = ssc_p->dma_params[dir];
- ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+ ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error);
pr_debug("%s enabled SSC_SR=0x%08x\n",
@@ -657,6 +657,33 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
return 0;
}
+static int atmel_ssc_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+ struct atmel_pcm_dma_params *dma_params;
+ int dir;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = 0;
+ else
+ dir = 1;
+
+ dma_params = ssc_p->dma_params[dir];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+ break;
+ default:
+ ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
+ break;
+ }
+
+ return 0;
+}
#ifdef CONFIG_PM
static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
@@ -731,6 +758,7 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.startup = atmel_ssc_startup,
.shutdown = atmel_ssc_shutdown,
.prepare = atmel_ssc_prepare,
+ .trigger = atmel_ssc_trigger,
.hw_params = atmel_ssc_hw_params,
.set_fmt = atmel_ssc_set_dai_fmt,
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
@@ -777,7 +805,7 @@ static int asoc_ssc_init(struct device *dev)
if (ret) {
dev_err(dev, "Could not register PCM: %d\n", ret);
goto err_unregister_dai;
- };
+ }
return 0;
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index 7222380131ea..b4e36901a40b 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
#include <sound/soc.h>
@@ -155,15 +154,8 @@ static int atmel_asoc_wm8904_probe(struct platform_device *pdev)
struct snd_soc_card *card = &atmel_asoc_wm8904_card;
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
struct clk *clk_src;
- struct pinctrl *pinctrl;
int id, ret;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- dev_err(&pdev->dev, "failed to request pinctrl\n");
- return PTR_ERR(pinctrl);
- }
-
card->dev = &pdev->dev;
ret = atmel_asoc_wm8904_dt_init(pdev);
if (ret) {
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 802717eccbd0..f15bff1548f8 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -37,6 +37,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/of.h>
#include <linux/atmel-ssc.h>
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
index 992ae38d5a15..3188036a18f0 100644
--- a/sound/soc/atmel/sam9x5_wm8731.c
+++ b/sound/soc/atmel/sam9x5_wm8731.c
@@ -97,6 +97,8 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
goto out;
}
+ snd_soc_card_set_drvdata(card, priv);
+
card->dev = &pdev->dev;
card->owner = THIS_MODULE;
card->dai_link = dai;
@@ -107,7 +109,7 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
dai->stream_name = "WM8731 PCM";
dai->codec_dai_name = "wm8731-hifi";
dai->init = sam9x5_wm8731_init;
- dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ dai->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM;
ret = snd_soc_of_parse_card_name(card, "atmel,model");
@@ -153,8 +155,6 @@ static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
of_node_put(codec_np);
of_node_put(cpu_np);
- platform_set_drvdata(pdev, card);
-
ret = snd_soc_register_card(card);
if (ret) {
dev_err(&pdev->dev,
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 3b4eafaf30d3..17a24d804734 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -65,19 +65,10 @@ struct au1xpsc_audio_dmadata {
#define AU1XPSC_PERIOD_MIN_BYTES 1024
#define AU1XPSC_BUFFER_MIN_BYTES 65536
-#define AU1XPSC_PCM_FMTS \
- (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
- SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
- SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
- SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
- 0)
-
/* PCM hardware DMA capabilities - platform specific */
static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
- .formats = AU1XPSC_PCM_FMTS,
.period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
.period_bytes_max = 4096 * 1024 - 1,
.periods_min = 2,
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
index befd1074f9bd..e920b60bf6c2 100644
--- a/sound/soc/au1x/dma.c
+++ b/sound/soc/au1x/dma.c
@@ -21,14 +21,6 @@
#include "psc.h"
-#define ALCHEMY_PCM_FMTS \
- (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
- SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
- SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
- SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
- 0)
-
struct pcm_period {
u32 start;
u32 relative_end; /* relative to start of buffer */
@@ -171,12 +163,6 @@ static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
static const struct snd_pcm_hardware alchemy_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
- .formats = ALCHEMY_PCM_FMTS,
- .rates = SNDRV_PCM_RATE_8000_192000,
- .rate_min = SNDRV_PCM_RATE_8000,
- .rate_max = SNDRV_PCM_RATE_192000,
- .channels_min = 2,
- .channels_max = 2,
.period_bytes_min = 1024,
.period_bytes_max = 16 * 1024 - 1,
.periods_min = 4,
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
new file mode 100644
index 000000000000..6a834e109f1d
--- /dev/null
+++ b/sound/soc/bcm/Kconfig
@@ -0,0 +1,9 @@
+config SND_BCM2835_SOC_I2S
+ tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the BCM2835 I2S interface. You will also need
+ to select the audio interfaces to support below.
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile
new file mode 100644
index 000000000000..bc816b71e5a4
--- /dev/null
+++ b/sound/soc/bcm/Makefile
@@ -0,0 +1,5 @@
+# BCM2835 Platform Support
+snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o
+
+obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o
+
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
new file mode 100644
index 000000000000..2685fe4f8427
--- /dev/null
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -0,0 +1,879 @@
+/*
+ * ALSA SoC I2S Audio Layer for Broadcom BCM2835 SoC
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * Based on
+ * Raspberry Pi PCM I2S ALSA Driver
+ * Copyright (c) by Phil Poole 2013
+ *
+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor
+ * Vladimir Barinov, <vbarinov@embeddedalley.com>
+ * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com>
+ *
+ * OMAP ALSA SoC DAI driver using McBSP port
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
+ * Peter Ujfalusi <peter.ujfalusi@ti.com>
+ *
+ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver
+ * Author: Timur Tabi <timur@freescale.com>
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+/* Clock registers */
+#define BCM2835_CLK_PCMCTL_REG 0x00
+#define BCM2835_CLK_PCMDIV_REG 0x04
+
+/* Clock register settings */
+#define BCM2835_CLK_PASSWD (0x5a000000)
+#define BCM2835_CLK_PASSWD_MASK (0xff000000)
+#define BCM2835_CLK_MASH(v) ((v) << 9)
+#define BCM2835_CLK_FLIP BIT(8)
+#define BCM2835_CLK_BUSY BIT(7)
+#define BCM2835_CLK_KILL BIT(5)
+#define BCM2835_CLK_ENAB BIT(4)
+#define BCM2835_CLK_SRC(v) (v)
+
+#define BCM2835_CLK_SHIFT (12)
+#define BCM2835_CLK_DIVI(v) ((v) << BCM2835_CLK_SHIFT)
+#define BCM2835_CLK_DIVF(v) (v)
+#define BCM2835_CLK_DIVF_MASK (0xFFF)
+
+enum {
+ BCM2835_CLK_MASH_0 = 0,
+ BCM2835_CLK_MASH_1,
+ BCM2835_CLK_MASH_2,
+ BCM2835_CLK_MASH_3,
+};
+
+enum {
+ BCM2835_CLK_SRC_GND = 0,
+ BCM2835_CLK_SRC_OSC,
+ BCM2835_CLK_SRC_DBG0,
+ BCM2835_CLK_SRC_DBG1,
+ BCM2835_CLK_SRC_PLLA,
+ BCM2835_CLK_SRC_PLLC,
+ BCM2835_CLK_SRC_PLLD,
+ BCM2835_CLK_SRC_HDMI,
+};
+
+/* Most clocks are not useable (freq = 0) */
+static const unsigned int bcm2835_clk_freq[BCM2835_CLK_SRC_HDMI+1] = {
+ [BCM2835_CLK_SRC_GND] = 0,
+ [BCM2835_CLK_SRC_OSC] = 19200000,
+ [BCM2835_CLK_SRC_DBG0] = 0,
+ [BCM2835_CLK_SRC_DBG1] = 0,
+ [BCM2835_CLK_SRC_PLLA] = 0,
+ [BCM2835_CLK_SRC_PLLC] = 0,
+ [BCM2835_CLK_SRC_PLLD] = 500000000,
+ [BCM2835_CLK_SRC_HDMI] = 0,
+};
+
+/* I2S registers */
+#define BCM2835_I2S_CS_A_REG 0x00
+#define BCM2835_I2S_FIFO_A_REG 0x04
+#define BCM2835_I2S_MODE_A_REG 0x08
+#define BCM2835_I2S_RXC_A_REG 0x0c
+#define BCM2835_I2S_TXC_A_REG 0x10
+#define BCM2835_I2S_DREQ_A_REG 0x14
+#define BCM2835_I2S_INTEN_A_REG 0x18
+#define BCM2835_I2S_INTSTC_A_REG 0x1c
+#define BCM2835_I2S_GRAY_REG 0x20
+
+/* I2S register settings */
+#define BCM2835_I2S_STBY BIT(25)
+#define BCM2835_I2S_SYNC BIT(24)
+#define BCM2835_I2S_RXSEX BIT(23)
+#define BCM2835_I2S_RXF BIT(22)
+#define BCM2835_I2S_TXE BIT(21)
+#define BCM2835_I2S_RXD BIT(20)
+#define BCM2835_I2S_TXD BIT(19)
+#define BCM2835_I2S_RXR BIT(18)
+#define BCM2835_I2S_TXW BIT(17)
+#define BCM2835_I2S_CS_RXERR BIT(16)
+#define BCM2835_I2S_CS_TXERR BIT(15)
+#define BCM2835_I2S_RXSYNC BIT(14)
+#define BCM2835_I2S_TXSYNC BIT(13)
+#define BCM2835_I2S_DMAEN BIT(9)
+#define BCM2835_I2S_RXTHR(v) ((v) << 7)
+#define BCM2835_I2S_TXTHR(v) ((v) << 5)
+#define BCM2835_I2S_RXCLR BIT(4)
+#define BCM2835_I2S_TXCLR BIT(3)
+#define BCM2835_I2S_TXON BIT(2)
+#define BCM2835_I2S_RXON BIT(1)
+#define BCM2835_I2S_EN (1)
+
+#define BCM2835_I2S_CLKDIS BIT(28)
+#define BCM2835_I2S_PDMN BIT(27)
+#define BCM2835_I2S_PDME BIT(26)
+#define BCM2835_I2S_FRXP BIT(25)
+#define BCM2835_I2S_FTXP BIT(24)
+#define BCM2835_I2S_CLKM BIT(23)
+#define BCM2835_I2S_CLKI BIT(22)
+#define BCM2835_I2S_FSM BIT(21)
+#define BCM2835_I2S_FSI BIT(20)
+#define BCM2835_I2S_FLEN(v) ((v) << 10)
+#define BCM2835_I2S_FSLEN(v) (v)
+
+#define BCM2835_I2S_CHWEX BIT(15)
+#define BCM2835_I2S_CHEN BIT(14)
+#define BCM2835_I2S_CHPOS(v) ((v) << 4)
+#define BCM2835_I2S_CHWID(v) (v)
+#define BCM2835_I2S_CH1(v) ((v) << 16)
+#define BCM2835_I2S_CH2(v) (v)
+
+#define BCM2835_I2S_TX_PANIC(v) ((v) << 24)
+#define BCM2835_I2S_RX_PANIC(v) ((v) << 16)
+#define BCM2835_I2S_TX(v) ((v) << 8)
+#define BCM2835_I2S_RX(v) (v)
+
+#define BCM2835_I2S_INT_RXERR BIT(3)
+#define BCM2835_I2S_INT_TXERR BIT(2)
+#define BCM2835_I2S_INT_RXR BIT(1)
+#define BCM2835_I2S_INT_TXW BIT(0)
+
+/* I2S DMA interface */
+/* FIXME: Needs IOMMU support */
+#define BCM2835_VCMMU_SHIFT (0x7E000000 - 0x20000000)
+
+/* General device struct */
+struct bcm2835_i2s_dev {
+ struct device *dev;
+ struct snd_dmaengine_dai_dma_data dma_data[2];
+ unsigned int fmt;
+ unsigned int bclk_ratio;
+
+ struct regmap *i2s_regmap;
+ struct regmap *clk_regmap;
+};
+
+static void bcm2835_i2s_start_clock(struct bcm2835_i2s_dev *dev)
+{
+ /* Start the clock if in master mode */
+ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+
+ switch (master) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+ BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
+ break;
+ default:
+ break;
+ }
+}
+
+static void bcm2835_i2s_stop_clock(struct bcm2835_i2s_dev *dev)
+{
+ uint32_t clkreg;
+ int timeout = 1000;
+
+ /* Stop clock */
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+ BCM2835_CLK_PASSWD);
+
+ /* Wait for the BUSY flag going down */
+ while (--timeout) {
+ regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
+ if (!(clkreg & BCM2835_CLK_BUSY))
+ break;
+ }
+
+ if (!timeout) {
+ /* KILL the clock */
+ dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n");
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_KILL | BCM2835_CLK_PASSWD_MASK,
+ BCM2835_CLK_KILL | BCM2835_CLK_PASSWD);
+ }
+}
+
+static void bcm2835_i2s_clear_fifos(struct bcm2835_i2s_dev *dev,
+ bool tx, bool rx)
+{
+ int timeout = 1000;
+ uint32_t syncval;
+ uint32_t csreg;
+ uint32_t i2s_active_state;
+ uint32_t clkreg;
+ uint32_t clk_active_state;
+ uint32_t off;
+ uint32_t clr;
+
+ off = tx ? BCM2835_I2S_TXON : 0;
+ off |= rx ? BCM2835_I2S_RXON : 0;
+
+ clr = tx ? BCM2835_I2S_TXCLR : 0;
+ clr |= rx ? BCM2835_I2S_RXCLR : 0;
+
+ /* Backup the current state */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+ i2s_active_state = csreg & (BCM2835_I2S_RXON | BCM2835_I2S_TXON);
+
+ regmap_read(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, &clkreg);
+ clk_active_state = clkreg & BCM2835_CLK_ENAB;
+
+ /* Start clock if not running */
+ if (!clk_active_state) {
+ regmap_update_bits(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
+ BCM2835_CLK_PASSWD_MASK | BCM2835_CLK_ENAB,
+ BCM2835_CLK_PASSWD | BCM2835_CLK_ENAB);
+ }
+
+ /* Stop I2S module */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, off, 0);
+
+ /*
+ * Clear the FIFOs
+ * Requires at least 2 PCM clock cycles to take effect
+ */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, clr, clr);
+
+ /* Wait for 2 PCM clock cycles */
+
+ /*
+ * Toggle the SYNC flag. After 2 PCM clock cycles it can be read back
+ * FIXME: This does not seem to work for slave mode!
+ */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &syncval);
+ syncval &= BCM2835_I2S_SYNC;
+
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_SYNC, ~syncval);
+
+ /* Wait for the SYNC flag changing it's state */
+ while (--timeout) {
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+ if ((csreg & BCM2835_I2S_SYNC) != syncval)
+ break;
+ }
+
+ if (!timeout)
+ dev_err(dev->dev, "I2S SYNC error!\n");
+
+ /* Stop clock if it was not running before */
+ if (!clk_active_state)
+ bcm2835_i2s_stop_clock(dev);
+
+ /* Restore I2S state */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_RXON | BCM2835_I2S_TXON, i2s_active_state);
+}
+
+static int bcm2835_i2s_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ dev->fmt = fmt;
+ return 0;
+}
+
+static int bcm2835_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+ unsigned int ratio)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ dev->bclk_ratio = ratio;
+ return 0;
+}
+
+static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ unsigned int sampling_rate = params_rate(params);
+ unsigned int data_length, data_delay, bclk_ratio;
+ unsigned int ch1pos, ch2pos, mode, format;
+ unsigned int mash = BCM2835_CLK_MASH_1;
+ unsigned int divi, divf, target_frequency;
+ int clk_src = -1;
+ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+ bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS
+ || master == SND_SOC_DAIFMT_CBS_CFM);
+
+ bool frame_master = (master == SND_SOC_DAIFMT_CBS_CFS
+ || master == SND_SOC_DAIFMT_CBM_CFS);
+ uint32_t csreg;
+
+ /*
+ * If a stream is already enabled,
+ * the registers are already set properly.
+ */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &csreg);
+
+ if (csreg & (BCM2835_I2S_TXON | BCM2835_I2S_RXON))
+ return 0;
+
+ /*
+ * Adjust the data length according to the format.
+ * We prefill the half frame length with an integer
+ * divider of 2400 as explained at the clock settings.
+ * Maybe it is overwritten there, if the Integer mode
+ * does not apply.
+ */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ data_length = 16;
+ bclk_ratio = 40;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ data_length = 32;
+ bclk_ratio = 80;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* If bclk_ratio already set, use that one. */
+ if (dev->bclk_ratio)
+ bclk_ratio = dev->bclk_ratio;
+
+ /*
+ * Clock Settings
+ *
+ * The target frequency of the bit clock is
+ * sampling rate * frame length
+ *
+ * Integer mode:
+ * Sampling rates that are multiples of 8000 kHz
+ * can be driven by the oscillator of 19.2 MHz
+ * with an integer divider as long as the frame length
+ * is an integer divider of 19200000/8000=2400 as set up above.
+ * This is no longer possible if the sampling rate
+ * is too high (e.g. 192 kHz), because the oscillator is too slow.
+ *
+ * MASH mode:
+ * For all other sampling rates, it is not possible to
+ * have an integer divider. Approximate the clock
+ * with the MASH module that induces a slight frequency
+ * variance. To minimize that it is best to have the fastest
+ * clock here. That is PLLD with 500 MHz.
+ */
+ target_frequency = sampling_rate * bclk_ratio;
+ clk_src = BCM2835_CLK_SRC_OSC;
+ mash = BCM2835_CLK_MASH_0;
+
+ if (bcm2835_clk_freq[clk_src] % target_frequency == 0
+ && bit_master && frame_master) {
+ divi = bcm2835_clk_freq[clk_src] / target_frequency;
+ divf = 0;
+ } else {
+ uint64_t dividend;
+
+ if (!dev->bclk_ratio) {
+ /*
+ * Overwrite bclk_ratio, because the
+ * above trick is not needed or can
+ * not be used.
+ */
+ bclk_ratio = 2 * data_length;
+ }
+
+ target_frequency = sampling_rate * bclk_ratio;
+
+ clk_src = BCM2835_CLK_SRC_PLLD;
+ mash = BCM2835_CLK_MASH_1;
+
+ dividend = bcm2835_clk_freq[clk_src];
+ dividend <<= BCM2835_CLK_SHIFT;
+ do_div(dividend, target_frequency);
+ divi = dividend >> BCM2835_CLK_SHIFT;
+ divf = dividend & BCM2835_CLK_DIVF_MASK;
+ }
+
+ /* Set clock divider */
+ regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
+ | BCM2835_CLK_DIVI(divi)
+ | BCM2835_CLK_DIVF(divf));
+
+ /* Setup clock, but don't start it yet */
+ regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
+ | BCM2835_CLK_MASH(mash)
+ | BCM2835_CLK_SRC(clk_src));
+
+ /* Setup the frame format */
+ format = BCM2835_I2S_CHEN;
+
+ if (data_length > 24)
+ format |= BCM2835_I2S_CHWEX;
+
+ format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
+
+ switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ data_delay = 1;
+ break;
+ default:
+ /*
+ * TODO
+ * Others are possible but are not implemented at the moment.
+ */
+ dev_err(dev->dev, "%s:bad format\n", __func__);
+ return -EINVAL;
+ }
+
+ ch1pos = data_delay;
+ ch2pos = bclk_ratio / 2 + data_delay;
+
+ switch (params_channels(params)) {
+ case 2:
+ format = BCM2835_I2S_CH1(format) | BCM2835_I2S_CH2(format);
+ format |= BCM2835_I2S_CH1(BCM2835_I2S_CHPOS(ch1pos));
+ format |= BCM2835_I2S_CH2(BCM2835_I2S_CHPOS(ch2pos));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Set format for both streams.
+ * We cannot set another frame length
+ * (and therefore word length) anyway,
+ * so the format will be the same.
+ */
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_RXC_A_REG, format);
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_TXC_A_REG, format);
+
+ /* Setup the I2S mode */
+ mode = 0;
+
+ if (data_length <= 16) {
+ /*
+ * Use frame packed mode (2 channels per 32 bit word)
+ * We cannot set another frame length in the second stream
+ * (and therefore word length) anyway,
+ * so the format will be the same.
+ */
+ mode |= BCM2835_I2S_FTXP | BCM2835_I2S_FRXP;
+ }
+
+ mode |= BCM2835_I2S_FLEN(bclk_ratio - 1);
+ mode |= BCM2835_I2S_FSLEN(bclk_ratio / 2);
+
+ /* Master or slave? */
+ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ /*
+ * CODEC is bit clock master
+ * CPU is frame master
+ */
+ mode |= BCM2835_I2S_CLKM;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ /*
+ * CODEC is frame master
+ * CPU is bit clock master
+ */
+ mode |= BCM2835_I2S_FSM;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CODEC is master */
+ mode |= BCM2835_I2S_CLKM;
+ mode |= BCM2835_I2S_FSM;
+ break;
+ default:
+ dev_err(dev->dev, "%s:bad master\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Invert clocks?
+ *
+ * The BCM approach seems to be inverted to the classical I2S approach.
+ */
+ switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* None. Therefore, both for BCM */
+ mode |= BCM2835_I2S_CLKI;
+ mode |= BCM2835_I2S_FSI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Both. Therefore, none for BCM */
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /*
+ * Invert only frame sync. Therefore,
+ * invert only bit clock for BCM
+ */
+ mode |= BCM2835_I2S_CLKI;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /*
+ * Invert only bit clock. Therefore,
+ * invert only frame sync for BCM
+ */
+ mode |= BCM2835_I2S_FSI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_write(dev->i2s_regmap, BCM2835_I2S_MODE_A_REG, mode);
+
+ /* Setup the DMA parameters */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_RXTHR(1)
+ | BCM2835_I2S_TXTHR(1)
+ | BCM2835_I2S_DMAEN, 0xffffffff);
+
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_DREQ_A_REG,
+ BCM2835_I2S_TX_PANIC(0x10)
+ | BCM2835_I2S_RX_PANIC(0x30)
+ | BCM2835_I2S_TX(0x30)
+ | BCM2835_I2S_RX(0x20), 0xffffffff);
+
+ /* Clear FIFOs */
+ bcm2835_i2s_clear_fifos(dev, true, true);
+
+ return 0;
+}
+
+static int bcm2835_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ uint32_t cs_reg;
+
+ bcm2835_i2s_start_clock(dev);
+
+ /*
+ * Clear both FIFOs if the one that should be started
+ * is not empty at the moment. This should only happen
+ * after overrun. Otherwise, hw_params would have cleared
+ * the FIFO.
+ */
+ regmap_read(dev->i2s_regmap, BCM2835_I2S_CS_A_REG, &cs_reg);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+ && !(cs_reg & BCM2835_I2S_TXE))
+ bcm2835_i2s_clear_fifos(dev, true, false);
+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE
+ && (cs_reg & BCM2835_I2S_RXD))
+ bcm2835_i2s_clear_fifos(dev, false, true);
+
+ return 0;
+}
+
+static void bcm2835_i2s_stop(struct bcm2835_i2s_dev *dev,
+ struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ uint32_t mask;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mask = BCM2835_I2S_RXON;
+ else
+ mask = BCM2835_I2S_TXON;
+
+ regmap_update_bits(dev->i2s_regmap,
+ BCM2835_I2S_CS_A_REG, mask, 0);
+
+ /* Stop also the clock when not SND_SOC_DAIFMT_CONT */
+ if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT))
+ bcm2835_i2s_stop_clock(dev);
+}
+
+static int bcm2835_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ uint32_t mask;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ bcm2835_i2s_start_clock(dev);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ mask = BCM2835_I2S_RXON;
+ else
+ mask = BCM2835_I2S_TXON;
+
+ regmap_update_bits(dev->i2s_regmap,
+ BCM2835_I2S_CS_A_REG, mask, mask);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ bcm2835_i2s_stop(dev, substream, dai);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bcm2835_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ if (dai->active)
+ return 0;
+
+ /* Should this still be running stop it */
+ bcm2835_i2s_stop_clock(dev);
+
+ /* Enable PCM block */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_EN, BCM2835_I2S_EN);
+
+ /*
+ * Disable STBY.
+ * Requires at least 4 PCM clock cycles to take effect.
+ */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_STBY, BCM2835_I2S_STBY);
+
+ return 0;
+}
+
+static void bcm2835_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ bcm2835_i2s_stop(dev, substream, dai);
+
+ /* If both streams are stopped, disable module and clock */
+ if (dai->active)
+ return;
+
+ /* Disable the module */
+ regmap_update_bits(dev->i2s_regmap, BCM2835_I2S_CS_A_REG,
+ BCM2835_I2S_EN, 0);
+
+ /*
+ * Stopping clock is necessary, because stop does
+ * not stop the clock when SND_SOC_DAIFMT_CONT
+ */
+ bcm2835_i2s_stop_clock(dev);
+}
+
+static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
+ .startup = bcm2835_i2s_startup,
+ .shutdown = bcm2835_i2s_shutdown,
+ .prepare = bcm2835_i2s_prepare,
+ .trigger = bcm2835_i2s_trigger,
+ .hw_params = bcm2835_i2s_hw_params,
+ .set_fmt = bcm2835_i2s_set_dai_fmt,
+ .set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio
+};
+
+static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct bcm2835_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai,
+ &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
+ &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver bcm2835_i2s_dai = {
+ .name = "bcm2835-i2s",
+ .probe = bcm2835_i2s_dai_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE
+ | SNDRV_PCM_FMTBIT_S32_LE
+ },
+ .ops = &bcm2835_i2s_dai_ops,
+ .symmetric_rates = 1
+};
+
+static bool bcm2835_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case BCM2835_I2S_CS_A_REG:
+ case BCM2835_I2S_FIFO_A_REG:
+ case BCM2835_I2S_INTSTC_A_REG:
+ case BCM2835_I2S_GRAY_REG:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool bcm2835_i2s_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case BCM2835_I2S_FIFO_A_REG:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool bcm2835_clk_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case BCM2835_CLK_PCMCTL_REG:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config bcm2835_regmap_config[] = {
+ {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = BCM2835_I2S_GRAY_REG,
+ .precious_reg = bcm2835_i2s_precious_reg,
+ .volatile_reg = bcm2835_i2s_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ },
+ {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = BCM2835_CLK_PCMDIV_REG,
+ .volatile_reg = bcm2835_clk_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+ },
+};
+
+static const struct snd_soc_component_driver bcm2835_i2s_component = {
+ .name = "bcm2835-i2s-comp",
+};
+
+static int bcm2835_i2s_probe(struct platform_device *pdev)
+{
+ struct bcm2835_i2s_dev *dev;
+ int i;
+ int ret;
+ struct regmap *regmap[2];
+ struct resource *mem[2];
+
+ /* Request both ioareas */
+ for (i = 0; i <= 1; i++) {
+ void __iomem *base;
+
+ mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ base = devm_ioremap_resource(&pdev->dev, mem[i]);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap[i] = devm_regmap_init_mmio(&pdev->dev, base,
+ &bcm2835_regmap_config[i]);
+ if (IS_ERR(regmap[i]))
+ return PTR_ERR(regmap[i]);
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->i2s_regmap = regmap[0];
+ dev->clk_regmap = regmap[1];
+
+ /* Set the DMA address */
+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
+ (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+ + BCM2835_VCMMU_SHIFT;
+
+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
+ (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
+ + BCM2835_VCMMU_SHIFT;
+
+ /* Set the bus width */
+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
+ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width =
+ DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+ /* Set burst */
+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2;
+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2;
+
+ /* BCLK ratio - use default */
+ dev->bclk_ratio = 0;
+
+ /* Store the pdev */
+ dev->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, dev);
+
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &bcm2835_i2s_component, &bcm2835_i2s_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_i2s_of_match[] = {
+ { .compatible = "brcm,bcm2835-i2s", },
+ {},
+};
+
+static struct platform_driver bcm2835_i2s_driver = {
+ .probe = bcm2835_i2s_probe,
+ .driver = {
+ .name = "bcm2835-i2s",
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_i2s_of_match,
+ },
+};
+
+module_platform_driver(bcm2835_i2s_driver);
+
+MODULE_ALIAS("platform:bcm2835-i2s");
+MODULE_DESCRIPTION("BCM2835 I2S interface");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 54f74f8cbb75..4544d8eb1452 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -11,7 +11,7 @@ config SND_BF5XX_I2S
config SND_BF5XX_SOC_SSM2602
tristate "SoC SSM2602 Audio Codec Add-On Card support"
- depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+ depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S if !BF60x
select SND_BF6XX_SOC_I2S if BF60x
select SND_SOC_SSM2602
@@ -21,10 +21,9 @@ config SND_BF5XX_SOC_SSM2602
config SND_SOC_BFIN_EVAL_ADAU1701
tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && I2C
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAU1701
- select I2C
help
Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
board connected to one of the Blackfin evaluation boards like the
@@ -45,7 +44,7 @@ config SND_SOC_BFIN_EVAL_ADAU1373
config SND_SOC_BFIN_EVAL_ADAV80X
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
- depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+ depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S
select SND_SOC_ADAV80X
help
@@ -58,7 +57,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X
config SND_BF5XX_SOC_AD1836
tristate "SoC AD1836 Audio support for BF5xx"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && SPI_MASTER
select SND_BF5XX_SOC_I2S
select SND_SOC_AD1836
help
@@ -66,7 +65,7 @@ config SND_BF5XX_SOC_AD1836
config SND_BF5XX_SOC_AD193X
tristate "SoC AD193X Audio support for Blackfin"
- depends on SND_BF5XX_I2S
+ depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
select SND_BF5XX_SOC_I2S
select SND_SOC_AD193X
help
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 53f84085bf1f..cdb8ee75ded9 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -107,7 +107,6 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
#endif
SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
.period_bytes_min = 32,
.period_bytes_max = 0x10000,
.periods_min = 1,
@@ -415,19 +414,16 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
}
-static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-
static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
pr_debug("%s enter\n", __func__);
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &bf5xx_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 9cb4a80df98e..a3881c4381c9 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -52,9 +52,6 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = 32,
.period_bytes_max = 0x10000,
.periods_min = 1,
@@ -323,18 +320,16 @@ static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
.silence = bf5xx_pcm_silence,
};
-static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
-
static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
+ int ret;
pr_debug("%s enter\n", __func__);
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &bf5xx_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
SNDRV_DMA_TYPE_DEV, card->dev, size, size);
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index 9a174fc47d39..39d774839b3e 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -121,6 +121,7 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
bf5xx_i2s->tcr2 |= 7;
bf5xx_i2s->rcr2 |= 7;
sport_handle->wdsize = 1;
+ break;
case SNDRV_PCM_FORMAT_S16_LE:
bf5xx_i2s->tcr2 |= 15;
bf5xx_i2s->rcr2 |= 15;
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index 695351241db8..9dfa1241ea66 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -179,8 +179,9 @@ static inline int sport_hook_rx_dummy(struct sport_device *sport)
struct dmasg *desc, temp_desc;
unsigned long flags;
- BUG_ON(sport->dummy_rx_desc == NULL);
- BUG_ON(sport->curr_rx_desc == sport->dummy_rx_desc);
+ if (WARN_ON(!sport->dummy_rx_desc) ||
+ WARN_ON(sport->curr_rx_desc == sport->dummy_rx_desc))
+ return -EINVAL;
/* Maybe the dummy buffer descriptor ring is damaged */
sport->dummy_rx_desc->next_desc_addr = sport->dummy_rx_desc + 1;
@@ -250,8 +251,9 @@ int sport_rx_start(struct sport_device *sport)
return -EBUSY;
if (sport->tx_run) {
/* tx is running, rx is not running */
- BUG_ON(sport->dma_rx_desc == NULL);
- BUG_ON(sport->curr_rx_desc != sport->dummy_rx_desc);
+ if (WARN_ON(!sport->dma_rx_desc) ||
+ WARN_ON(sport->curr_rx_desc != sport->dummy_rx_desc))
+ return -EINVAL;
local_irq_save(flags);
while ((get_dma_curr_desc_ptr(sport->dma_rx_chan) -
sizeof(struct dmasg)) != sport->dummy_rx_desc)
@@ -298,8 +300,9 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport)
struct dmasg *desc, temp_desc;
unsigned long flags;
- BUG_ON(sport->dummy_tx_desc == NULL);
- BUG_ON(sport->curr_tx_desc == sport->dummy_tx_desc);
+ if (WARN_ON(!sport->dummy_tx_desc) ||
+ WARN_ON(sport->curr_tx_desc == sport->dummy_tx_desc))
+ return -EINVAL;
sport->dummy_tx_desc->next_desc_addr = sport->dummy_tx_desc + 1;
@@ -331,8 +334,9 @@ int sport_tx_start(struct sport_device *sport)
if (sport->tx_run)
return -EBUSY;
if (sport->rx_run) {
- BUG_ON(sport->dma_tx_desc == NULL);
- BUG_ON(sport->curr_tx_desc != sport->dummy_tx_desc);
+ if (WARN_ON(!sport->dma_tx_desc) ||
+ WARN_ON(sport->curr_tx_desc != sport->dummy_tx_desc))
+ return -EINVAL;
/* Hook the normal buffer descriptor */
local_irq_save(flags);
while ((get_dma_curr_desc_ptr(sport->dma_tx_chan) -
@@ -767,7 +771,8 @@ static irqreturn_t err_handler(int irq, void *dev_id)
int sport_set_rx_callback(struct sport_device *sport,
void (*rx_callback)(void *), void *rx_data)
{
- BUG_ON(rx_callback == NULL);
+ if (WARN_ON(!rx_callback))
+ return -EINVAL;
sport->rx_callback = rx_callback;
sport->rx_data = rx_data;
@@ -778,7 +783,8 @@ EXPORT_SYMBOL(sport_set_rx_callback);
int sport_set_tx_callback(struct sport_device *sport,
void (*tx_callback)(void *), void *tx_data)
{
- BUG_ON(tx_callback == NULL);
+ if (WARN_ON(!tx_callback))
+ return -EINVAL;
sport->tx_callback = tx_callback;
sport->tx_data = tx_data;
@@ -789,7 +795,8 @@ EXPORT_SYMBOL(sport_set_tx_callback);
int sport_set_err_callback(struct sport_device *sport,
void (*err_callback)(void *), void *err_data)
{
- BUG_ON(err_callback == NULL);
+ if (WARN_ON(!err_callback))
+ return -EINVAL;
sport->err_callback = err_callback;
sport->err_data = err_data;
@@ -856,7 +863,8 @@ struct sport_device *sport_init(struct platform_device *pdev,
param.wdsize = wdsize;
param.dummy_count = dummy_count;
- BUG_ON(param.wdsize == 0 || param.dummy_count == 0);
+ if (WARN_ON(param.wdsize == 0 || param.dummy_count == 0))
+ return NULL;
ret = sport_config_pdev(pdev, &param);
if (ret)
diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c
index c02405cc007d..5810a0603f2f 100644
--- a/sound/soc/blackfin/bf6xx-i2s.c
+++ b/sound/soc/blackfin/bf6xx-i2s.c
@@ -88,6 +88,7 @@ static int bfin_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S8:
param.spctl |= 0x70;
sport->wdsize = 1;
+ break;
case SNDRV_PCM_FORMAT_S16_LE:
param.spctl |= 0xf0;
sport->wdsize = 2;
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
index 2c20f01e1f7e..06f938deda15 100644
--- a/sound/soc/cirrus/Kconfig
+++ b/sound/soc/cirrus/Kconfig
@@ -1,6 +1,6 @@
config SND_EP93XX_SOC
tristate "SoC Audio support for the Cirrus Logic EP93xx series"
- depends on ARCH_EP93XX && SND_SOC
+ depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index c43fb214558a..4f900efc437c 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -63,7 +63,7 @@ static struct snd_soc_ops edb93xx_ops = {
static struct snd_soc_dai_link edb93xx_dai = {
.name = "CS4271",
.stream_name = "CS4271 HiFi",
- .platform_name = "ep93xx-pcm-audio",
+ .platform_name = "ep93xx-i2s",
.cpu_dai_name = "ep93xx-i2s",
.codec_name = "spi0.0",
.codec_dai_name = "cs4271-hifi",
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index efa75b5086a4..f30dadf85b99 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -19,11 +19,14 @@
#include <linux/slab.h>
#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
#include <sound/ac97_codec.h>
#include <sound/soc.h>
#include <linux/platform_data/dma-ep93xx.h>
+#include "ep93xx-pcm.h"
+
/*
* Per channel (1-4) registers.
*/
@@ -95,6 +98,8 @@ struct ep93xx_ac97_info {
struct device *dev;
void __iomem *regs;
struct completion done;
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
};
/* currently ALSA only supports a single AC97 device */
@@ -315,8 +320,13 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
static int ep93xx_ac97_dai_probe(struct snd_soc_dai *dai)
{
- dai->playback_dma_data = &ep93xx_ac97_pcm_out;
- dai->capture_dma_data = &ep93xx_ac97_pcm_in;
+ struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
+
+ info->dma_params_tx.filter_data = &ep93xx_ac97_pcm_out;
+ info->dma_params_rx.filter_data = &ep93xx_ac97_pcm_in;
+
+ dai->playback_dma_data = &info->dma_params_tx;
+ dai->capture_dma_data = &info->dma_params_rx;
return 0;
}
@@ -394,8 +404,14 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
if (ret)
goto fail;
+ ret = devm_ep93xx_pcm_platform_register(&pdev->dev);
+ if (ret)
+ goto fail_unregister;
+
return 0;
+fail_unregister:
+ snd_soc_unregister_component(&pdev->dev);
fail:
ep93xx_ac97_info = NULL;
snd_soc_set_ac97_ops(NULL);
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index a57643d6402f..943145f9d1b6 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
@@ -30,6 +31,8 @@
#include <mach/ep93xx-regs.h>
#include <linux/platform_data/dma-ep93xx.h>
+#include "ep93xx-pcm.h"
+
#define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04
#define EP93XX_I2S_GLCTRL 0x0C
@@ -61,6 +64,8 @@ struct ep93xx_i2s_info {
struct clk *sclk;
struct clk *lrclk;
void __iomem *regs;
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
};
static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
@@ -140,8 +145,15 @@ static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
{
- dai->playback_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
- dai->capture_dma_data = &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
+ struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
+
+ info->dma_params_tx.filter_data =
+ &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
+ info->dma_params_rx.filter_data =
+ &ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
+
+ dai->playback_dma_data = &info->dma_params_tx;
+ dai->capture_dma_data = &info->dma_params_rx;
return 0;
}
@@ -405,8 +417,14 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
if (err)
goto fail_put_lrclk;
+ err = devm_ep93xx_pcm_platform_register(&pdev->dev);
+ if (err)
+ goto fail_unregister;
+
return 0;
+fail_unregister:
+ snd_soc_unregister_component(&pdev->dev);
fail_put_lrclk:
clk_put(info->lrclk);
fail_put_sclk:
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
index 0e9f56e0d4b2..5f664471d99e 100644
--- a/sound/soc/cirrus/ep93xx-pcm.c
+++ b/sound/soc/cirrus/ep93xx-pcm.c
@@ -23,20 +23,13 @@
#include <linux/platform_data/dma-ep93xx.h>
+#include "ep93xx-pcm.h"
+
static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER),
-
- .rates = SNDRV_PCM_RATE_8000_192000,
- .rate_min = SNDRV_PCM_RATE_8000,
- .rate_max = SNDRV_PCM_RATE_192000,
-
- .formats = (SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE),
-
.buffer_bytes_max = 131072,
.period_bytes_min = 32,
.period_bytes_max = 32768,
@@ -63,34 +56,16 @@ static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
.prealloc_buffer_size = 131072,
};
-static int ep93xx_soc_platform_probe(struct platform_device *pdev)
+int devm_ep93xx_pcm_platform_register(struct device *dev)
{
- return snd_dmaengine_pcm_register(&pdev->dev,
+ return devm_snd_dmaengine_pcm_register(dev,
&ep93xx_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
-
-static int ep93xx_soc_platform_remove(struct platform_device *pdev)
-{
- snd_dmaengine_pcm_unregister(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver ep93xx_pcm_driver = {
- .driver = {
- .name = "ep93xx-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = ep93xx_soc_platform_probe,
- .remove = ep93xx_soc_platform_remove,
-};
-
-module_platform_driver(ep93xx_pcm_driver);
+EXPORT_SYMBOL_GPL(devm_ep93xx_pcm_platform_register);
MODULE_AUTHOR("Ryan Mallon");
MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ep93xx-pcm-audio");
diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
new file mode 100644
index 000000000000..b7a12a2fae9c
--- /dev/null
+++ b/sound/soc/cirrus/ep93xx-pcm.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __EP93XX_PCM_H__
+#define __EP93XX_PCM_H__
+
+int devm_ep93xx_pcm_platform_register(struct device *dev);
+
+#endif
diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c
index 4d094d00c34a..822a19a89e74 100644
--- a/sound/soc/cirrus/simone.c
+++ b/sound/soc/cirrus/simone.c
@@ -27,7 +27,7 @@ static struct snd_soc_dai_link simone_dai = {
.cpu_dai_name = "ep93xx-ac97",
.codec_dai_name = "ac97-hifi",
.codec_name = "ac97-codec",
- .platform_name = "ep93xx-pcm-audio",
+ .platform_name = "ep93xx-ac97",
};
static struct snd_soc_card snd_soc_simone = {
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 69041074f2c1..29238a7476dd 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -83,7 +83,7 @@ static struct snd_soc_dai_link snappercl15_dai = {
.cpu_dai_name = "ep93xx-i2s",
.codec_dai_name = "tlv320aic23-hifi",
.codec_name = "tlv320aic23-codec.0-001a",
- .platform_name = "ep93xx-pcm-audio",
+ .platform_name = "ep93xx-i2s",
.init = snappercl15_tlv320aic23_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
SND_SOC_DAIFMT_CBS_CFS,
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
index 8af04343cc1a..75d0ad5d2dcb 100644
--- a/sound/soc/codecs/88pm860x-codec.c
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -16,6 +16,7 @@
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -140,6 +141,7 @@ struct pm860x_priv {
unsigned int filter;
struct snd_soc_codec *codec;
struct i2c_client *i2c;
+ struct regmap *regmap;
struct pm860x_chip *chip;
struct pm860x_det det;
@@ -269,48 +271,6 @@ static struct st_gain st_table[] = {
{ -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0},
};
-static int pm860x_volatile(unsigned int reg)
-{
- BUG_ON(reg >= REG_CACHE_SIZE);
-
- switch (reg) {
- case PM860X_AUDIO_SUPPLIES_2:
- return 1;
- }
-
- return 0;
-}
-
-static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- unsigned char *cache = codec->reg_cache;
-
- BUG_ON(reg >= REG_CACHE_SIZE);
-
- if (pm860x_volatile(reg))
- return cache[reg];
-
- reg += REG_CACHE_BASE;
-
- return pm860x_reg_read(codec->control_data, reg);
-}
-
-static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
-{
- unsigned char *cache = codec->reg_cache;
-
- BUG_ON(reg >= REG_CACHE_SIZE);
-
- if (!pm860x_volatile(reg))
- cache[reg] = (unsigned char)value;
-
- reg += REG_CACHE_BASE;
-
- return pm860x_reg_write(codec->control_data, reg, value);
-}
-
static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -349,6 +309,9 @@ static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
val = ucontrol->value.integer.value[0];
val2 = ucontrol->value.integer.value[1];
+ if (val >= ARRAY_SIZE(st_table) || val2 >= ARRAY_SIZE(st_table))
+ return -EINVAL;
+
err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
if (err < 0)
return err;
@@ -1166,6 +1129,7 @@ static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int pm860x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
int data;
switch (level) {
@@ -1179,17 +1143,17 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Enable Audio PLL & Audio section */
data = AUDIO_PLL | AUDIO_SECTION_ON;
- pm860x_reg_write(codec->control_data, REG_MISC2, data);
+ pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
udelay(300);
data = AUDIO_PLL | AUDIO_SECTION_RESET
| AUDIO_SECTION_ON;
- pm860x_reg_write(codec->control_data, REG_MISC2, data);
+ pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
}
break;
case SND_SOC_BIAS_OFF:
data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
- pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
+ pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
break;
}
codec->dapm.bias_level = level;
@@ -1319,17 +1283,17 @@ int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
pm860x->det.lo_shrt = lo_shrt;
if (det & SND_JACK_HEADPHONE)
- pm860x_set_bits(codec->control_data, REG_HS_DET,
+ pm860x_set_bits(pm860x->i2c, REG_HS_DET,
EN_HS_DET, EN_HS_DET);
/* headset short detect */
if (hs_shrt) {
data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
- pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+ pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
}
/* Lineout short detect */
if (lo_shrt) {
data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
- pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+ pm860x_set_bits(pm860x->i2c, REG_SHORTS, data, data);
}
/* sync status */
@@ -1347,7 +1311,7 @@ int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
pm860x->det.mic_det = det;
if (det & SND_JACK_MICROPHONE)
- pm860x_set_bits(codec->control_data, REG_MIC_DET,
+ pm860x_set_bits(pm860x->i2c, REG_MIC_DET,
MICDET_MASK, MICDET_MASK);
/* sync status */
@@ -1363,7 +1327,7 @@ static int pm860x_probe(struct snd_soc_codec *codec)
pm860x->codec = codec;
- codec->control_data = pm860x->i2c;
+ codec->control_data = pm860x->regmap;
for (i = 0; i < 4; i++) {
ret = request_threaded_irq(pm860x->irq[i], NULL,
@@ -1377,14 +1341,6 @@ static int pm860x_probe(struct snd_soc_codec *codec)
pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
- REG_CACHE_SIZE, codec->reg_cache);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to fill register cache: %d\n",
- ret);
- goto out;
- }
-
return 0;
out:
@@ -1407,10 +1363,6 @@ static int pm860x_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
.probe = pm860x_probe,
.remove = pm860x_remove,
- .read = pm860x_read_reg_cache,
- .write = pm860x_write_reg_cache,
- .reg_cache_size = REG_CACHE_SIZE,
- .reg_word_size = sizeof(u8),
.set_bias_level = pm860x_set_bias_level,
.controls = pm860x_snd_controls,
@@ -1436,6 +1388,8 @@ static int pm860x_codec_probe(struct platform_device *pdev)
pm860x->chip = chip;
pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
: chip->companion;
+ pm860x->regmap = (chip->id == CHIP_PM8607) ? chip->regmap
+ : chip->regmap_companion;
platform_set_drvdata(pdev, pm860x);
for (i = 0; i < 4; i++) {
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
index 3364ba4a3607..f7282f4f4a79 100644
--- a/sound/soc/codecs/88pm860x-codec.h
+++ b/sound/soc/codecs/88pm860x-codec.h
@@ -12,67 +12,66 @@
#ifndef __88PM860X_H
#define __88PM860X_H
-/* The offset of these registers are 0xb0 */
-#define PM860X_PCM_IFACE_1 0x00
-#define PM860X_PCM_IFACE_2 0x01
-#define PM860X_PCM_IFACE_3 0x02
-#define PM860X_PCM_RATE 0x03
-#define PM860X_EC_PATH 0x04
-#define PM860X_SIDETONE_L_GAIN 0x05
-#define PM860X_SIDETONE_R_GAIN 0x06
-#define PM860X_SIDETONE_SHIFT 0x07
-#define PM860X_ADC_OFFSET_1 0x08
-#define PM860X_ADC_OFFSET_2 0x09
-#define PM860X_DMIC_DELAY 0x0a
+#define PM860X_PCM_IFACE_1 0xb0
+#define PM860X_PCM_IFACE_2 0xb1
+#define PM860X_PCM_IFACE_3 0xb2
+#define PM860X_PCM_RATE 0xb3
+#define PM860X_EC_PATH 0xb4
+#define PM860X_SIDETONE_L_GAIN 0xb5
+#define PM860X_SIDETONE_R_GAIN 0xb6
+#define PM860X_SIDETONE_SHIFT 0xb7
+#define PM860X_ADC_OFFSET_1 0xb8
+#define PM860X_ADC_OFFSET_2 0xb9
+#define PM860X_DMIC_DELAY 0xba
-#define PM860X_I2S_IFACE_1 0x0b
-#define PM860X_I2S_IFACE_2 0x0c
-#define PM860X_I2S_IFACE_3 0x0d
-#define PM860X_I2S_IFACE_4 0x0e
-#define PM860X_EQUALIZER_N0_1 0x0f
-#define PM860X_EQUALIZER_N0_2 0x10
-#define PM860X_EQUALIZER_N1_1 0x11
-#define PM860X_EQUALIZER_N1_2 0x12
-#define PM860X_EQUALIZER_D1_1 0x13
-#define PM860X_EQUALIZER_D1_2 0x14
-#define PM860X_LOFI_GAIN_LEFT 0x15
-#define PM860X_LOFI_GAIN_RIGHT 0x16
-#define PM860X_HIFIL_GAIN_LEFT 0x17
-#define PM860X_HIFIL_GAIN_RIGHT 0x18
-#define PM860X_HIFIR_GAIN_LEFT 0x19
-#define PM860X_HIFIR_GAIN_RIGHT 0x1a
-#define PM860X_DAC_OFFSET 0x1b
-#define PM860X_OFFSET_LEFT_1 0x1c
-#define PM860X_OFFSET_LEFT_2 0x1d
-#define PM860X_OFFSET_RIGHT_1 0x1e
-#define PM860X_OFFSET_RIGHT_2 0x1f
-#define PM860X_ADC_ANA_1 0x20
-#define PM860X_ADC_ANA_2 0x21
-#define PM860X_ADC_ANA_3 0x22
-#define PM860X_ADC_ANA_4 0x23
-#define PM860X_ANA_TO_ANA 0x24
-#define PM860X_HS1_CTRL 0x25
-#define PM860X_HS2_CTRL 0x26
-#define PM860X_LO1_CTRL 0x27
-#define PM860X_LO2_CTRL 0x28
-#define PM860X_EAR_CTRL_1 0x29
-#define PM860X_EAR_CTRL_2 0x2a
-#define PM860X_AUDIO_SUPPLIES_1 0x2b
-#define PM860X_AUDIO_SUPPLIES_2 0x2c
-#define PM860X_ADC_EN_1 0x2d
-#define PM860X_ADC_EN_2 0x2e
-#define PM860X_DAC_EN_1 0x2f
-#define PM860X_DAC_EN_2 0x31
-#define PM860X_AUDIO_CAL_1 0x32
-#define PM860X_AUDIO_CAL_2 0x33
-#define PM860X_AUDIO_CAL_3 0x34
-#define PM860X_AUDIO_CAL_4 0x35
-#define PM860X_AUDIO_CAL_5 0x36
-#define PM860X_ANA_INPUT_SEL_1 0x37
-#define PM860X_ANA_INPUT_SEL_2 0x38
+#define PM860X_I2S_IFACE_1 0xbb
+#define PM860X_I2S_IFACE_2 0xbc
+#define PM860X_I2S_IFACE_3 0xbd
+#define PM860X_I2S_IFACE_4 0xbe
+#define PM860X_EQUALIZER_N0_1 0xbf
+#define PM860X_EQUALIZER_N0_2 0xc0
+#define PM860X_EQUALIZER_N1_1 0xc1
+#define PM860X_EQUALIZER_N1_2 0xc2
+#define PM860X_EQUALIZER_D1_1 0xc3
+#define PM860X_EQUALIZER_D1_2 0xc4
+#define PM860X_LOFI_GAIN_LEFT 0xc5
+#define PM860X_LOFI_GAIN_RIGHT 0xc6
+#define PM860X_HIFIL_GAIN_LEFT 0xc7
+#define PM860X_HIFIL_GAIN_RIGHT 0xc8
+#define PM860X_HIFIR_GAIN_LEFT 0xc9
+#define PM860X_HIFIR_GAIN_RIGHT 0xca
+#define PM860X_DAC_OFFSET 0xcb
+#define PM860X_OFFSET_LEFT_1 0xcc
+#define PM860X_OFFSET_LEFT_2 0xcd
+#define PM860X_OFFSET_RIGHT_1 0xce
+#define PM860X_OFFSET_RIGHT_2 0xcf
+#define PM860X_ADC_ANA_1 0xd0
+#define PM860X_ADC_ANA_2 0xd1
+#define PM860X_ADC_ANA_3 0xd2
+#define PM860X_ADC_ANA_4 0xd3
+#define PM860X_ANA_TO_ANA 0xd4
+#define PM860X_HS1_CTRL 0xd5
+#define PM860X_HS2_CTRL 0xd6
+#define PM860X_LO1_CTRL 0xd7
+#define PM860X_LO2_CTRL 0xd8
+#define PM860X_EAR_CTRL_1 0xd9
+#define PM860X_EAR_CTRL_2 0xda
+#define PM860X_AUDIO_SUPPLIES_1 0xdb
+#define PM860X_AUDIO_SUPPLIES_2 0xdc
+#define PM860X_ADC_EN_1 0xdd
+#define PM860X_ADC_EN_2 0xde
+#define PM860X_DAC_EN_1 0xdf
+#define PM860X_DAC_EN_2 0xe1
+#define PM860X_AUDIO_CAL_1 0xe2
+#define PM860X_AUDIO_CAL_2 0xe3
+#define PM860X_AUDIO_CAL_3 0xe4
+#define PM860X_AUDIO_CAL_4 0xe5
+#define PM860X_AUDIO_CAL_5 0xe6
+#define PM860X_ANA_INPUT_SEL_1 0xe7
+#define PM860X_ANA_INPUT_SEL_2 0xe8
-#define PM860X_PCM_IFACE_4 0x39
-#define PM860X_I2S_IFACE_5 0x3a
+#define PM860X_PCM_IFACE_4 0xe9
+#define PM860X_I2S_IFACE_5 0xea
#define PM860X_SHORTS 0x3b
#define PM860X_PLL_ADJ_1 0x3c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index b33b45dfceec..983d087aa92a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -163,8 +163,10 @@ config SND_SOC_WM_HUBS
config SND_SOC_WM_ADSP
tristate
default y if SND_SOC_WM5102=y
+ default y if SND_SOC_WM5110=y
default y if SND_SOC_WM2200=y
default m if SND_SOC_WM5102=m
+ default m if SND_SOC_WM5110=m
default m if SND_SOC_WM2200=m
config SND_SOC_AB8500_CODEC
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index b8ba0adacfce..1ad92cbf0b24 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -1225,13 +1225,18 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
struct device *dev = codec->dev;
bool apply_fir, apply_iir;
- int req, status;
+ unsigned int req;
+ int status;
dev_dbg(dev, "%s: Enter.\n", __func__);
mutex_lock(&drvdata->anc_lock);
req = ucontrol->value.integer.value[0];
+ if (req >= ARRAY_SIZE(enum_anc_state)) {
+ status = -EINVAL;
+ goto cleanup;
+ }
if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR &&
req != ANC_APPLY_IIR) {
dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n",
@@ -2307,17 +2312,17 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
case 0:
break;
case 1:
- slot = find_first_bit((unsigned long *)&tx_mask, 32);
+ slot = ffs(tx_mask);
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
break;
case 2:
- slot = find_first_bit((unsigned long *)&tx_mask, 32);
+ slot = ffs(tx_mask);
snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, slot);
- slot = find_next_bit((unsigned long *)&tx_mask, 32, slot + 1);
+ slot = fls(tx_mask);
snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, slot);
snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, slot);
break;
@@ -2348,18 +2353,18 @@ static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai,
case 0:
break;
case 1:
- slot = find_first_bit((unsigned long *)&rx_mask, 32);
+ slot = ffs(rx_mask);
snd_soc_update_bits(codec, AB8500_ADSLOTSEL(slot),
AB8500_MASK_SLOT(slot),
AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
break;
case 2:
- slot = find_first_bit((unsigned long *)&rx_mask, 32);
+ slot = ffs(rx_mask);
snd_soc_update_bits(codec,
AB8500_ADSLOTSEL(slot),
AB8500_MASK_SLOT(slot),
AB8500_ADSLOTSELX_AD_OUT_TO_SLOT(AB8500_AD_OUT3, slot));
- slot = find_next_bit((unsigned long *)&rx_mask, 32, slot + 1);
+ slot = fls(rx_mask);
snd_soc_update_bits(codec,
AB8500_ADSLOTSEL(slot),
AB8500_MASK_SLOT(slot),
@@ -2527,12 +2532,10 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
}
/* Override HW-defaults */
- ab8500_codec_write_reg(codec,
- AB8500_ANACONF5,
- BIT(AB8500_ANACONF5_HSAUTOEN));
- ab8500_codec_write_reg(codec,
- AB8500_SHORTCIRCONF,
- BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
+ snd_soc_write(codec, AB8500_ANACONF5,
+ BIT(AB8500_ANACONF5_HSAUTOEN));
+ snd_soc_write(codec, AB8500_SHORTCIRCONF,
+ BIT(AB8500_SHORTCIRCONF_HSZCDDIS));
/* Add filter controls */
status = snd_soc_add_codec_controls(codec, ab8500_filter_controls,
@@ -2583,6 +2586,8 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
/* Create driver private-data struct */
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata),
GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
drvdata->sid_status = SID_UNCONFIGURED;
drvdata->anc_status = ANC_UNCONFIGURED;
dev_set_drvdata(&pdev->dev, drvdata);
@@ -2601,7 +2606,7 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev)
static int ab8500_codec_driver_remove(struct platform_device *pdev)
{
- dev_info(&pdev->dev, "%s Enter.\n", __func__);
+ dev_dbg(&pdev->dev, "%s Enter.\n", __func__);
snd_soc_unregister_codec(&pdev->dev);
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 9a92b7962f41..77f459868579 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -168,17 +168,19 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
int word_len = 0;
/* bit size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
word_len = AD1836_WORD_LEN_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
word_len = AD1836_WORD_LEN_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 24:
+ case 32:
word_len = AD1836_WORD_LEN_24;
break;
+ default:
+ return -EINVAL;
}
regmap_update_bits(ad1836->regmap, AD1836_DAC_CTRL1,
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index aea7e52cf714..5a42dca535b7 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -249,15 +249,15 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
word_len = 3;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
word_len = 1;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 24:
+ case 32:
word_len = 0;
break;
}
@@ -413,7 +413,7 @@ static struct spi_driver ad193x_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static const struct regmap_config ad193x_i2c_regmap_config = {
.val_bits = 8,
@@ -470,7 +470,7 @@ static int __init ad193x_modinit(void)
{
int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&ad193x_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
@@ -495,7 +495,7 @@ static void __exit ad193x_modexit(void)
spi_unregister_driver(&ad193x_spi_driver);
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&ad193x_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 1aa10ddf3a61..eb836ed5271f 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -32,6 +32,7 @@ struct adau1373_dai {
};
struct adau1373 {
+ struct regmap *regmap;
struct adau1373_dai dais[3];
};
@@ -73,7 +74,6 @@ struct adau1373 {
#define ADAU1373_PLL_CTRL4(x) (0x2c + (x) * 7)
#define ADAU1373_PLL_CTRL5(x) (0x2d + (x) * 7)
#define ADAU1373_PLL_CTRL6(x) (0x2e + (x) * 7)
-#define ADAU1373_PLL_CTRL7(x) (0x2f + (x) * 7)
#define ADAU1373_HEADDECT 0x36
#define ADAU1373_ADC_DAC_STATUS 0x37
#define ADAU1373_ADC_CTRL 0x3c
@@ -152,37 +152,172 @@ struct adau1373 {
#define ADAU1373_EP_CTRL_MICBIAS1_OFFSET 4
#define ADAU1373_EP_CTRL_MICBIAS2_OFFSET 2
-static const uint8_t adau1373_default_regs[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x30 */
- 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x00, /* 0x40 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x80 */
- 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
- 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0x90 */
- 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
- 0x78, 0x18, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, /* 0xa0 */
- 0x00, 0xc0, 0x88, 0x7a, 0xdf, 0x20, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, /* 0xe0 */
- 0x00, 0x1f, 0x0f, 0x00, 0x00,
+static const struct reg_default adau1373_reg_defaults[] = {
+ { ADAU1373_INPUT_MODE, 0x00 },
+ { ADAU1373_AINL_CTRL(0), 0x00 },
+ { ADAU1373_AINR_CTRL(0), 0x00 },
+ { ADAU1373_AINL_CTRL(1), 0x00 },
+ { ADAU1373_AINR_CTRL(1), 0x00 },
+ { ADAU1373_AINL_CTRL(2), 0x00 },
+ { ADAU1373_AINR_CTRL(2), 0x00 },
+ { ADAU1373_AINL_CTRL(3), 0x00 },
+ { ADAU1373_AINR_CTRL(3), 0x00 },
+ { ADAU1373_LLINE_OUT(0), 0x00 },
+ { ADAU1373_RLINE_OUT(0), 0x00 },
+ { ADAU1373_LLINE_OUT(1), 0x00 },
+ { ADAU1373_RLINE_OUT(1), 0x00 },
+ { ADAU1373_LSPK_OUT, 0x00 },
+ { ADAU1373_RSPK_OUT, 0x00 },
+ { ADAU1373_LHP_OUT, 0x00 },
+ { ADAU1373_RHP_OUT, 0x00 },
+ { ADAU1373_ADC_GAIN, 0x00 },
+ { ADAU1373_LADC_MIXER, 0x00 },
+ { ADAU1373_RADC_MIXER, 0x00 },
+ { ADAU1373_LLINE1_MIX, 0x00 },
+ { ADAU1373_RLINE1_MIX, 0x00 },
+ { ADAU1373_LLINE2_MIX, 0x00 },
+ { ADAU1373_RLINE2_MIX, 0x00 },
+ { ADAU1373_LSPK_MIX, 0x00 },
+ { ADAU1373_RSPK_MIX, 0x00 },
+ { ADAU1373_LHP_MIX, 0x00 },
+ { ADAU1373_RHP_MIX, 0x00 },
+ { ADAU1373_EP_MIX, 0x00 },
+ { ADAU1373_HP_CTRL, 0x00 },
+ { ADAU1373_HP_CTRL2, 0x00 },
+ { ADAU1373_LS_CTRL, 0x00 },
+ { ADAU1373_EP_CTRL, 0x00 },
+ { ADAU1373_MICBIAS_CTRL1, 0x00 },
+ { ADAU1373_MICBIAS_CTRL2, 0x00 },
+ { ADAU1373_OUTPUT_CTRL, 0x00 },
+ { ADAU1373_PWDN_CTRL1, 0x00 },
+ { ADAU1373_PWDN_CTRL2, 0x00 },
+ { ADAU1373_PWDN_CTRL3, 0x00 },
+ { ADAU1373_DPLL_CTRL(0), 0x00 },
+ { ADAU1373_PLL_CTRL1(0), 0x00 },
+ { ADAU1373_PLL_CTRL2(0), 0x00 },
+ { ADAU1373_PLL_CTRL3(0), 0x00 },
+ { ADAU1373_PLL_CTRL4(0), 0x00 },
+ { ADAU1373_PLL_CTRL5(0), 0x00 },
+ { ADAU1373_PLL_CTRL6(0), 0x02 },
+ { ADAU1373_DPLL_CTRL(1), 0x00 },
+ { ADAU1373_PLL_CTRL1(1), 0x00 },
+ { ADAU1373_PLL_CTRL2(1), 0x00 },
+ { ADAU1373_PLL_CTRL3(1), 0x00 },
+ { ADAU1373_PLL_CTRL4(1), 0x00 },
+ { ADAU1373_PLL_CTRL5(1), 0x00 },
+ { ADAU1373_PLL_CTRL6(1), 0x02 },
+ { ADAU1373_HEADDECT, 0x00 },
+ { ADAU1373_ADC_CTRL, 0x00 },
+ { ADAU1373_CLK_SRC_DIV(0), 0x00 },
+ { ADAU1373_CLK_SRC_DIV(1), 0x00 },
+ { ADAU1373_DAI(0), 0x0a },
+ { ADAU1373_DAI(1), 0x0a },
+ { ADAU1373_DAI(2), 0x0a },
+ { ADAU1373_BCLKDIV(0), 0x00 },
+ { ADAU1373_BCLKDIV(1), 0x00 },
+ { ADAU1373_BCLKDIV(2), 0x00 },
+ { ADAU1373_SRC_RATIOA(0), 0x00 },
+ { ADAU1373_SRC_RATIOB(0), 0x00 },
+ { ADAU1373_SRC_RATIOA(1), 0x00 },
+ { ADAU1373_SRC_RATIOB(1), 0x00 },
+ { ADAU1373_SRC_RATIOA(2), 0x00 },
+ { ADAU1373_SRC_RATIOB(2), 0x00 },
+ { ADAU1373_DEEMP_CTRL, 0x00 },
+ { ADAU1373_SRC_DAI_CTRL(0), 0x08 },
+ { ADAU1373_SRC_DAI_CTRL(1), 0x08 },
+ { ADAU1373_SRC_DAI_CTRL(2), 0x08 },
+ { ADAU1373_DIN_MIX_CTRL(0), 0x00 },
+ { ADAU1373_DIN_MIX_CTRL(1), 0x00 },
+ { ADAU1373_DIN_MIX_CTRL(2), 0x00 },
+ { ADAU1373_DIN_MIX_CTRL(3), 0x00 },
+ { ADAU1373_DIN_MIX_CTRL(4), 0x00 },
+ { ADAU1373_DOUT_MIX_CTRL(0), 0x00 },
+ { ADAU1373_DOUT_MIX_CTRL(1), 0x00 },
+ { ADAU1373_DOUT_MIX_CTRL(2), 0x00 },
+ { ADAU1373_DOUT_MIX_CTRL(3), 0x00 },
+ { ADAU1373_DOUT_MIX_CTRL(4), 0x00 },
+ { ADAU1373_DAI_PBL_VOL(0), 0x00 },
+ { ADAU1373_DAI_PBR_VOL(0), 0x00 },
+ { ADAU1373_DAI_PBL_VOL(1), 0x00 },
+ { ADAU1373_DAI_PBR_VOL(1), 0x00 },
+ { ADAU1373_DAI_PBL_VOL(2), 0x00 },
+ { ADAU1373_DAI_PBR_VOL(2), 0x00 },
+ { ADAU1373_DAI_RECL_VOL(0), 0x00 },
+ { ADAU1373_DAI_RECR_VOL(0), 0x00 },
+ { ADAU1373_DAI_RECL_VOL(1), 0x00 },
+ { ADAU1373_DAI_RECR_VOL(1), 0x00 },
+ { ADAU1373_DAI_RECL_VOL(2), 0x00 },
+ { ADAU1373_DAI_RECR_VOL(2), 0x00 },
+ { ADAU1373_DAC1_PBL_VOL, 0x00 },
+ { ADAU1373_DAC1_PBR_VOL, 0x00 },
+ { ADAU1373_DAC2_PBL_VOL, 0x00 },
+ { ADAU1373_DAC2_PBR_VOL, 0x00 },
+ { ADAU1373_ADC_RECL_VOL, 0x00 },
+ { ADAU1373_ADC_RECR_VOL, 0x00 },
+ { ADAU1373_DMIC_RECL_VOL, 0x00 },
+ { ADAU1373_DMIC_RECR_VOL, 0x00 },
+ { ADAU1373_VOL_GAIN1, 0x00 },
+ { ADAU1373_VOL_GAIN2, 0x00 },
+ { ADAU1373_VOL_GAIN3, 0x00 },
+ { ADAU1373_HPF_CTRL, 0x00 },
+ { ADAU1373_BASS1, 0x00 },
+ { ADAU1373_BASS2, 0x00 },
+ { ADAU1373_DRC(0) + 0x0, 0x78 },
+ { ADAU1373_DRC(0) + 0x1, 0x18 },
+ { ADAU1373_DRC(0) + 0x2, 0x00 },
+ { ADAU1373_DRC(0) + 0x3, 0x00 },
+ { ADAU1373_DRC(0) + 0x4, 0x00 },
+ { ADAU1373_DRC(0) + 0x5, 0xc0 },
+ { ADAU1373_DRC(0) + 0x6, 0x00 },
+ { ADAU1373_DRC(0) + 0x7, 0x00 },
+ { ADAU1373_DRC(0) + 0x8, 0x00 },
+ { ADAU1373_DRC(0) + 0x9, 0xc0 },
+ { ADAU1373_DRC(0) + 0xa, 0x88 },
+ { ADAU1373_DRC(0) + 0xb, 0x7a },
+ { ADAU1373_DRC(0) + 0xc, 0xdf },
+ { ADAU1373_DRC(0) + 0xd, 0x20 },
+ { ADAU1373_DRC(0) + 0xe, 0x00 },
+ { ADAU1373_DRC(0) + 0xf, 0x00 },
+ { ADAU1373_DRC(1) + 0x0, 0x78 },
+ { ADAU1373_DRC(1) + 0x1, 0x18 },
+ { ADAU1373_DRC(1) + 0x2, 0x00 },
+ { ADAU1373_DRC(1) + 0x3, 0x00 },
+ { ADAU1373_DRC(1) + 0x4, 0x00 },
+ { ADAU1373_DRC(1) + 0x5, 0xc0 },
+ { ADAU1373_DRC(1) + 0x6, 0x00 },
+ { ADAU1373_DRC(1) + 0x7, 0x00 },
+ { ADAU1373_DRC(1) + 0x8, 0x00 },
+ { ADAU1373_DRC(1) + 0x9, 0xc0 },
+ { ADAU1373_DRC(1) + 0xa, 0x88 },
+ { ADAU1373_DRC(1) + 0xb, 0x7a },
+ { ADAU1373_DRC(1) + 0xc, 0xdf },
+ { ADAU1373_DRC(1) + 0xd, 0x20 },
+ { ADAU1373_DRC(1) + 0xe, 0x00 },
+ { ADAU1373_DRC(1) + 0xf, 0x00 },
+ { ADAU1373_DRC(2) + 0x0, 0x78 },
+ { ADAU1373_DRC(2) + 0x1, 0x18 },
+ { ADAU1373_DRC(2) + 0x2, 0x00 },
+ { ADAU1373_DRC(2) + 0x3, 0x00 },
+ { ADAU1373_DRC(2) + 0x4, 0x00 },
+ { ADAU1373_DRC(2) + 0x5, 0xc0 },
+ { ADAU1373_DRC(2) + 0x6, 0x00 },
+ { ADAU1373_DRC(2) + 0x7, 0x00 },
+ { ADAU1373_DRC(2) + 0x8, 0x00 },
+ { ADAU1373_DRC(2) + 0x9, 0xc0 },
+ { ADAU1373_DRC(2) + 0xa, 0x88 },
+ { ADAU1373_DRC(2) + 0xb, 0x7a },
+ { ADAU1373_DRC(2) + 0xc, 0xdf },
+ { ADAU1373_DRC(2) + 0xd, 0x20 },
+ { ADAU1373_DRC(2) + 0xe, 0x00 },
+ { ADAU1373_DRC(2) + 0xf, 0x00 },
+ { ADAU1373_3D_CTRL1, 0x00 },
+ { ADAU1373_3D_CTRL2, 0x00 },
+ { ADAU1373_FDSP_SEL1, 0x00 },
+ { ADAU1373_FDSP_SEL2, 0x00 },
+ { ADAU1373_FDSP_SEL2, 0x00 },
+ { ADAU1373_FDSP_SEL4, 0x00 },
+ { ADAU1373_DIGMICCTRL, 0x00 },
+ { ADAU1373_DIGEN, 0x00 },
};
static const unsigned int adau1373_out_tlv[] = {
@@ -418,6 +553,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int pll_id = w->name[3] - '1';
unsigned int val;
@@ -426,7 +562,7 @@ static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
else
val = 0;
- snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
+ regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
ADAU1373_PLL_CTRL6_PLL_EN, val);
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -938,28 +1074,28 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
adau1373_dai->enable_src = (div != 0);
- snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
+ regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),
ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
(div << 2) | ADAU1373_BCLKDIV_64);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
ctrl = ADAU1373_DAI_WLEN_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
ctrl = ADAU1373_DAI_WLEN_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
ctrl = ADAU1373_DAI_WLEN_24;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
ctrl = ADAU1373_DAI_WLEN_32;
break;
default:
return -EINVAL;
}
- return snd_soc_update_bits(codec, ADAU1373_DAI(dai->id),
+ return regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),
ADAU1373_DAI_WLEN_MASK, ctrl);
}
@@ -1016,7 +1152,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- snd_soc_update_bits(codec, ADAU1373_DAI(dai->id),
+ regmap_update_bits(adau1373->regmap, ADAU1373_DAI(dai->id),
~ADAU1373_DAI_WLEN_MASK, ctrl);
return 0;
@@ -1039,7 +1175,7 @@ static int adau1373_set_dai_sysclk(struct snd_soc_dai *dai,
adau1373_dai->sysclk = freq;
adau1373_dai->clk_src = clk_id;
- snd_soc_update_bits(dai->codec, ADAU1373_BCLKDIV(dai->id),
+ regmap_update_bits(adau1373->regmap, ADAU1373_BCLKDIV(dai->id),
ADAU1373_BCLKDIV_SOURCE, clk_id << 5);
return 0;
@@ -1120,6 +1256,7 @@ static struct snd_soc_dai_driver adau1373_dai_driver[] = {
static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out)
{
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int dpll_div = 0;
unsigned int x, r, n, m, i, j, mode;
@@ -1187,36 +1324,36 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
if (dpll_div) {
dpll_div = 11 - dpll_div;
- snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
+ regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
ADAU1373_PLL_CTRL6_DPLL_BYPASS, 0);
} else {
- snd_soc_update_bits(codec, ADAU1373_PLL_CTRL6(pll_id),
+ regmap_update_bits(adau1373->regmap, ADAU1373_PLL_CTRL6(pll_id),
ADAU1373_PLL_CTRL6_DPLL_BYPASS,
ADAU1373_PLL_CTRL6_DPLL_BYPASS);
}
- snd_soc_write(codec, ADAU1373_DPLL_CTRL(pll_id),
+ regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
(source << 4) | dpll_div);
- snd_soc_write(codec, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
- snd_soc_write(codec, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
- snd_soc_write(codec, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
- snd_soc_write(codec, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
- snd_soc_write(codec, ADAU1373_PLL_CTRL5(pll_id),
+ regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
+ regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
+ regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
+ regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
+ regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
(r << 3) | (x << 1) | mode);
/* Set sysclk to pll_rate / 4 */
- snd_soc_update_bits(codec, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
+ regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
return 0;
}
-static void adau1373_load_drc_settings(struct snd_soc_codec *codec,
+static void adau1373_load_drc_settings(struct adau1373 *adau1373,
unsigned int nr, uint8_t *drc)
{
unsigned int i;
for (i = 0; i < ADAU1373_DRC_SIZE; ++i)
- snd_soc_write(codec, ADAU1373_DRC(nr) + i, drc[i]);
+ regmap_write(adau1373->regmap, ADAU1373_DRC(nr) + i, drc[i]);
}
static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
@@ -1235,13 +1372,14 @@ static bool adau1373_valid_micbias(enum adau1373_micbias_voltage micbias)
static int adau1373_probe(struct snd_soc_codec *codec)
{
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
struct adau1373_platform_data *pdata = codec->dev->platform_data;
bool lineout_differential = false;
unsigned int val;
int ret;
int i;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
if (ret) {
dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
return ret;
@@ -1256,7 +1394,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)
return -EINVAL;
for (i = 0; i < pdata->num_drc; ++i) {
- adau1373_load_drc_settings(codec, i,
+ adau1373_load_drc_settings(adau1373, i,
pdata->drc_setting[i]);
}
@@ -1268,18 +1406,18 @@ static int adau1373_probe(struct snd_soc_codec *codec)
if (pdata->input_differential[i])
val |= BIT(i);
}
- snd_soc_write(codec, ADAU1373_INPUT_MODE, val);
+ regmap_write(adau1373->regmap, ADAU1373_INPUT_MODE, val);
val = 0;
if (pdata->lineout_differential)
val |= ADAU1373_OUTPUT_CTRL_LDIFF;
if (pdata->lineout_ground_sense)
val |= ADAU1373_OUTPUT_CTRL_LNFBEN;
- snd_soc_write(codec, ADAU1373_OUTPUT_CTRL, val);
+ regmap_write(adau1373->regmap, ADAU1373_OUTPUT_CTRL, val);
lineout_differential = pdata->lineout_differential;
- snd_soc_write(codec, ADAU1373_EP_CTRL,
+ regmap_write(adau1373->regmap, ADAU1373_EP_CTRL,
(pdata->micbias1 << ADAU1373_EP_CTRL_MICBIAS1_OFFSET) |
(pdata->micbias2 << ADAU1373_EP_CTRL_MICBIAS2_OFFSET));
}
@@ -1289,7 +1427,7 @@ static int adau1373_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(adau1373_lineout2_controls));
}
- snd_soc_write(codec, ADAU1373_ADC_CTRL,
+ regmap_write(adau1373->regmap, ADAU1373_ADC_CTRL,
ADAU1373_ADC_CTRL_RESET_FORCE | ADAU1373_ADC_CTRL_PEAK_DETECT);
return 0;
@@ -1298,17 +1436,19 @@ static int adau1373_probe(struct snd_soc_codec *codec)
static int adau1373_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3,
+ regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,
ADAU1373_PWDN_CTRL3_PWR_EN, ADAU1373_PWDN_CTRL3_PWR_EN);
break;
case SND_SOC_BIAS_OFF:
- snd_soc_update_bits(codec, ADAU1373_PWDN_CTRL3,
+ regmap_update_bits(adau1373->regmap, ADAU1373_PWDN_CTRL3,
ADAU1373_PWDN_CTRL3_PWR_EN, 0);
break;
}
@@ -1324,17 +1464,49 @@ static int adau1373_remove(struct snd_soc_codec *codec)
static int adau1373_suspend(struct snd_soc_codec *codec)
{
- return adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regcache_cache_only(adau1373->regmap, true);
+
+ return ret;
}
static int adau1373_resume(struct snd_soc_codec *codec)
{
+ struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(adau1373->regmap, false);
adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- snd_soc_cache_sync(codec);
+ regcache_sync(adau1373->regmap);
return 0;
}
+static bool adau1373_register_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ADAU1373_SOFT_RESET:
+ case ADAU1373_ADC_DAC_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config adau1373_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 8,
+
+ .volatile_reg = adau1373_register_volatile,
+ .max_register = ADAU1373_SOFT_RESET,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = adau1373_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adau1373_reg_defaults),
+};
+
static struct snd_soc_codec_driver adau1373_codec_driver = {
.probe = adau1373_probe,
.remove = adau1373_remove,
@@ -1342,9 +1514,6 @@ static struct snd_soc_codec_driver adau1373_codec_driver = {
.resume = adau1373_resume,
.set_bias_level = adau1373_set_bias_level,
.idle_bias_off = true,
- .reg_cache_size = ARRAY_SIZE(adau1373_default_regs),
- .reg_cache_default = adau1373_default_regs,
- .reg_word_size = sizeof(uint8_t),
.set_pll = adau1373_set_pll,
@@ -1366,6 +1535,13 @@ static int adau1373_i2c_probe(struct i2c_client *client,
if (!adau1373)
return -ENOMEM;
+ adau1373->regmap = devm_regmap_init_i2c(client,
+ &adau1373_regmap_config);
+ if (IS_ERR(adau1373->regmap))
+ return PTR_ERR(adau1373->regmap);
+
+ regmap_write(adau1373->regmap, ADAU1373_SOFT_RESET, 0x00);
+
dev_set_drvdata(&client->dev, adau1373);
ret = snd_soc_register_codec(&client->dev, &adau1373_codec_driver,
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index ebff1128be59..d71c59cf7bdd 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -71,7 +71,7 @@
#define ADAU1701_SEROCTL_WORD_LEN_24 0x0000
#define ADAU1701_SEROCTL_WORD_LEN_20 0x0001
-#define ADAU1701_SEROCTL_WORD_LEN_16 0x0010
+#define ADAU1701_SEROCTL_WORD_LEN_16 0x0002
#define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003
#define ADAU1701_AUXNPOW_VBPD 0x40
@@ -299,20 +299,20 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
}
static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
- snd_pcm_format_t format)
+ struct snd_pcm_hw_params *params)
{
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK;
unsigned int val;
- switch (format) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
val = ADAU1701_SEROCTL_WORD_LEN_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
val = ADAU1701_SEROCTL_WORD_LEN_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
val = ADAU1701_SEROCTL_WORD_LEN_24;
break;
default:
@@ -320,14 +320,14 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
}
if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) {
- switch (format) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
val |= ADAU1701_SEROCTL_MSB_DEALY16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
val |= ADAU1701_SEROCTL_MSB_DEALY12;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
val |= ADAU1701_SEROCTL_MSB_DEALY8;
break;
}
@@ -340,7 +340,7 @@ static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec,
}
static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
- snd_pcm_format_t format)
+ struct snd_pcm_hw_params *params)
{
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
unsigned int val;
@@ -348,14 +348,14 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
return 0;
- switch (format) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
val = ADAU1701_SERICTL_RIGHTJ_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
val = ADAU1701_SERICTL_RIGHTJ_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
val = ADAU1701_SERICTL_RIGHTJ_24;
break;
default:
@@ -374,7 +374,6 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
unsigned int clkdiv = adau1701->sysclk / params_rate(params);
- snd_pcm_format_t format;
unsigned int val;
int ret;
@@ -406,11 +405,10 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
ADAU1701_DSPCTRL_SR_MASK, val);
- format = params_format(params);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return adau1701_set_playback_pcm_format(codec, format);
+ return adau1701_set_playback_pcm_format(codec, params);
else
- return adau1701_set_capture_pcm_format(codec, format);
+ return adau1701_set_capture_pcm_format(codec, params);
}
static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai,
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 15b012d0f226..f78b27a7c461 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -115,22 +115,34 @@
#define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x))
-static u8 adav80x_default_regs[] = {
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00,
- 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37,
- 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b,
- 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00,
- 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee,
- 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x52, 0x00,
+static struct reg_default adav80x_reg_defaults[] = {
+ { ADAV80X_PLAYBACK_CTRL, 0x01 },
+ { ADAV80X_AUX_IN_CTRL, 0x01 },
+ { ADAV80X_REC_CTRL, 0x02 },
+ { ADAV80X_AUX_OUT_CTRL, 0x01 },
+ { ADAV80X_DPATH_CTRL1, 0xc0 },
+ { ADAV80X_DPATH_CTRL2, 0x11 },
+ { ADAV80X_DAC_CTRL1, 0x00 },
+ { ADAV80X_DAC_CTRL2, 0x00 },
+ { ADAV80X_DAC_CTRL3, 0x00 },
+ { ADAV80X_DAC_L_VOL, 0xff },
+ { ADAV80X_DAC_R_VOL, 0xff },
+ { ADAV80X_PGA_L_VOL, 0x00 },
+ { ADAV80X_PGA_R_VOL, 0x00 },
+ { ADAV80X_ADC_CTRL1, 0x00 },
+ { ADAV80X_ADC_CTRL2, 0x00 },
+ { ADAV80X_ADC_L_VOL, 0xff },
+ { ADAV80X_ADC_R_VOL, 0xff },
+ { ADAV80X_PLL_CTRL1, 0x00 },
+ { ADAV80X_PLL_CTRL2, 0x00 },
+ { ADAV80X_ICLK_CTRL1, 0x00 },
+ { ADAV80X_ICLK_CTRL2, 0x00 },
+ { ADAV80X_PLL_CLK_SRC, 0x00 },
+ { ADAV80X_PLL_OUTE, 0x00 },
};
struct adav80x {
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
enum adav80x_clk_src clk_src;
unsigned int sysclk;
@@ -298,7 +310,7 @@ static int adav80x_set_deemph(struct snd_soc_codec *codec)
val = ADAV80X_DAC_CTRL2_DEEMPH_NONE;
}
- return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2,
+ return regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
ADAV80X_DAC_CTRL2_DEEMPH_MASK, val);
}
@@ -394,10 +406,11 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0],
+ regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER,
capture);
- snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback);
+ regmap_write(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
+ playback);
adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
@@ -407,6 +420,7 @@ static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
unsigned int sample_rate)
{
+ struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int val;
if (sample_rate <= 48000)
@@ -414,7 +428,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
else
val = ADAV80X_ADC_CTRL1_MODULATOR_64FS;
- snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1,
+ regmap_update_bits(adav80x->regmap, ADAV80X_ADC_CTRL1,
ADAV80X_ADC_CTRL1_MODULATOR_MASK, val);
return 0;
@@ -423,6 +437,7 @@ static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
unsigned int sample_rate)
{
+ struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int val;
if (sample_rate <= 48000)
@@ -430,7 +445,7 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
else
val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS;
- snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2,
+ regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL2,
ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK,
val);
@@ -438,35 +453,36 @@ static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
}
static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec,
- struct snd_soc_dai *dai, snd_pcm_format_t format)
+ struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
{
+ struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int val;
- switch (format) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
val = ADAV80X_CAPTURE_WORD_LEN16;
break;
- case SNDRV_PCM_FORMAT_S18_3LE:
+ case 18:
val = ADAV80X_CAPTRUE_WORD_LEN18;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
val = ADAV80X_CAPTURE_WORD_LEN20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
val = ADAV80X_CAPTURE_WORD_LEN24;
break;
default:
return -EINVAL;
}
- snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0],
+ regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][0],
ADAV80X_CAPTURE_WORD_LEN_MASK, val);
return 0;
}
static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
- struct snd_soc_dai *dai, snd_pcm_format_t format)
+ struct snd_soc_dai *dai, struct snd_pcm_hw_params *params)
{
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int val;
@@ -474,24 +490,24 @@ static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec,
if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J)
return 0;
- switch (format) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16;
break;
- case SNDRV_PCM_FORMAT_S18_3LE:
+ case 18:
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24;
break;
default:
return -EINVAL;
}
- snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1],
+ regmap_update_bits(adav80x->regmap, adav80x_port_ctrl_regs[dai->id][1],
ADAV80X_PLAYBACK_MODE_MASK, val);
return 0;
@@ -508,12 +524,10 @@ static int adav80x_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- adav80x_set_playback_pcm_format(codec, dai,
- params_format(params));
+ adav80x_set_playback_pcm_format(codec, dai, params);
adav80x_set_dac_clock(codec, rate);
} else {
- adav80x_set_capture_pcm_format(codec, dai,
- params_format(params));
+ adav80x_set_capture_pcm_format(codec, dai, params);
adav80x_set_adc_clock(codec, rate);
}
adav80x->rate = rate;
@@ -554,8 +568,10 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id);
iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id);
- snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1);
- snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2);
+ regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL1,
+ iclk_ctrl1);
+ regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2,
+ iclk_ctrl2);
snd_soc_dapm_sync(&codec->dapm);
}
@@ -575,10 +591,12 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec,
mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id);
if (freq == 0) {
- snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask);
+ regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
+ mask, mask);
adav80x->sysclk_pd[clk_id] = true;
} else {
- snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0);
+ regmap_update_bits(adav80x->regmap, ADAV80X_PLL_OUTE,
+ mask, 0);
adav80x->sysclk_pd[clk_id] = false;
}
@@ -650,9 +668,9 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
return -EINVAL;
}
- snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV,
- pll_ctrl1);
- snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2,
+ regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL1,
+ ADAV80X_PLL_CTRL1_PLLDIV, pll_ctrl1);
+ regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CTRL2,
ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2);
if (source != adav80x->pll_src) {
@@ -661,7 +679,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
else
pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id);
- snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC,
+ regmap_update_bits(adav80x->regmap, ADAV80X_PLL_CLK_SRC,
ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src);
adav80x->pll_src = source;
@@ -675,6 +693,7 @@ static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id,
static int adav80x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
unsigned int mask = ADAV80X_DAC_CTRL1_PD;
switch (level) {
@@ -683,10 +702,12 @@ static int adav80x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00);
+ regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
+ 0x00);
break;
case SND_SOC_BIAS_OFF:
- snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask);
+ regmap_update_bits(adav80x->regmap, ADAV80X_DAC_CTRL1, mask,
+ mask);
break;
}
@@ -780,7 +801,7 @@ static int adav80x_probe(struct snd_soc_codec *codec)
int ret;
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type);
+ ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
if (ret) {
dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
return ret;
@@ -791,23 +812,31 @@ static int adav80x_probe(struct snd_soc_codec *codec)
snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2");
/* Power down S/PDIF receiver, since it is currently not supported */
- snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20);
+ regmap_write(adav80x->regmap, ADAV80X_PLL_OUTE, 0x20);
/* Disable DAC zero flag */
- snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6);
+ regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6);
return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
}
static int adav80x_suspend(struct snd_soc_codec *codec)
{
- return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ regcache_cache_only(adav80x->regmap, true);
+
+ return ret;
}
static int adav80x_resume(struct snd_soc_codec *codec)
{
+ struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(adav80x->regmap, false);
adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- codec->cache_sync = 1;
- snd_soc_cache_sync(codec);
+ regcache_sync(adav80x->regmap);
return 0;
}
@@ -827,10 +856,6 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
.set_pll = adav80x_set_pll,
.set_sysclk = adav80x_set_sysclk,
- .reg_word_size = sizeof(u8),
- .reg_cache_size = ARRAY_SIZE(adav80x_default_regs),
- .reg_cache_default = adav80x_default_regs,
-
.controls = adav80x_controls,
.num_controls = ARRAY_SIZE(adav80x_controls),
.dapm_widgets = adav80x_dapm_widgets,
@@ -839,18 +864,21 @@ static struct snd_soc_codec_driver adav80x_codec_driver = {
.num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes),
};
-static int adav80x_bus_probe(struct device *dev,
- enum snd_soc_control_type control_type)
+static int adav80x_bus_probe(struct device *dev, struct regmap *regmap)
{
struct adav80x *adav80x;
int ret;
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL);
if (!adav80x)
return -ENOMEM;
+
dev_set_drvdata(dev, adav80x);
- adav80x->control_type = control_type;
+ adav80x->regmap = regmap;
ret = snd_soc_register_codec(dev, &adav80x_codec_driver,
adav80x_dais, ARRAY_SIZE(adav80x_dais));
@@ -868,6 +896,19 @@ static int adav80x_bus_remove(struct device *dev)
}
#if defined(CONFIG_SPI_MASTER)
+static const struct regmap_config adav80x_spi_regmap_config = {
+ .val_bits = 8,
+ .pad_bits = 1,
+ .reg_bits = 7,
+ .read_flag_mask = 0x01,
+
+ .max_register = ADAV80X_PLL_OUTE,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = adav80x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
+};
+
static const struct spi_device_id adav80x_spi_id[] = {
{ "adav801", 0 },
{ }
@@ -876,7 +917,8 @@ MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
static int adav80x_spi_probe(struct spi_device *spi)
{
- return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
+ return adav80x_bus_probe(&spi->dev,
+ devm_regmap_init_spi(spi, &adav80x_spi_regmap_config));
}
static int adav80x_spi_remove(struct spi_device *spi)
@@ -895,7 +937,19 @@ static struct spi_driver adav80x_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
+static const struct regmap_config adav80x_i2c_regmap_config = {
+ .val_bits = 8,
+ .pad_bits = 1,
+ .reg_bits = 7,
+
+ .max_register = ADAV80X_PLL_OUTE,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = adav80x_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults),
+};
+
static const struct i2c_device_id adav80x_i2c_id[] = {
{ "adav803", 0 },
{ }
@@ -905,7 +959,8 @@ MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
static int adav80x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- return adav80x_bus_probe(&client->dev, SND_SOC_I2C);
+ return adav80x_bus_probe(&client->dev,
+ devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config));
}
static int adav80x_i2c_remove(struct i2c_client *client)
@@ -928,7 +983,7 @@ static int __init adav80x_init(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&adav80x_i2c_driver);
if (ret)
return ret;
@@ -944,7 +999,7 @@ module_init(adav80x_init);
static void __exit adav80x_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&adav80x_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index 71059c07ae7b..b4819dcd4f4d 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -45,8 +45,6 @@
#define AK4104_TX_TXE (1 << 0)
#define AK4104_TX_V (1 << 1)
-#define DRV_NAME "ak4104-codec"
-
struct ak4104_private {
struct regmap *regmap;
};
@@ -291,12 +289,19 @@ static const struct of_device_id ak4104_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ak4104_of_match);
+static const struct spi_device_id ak4104_id_table[] = {
+ { "ak4104", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ak4104_id_table);
+
static struct spi_driver ak4104_spi_driver = {
.driver = {
- .name = DRV_NAME,
+ .name = "ak4104",
.owner = THIS_MODULE,
.of_match_table = ak4104_of_match,
},
+ .id_table = ak4104_id_table,
.probe = ak4104_spi_probe,
.remove = ak4104_spi_remove,
};
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 5f9af1fb76e8..94cbe508dd37 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -17,6 +17,7 @@
#include <linux/gpio.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -30,6 +31,7 @@
/* codec private data */
struct ak4641_priv {
+ struct regmap *regmap;
unsigned int sysclk;
int deemph;
int playback_fs;
@@ -38,12 +40,12 @@ struct ak4641_priv {
/*
* ak4641 register cache
*/
-static const u8 ak4641_reg[AK4641_CACHEREGNUM] = {
- 0x00, 0x80, 0x00, 0x80,
- 0x02, 0x00, 0x11, 0x05,
- 0x00, 0x00, 0x36, 0x10,
- 0x00, 0x00, 0x57, 0x00,
- 0x88, 0x88, 0x08, 0x08
+static const struct reg_default ak4641_reg_defaults[] = {
+ { 0, 0x00 }, { 1, 0x80 }, { 2, 0x00 }, { 3, 0x80 },
+ { 4, 0x02 }, { 5, 0x00 }, { 6, 0x11 }, { 7, 0x05 },
+ { 8, 0x00 }, { 9, 0x00 }, { 10, 0x36 }, { 11, 0x10 },
+ { 12, 0x00 }, { 13, 0x00 }, { 14, 0x57 }, { 15, 0x00 },
+ { 16, 0x88 }, { 17, 0x88 }, { 18, 0x08 }, { 19, 0x08 }
};
static const int deemph_settings[] = {44100, 0, 48000, 32000};
@@ -328,7 +330,7 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ak4641->playback_fs = rate;
ak4641_set_deemph(codec);
- };
+ }
return 0;
}
@@ -396,6 +398,7 @@ static int ak4641_mute(struct snd_soc_dai *dai, int mute)
static int ak4641_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
struct ak4641_platform_data *pdata = codec->dev->platform_data;
int ret;
@@ -417,7 +420,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
gpio_set_value(pdata->gpio_npdn, 1);
mdelay(1);
- ret = snd_soc_cache_sync(codec);
+ ret = regcache_sync(ak4641->regmap);
if (ret) {
dev_err(codec->dev,
"Failed to sync cache: %d\n", ret);
@@ -433,7 +436,7 @@ static int ak4641_set_bias_level(struct snd_soc_codec *codec,
gpio_set_value(pdata->gpio_npdn, 0);
if (pdata && gpio_is_valid(pdata->gpio_power))
gpio_set_value(pdata->gpio_power, 0);
- codec->cache_sync = 1;
+ regcache_mark_dirty(ak4641->regmap);
break;
}
codec->dapm.bias_level = level;
@@ -518,7 +521,7 @@ static int ak4641_probe(struct snd_soc_codec *codec)
{
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -550,12 +553,17 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
.dapm_routes = ak4641_audio_map,
.num_dapm_routes = ARRAY_SIZE(ak4641_audio_map),
.set_bias_level = ak4641_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(ak4641_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = ak4641_reg,
- .reg_cache_step = 1,
};
+static const struct regmap_config ak4641_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = AK4641_BTIF,
+ .reg_defaults = ak4641_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ak4641_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+};
static int ak4641_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
@@ -569,6 +577,10 @@ static int ak4641_i2c_probe(struct i2c_client *i2c,
if (!ak4641)
return -ENOMEM;
+ ak4641->regmap = devm_regmap_init_i2c(i2c, &ak4641_regmap);
+ if (IS_ERR(ak4641->regmap))
+ return PTR_ERR(ak4641->regmap);
+
if (pdata) {
if (gpio_is_valid(pdata->gpio_power)) {
ret = gpio_request_one(pdata->gpio_power,
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 2d0378709702..1f646c6e90c6 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@@ -198,30 +199,30 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = {
/*
* ak4642 register cache
*/
-static const u8 ak4642_reg[] = {
- 0x00, 0x00, 0x01, 0x00,
- 0x02, 0x00, 0x00, 0x00,
- 0xe1, 0xe1, 0x18, 0x00,
- 0xe1, 0x18, 0x11, 0x08,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00,
+static const struct reg_default ak4642_reg[] = {
+ { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
+ { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
+ { 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
+ { 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0x08 },
+ { 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
+ { 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
+ { 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
+ { 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
+ { 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
+ { 36, 0x00 },
};
-static const u8 ak4648_reg[] = {
- 0x00, 0x00, 0x01, 0x00,
- 0x02, 0x00, 0x00, 0x00,
- 0xe1, 0xe1, 0x18, 0x00,
- 0xe1, 0x18, 0x11, 0xb8,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x88, 0x88, 0x08,
+static const struct reg_default ak4648_reg[] = {
+ { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 },
+ { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
+ { 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 },
+ { 12, 0xe1 }, { 13, 0x18 }, { 14, 0x11 }, { 15, 0xb8 },
+ { 16, 0x00 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x00 },
+ { 20, 0x00 }, { 21, 0x00 }, { 22, 0x00 }, { 23, 0x00 },
+ { 24, 0x00 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0x00 },
+ { 28, 0x00 }, { 29, 0x00 }, { 30, 0x00 }, { 31, 0x00 },
+ { 32, 0x00 }, { 33, 0x00 }, { 34, 0x00 }, { 35, 0x00 },
+ { 36, 0x00 }, { 37, 0x88 }, { 38, 0x88 }, { 39, 0x08 },
};
static int ak4642_dai_startup(struct snd_pcm_substream *substream,
@@ -257,7 +258,7 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
- snd_soc_write(codec, SG_SL1, PMMP | MGAIN0);
+ snd_soc_update_bits(codec, SG_SL1, PMMP | MGAIN0, PMMP | MGAIN0);
snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
snd_soc_update_bits(codec, PW_MGMT1, PMADL, PMADL);
@@ -352,7 +353,6 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
*/
default:
return -EINVAL;
- break;
}
snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data);
@@ -405,7 +405,6 @@ static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
break;
default:
return -EINVAL;
- break;
}
snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
@@ -456,7 +455,10 @@ static struct snd_soc_dai_driver ak4642_dai = {
static int ak4642_resume(struct snd_soc_codec *codec)
{
- snd_soc_cache_sync(codec);
+ struct regmap *regmap = dev_get_regmap(codec->dev, NULL);
+
+ regcache_mark_dirty(regmap);
+ regcache_sync(regmap);
return 0;
}
@@ -465,15 +467,12 @@ static int ak4642_probe(struct snd_soc_codec *codec)
{
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
- snd_soc_add_codec_controls(codec, ak4642_snd_controls,
- ARRAY_SIZE(ak4642_snd_controls));
-
ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -490,55 +489,59 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
.remove = ak4642_remove,
.resume = ak4642_resume,
.set_bias_level = ak4642_set_bias_level,
- .reg_cache_default = ak4642_reg, /* ak4642 reg */
- .reg_cache_size = ARRAY_SIZE(ak4642_reg), /* ak4642 reg */
- .reg_word_size = sizeof(u8),
+ .controls = ak4642_snd_controls,
+ .num_controls = ARRAY_SIZE(ak4642_snd_controls),
.dapm_widgets = ak4642_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets),
.dapm_routes = ak4642_intercon,
.num_dapm_routes = ARRAY_SIZE(ak4642_intercon),
};
-static struct snd_soc_codec_driver soc_codec_dev_ak4648 = {
- .probe = ak4642_probe,
- .remove = ak4642_remove,
- .resume = ak4642_resume,
- .set_bias_level = ak4642_set_bias_level,
- .reg_cache_default = ak4648_reg, /* ak4648 reg */
- .reg_cache_size = ARRAY_SIZE(ak4648_reg), /* ak4648 reg */
- .reg_word_size = sizeof(u8),
- .dapm_widgets = ak4642_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(ak4642_dapm_widgets),
- .dapm_routes = ak4642_intercon,
- .num_dapm_routes = ARRAY_SIZE(ak4642_intercon),
+static const struct regmap_config ak4642_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ARRAY_SIZE(ak4642_reg) + 1,
+ .reg_defaults = ak4642_reg,
+ .num_reg_defaults = ARRAY_SIZE(ak4642_reg),
+};
+
+static const struct regmap_config ak4648_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = ARRAY_SIZE(ak4648_reg) + 1,
+ .reg_defaults = ak4648_reg,
+ .num_reg_defaults = ARRAY_SIZE(ak4648_reg),
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static struct of_device_id ak4642_of_match[];
static int ak4642_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct device_node *np = i2c->dev.of_node;
- const struct snd_soc_codec_driver *driver;
+ const struct regmap_config *regmap_config = NULL;
+ struct regmap *regmap;
- driver = NULL;
if (np) {
const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev);
if (of_id)
- driver = of_id->data;
+ regmap_config = of_id->data;
} else {
- driver = (struct snd_soc_codec_driver *)id->driver_data;
+ regmap_config = (const struct regmap_config *)id->driver_data;
}
- if (!driver) {
- dev_err(&i2c->dev, "no driver\n");
+ if (!regmap_config) {
+ dev_err(&i2c->dev, "Unknown device type\n");
return -EINVAL;
}
+ regmap = devm_regmap_init_i2c(i2c, regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
return snd_soc_register_codec(&i2c->dev,
- driver, &ak4642_dai, 1);
+ &soc_codec_dev_ak4642, &ak4642_dai, 1);
}
static int ak4642_i2c_remove(struct i2c_client *client)
@@ -548,17 +551,17 @@ static int ak4642_i2c_remove(struct i2c_client *client)
}
static struct of_device_id ak4642_of_match[] = {
- { .compatible = "asahi-kasei,ak4642", .data = &soc_codec_dev_ak4642},
- { .compatible = "asahi-kasei,ak4643", .data = &soc_codec_dev_ak4642},
- { .compatible = "asahi-kasei,ak4648", .data = &soc_codec_dev_ak4648},
+ { .compatible = "asahi-kasei,ak4642", .data = &ak4642_regmap},
+ { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap},
+ { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap},
{},
};
MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = {
- { "ak4642", (kernel_ulong_t)&soc_codec_dev_ak4642 },
- { "ak4643", (kernel_ulong_t)&soc_codec_dev_ak4642 },
- { "ak4648", (kernel_ulong_t)&soc_codec_dev_ak4648 },
+ { "ak4642", (kernel_ulong_t)&ak4642_regmap },
+ { "ak4643", (kernel_ulong_t)&ak4642_regmap },
+ { "ak4648", (kernel_ulong_t)&ak4648_regmap },
{ }
};
MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
@@ -573,27 +576,8 @@ static struct i2c_driver ak4642_i2c_driver = {
.remove = ak4642_i2c_remove,
.id_table = ak4642_i2c_id,
};
-#endif
-
-static int __init ak4642_modinit(void)
-{
- int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- ret = i2c_add_driver(&ak4642_i2c_driver);
-#endif
- return ret;
-}
-module_init(ak4642_modinit);
-
-static void __exit ak4642_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_del_driver(&ak4642_i2c_driver);
-#endif
-
-}
-module_exit(ak4642_exit);
+module_i2c_driver(ak4642_i2c_driver);
MODULE_DESCRIPTION("Soc AK4642 driver");
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 256c364193a5..d3036283482a 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -714,17 +714,17 @@ static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
iface &= ~ALC5623_DAI_I2S_DL_MASK;
/* bit size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
iface |= ALC5623_DAI_I2S_DL_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
iface |= ALC5623_DAI_I2S_DL_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
iface |= ALC5623_DAI_I2S_DL_24;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
iface |= ALC5623_DAI_I2S_DL_32;
break;
default:
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index f2e62e45f912..fb001c56cf8d 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -614,7 +614,7 @@ struct _pll_div {
};
/* Note : pll code from original alc5632 driver. Not sure of how good it is */
-/* usefull only for master mode */
+/* useful only for master mode */
static const struct _pll_div codec_master_pll_div[] = {
{ 2048000, 8192000, 0x0ea0},
@@ -869,14 +869,14 @@ static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
iface &= ~ALC5632_DAI_I2S_DL_MASK;
/* bit size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
iface |= ALC5632_DAI_I2S_DL_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
iface |= ALC5632_DAI_I2S_DL_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
iface |= ALC5632_DAI_I2S_DL_24;
break;
default:
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 657808ba1418..e4295fee8f13 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -93,7 +93,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (!priv->spk_ena && manual_ena) {
- snd_soc_write(codec, 0x4f5, 0x25a);
+ regmap_write_async(arizona->regmap, 0x4f5, 0x25a);
priv->spk_ena_pending = true;
}
break;
@@ -105,12 +105,13 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
return -EBUSY;
}
- snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
- 1 << w->shift, 1 << w->shift);
+ regmap_update_bits_async(arizona->regmap,
+ ARIZONA_OUTPUT_ENABLES_1,
+ 1 << w->shift, 1 << w->shift);
if (priv->spk_ena_pending) {
msleep(75);
- snd_soc_write(codec, 0x4f5, 0xda);
+ regmap_write_async(arizona->regmap, 0x4f5, 0xda);
priv->spk_ena_pending = false;
priv->spk_ena++;
}
@@ -119,16 +120,19 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
if (manual_ena) {
priv->spk_ena--;
if (!priv->spk_ena)
- snd_soc_write(codec, 0x4f5, 0x25a);
+ regmap_write_async(arizona->regmap,
+ 0x4f5, 0x25a);
}
- snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
- 1 << w->shift, 0);
+ regmap_update_bits_async(arizona->regmap,
+ ARIZONA_OUTPUT_ENABLES_1,
+ 1 << w->shift, 0);
break;
case SND_SOC_DAPM_POST_PMD:
if (manual_ena) {
if (!priv->spk_ena)
- snd_soc_write(codec, 0x4f5, 0x0da);
+ regmap_write_async(arizona->regmap,
+ 0x4f5, 0x0da);
}
break;
}
@@ -292,6 +296,10 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"AIF1RX8",
"AIF2RX1",
"AIF2RX2",
+ "AIF2RX3",
+ "AIF2RX4",
+ "AIF2RX5",
+ "AIF2RX6",
"AIF3RX1",
"AIF3RX2",
"SLIMRX1",
@@ -395,6 +403,10 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x27,
0x28, /* AIF2RX1 */
0x29,
+ 0x2a,
+ 0x2b,
+ 0x2c,
+ 0x2d,
0x30, /* AIF3RX1 */
0x31,
0x38, /* SLIMRX1 */
@@ -486,6 +498,22 @@ const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
EXPORT_SYMBOL_GPL(arizona_rate_val);
+const struct soc_enum arizona_isrc_fsh[] = {
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_1,
+ ARIZONA_ISRC1_FSH_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_1,
+ ARIZONA_ISRC2_FSH_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_1,
+ ARIZONA_ISRC3_FSH_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE,
+ arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsh);
+
const struct soc_enum arizona_isrc_fsl[] = {
SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
ARIZONA_ISRC1_FSL_SHIFT, 0xf,
@@ -502,6 +530,13 @@ const struct soc_enum arizona_isrc_fsl[] = {
};
EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
+const struct soc_enum arizona_asrc_rate1 =
+ SOC_VALUE_ENUM_SINGLE(ARIZONA_ASRC_RATE1,
+ ARIZONA_ASRC_RATE1_SHIFT, 0xf,
+ ARIZONA_RATE_ENUM_SIZE - 1,
+ arizona_rate_text, arizona_rate_val);
+EXPORT_SYMBOL_GPL(arizona_asrc_rate1);
+
static const char *arizona_vol_ramp_text[] = {
"0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
"15ms/6dB", "30ms/6dB",
@@ -560,6 +595,16 @@ const struct soc_enum arizona_ng_hold =
4, arizona_ng_hold_text);
EXPORT_SYMBOL_GPL(arizona_ng_hold);
+static const char * const arizona_in_hpf_cut_text[] = {
+ "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz"
+};
+
+const struct soc_enum arizona_in_hpf_cut_enum =
+ SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT,
+ ARRAY_SIZE(arizona_in_hpf_cut_text),
+ arizona_in_hpf_cut_text);
+EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
+
static const char * const arizona_in_dmic_osr_text[] = {
"1.536MHz", "3.072MHz", "6.144MHz",
};
@@ -669,6 +714,7 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
int event)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+ struct arizona *arizona = priv->arizona;
unsigned int mask = 1 << w->shift;
unsigned int val;
@@ -691,7 +737,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
if (priv->arizona->hpdet_magic)
val = 0;
- snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
+ regmap_update_bits_async(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1,
+ mask, val);
return arizona_out_ev(w, kcontrol, event);
}
@@ -846,6 +893,8 @@ EXPORT_SYMBOL_GPL(arizona_set_sysclk);
static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
+ struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+ struct arizona *arizona = priv->arizona;
int lrclk, bclk, mode, base;
base = dai->driver->base;
@@ -902,17 +951,19 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
}
- snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
- ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR,
- bclk);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL,
- ARIZONA_AIF1TX_LRCLK_INV |
- ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL,
- ARIZONA_AIF1RX_LRCLK_INV |
- ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT,
- ARIZONA_AIF1_FMT_MASK, mode);
+ regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
+ ARIZONA_AIF1_BCLK_INV |
+ ARIZONA_AIF1_BCLK_MSTR,
+ bclk);
+ regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_TX_PIN_CTRL,
+ ARIZONA_AIF1TX_LRCLK_INV |
+ ARIZONA_AIF1TX_LRCLK_MSTR, lrclk);
+ regmap_update_bits_async(arizona->regmap,
+ base + ARIZONA_AIF_RX_PIN_CTRL,
+ ARIZONA_AIF1RX_LRCLK_INV |
+ ARIZONA_AIF1RX_LRCLK_MSTR, lrclk);
+ regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FORMAT,
+ ARIZONA_AIF1_FMT_MASK, mode);
return 0;
}
@@ -1164,18 +1215,22 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
if (ret != 0)
return ret;
- snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL,
- ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE,
- ARIZONA_AIF1TX_BCPF_MASK, lrclk);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE,
- ARIZONA_AIF1RX_BCPF_MASK, lrclk);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1,
- ARIZONA_AIF1TX_WL_MASK |
- ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
- snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2,
- ARIZONA_AIF1RX_WL_MASK |
- ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
+ regmap_update_bits_async(arizona->regmap,
+ base + ARIZONA_AIF_BCLK_CTRL,
+ ARIZONA_AIF1_BCLK_FREQ_MASK, bclk);
+ regmap_update_bits_async(arizona->regmap,
+ base + ARIZONA_AIF_TX_BCLK_RATE,
+ ARIZONA_AIF1TX_BCPF_MASK, lrclk);
+ regmap_update_bits_async(arizona->regmap,
+ base + ARIZONA_AIF_RX_BCLK_RATE,
+ ARIZONA_AIF1RX_BCPF_MASK, lrclk);
+ regmap_update_bits_async(arizona->regmap,
+ base + ARIZONA_AIF_FRAME_CTRL_1,
+ ARIZONA_AIF1TX_WL_MASK |
+ ARIZONA_AIF1TX_SLOT_LEN_MASK, frame);
+ regmap_update_bits(arizona->regmap, base + ARIZONA_AIF_FRAME_CTRL_2,
+ ARIZONA_AIF1RX_WL_MASK |
+ ARIZONA_AIF1RX_SLOT_LEN_MASK, frame);
return 0;
}
@@ -1428,31 +1483,31 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
struct arizona_fll_cfg *cfg, int source,
bool sync)
{
- regmap_update_bits(arizona->regmap, base + 3,
- ARIZONA_FLL1_THETA_MASK, cfg->theta);
- regmap_update_bits(arizona->regmap, base + 4,
- ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
- regmap_update_bits(arizona->regmap, base + 5,
- ARIZONA_FLL1_FRATIO_MASK,
- cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
- regmap_update_bits(arizona->regmap, base + 6,
- ARIZONA_FLL1_CLK_REF_DIV_MASK |
- ARIZONA_FLL1_CLK_REF_SRC_MASK,
- cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
- source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
+ regmap_update_bits_async(arizona->regmap, base + 3,
+ ARIZONA_FLL1_THETA_MASK, cfg->theta);
+ regmap_update_bits_async(arizona->regmap, base + 4,
+ ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda);
+ regmap_update_bits_async(arizona->regmap, base + 5,
+ ARIZONA_FLL1_FRATIO_MASK,
+ cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT);
+ regmap_update_bits_async(arizona->regmap, base + 6,
+ ARIZONA_FLL1_CLK_REF_DIV_MASK |
+ ARIZONA_FLL1_CLK_REF_SRC_MASK,
+ cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
+ source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
if (sync)
- regmap_update_bits(arizona->regmap, base + 0x7,
- ARIZONA_FLL1_GAIN_MASK,
- cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+ regmap_update_bits_async(arizona->regmap, base + 0x7,
+ ARIZONA_FLL1_GAIN_MASK,
+ cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
else
- regmap_update_bits(arizona->regmap, base + 0x9,
- ARIZONA_FLL1_GAIN_MASK,
- cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+ regmap_update_bits_async(arizona->regmap, base + 0x9,
+ ARIZONA_FLL1_GAIN_MASK,
+ cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
- regmap_update_bits(arizona->regmap, base + 2,
- ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
- ARIZONA_FLL1_CTRL_UPD | cfg->n);
+ regmap_update_bits_async(arizona->regmap, base + 2,
+ ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
+ ARIZONA_FLL1_CTRL_UPD | cfg->n);
}
static bool arizona_is_enabled_fll(struct arizona_fll *fll)
@@ -1477,31 +1532,35 @@ static void arizona_enable_fll(struct arizona_fll *fll,
{
struct arizona *arizona = fll->arizona;
int ret;
+ bool use_sync = false;
/*
* If we have both REFCLK and SYNCCLK then enable both,
* otherwise apply the SYNCCLK settings to REFCLK.
*/
- if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
- regmap_update_bits(arizona->regmap, fll->base + 5,
- ARIZONA_FLL1_OUTDIV_MASK,
- ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+ if (fll->ref_src >= 0 && fll->ref_freq &&
+ fll->ref_src != fll->sync_src) {
+ regmap_update_bits_async(arizona->regmap, fll->base + 5,
+ ARIZONA_FLL1_OUTDIV_MASK,
+ ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
false);
- if (fll->sync_src >= 0)
+ if (fll->sync_src >= 0) {
arizona_apply_fll(arizona, fll->base + 0x10, sync,
fll->sync_src, true);
+ use_sync = true;
+ }
} else if (fll->sync_src >= 0) {
- regmap_update_bits(arizona->regmap, fll->base + 5,
- ARIZONA_FLL1_OUTDIV_MASK,
- sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+ regmap_update_bits_async(arizona->regmap, fll->base + 5,
+ ARIZONA_FLL1_OUTDIV_MASK,
+ sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
arizona_apply_fll(arizona, fll->base, sync,
fll->sync_src, false);
- regmap_update_bits(arizona->regmap, fll->base + 0x11,
- ARIZONA_FLL1_SYNC_ENA, 0);
+ regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
+ ARIZONA_FLL1_SYNC_ENA, 0);
} else {
arizona_fll_err(fll, "No clocks provided\n");
return;
@@ -1511,12 +1570,13 @@ static void arizona_enable_fll(struct arizona_fll *fll,
* Increase the bandwidth if we're not using a low frequency
* sync source.
*/
- if (fll->sync_src >= 0 && fll->sync_freq > 100000)
- regmap_update_bits(arizona->regmap, fll->base + 0x17,
- ARIZONA_FLL1_SYNC_BW, 0);
+ if (use_sync && fll->sync_freq > 100000)
+ regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
+ ARIZONA_FLL1_SYNC_BW, 0);
else
- regmap_update_bits(arizona->regmap, fll->base + 0x17,
- ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
+ regmap_update_bits_async(arizona->regmap, fll->base + 0x17,
+ ARIZONA_FLL1_SYNC_BW,
+ ARIZONA_FLL1_SYNC_BW);
if (!arizona_is_enabled_fll(fll))
pm_runtime_get(arizona->dev);
@@ -1524,13 +1584,14 @@ static void arizona_enable_fll(struct arizona_fll *fll,
/* Clear any pending completions */
try_wait_for_completion(&fll->ok);
- regmap_update_bits(arizona->regmap, fll->base + 1,
- ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
- if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
- fll->ref_src != fll->sync_src)
- regmap_update_bits(arizona->regmap, fll->base + 0x11,
- ARIZONA_FLL1_SYNC_ENA,
- ARIZONA_FLL1_SYNC_ENA);
+ regmap_update_bits_async(arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_FREERUN, 0);
+ regmap_update_bits_async(arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
+ if (use_sync)
+ regmap_update_bits_async(arizona->regmap, fll->base + 0x11,
+ ARIZONA_FLL1_SYNC_ENA,
+ ARIZONA_FLL1_SYNC_ENA);
ret = wait_for_completion_timeout(&fll->ok,
msecs_to_jiffies(250));
@@ -1543,6 +1604,8 @@ static void arizona_disable_fll(struct arizona_fll *fll)
struct arizona *arizona = fll->arizona;
bool change;
+ regmap_update_bits_async(arizona->regmap, fll->base + 1,
+ ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN);
regmap_update_bits_check(arizona->regmap, fll->base + 1,
ARIZONA_FLL1_ENA, 0, &change);
regmap_update_bits(arizona->regmap, fll->base + 0x11,
@@ -1561,10 +1624,12 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
if (fll->ref_src == source && fll->ref_freq == Fref)
return 0;
- if (fll->fout && Fref > 0) {
- ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
- if (ret != 0)
- return ret;
+ if (fll->fout) {
+ if (Fref > 0) {
+ ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
+ if (ret != 0)
+ return ret;
+ }
if (fll->sync_src >= 0) {
ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 9e81b6392692..16df0f913353 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -81,7 +81,7 @@ struct arizona_priv {
unsigned int spk_ena_pending:1;
};
-#define ARIZONA_NUM_MIXER_INPUTS 99
+#define ARIZONA_NUM_MIXER_INPUTS 103
extern const unsigned int arizona_mixer_tlv[];
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
@@ -166,26 +166,29 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
ARIZONA_MIXER_INPUT_ROUTES(name " Input 4")
#define ARIZONA_DSP_ROUTES(name) \
- { name, NULL, name " Aux 1" }, \
- { name, NULL, name " Aux 2" }, \
- { name, NULL, name " Aux 3" }, \
- { name, NULL, name " Aux 4" }, \
- { name, NULL, name " Aux 5" }, \
- { name, NULL, name " Aux 6" }, \
+ { name, NULL, name " Preloader"}, \
+ { name " Preloader", NULL, name " Aux 1" }, \
+ { name " Preloader", NULL, name " Aux 2" }, \
+ { name " Preloader", NULL, name " Aux 3" }, \
+ { name " Preloader", NULL, name " Aux 4" }, \
+ { name " Preloader", NULL, name " Aux 5" }, \
+ { name " Preloader", NULL, name " Aux 6" }, \
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \
ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \
- ARIZONA_MIXER_ROUTES(name, name "L"), \
- ARIZONA_MIXER_ROUTES(name, name "R")
+ ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \
+ ARIZONA_MIXER_ROUTES(name " Preloader", name "R")
#define ARIZONA_RATE_ENUM_SIZE 4
extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
extern const struct soc_enum arizona_isrc_fsl[];
+extern const struct soc_enum arizona_isrc_fsh[];
+extern const struct soc_enum arizona_asrc_rate1;
extern const struct soc_enum arizona_in_vi_ramp;
extern const struct soc_enum arizona_in_vd_ramp;
@@ -199,6 +202,7 @@ extern const struct soc_enum arizona_lhpf3_mode;
extern const struct soc_enum arizona_lhpf4_mode;
extern const struct soc_enum arizona_ng_hold;
+extern const struct soc_enum arizona_in_hpf_cut_enum;
extern const struct soc_enum arizona_in_dmic_osr[];
extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 23316c887b19..43737a27d79c 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -38,24 +38,6 @@
#include <sound/soc.h>
#include <sound/initval.h>
-static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct davinci_vc *davinci_vc = codec->control_data;
-
- return readl(davinci_vc->base + reg);
-}
-
-static inline int cq93vc_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- struct davinci_vc *davinci_vc = codec->control_data;
-
- writel(value, davinci_vc->base + reg);
-
- return 0;
-}
-
static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),
SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0),
@@ -64,13 +46,15 @@ static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u8 reg = cq93vc_read(codec, DAVINCI_VC_REG09) & ~DAVINCI_VC_REG09_MUTE;
+ u8 reg;
if (mute)
- cq93vc_write(codec, DAVINCI_VC_REG09,
- reg | DAVINCI_VC_REG09_MUTE);
+ reg = DAVINCI_VC_REG09_MUTE;
else
- cq93vc_write(codec, DAVINCI_VC_REG09, reg);
+ reg = 0;
+
+ snd_soc_update_bits(codec, DAVINCI_VC_REG09, DAVINCI_VC_REG09_MUTE,
+ reg);
return 0;
}
@@ -79,7 +63,7 @@ static int cq93vc_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 davinci_vc *davinci_vc = codec->control_data;
+ struct davinci_vc *davinci_vc = codec->dev->platform_data;
switch (freq) {
case 22579200:
@@ -97,18 +81,18 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
{
switch (level) {
case SND_SOC_BIAS_ON:
- cq93vc_write(codec, DAVINCI_VC_REG12,
+ snd_soc_write(codec, DAVINCI_VC_REG12,
DAVINCI_VC_REG12_POWER_ALL_ON);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
- cq93vc_write(codec, DAVINCI_VC_REG12,
+ snd_soc_write(codec, DAVINCI_VC_REG12,
DAVINCI_VC_REG12_POWER_ALL_OFF);
break;
case SND_SOC_BIAS_OFF:
/* force all power off */
- cq93vc_write(codec, DAVINCI_VC_REG12,
+ snd_soc_write(codec, DAVINCI_VC_REG12,
DAVINCI_VC_REG12_POWER_ALL_OFF);
break;
}
@@ -154,11 +138,9 @@ static int cq93vc_probe(struct snd_soc_codec *codec)
struct davinci_vc *davinci_vc = codec->dev->platform_data;
davinci_vc->cq93vc.codec = codec;
- codec->control_data = davinci_vc;
+ codec->control_data = davinci_vc->regmap;
- /* Set controls */
- snd_soc_add_codec_controls(codec, cq93vc_snd_controls,
- ARRAY_SIZE(cq93vc_snd_controls));
+ snd_soc_codec_set_cache_io(codec, 32, 32, SND_SOC_REGMAP);
/* Off, with power on */
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -174,12 +156,12 @@ static int cq93vc_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
- .read = cq93vc_read,
- .write = cq93vc_write,
.set_bias_level = cq93vc_set_bias_level,
.probe = cq93vc_probe,
.remove = cq93vc_remove,
.resume = cq93vc_resume,
+ .controls = cq93vc_snd_controls,
+ .num_controls = ARRAY_SIZE(cq93vc_snd_controls),
};
static int cq93vc_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index a20f1bb8f071..ce05fd93dc74 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
+#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
@@ -674,7 +675,7 @@ static struct spi_driver cs4271_spi_driver = {
};
#endif /* defined(CONFIG_SPI_MASTER) */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static const struct i2c_device_id cs4271_i2c_id[] = {
{"cs4271", 0},
{}
@@ -727,7 +728,7 @@ static struct i2c_driver cs4271_i2c_driver = {
.probe = cs4271_i2c_probe,
.remove = cs4271_i2c_remove,
};
-#endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */
+#endif /* IS_ENABLED(CONFIG_I2C) */
/*
* We only register our serial bus driver here without
@@ -740,7 +741,7 @@ static int __init cs4271_modinit(void)
{
int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&cs4271_i2c_driver);
if (ret) {
pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
@@ -766,7 +767,7 @@ static void __exit cs4271_modexit(void)
spi_unregister_driver(&cs4271_spi_driver);
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&cs4271_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 1e0fa3b5f79a..6e9ea8379a91 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -423,21 +423,17 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
break;
case SND_SOC_DAIFMT_RIGHT_J:
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S16_BE:
+ switch (params_width(params)) {
+ case 16:
fmt = CS42L51_DAC_DIF_RJ16;
break;
- case SNDRV_PCM_FORMAT_S18_3LE:
- case SNDRV_PCM_FORMAT_S18_3BE:
+ case 18:
fmt = CS42L51_DAC_DIF_RJ18;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- case SNDRV_PCM_FORMAT_S20_3BE:
+ case 20:
fmt = CS42L51_DAC_DIF_RJ20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
- case SNDRV_PCM_FORMAT_S24_BE:
+ case 24:
fmt = CS42L51_DAC_DIF_RJ24;
break;
default:
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index be2ba1b6fe4a..0bac6d5a4ac8 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/input.h>
@@ -49,7 +50,7 @@ struct cs42l52_private {
u8 mclksel;
u32 mclk;
u8 flags;
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
@@ -232,7 +233,7 @@ static const struct soc_enum mic_bias_level_enum =
SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0,
ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
-static const char * const cs42l52_mic_text[] = { "Single", "Differential" };
+static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" };
static const struct soc_enum mica_enum =
SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
@@ -242,12 +243,6 @@ static const struct soc_enum micb_enum =
SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
-static const struct snd_kcontrol_new mica_mux =
- SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum);
-
-static const struct snd_kcontrol_new micb_mux =
- SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum);
-
static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
static const struct soc_enum digital_output_mux_enum =
@@ -530,6 +525,30 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
};
+static const struct snd_kcontrol_new cs42l52_mica_controls[] = {
+ SOC_ENUM("MICA Select", mica_enum),
+};
+
+static const struct snd_kcontrol_new cs42l52_micb_controls[] = {
+ SOC_ENUM("MICB Select", micb_enum),
+};
+
+static int cs42l52_add_mic_controls(struct snd_soc_codec *codec)
+{
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+ struct cs42l52_platform_data *pdata = &cs42l52->pdata;
+
+ if (!pdata->mica_diff_cfg)
+ snd_soc_add_codec_controls(codec, cs42l52_mica_controls,
+ ARRAY_SIZE(cs42l52_mica_controls));
+
+ if (!pdata->micb_diff_cfg)
+ snd_soc_add_codec_controls(codec, cs42l52_micb_controls,
+ ARRAY_SIZE(cs42l52_micb_controls));
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AIN1L"),
@@ -549,9 +568,6 @@ static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL, 0,
SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux),
- SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux),
-
SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
@@ -952,7 +968,7 @@ static int cs42l52_resume(struct snd_soc_codec *codec)
return 0;
}
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = {
261, 522, 585, 667, 706, 774, 889, 1000,
1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
@@ -1109,6 +1125,8 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
}
regcache_cache_only(cs42l52->regmap, true);
+ cs42l52_add_mic_controls(codec);
+
cs42l52_init_beep(codec);
cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1116,40 +1134,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec)
cs42l52->sysclk = CS42L52_DEFAULT_CLK;
cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
- /* Set Platform MICx CFG */
- snd_soc_update_bits(codec, CS42L52_MICA_CTL,
- CS42L52_MIC_CTL_TYPE_MASK,
- cs42l52->pdata.mica_cfg <<
- CS42L52_MIC_CTL_TYPE_SHIFT);
-
- snd_soc_update_bits(codec, CS42L52_MICB_CTL,
- CS42L52_MIC_CTL_TYPE_MASK,
- cs42l52->pdata.micb_cfg <<
- CS42L52_MIC_CTL_TYPE_SHIFT);
-
- /* if Single Ended, Get Mic_Select */
- if (cs42l52->pdata.mica_cfg)
- snd_soc_update_bits(codec, CS42L52_MICA_CTL,
- CS42L52_MIC_CTL_MIC_SEL_MASK,
- cs42l52->pdata.mica_sel <<
- CS42L52_MIC_CTL_MIC_SEL_SHIFT);
- if (cs42l52->pdata.micb_cfg)
- snd_soc_update_bits(codec, CS42L52_MICB_CTL,
- CS42L52_MIC_CTL_MIC_SEL_MASK,
- cs42l52->pdata.micb_sel <<
- CS42L52_MIC_CTL_MIC_SEL_SHIFT);
-
- /* Set Platform Charge Pump Freq */
- snd_soc_update_bits(codec, CS42L52_CHARGE_PUMP,
- CS42L52_CHARGE_PUMP_MASK,
- cs42l52->pdata.chgfreq <<
- CS42L52_CHARGE_PUMP_SHIFT);
-
- /* Set Platform Bias Level */
- snd_soc_update_bits(codec, CS42L52_IFACE_CTL2,
- CS42L52_IFACE_CTL2_BIAS_LVL,
- cs42l52->pdata.micbias_lvl);
-
return ret;
}
@@ -1205,9 +1189,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct cs42l52_private *cs42l52;
+ struct cs42l52_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
int ret;
unsigned int devid = 0;
unsigned int reg;
+ u32 val32;
cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
GFP_KERNEL);
@@ -1221,12 +1207,53 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
+ if (pdata) {
+ cs42l52->pdata = *pdata;
+ } else {
+ pdata = devm_kzalloc(&i2c_client->dev,
+ sizeof(struct cs42l52_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&i2c_client->dev, "could not allocate pdata\n");
+ return -ENOMEM;
+ }
+ if (i2c_client->dev.of_node) {
+ if (of_property_read_bool(i2c_client->dev.of_node,
+ "cirrus,mica-differential-cfg"))
+ pdata->mica_diff_cfg = true;
+
+ if (of_property_read_bool(i2c_client->dev.of_node,
+ "cirrus,micb-differential-cfg"))
+ pdata->micb_diff_cfg = true;
+
+ if (of_property_read_u32(i2c_client->dev.of_node,
+ "cirrus,micbias-lvl", &val32) >= 0)
+ pdata->micbias_lvl = val32;
+
+ if (of_property_read_u32(i2c_client->dev.of_node,
+ "cirrus,chgfreq-divisor", &val32) >= 0)
+ pdata->chgfreq = val32;
+
+ pdata->reset_gpio =
+ of_get_named_gpio(i2c_client->dev.of_node,
+ "cirrus,reset-gpio", 0);
+ }
+ cs42l52->pdata = *pdata;
+ }
- i2c_set_clientdata(i2c_client, cs42l52);
+ if (cs42l52->pdata.reset_gpio) {
+ ret = gpio_request_one(cs42l52->pdata.reset_gpio,
+ GPIOF_OUT_INIT_HIGH, "CS42L52 /RST");
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
+ cs42l52->pdata.reset_gpio, ret);
+ return ret;
+ }
+ gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 0);
+ gpio_set_value_cansleep(cs42l52->pdata.reset_gpio, 1);
+ }
- if (dev_get_platdata(&i2c_client->dev))
- memcpy(&cs42l52->pdata, dev_get_platdata(&i2c_client->dev),
- sizeof(cs42l52->pdata));
+ i2c_set_clientdata(i2c_client, cs42l52);
ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,
ARRAY_SIZE(cs42l52_threshold_patch));
@@ -1244,7 +1271,32 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
return ret;
}
- regcache_cache_only(cs42l52->regmap, true);
+ dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n",
+ reg & 0xFF);
+
+ /* Set Platform Data */
+ if (cs42l52->pdata.mica_diff_cfg)
+ regmap_update_bits(cs42l52->regmap, CS42L52_MICA_CTL,
+ CS42L52_MIC_CTL_TYPE_MASK,
+ cs42l52->pdata.mica_diff_cfg <<
+ CS42L52_MIC_CTL_TYPE_SHIFT);
+
+ if (cs42l52->pdata.micb_diff_cfg)
+ regmap_update_bits(cs42l52->regmap, CS42L52_MICB_CTL,
+ CS42L52_MIC_CTL_TYPE_MASK,
+ cs42l52->pdata.micb_diff_cfg <<
+ CS42L52_MIC_CTL_TYPE_SHIFT);
+
+ if (cs42l52->pdata.chgfreq)
+ regmap_update_bits(cs42l52->regmap, CS42L52_CHARGE_PUMP,
+ CS42L52_CHARGE_PUMP_MASK,
+ cs42l52->pdata.chgfreq <<
+ CS42L52_CHARGE_PUMP_SHIFT);
+
+ if (cs42l52->pdata.micbias_lvl)
+ regmap_update_bits(cs42l52->regmap, CS42L52_IFACE_CTL2,
+ CS42L52_IFACE_CTL2_BIAS_LVL,
+ cs42l52->pdata.micbias_lvl);
ret = snd_soc_register_codec(&i2c_client->dev,
&soc_codec_dev_cs42l52, &cs42l52_dai, 1);
@@ -1259,6 +1311,13 @@ static int cs42l52_i2c_remove(struct i2c_client *client)
return 0;
}
+static const struct of_device_id cs42l52_of_match[] = {
+ { .compatible = "cirrus,cs42l52", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs42l52_of_match);
+
+
static const struct i2c_device_id cs42l52_id[] = {
{ "cs42l52", 0 },
{ }
@@ -1269,6 +1328,7 @@ static struct i2c_driver cs42l52_i2c_driver = {
.driver = {
.name = "cs42l52",
.owner = THIS_MODULE,
+ .of_match_table = cs42l52_of_match,
},
.id_table = cs42l52_id,
.probe = cs42l52_i2c_probe,
diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h
index 4277012c4719..6fb8f00f4191 100644
--- a/sound/soc/codecs/cs42l52.h
+++ b/sound/soc/codecs/cs42l52.h
@@ -179,7 +179,7 @@
#define CS42L52_MICB_CTL 0x11
#define CS42L52_MIC_CTL_MIC_SEL_MASK 0xBF
#define CS42L52_MIC_CTL_MIC_SEL_SHIFT 6
-#define CS42L52_MIC_CTL_TYPE_MASK 0xDF
+#define CS42L52_MIC_CTL_TYPE_MASK 0x20
#define CS42L52_MIC_CTL_TYPE_SHIFT 5
@@ -269,6 +269,6 @@
#define CS42L52_FIX_BITS1 0x3E
#define CS42L52_FIX_BITS2 0x47
-#define CS42L52_MAX_REGISTER 0x34
+#define CS42L52_MAX_REGISTER 0x47
#endif
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 3b20c86cdb01..549d5d6a3fef 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -28,6 +29,7 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
+#include <sound/cs42l73.h>
#include "cs42l73.h"
struct sp_config {
@@ -35,6 +37,7 @@ struct sp_config {
u32 srate;
};
struct cs42l73_private {
+ struct cs42l73_platform_data pdata;
struct sp_config config[3];
struct regmap *regmap;
u32 sysclk;
@@ -310,15 +313,6 @@ static const struct soc_enum ng_delay_enum =
SOC_ENUM_SINGLE(CS42L73_NGCAB, 0,
ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text);
-static const char * const charge_pump_freq_text[] = {
- "0", "1", "2", "3", "4",
- "5", "6", "7", "8", "9",
- "10", "11", "12", "13", "14", "15" };
-
-static const struct soc_enum charge_pump_enum =
- SOC_ENUM_SINGLE(CS42L73_CPFCHC, 4,
- ARRAY_SIZE(charge_pump_freq_text), charge_pump_freq_text);
-
static const char * const cs42l73_mono_mix_texts[] = {
"Left", "Right", "Mono Mix"};
@@ -511,8 +505,6 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
SOC_SINGLE("NG Threshold", CS42L73_NGCAB, 2, 7, 0),
SOC_ENUM("NG Delay", ng_delay_enum),
- SOC_ENUM("Charge Pump Frequency", charge_pump_enum),
-
SOC_DOUBLE_R_TLV("XSP-IP Volume",
CS42L73_XSPAIPAA, CS42L73_XSPBIPBA, 0, 0x3F, 1,
attn_tlv),
@@ -1055,11 +1047,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- mmcc |= MS_MASTER;
+ mmcc |= CS42L73_MS_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFS:
- mmcc &= ~MS_MASTER;
+ mmcc &= ~CS42L73_MS_MASTER;
break;
default:
@@ -1071,11 +1063,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
switch (format) {
case SND_SOC_DAIFMT_I2S:
- spc &= ~SPDIF_PCM;
+ spc &= ~CS42L73_SPDIF_PCM;
break;
case SND_SOC_DAIFMT_DSP_A:
case SND_SOC_DAIFMT_DSP_B:
- if (mmcc & MS_MASTER) {
+ if (mmcc & CS42L73_MS_MASTER) {
dev_err(codec->dev,
"PCM format in slave mode only\n");
return -EINVAL;
@@ -1085,25 +1077,25 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
"PCM format is not supported on ASP port\n");
return -EINVAL;
}
- spc |= SPDIF_PCM;
+ spc |= CS42L73_SPDIF_PCM;
break;
default:
return -EINVAL;
}
- if (spc & SPDIF_PCM) {
+ if (spc & CS42L73_SPDIF_PCM) {
/* Clear PCM mode, clear PCM_BIT_ORDER bit for MSB->LSB */
- spc &= ~(PCM_MODE_MASK | PCM_BIT_ORDER);
+ spc &= ~(CS42L73_PCM_MODE_MASK | CS42L73_PCM_BIT_ORDER);
switch (format) {
case SND_SOC_DAIFMT_DSP_B:
if (inv == SND_SOC_DAIFMT_IB_IF)
- spc |= PCM_MODE0;
+ spc |= CS42L73_PCM_MODE0;
if (inv == SND_SOC_DAIFMT_IB_NF)
- spc |= PCM_MODE1;
+ spc |= CS42L73_PCM_MODE1;
break;
case SND_SOC_DAIFMT_DSP_A:
if (inv == SND_SOC_DAIFMT_IB_IF)
- spc |= PCM_MODE1;
+ spc |= CS42L73_PCM_MODE1;
break;
default:
return -EINVAL;
@@ -1163,7 +1155,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
int mclk_coeff;
int srate = params_rate(params);
- if (priv->config[id].mmcc & MS_MASTER) {
+ if (priv->config[id].mmcc & CS42L73_MS_MASTER) {
/* CS42L73 Master */
/* MCLK -> srate */
mclk_coeff =
@@ -1182,13 +1174,13 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
priv->config[id].spc &= 0xFC;
/* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
if (priv->mclk >= 6400000)
- priv->config[id].spc |= MCK_SCLK_64FS;
+ priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
else
- priv->config[id].spc |= MCK_SCLK_MCLK;
+ priv->config[id].spc |= CS42L73_MCK_SCLK_MCLK;
} else {
/* CS42L73 Slave */
priv->config[id].spc &= 0xFC;
- priv->config[id].spc |= MCK_SCLK_64FS;
+ priv->config[id].spc |= CS42L73_MCK_SCLK_64FS;
}
/* Update ASRCs */
priv->config[id].srate = srate;
@@ -1208,8 +1200,8 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 0);
- snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 0);
+ snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 0);
+ snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 0);
break;
case SND_SOC_BIAS_PREPARE:
@@ -1220,11 +1212,11 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
regcache_cache_only(cs42l73->regmap, false);
regcache_sync(cs42l73->regmap);
}
- snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
+ snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);
break;
case SND_SOC_BIAS_OFF:
- snd_soc_update_bits(codec, CS42L73_PWRCTL1, PDN, 1);
+ snd_soc_update_bits(codec, CS42L73_PWRCTL1, CS42L73_PDN, 1);
if (cs42l73->shutdwn_delay > 0) {
mdelay(cs42l73->shutdwn_delay);
cs42l73->shutdwn_delay = 0;
@@ -1233,7 +1225,7 @@ static int cs42l73_set_bias_level(struct snd_soc_codec *codec,
* down.
*/
}
- snd_soc_update_bits(codec, CS42L73_DMMCC, MCLKDIS, 1);
+ snd_soc_update_bits(codec, CS42L73_DMMCC, CS42L73_MCLKDIS, 1);
break;
}
codec->dapm.bias_level = level;
@@ -1367,11 +1359,16 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
return ret;
}
- regcache_cache_only(cs42l73->regmap, true);
-
cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- cs42l73->mclksel = CS42L73_CLKID_MCLK1; /* MCLK1 as master clk */
+ /* Set Charge Pump Frequency */
+ if (cs42l73->pdata.chgfreq)
+ snd_soc_update_bits(codec, CS42L73_CPFCHC,
+ CS42L73_CHARGEPUMP_MASK,
+ cs42l73->pdata.chgfreq << 4);
+
+ /* MCLK1 as master clk */
+ cs42l73->mclksel = CS42L73_CLKID_MCLK1;
cs42l73->mclk = 0;
return ret;
@@ -1415,9 +1412,11 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
{
struct cs42l73_private *cs42l73;
+ struct cs42l73_platform_data *pdata = dev_get_platdata(&i2c_client->dev);
int ret;
unsigned int devid = 0;
unsigned int reg;
+ u32 val32;
cs42l73 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l73_private),
GFP_KERNEL);
@@ -1426,14 +1425,49 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
return -ENOMEM;
}
- i2c_set_clientdata(i2c_client, cs42l73);
-
cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap);
if (IS_ERR(cs42l73->regmap)) {
ret = PTR_ERR(cs42l73->regmap);
dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
+
+ if (pdata) {
+ cs42l73->pdata = *pdata;
+ } else {
+ pdata = devm_kzalloc(&i2c_client->dev,
+ sizeof(struct cs42l73_platform_data),
+ GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&i2c_client->dev, "could not allocate pdata\n");
+ return -ENOMEM;
+ }
+ if (i2c_client->dev.of_node) {
+ if (of_property_read_u32(i2c_client->dev.of_node,
+ "chgfreq", &val32) >= 0)
+ pdata->chgfreq = val32;
+ }
+ pdata->reset_gpio = of_get_named_gpio(i2c_client->dev.of_node,
+ "reset-gpio", 0);
+ cs42l73->pdata = *pdata;
+ }
+
+ i2c_set_clientdata(i2c_client, cs42l73);
+
+ if (cs42l73->pdata.reset_gpio) {
+ ret = gpio_request_one(cs42l73->pdata.reset_gpio,
+ GPIOF_OUT_INIT_HIGH, "CS42L73 /RST");
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Failed to request /RST %d: %d\n",
+ cs42l73->pdata.reset_gpio, ret);
+ return ret;
+ }
+ gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 0);
+ gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1);
+ }
+
+ regcache_cache_bypass(cs42l73->regmap, true);
+
/* initialize codec */
ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, &reg);
devid = (reg & 0xFF) << 12;
@@ -1444,7 +1478,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_E, &reg);
devid |= (reg & 0xF0) >> 4;
-
if (devid != CS42L73_DEVID) {
ret = -ENODEV;
dev_err(&i2c_client->dev,
@@ -1462,7 +1495,7 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client,
dev_info(&i2c_client->dev,
"Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF);
- regcache_cache_only(cs42l73->regmap, true);
+ regcache_cache_bypass(cs42l73->regmap, false);
ret = snd_soc_register_codec(&i2c_client->dev,
&soc_codec_dev_cs42l73, cs42l73_dai,
@@ -1478,6 +1511,12 @@ static int cs42l73_i2c_remove(struct i2c_client *client)
return 0;
}
+static const struct of_device_id cs42l73_of_match[] = {
+ { .compatible = "cirrus,cs42l73", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs42l73_of_match);
+
static const struct i2c_device_id cs42l73_id[] = {
{"cs42l73", 0},
{}
@@ -1489,6 +1528,7 @@ static struct i2c_driver cs42l73_i2c_driver = {
.driver = {
.name = "cs42l73",
.owner = THIS_MODULE,
+ .of_match_table = cs42l73_of_match,
},
.id_table = cs42l73_id,
.probe = cs42l73_i2c_probe,
diff --git a/sound/soc/codecs/cs42l73.h b/sound/soc/codecs/cs42l73.h
index f30a4c4d62e6..45746186a678 100644
--- a/sound/soc/codecs/cs42l73.h
+++ b/sound/soc/codecs/cs42l73.h
@@ -128,59 +128,60 @@
/* Bitfield Definitions */
/* CS42L73_PWRCTL1 */
-#define PDN_ADCB (1 << 7)
-#define PDN_DMICB (1 << 6)
-#define PDN_ADCA (1 << 5)
-#define PDN_DMICA (1 << 4)
-#define PDN_LDO (1 << 2)
-#define DISCHG_FILT (1 << 1)
-#define PDN (1 << 0)
+#define CS42L73_PDN_ADCB (1 << 7)
+#define CS42L73_PDN_DMICB (1 << 6)
+#define CS42L73_PDN_ADCA (1 << 5)
+#define CS42L73_PDN_DMICA (1 << 4)
+#define CS42L73_PDN_LDO (1 << 2)
+#define CS42L73_DISCHG_FILT (1 << 1)
+#define CS42L73_PDN (1 << 0)
/* CS42L73_PWRCTL2 */
-#define PDN_MIC2_BIAS (1 << 7)
-#define PDN_MIC1_BIAS (1 << 6)
-#define PDN_VSP (1 << 4)
-#define PDN_ASP_SDOUT (1 << 3)
-#define PDN_ASP_SDIN (1 << 2)
-#define PDN_XSP_SDOUT (1 << 1)
-#define PDN_XSP_SDIN (1 << 0)
+#define CS42L73_PDN_MIC2_BIAS (1 << 7)
+#define CS42L73_PDN_MIC1_BIAS (1 << 6)
+#define CS42L73_PDN_VSP (1 << 4)
+#define CS42L73_PDN_ASP_SDOUT (1 << 3)
+#define CS42L73_PDN_ASP_SDIN (1 << 2)
+#define CS42L73_PDN_XSP_SDOUT (1 << 1)
+#define CS42L73_PDN_XSP_SDIN (1 << 0)
/* CS42L73_PWRCTL3 */
-#define PDN_THMS (1 << 5)
-#define PDN_SPKLO (1 << 4)
-#define PDN_EAR (1 << 3)
-#define PDN_SPK (1 << 2)
-#define PDN_LO (1 << 1)
-#define PDN_HP (1 << 0)
+#define CS42L73_PDN_THMS (1 << 5)
+#define CS42L73_PDN_SPKLO (1 << 4)
+#define CS42L73_PDN_EAR (1 << 3)
+#define CS42L73_PDN_SPK (1 << 2)
+#define CS42L73_PDN_LO (1 << 1)
+#define CS42L73_PDN_HP (1 << 0)
/* Thermal Overload Detect. Requires interrupt ... */
-#define THMOVLD_150C 0
-#define THMOVLD_132C 1
-#define THMOVLD_115C 2
-#define THMOVLD_098C 3
+#define CS42L73_THMOVLD_150C 0
+#define CS42L73_THMOVLD_132C 1
+#define CS42L73_THMOVLD_115C 2
+#define CS42L73_THMOVLD_098C 3
+#define CS42L73_CHARGEPUMP_MASK (0xF0)
/* CS42L73_ASPC, CS42L73_XSPC, CS42L73_VSPC */
-#define SP_3ST (1 << 7)
-#define SPDIF_I2S (0 << 6)
-#define SPDIF_PCM (1 << 6)
-#define PCM_MODE0 (0 << 4)
-#define PCM_MODE1 (1 << 4)
-#define PCM_MODE2 (2 << 4)
-#define PCM_MODE_MASK (3 << 4)
-#define PCM_BIT_ORDER (1 << 3)
-#define MCK_SCLK_64FS (0 << 0)
-#define MCK_SCLK_MCLK (2 << 0)
-#define MCK_SCLK_PREMCLK (3 << 0)
+#define CS42L73_SP_3ST (1 << 7)
+#define CS42L73_SPDIF_I2S (0 << 6)
+#define CS42L73_SPDIF_PCM (1 << 6)
+#define CS42L73_PCM_MODE0 (0 << 4)
+#define CS42L73_PCM_MODE1 (1 << 4)
+#define CS42L73_PCM_MODE2 (2 << 4)
+#define CS42L73_PCM_MODE_MASK (3 << 4)
+#define CS42L73_PCM_BIT_ORDER (1 << 3)
+#define CS42L73_MCK_SCLK_64FS (0 << 0)
+#define CS42L73_MCK_SCLK_MCLK (2 << 0)
+#define CS42L73_MCK_SCLK_PREMCLK (3 << 0)
/* CS42L73_xSPMMCC */
-#define MS_MASTER (1 << 7)
+#define CS42L73_MS_MASTER (1 << 7)
/* CS42L73_DMMCC */
-#define MCLKDIS (1 << 0)
-#define MCLKSEL_MCLK2 (1 << 4)
-#define MCLKSEL_MCLK1 (0 << 4)
+#define CS42L73_MCLKDIS (1 << 0)
+#define CS42L73_MCLKSEL_MCLK2 (1 << 4)
+#define CS42L73_MCLKSEL_MCLK1 (0 << 4)
/* CS42L73 MCLK derived from MCLK1 or MCLK2 */
#define CS42L73_CLKID_MCLK1 0
@@ -194,28 +195,26 @@
#define CS42L73_VSP 2
/* IS1, IM1 */
-#define MIC2_SDET (1 << 6)
-#define THMOVLD (1 << 4)
-#define DIGMIXOVFL (1 << 3)
-#define IPBOVFL (1 << 1)
-#define IPAOVFL (1 << 0)
+#define CS42L73_MIC2_SDET (1 << 6)
+#define CS42L73_THMOVLD (1 << 4)
+#define CS42L73_DIGMIXOVFL (1 << 3)
+#define CS42L73_IPBOVFL (1 << 1)
+#define CS42L73_IPAOVFL (1 << 0)
/* Analog Softramp */
-#define ANLGOSFT (1 << 0)
+#define CS42L73_ANLGOSFT (1 << 0)
/* HP A/B Analog Mute */
-#define HPA_MUTE (1 << 7)
+#define CS42L73_HPA_MUTE (1 << 7)
/* LO A/B Analog Mute */
-#define LOA_MUTE (1 << 7)
+#define CS42L73_LOA_MUTE (1 << 7)
/* Digital Mute */
-#define HLAD_MUTE (1 << 0)
-#define HLBD_MUTE (1 << 1)
-#define SPKD_MUTE (1 << 2)
-#define ESLD_MUTE (1 << 3)
+#define CS42L73_HLAD_MUTE (1 << 0)
+#define CS42L73_HLBD_MUTE (1 << 1)
+#define CS42L73_SPKD_MUTE (1 << 2)
+#define CS42L73_ESLD_MUTE (1 << 3)
/* Misc defines for codec */
-#define CS42L73_RESET_GPIO 143
-
#define CS42L73_DEVID 0x00042A73
#define CS42L73_MCLKX_MIN 5644800
#define CS42L73_MCLKX_MAX 38400000
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 9c1231456502..e62e294a8033 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -778,17 +778,17 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
dai_cfg1 |= DA7210_DAI_WORD_S20_3LE;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
dai_cfg1 |= DA7210_DAI_WORD_S32_LE;
break;
default:
@@ -1188,7 +1188,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
.num_dapm_routes = ARRAY_SIZE(da7210_audio_map),
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static struct reg_default da7210_regmap_i2c_patch[] = {
@@ -1362,7 +1362,7 @@ static struct spi_driver da7210_spi_driver = {
static int __init da7210_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&da7210_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
@@ -1378,7 +1378,7 @@ module_init(da7210_modinit);
static void __exit da7210_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&da7210_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 4a6f1daf911f..0c77e7ad7423 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1067,17 +1067,17 @@ static int da7213_hw_params(struct snd_pcm_substream *substream,
u8 fs;
/* Set DAI format */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
dai_ctrl |= DA7213_DAI_WORD_LENGTH_S16_LE;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
dai_ctrl |= DA7213_DAI_WORD_LENGTH_S20_LE;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
dai_ctrl |= DA7213_DAI_WORD_LENGTH_S24_LE;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
dai_ctrl |= DA7213_DAI_WORD_LENGTH_S32_LE;
break;
default:
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index dc0284dc9e6f..f295b6569910 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -973,17 +973,17 @@ static int da732x_hw_params(struct snd_pcm_substream *substream,
reg_aif = dai->driver->base;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
aif |= DA732X_AIF_WORD_16;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
aif |= DA732X_AIF_WORD_20;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
aif |= DA732X_AIF_WORD_24;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
aif |= DA732X_AIF_WORD_32;
break;
default:
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index fc9802d1281d..422812613a28 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1058,17 +1058,17 @@ static int da9055_hw_params(struct snd_pcm_substream *substream,
u8 aif_ctrl, fs;
u32 sysclk;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
aif_ctrl = DA9055_AIF_WORD_S16_LE;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
aif_ctrl = DA9055_AIF_WORD_S20_3LE;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
aif_ctrl = DA9055_AIF_WORD_S24_LE;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
aif_ctrl = DA9055_AIF_WORD_S32_LE;
break;
default:
@@ -1523,8 +1523,15 @@ static int da9055_remove(struct i2c_client *client)
return 0;
}
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the CODEC and PMIC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 Ids for CODEC
+ * and PMIC, which must be different to operate together.
+ */
static const struct i2c_device_id da9055_i2c_id[] = {
- { "da9055", 0 },
+ { "da9055-codec", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
@@ -1532,7 +1539,7 @@ MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
/* I2C codec control layer */
static struct i2c_driver da9055_i2c_driver = {
.driver = {
- .name = "da9055",
+ .name = "da9055-codec",
.owner = THIS_MODULE,
},
.probe = da9055_i2c_probe,
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c
index 68342b121c96..9cb1c7d3e1dc 100644
--- a/sound/soc/codecs/hdmi.c
+++ b/sound/soc/codecs/hdmi.c
@@ -20,6 +20,7 @@
*/
#include <linux/module.h>
#include <sound/soc.h>
+#include <linux/of_device.h>
#define DRV_NAME "hdmi-audio-codec"
@@ -44,7 +45,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
},
.capture = {
.stream_name = "Capture",
@@ -60,6 +61,14 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
};
+#ifdef CONFIG_OF
+static const struct of_device_id hdmi_audio_codec_ids[] = {
+ { .compatible = "linux,hdmi-audio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hdmi_audio_codec_ids);
+#endif
+
static struct snd_soc_codec_driver hdmi_codec = {
.dapm_widgets = hdmi_widgets,
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
@@ -83,6 +92,7 @@ static struct platform_driver hdmi_codec_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(hdmi_audio_codec_ids),
},
.probe = hdmi_codec_probe,
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c
index 53b455b8c07a..5839048ec467 100644
--- a/sound/soc/codecs/isabelle.c
+++ b/sound/soc/codecs/isabelle.c
@@ -951,11 +951,11 @@ static int isabelle_hw_params(struct snd_pcm_substream *substream,
ISABELLE_FS_RATE_MASK, fs_val);
/* bit size */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S20_3LE:
+ switch (params_width(params)) {
+ case 20:
aif |= ISABELLE_AIF_LENGTH_20;
break;
- case SNDRV_PCM_FORMAT_S32_LE:
+ case 32:
aif |= ISABELLE_AIF_LENGTH_32;
break;
default:
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 566a367c94fa..ee660e2d3df3 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -38,294 +39,223 @@ struct max98088_cdata {
};
struct max98088_priv {
- enum max98088_type devtype;
- struct max98088_pdata *pdata;
- unsigned int sysclk;
- struct max98088_cdata dai[2];
- int eq_textcnt;
- const char **eq_texts;
- struct soc_enum eq_enum;
- u8 ina_state;
- u8 inb_state;
- unsigned int ex_mode;
- unsigned int digmic;
- unsigned int mic1pre;
- unsigned int mic2pre;
- unsigned int extmic_mode;
+ struct regmap *regmap;
+ enum max98088_type devtype;
+ struct max98088_pdata *pdata;
+ unsigned int sysclk;
+ struct max98088_cdata dai[2];
+ int eq_textcnt;
+ const char **eq_texts;
+ struct soc_enum eq_enum;
+ u8 ina_state;
+ u8 inb_state;
+ unsigned int ex_mode;
+ unsigned int digmic;
+ unsigned int mic1pre;
+ unsigned int mic2pre;
+ unsigned int extmic_mode;
};
-static const u8 max98088_reg[M98088_REG_CNT] = {
- 0x00, /* 00 IRQ status */
- 0x00, /* 01 MIC status */
- 0x00, /* 02 jack status */
- 0x00, /* 03 battery voltage */
- 0x00, /* 04 */
- 0x00, /* 05 */
- 0x00, /* 06 */
- 0x00, /* 07 */
- 0x00, /* 08 */
- 0x00, /* 09 */
- 0x00, /* 0A */
- 0x00, /* 0B */
- 0x00, /* 0C */
- 0x00, /* 0D */
- 0x00, /* 0E */
- 0x00, /* 0F interrupt enable */
-
- 0x00, /* 10 master clock */
- 0x00, /* 11 DAI1 clock mode */
- 0x00, /* 12 DAI1 clock control */
- 0x00, /* 13 DAI1 clock control */
- 0x00, /* 14 DAI1 format */
- 0x00, /* 15 DAI1 clock */
- 0x00, /* 16 DAI1 config */
- 0x00, /* 17 DAI1 TDM */
- 0x00, /* 18 DAI1 filters */
- 0x00, /* 19 DAI2 clock mode */
- 0x00, /* 1A DAI2 clock control */
- 0x00, /* 1B DAI2 clock control */
- 0x00, /* 1C DAI2 format */
- 0x00, /* 1D DAI2 clock */
- 0x00, /* 1E DAI2 config */
- 0x00, /* 1F DAI2 TDM */
-
- 0x00, /* 20 DAI2 filters */
- 0x00, /* 21 data config */
- 0x00, /* 22 DAC mixer */
- 0x00, /* 23 left ADC mixer */
- 0x00, /* 24 right ADC mixer */
- 0x00, /* 25 left HP mixer */
- 0x00, /* 26 right HP mixer */
- 0x00, /* 27 HP control */
- 0x00, /* 28 left REC mixer */
- 0x00, /* 29 right REC mixer */
- 0x00, /* 2A REC control */
- 0x00, /* 2B left SPK mixer */
- 0x00, /* 2C right SPK mixer */
- 0x00, /* 2D SPK control */
- 0x00, /* 2E sidetone */
- 0x00, /* 2F DAI1 playback level */
-
- 0x00, /* 30 DAI1 playback level */
- 0x00, /* 31 DAI2 playback level */
- 0x00, /* 32 DAI2 playbakc level */
- 0x00, /* 33 left ADC level */
- 0x00, /* 34 right ADC level */
- 0x00, /* 35 MIC1 level */
- 0x00, /* 36 MIC2 level */
- 0x00, /* 37 INA level */
- 0x00, /* 38 INB level */
- 0x00, /* 39 left HP volume */
- 0x00, /* 3A right HP volume */
- 0x00, /* 3B left REC volume */
- 0x00, /* 3C right REC volume */
- 0x00, /* 3D left SPK volume */
- 0x00, /* 3E right SPK volume */
- 0x00, /* 3F MIC config */
-
- 0x00, /* 40 MIC threshold */
- 0x00, /* 41 excursion limiter filter */
- 0x00, /* 42 excursion limiter threshold */
- 0x00, /* 43 ALC */
- 0x00, /* 44 power limiter threshold */
- 0x00, /* 45 power limiter config */
- 0x00, /* 46 distortion limiter config */
- 0x00, /* 47 audio input */
- 0x00, /* 48 microphone */
- 0x00, /* 49 level control */
- 0x00, /* 4A bypass switches */
- 0x00, /* 4B jack detect */
- 0x00, /* 4C input enable */
- 0x00, /* 4D output enable */
- 0xF0, /* 4E bias control */
- 0x00, /* 4F DAC power */
-
- 0x0F, /* 50 DAC power */
- 0x00, /* 51 system */
- 0x00, /* 52 DAI1 EQ1 */
- 0x00, /* 53 DAI1 EQ1 */
- 0x00, /* 54 DAI1 EQ1 */
- 0x00, /* 55 DAI1 EQ1 */
- 0x00, /* 56 DAI1 EQ1 */
- 0x00, /* 57 DAI1 EQ1 */
- 0x00, /* 58 DAI1 EQ1 */
- 0x00, /* 59 DAI1 EQ1 */
- 0x00, /* 5A DAI1 EQ1 */
- 0x00, /* 5B DAI1 EQ1 */
- 0x00, /* 5C DAI1 EQ2 */
- 0x00, /* 5D DAI1 EQ2 */
- 0x00, /* 5E DAI1 EQ2 */
- 0x00, /* 5F DAI1 EQ2 */
-
- 0x00, /* 60 DAI1 EQ2 */
- 0x00, /* 61 DAI1 EQ2 */
- 0x00, /* 62 DAI1 EQ2 */
- 0x00, /* 63 DAI1 EQ2 */
- 0x00, /* 64 DAI1 EQ2 */
- 0x00, /* 65 DAI1 EQ2 */
- 0x00, /* 66 DAI1 EQ3 */
- 0x00, /* 67 DAI1 EQ3 */
- 0x00, /* 68 DAI1 EQ3 */
- 0x00, /* 69 DAI1 EQ3 */
- 0x00, /* 6A DAI1 EQ3 */
- 0x00, /* 6B DAI1 EQ3 */
- 0x00, /* 6C DAI1 EQ3 */
- 0x00, /* 6D DAI1 EQ3 */
- 0x00, /* 6E DAI1 EQ3 */
- 0x00, /* 6F DAI1 EQ3 */
-
- 0x00, /* 70 DAI1 EQ4 */
- 0x00, /* 71 DAI1 EQ4 */
- 0x00, /* 72 DAI1 EQ4 */
- 0x00, /* 73 DAI1 EQ4 */
- 0x00, /* 74 DAI1 EQ4 */
- 0x00, /* 75 DAI1 EQ4 */
- 0x00, /* 76 DAI1 EQ4 */
- 0x00, /* 77 DAI1 EQ4 */
- 0x00, /* 78 DAI1 EQ4 */
- 0x00, /* 79 DAI1 EQ4 */
- 0x00, /* 7A DAI1 EQ5 */
- 0x00, /* 7B DAI1 EQ5 */
- 0x00, /* 7C DAI1 EQ5 */
- 0x00, /* 7D DAI1 EQ5 */
- 0x00, /* 7E DAI1 EQ5 */
- 0x00, /* 7F DAI1 EQ5 */
-
- 0x00, /* 80 DAI1 EQ5 */
- 0x00, /* 81 DAI1 EQ5 */
- 0x00, /* 82 DAI1 EQ5 */
- 0x00, /* 83 DAI1 EQ5 */
- 0x00, /* 84 DAI2 EQ1 */
- 0x00, /* 85 DAI2 EQ1 */
- 0x00, /* 86 DAI2 EQ1 */
- 0x00, /* 87 DAI2 EQ1 */
- 0x00, /* 88 DAI2 EQ1 */
- 0x00, /* 89 DAI2 EQ1 */
- 0x00, /* 8A DAI2 EQ1 */
- 0x00, /* 8B DAI2 EQ1 */
- 0x00, /* 8C DAI2 EQ1 */
- 0x00, /* 8D DAI2 EQ1 */
- 0x00, /* 8E DAI2 EQ2 */
- 0x00, /* 8F DAI2 EQ2 */
-
- 0x00, /* 90 DAI2 EQ2 */
- 0x00, /* 91 DAI2 EQ2 */
- 0x00, /* 92 DAI2 EQ2 */
- 0x00, /* 93 DAI2 EQ2 */
- 0x00, /* 94 DAI2 EQ2 */
- 0x00, /* 95 DAI2 EQ2 */
- 0x00, /* 96 DAI2 EQ2 */
- 0x00, /* 97 DAI2 EQ2 */
- 0x00, /* 98 DAI2 EQ3 */
- 0x00, /* 99 DAI2 EQ3 */
- 0x00, /* 9A DAI2 EQ3 */
- 0x00, /* 9B DAI2 EQ3 */
- 0x00, /* 9C DAI2 EQ3 */
- 0x00, /* 9D DAI2 EQ3 */
- 0x00, /* 9E DAI2 EQ3 */
- 0x00, /* 9F DAI2 EQ3 */
-
- 0x00, /* A0 DAI2 EQ3 */
- 0x00, /* A1 DAI2 EQ3 */
- 0x00, /* A2 DAI2 EQ4 */
- 0x00, /* A3 DAI2 EQ4 */
- 0x00, /* A4 DAI2 EQ4 */
- 0x00, /* A5 DAI2 EQ4 */
- 0x00, /* A6 DAI2 EQ4 */
- 0x00, /* A7 DAI2 EQ4 */
- 0x00, /* A8 DAI2 EQ4 */
- 0x00, /* A9 DAI2 EQ4 */
- 0x00, /* AA DAI2 EQ4 */
- 0x00, /* AB DAI2 EQ4 */
- 0x00, /* AC DAI2 EQ5 */
- 0x00, /* AD DAI2 EQ5 */
- 0x00, /* AE DAI2 EQ5 */
- 0x00, /* AF DAI2 EQ5 */
-
- 0x00, /* B0 DAI2 EQ5 */
- 0x00, /* B1 DAI2 EQ5 */
- 0x00, /* B2 DAI2 EQ5 */
- 0x00, /* B3 DAI2 EQ5 */
- 0x00, /* B4 DAI2 EQ5 */
- 0x00, /* B5 DAI2 EQ5 */
- 0x00, /* B6 DAI1 biquad */
- 0x00, /* B7 DAI1 biquad */
- 0x00, /* B8 DAI1 biquad */
- 0x00, /* B9 DAI1 biquad */
- 0x00, /* BA DAI1 biquad */
- 0x00, /* BB DAI1 biquad */
- 0x00, /* BC DAI1 biquad */
- 0x00, /* BD DAI1 biquad */
- 0x00, /* BE DAI1 biquad */
- 0x00, /* BF DAI1 biquad */
-
- 0x00, /* C0 DAI2 biquad */
- 0x00, /* C1 DAI2 biquad */
- 0x00, /* C2 DAI2 biquad */
- 0x00, /* C3 DAI2 biquad */
- 0x00, /* C4 DAI2 biquad */
- 0x00, /* C5 DAI2 biquad */
- 0x00, /* C6 DAI2 biquad */
- 0x00, /* C7 DAI2 biquad */
- 0x00, /* C8 DAI2 biquad */
- 0x00, /* C9 DAI2 biquad */
- 0x00, /* CA */
- 0x00, /* CB */
- 0x00, /* CC */
- 0x00, /* CD */
- 0x00, /* CE */
- 0x00, /* CF */
-
- 0x00, /* D0 */
- 0x00, /* D1 */
- 0x00, /* D2 */
- 0x00, /* D3 */
- 0x00, /* D4 */
- 0x00, /* D5 */
- 0x00, /* D6 */
- 0x00, /* D7 */
- 0x00, /* D8 */
- 0x00, /* D9 */
- 0x00, /* DA */
- 0x70, /* DB */
- 0x00, /* DC */
- 0x00, /* DD */
- 0x00, /* DE */
- 0x00, /* DF */
-
- 0x00, /* E0 */
- 0x00, /* E1 */
- 0x00, /* E2 */
- 0x00, /* E3 */
- 0x00, /* E4 */
- 0x00, /* E5 */
- 0x00, /* E6 */
- 0x00, /* E7 */
- 0x00, /* E8 */
- 0x00, /* E9 */
- 0x00, /* EA */
- 0x00, /* EB */
- 0x00, /* EC */
- 0x00, /* ED */
- 0x00, /* EE */
- 0x00, /* EF */
-
- 0x00, /* F0 */
- 0x00, /* F1 */
- 0x00, /* F2 */
- 0x00, /* F3 */
- 0x00, /* F4 */
- 0x00, /* F5 */
- 0x00, /* F6 */
- 0x00, /* F7 */
- 0x00, /* F8 */
- 0x00, /* F9 */
- 0x00, /* FA */
- 0x00, /* FB */
- 0x00, /* FC */
- 0x00, /* FD */
- 0x00, /* FE */
- 0x00, /* FF */
+static const struct reg_default max98088_reg[] = {
+ { 0xf, 0x00 }, /* 0F interrupt enable */
+
+ { 0x10, 0x00 }, /* 10 master clock */
+ { 0x11, 0x00 }, /* 11 DAI1 clock mode */
+ { 0x12, 0x00 }, /* 12 DAI1 clock control */
+ { 0x13, 0x00 }, /* 13 DAI1 clock control */
+ { 0x14, 0x00 }, /* 14 DAI1 format */
+ { 0x15, 0x00 }, /* 15 DAI1 clock */
+ { 0x16, 0x00 }, /* 16 DAI1 config */
+ { 0x17, 0x00 }, /* 17 DAI1 TDM */
+ { 0x18, 0x00 }, /* 18 DAI1 filters */
+ { 0x19, 0x00 }, /* 19 DAI2 clock mode */
+ { 0x1a, 0x00 }, /* 1A DAI2 clock control */
+ { 0x1b, 0x00 }, /* 1B DAI2 clock control */
+ { 0x1c, 0x00 }, /* 1C DAI2 format */
+ { 0x1d, 0x00 }, /* 1D DAI2 clock */
+ { 0x1e, 0x00 }, /* 1E DAI2 config */
+ { 0x1f, 0x00 }, /* 1F DAI2 TDM */
+
+ { 0x20, 0x00 }, /* 20 DAI2 filters */
+ { 0x21, 0x00 }, /* 21 data config */
+ { 0x22, 0x00 }, /* 22 DAC mixer */
+ { 0x23, 0x00 }, /* 23 left ADC mixer */
+ { 0x24, 0x00 }, /* 24 right ADC mixer */
+ { 0x25, 0x00 }, /* 25 left HP mixer */
+ { 0x26, 0x00 }, /* 26 right HP mixer */
+ { 0x27, 0x00 }, /* 27 HP control */
+ { 0x28, 0x00 }, /* 28 left REC mixer */
+ { 0x29, 0x00 }, /* 29 right REC mixer */
+ { 0x2a, 0x00 }, /* 2A REC control */
+ { 0x2b, 0x00 }, /* 2B left SPK mixer */
+ { 0x2c, 0x00 }, /* 2C right SPK mixer */
+ { 0x2d, 0x00 }, /* 2D SPK control */
+ { 0x2e, 0x00 }, /* 2E sidetone */
+ { 0x2f, 0x00 }, /* 2F DAI1 playback level */
+
+ { 0x30, 0x00 }, /* 30 DAI1 playback level */
+ { 0x31, 0x00 }, /* 31 DAI2 playback level */
+ { 0x32, 0x00 }, /* 32 DAI2 playbakc level */
+ { 0x33, 0x00 }, /* 33 left ADC level */
+ { 0x34, 0x00 }, /* 34 right ADC level */
+ { 0x35, 0x00 }, /* 35 MIC1 level */
+ { 0x36, 0x00 }, /* 36 MIC2 level */
+ { 0x37, 0x00 }, /* 37 INA level */
+ { 0x38, 0x00 }, /* 38 INB level */
+ { 0x39, 0x00 }, /* 39 left HP volume */
+ { 0x3a, 0x00 }, /* 3A right HP volume */
+ { 0x3b, 0x00 }, /* 3B left REC volume */
+ { 0x3c, 0x00 }, /* 3C right REC volume */
+ { 0x3d, 0x00 }, /* 3D left SPK volume */
+ { 0x3e, 0x00 }, /* 3E right SPK volume */
+ { 0x3f, 0x00 }, /* 3F MIC config */
+
+ { 0x40, 0x00 }, /* 40 MIC threshold */
+ { 0x41, 0x00 }, /* 41 excursion limiter filter */
+ { 0x42, 0x00 }, /* 42 excursion limiter threshold */
+ { 0x43, 0x00 }, /* 43 ALC */
+ { 0x44, 0x00 }, /* 44 power limiter threshold */
+ { 0x45, 0x00 }, /* 45 power limiter config */
+ { 0x46, 0x00 }, /* 46 distortion limiter config */
+ { 0x47, 0x00 }, /* 47 audio input */
+ { 0x48, 0x00 }, /* 48 microphone */
+ { 0x49, 0x00 }, /* 49 level control */
+ { 0x4a, 0x00 }, /* 4A bypass switches */
+ { 0x4b, 0x00 }, /* 4B jack detect */
+ { 0x4c, 0x00 }, /* 4C input enable */
+ { 0x4d, 0x00 }, /* 4D output enable */
+ { 0x4e, 0xF0 }, /* 4E bias control */
+ { 0x4f, 0x00 }, /* 4F DAC power */
+
+ { 0x50, 0x0F }, /* 50 DAC power */
+ { 0x51, 0x00 }, /* 51 system */
+ { 0x52, 0x00 }, /* 52 DAI1 EQ1 */
+ { 0x53, 0x00 }, /* 53 DAI1 EQ1 */
+ { 0x54, 0x00 }, /* 54 DAI1 EQ1 */
+ { 0x55, 0x00 }, /* 55 DAI1 EQ1 */
+ { 0x56, 0x00 }, /* 56 DAI1 EQ1 */
+ { 0x57, 0x00 }, /* 57 DAI1 EQ1 */
+ { 0x58, 0x00 }, /* 58 DAI1 EQ1 */
+ { 0x59, 0x00 }, /* 59 DAI1 EQ1 */
+ { 0x5a, 0x00 }, /* 5A DAI1 EQ1 */
+ { 0x5b, 0x00 }, /* 5B DAI1 EQ1 */
+ { 0x5c, 0x00 }, /* 5C DAI1 EQ2 */
+ { 0x5d, 0x00 }, /* 5D DAI1 EQ2 */
+ { 0x5e, 0x00 }, /* 5E DAI1 EQ2 */
+ { 0x5f, 0x00 }, /* 5F DAI1 EQ2 */
+
+ { 0x60, 0x00 }, /* 60 DAI1 EQ2 */
+ { 0x61, 0x00 }, /* 61 DAI1 EQ2 */
+ { 0x62, 0x00 }, /* 62 DAI1 EQ2 */
+ { 0x63, 0x00 }, /* 63 DAI1 EQ2 */
+ { 0x64, 0x00 }, /* 64 DAI1 EQ2 */
+ { 0x65, 0x00 }, /* 65 DAI1 EQ2 */
+ { 0x66, 0x00 }, /* 66 DAI1 EQ3 */
+ { 0x67, 0x00 }, /* 67 DAI1 EQ3 */
+ { 0x68, 0x00 }, /* 68 DAI1 EQ3 */
+ { 0x69, 0x00 }, /* 69 DAI1 EQ3 */
+ { 0x6a, 0x00 }, /* 6A DAI1 EQ3 */
+ { 0x6b, 0x00 }, /* 6B DAI1 EQ3 */
+ { 0x6c, 0x00 }, /* 6C DAI1 EQ3 */
+ { 0x6d, 0x00 }, /* 6D DAI1 EQ3 */
+ { 0x6e, 0x00 }, /* 6E DAI1 EQ3 */
+ { 0x6f, 0x00 }, /* 6F DAI1 EQ3 */
+
+ { 0x70, 0x00 }, /* 70 DAI1 EQ4 */
+ { 0x71, 0x00 }, /* 71 DAI1 EQ4 */
+ { 0x72, 0x00 }, /* 72 DAI1 EQ4 */
+ { 0x73, 0x00 }, /* 73 DAI1 EQ4 */
+ { 0x74, 0x00 }, /* 74 DAI1 EQ4 */
+ { 0x75, 0x00 }, /* 75 DAI1 EQ4 */
+ { 0x76, 0x00 }, /* 76 DAI1 EQ4 */
+ { 0x77, 0x00 }, /* 77 DAI1 EQ4 */
+ { 0x78, 0x00 }, /* 78 DAI1 EQ4 */
+ { 0x79, 0x00 }, /* 79 DAI1 EQ4 */
+ { 0x7a, 0x00 }, /* 7A DAI1 EQ5 */
+ { 0x7b, 0x00 }, /* 7B DAI1 EQ5 */
+ { 0x7c, 0x00 }, /* 7C DAI1 EQ5 */
+ { 0x7d, 0x00 }, /* 7D DAI1 EQ5 */
+ { 0x7e, 0x00 }, /* 7E DAI1 EQ5 */
+ { 0x7f, 0x00 }, /* 7F DAI1 EQ5 */
+
+ { 0x80, 0x00 }, /* 80 DAI1 EQ5 */
+ { 0x81, 0x00 }, /* 81 DAI1 EQ5 */
+ { 0x82, 0x00 }, /* 82 DAI1 EQ5 */
+ { 0x83, 0x00 }, /* 83 DAI1 EQ5 */
+ { 0x84, 0x00 }, /* 84 DAI2 EQ1 */
+ { 0x85, 0x00 }, /* 85 DAI2 EQ1 */
+ { 0x86, 0x00 }, /* 86 DAI2 EQ1 */
+ { 0x87, 0x00 }, /* 87 DAI2 EQ1 */
+ { 0x88, 0x00 }, /* 88 DAI2 EQ1 */
+ { 0x89, 0x00 }, /* 89 DAI2 EQ1 */
+ { 0x8a, 0x00 }, /* 8A DAI2 EQ1 */
+ { 0x8b, 0x00 }, /* 8B DAI2 EQ1 */
+ { 0x8c, 0x00 }, /* 8C DAI2 EQ1 */
+ { 0x8d, 0x00 }, /* 8D DAI2 EQ1 */
+ { 0x8e, 0x00 }, /* 8E DAI2 EQ2 */
+ { 0x8f, 0x00 }, /* 8F DAI2 EQ2 */
+
+ { 0x90, 0x00 }, /* 90 DAI2 EQ2 */
+ { 0x91, 0x00 }, /* 91 DAI2 EQ2 */
+ { 0x92, 0x00 }, /* 92 DAI2 EQ2 */
+ { 0x93, 0x00 }, /* 93 DAI2 EQ2 */
+ { 0x94, 0x00 }, /* 94 DAI2 EQ2 */
+ { 0x95, 0x00 }, /* 95 DAI2 EQ2 */
+ { 0x96, 0x00 }, /* 96 DAI2 EQ2 */
+ { 0x97, 0x00 }, /* 97 DAI2 EQ2 */
+ { 0x98, 0x00 }, /* 98 DAI2 EQ3 */
+ { 0x99, 0x00 }, /* 99 DAI2 EQ3 */
+ { 0x9a, 0x00 }, /* 9A DAI2 EQ3 */
+ { 0x9b, 0x00 }, /* 9B DAI2 EQ3 */
+ { 0x9c, 0x00 }, /* 9C DAI2 EQ3 */
+ { 0x9d, 0x00 }, /* 9D DAI2 EQ3 */
+ { 0x9e, 0x00 }, /* 9E DAI2 EQ3 */
+ { 0x9f, 0x00 }, /* 9F DAI2 EQ3 */
+
+ { 0xa0, 0x00 }, /* A0 DAI2 EQ3 */
+ { 0xa1, 0x00 }, /* A1 DAI2 EQ3 */
+ { 0xa2, 0x00 }, /* A2 DAI2 EQ4 */
+ { 0xa3, 0x00 }, /* A3 DAI2 EQ4 */
+ { 0xa4, 0x00 }, /* A4 DAI2 EQ4 */
+ { 0xa5, 0x00 }, /* A5 DAI2 EQ4 */
+ { 0xa6, 0x00 }, /* A6 DAI2 EQ4 */
+ { 0xa7, 0x00 }, /* A7 DAI2 EQ4 */
+ { 0xa8, 0x00 }, /* A8 DAI2 EQ4 */
+ { 0xa9, 0x00 }, /* A9 DAI2 EQ4 */
+ { 0xaa, 0x00 }, /* AA DAI2 EQ4 */
+ { 0xab, 0x00 }, /* AB DAI2 EQ4 */
+ { 0xac, 0x00 }, /* AC DAI2 EQ5 */
+ { 0xad, 0x00 }, /* AD DAI2 EQ5 */
+ { 0xae, 0x00 }, /* AE DAI2 EQ5 */
+ { 0xaf, 0x00 }, /* AF DAI2 EQ5 */
+
+ { 0xb0, 0x00 }, /* B0 DAI2 EQ5 */
+ { 0xb1, 0x00 }, /* B1 DAI2 EQ5 */
+ { 0xb2, 0x00 }, /* B2 DAI2 EQ5 */
+ { 0xb3, 0x00 }, /* B3 DAI2 EQ5 */
+ { 0xb4, 0x00 }, /* B4 DAI2 EQ5 */
+ { 0xb5, 0x00 }, /* B5 DAI2 EQ5 */
+ { 0xb6, 0x00 }, /* B6 DAI1 biquad */
+ { 0xb7, 0x00 }, /* B7 DAI1 biquad */
+ { 0xb8 ,0x00 }, /* B8 DAI1 biquad */
+ { 0xb9, 0x00 }, /* B9 DAI1 biquad */
+ { 0xba, 0x00 }, /* BA DAI1 biquad */
+ { 0xbb, 0x00 }, /* BB DAI1 biquad */
+ { 0xbc, 0x00 }, /* BC DAI1 biquad */
+ { 0xbd, 0x00 }, /* BD DAI1 biquad */
+ { 0xbe, 0x00 }, /* BE DAI1 biquad */
+ { 0xbf, 0x00 }, /* BF DAI1 biquad */
+
+ { 0xc0, 0x00 }, /* C0 DAI2 biquad */
+ { 0xc1, 0x00 }, /* C1 DAI2 biquad */
+ { 0xc2, 0x00 }, /* C2 DAI2 biquad */
+ { 0xc3, 0x00 }, /* C3 DAI2 biquad */
+ { 0xc4, 0x00 }, /* C4 DAI2 biquad */
+ { 0xc5, 0x00 }, /* C5 DAI2 biquad */
+ { 0xc6, 0x00 }, /* C6 DAI2 biquad */
+ { 0xc7, 0x00 }, /* C7 DAI2 biquad */
+ { 0xc8, 0x00 }, /* C8 DAI2 biquad */
+ { 0xc9, 0x00 }, /* C9 DAI2 biquad */
};
static struct {
@@ -606,11 +536,28 @@ static struct {
{ 0xFF, 0x00, 1 }, /* FF */
};
-static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+static bool max98088_readable_register(struct device *dev, unsigned int reg)
+{
+ return max98088_access[reg].readable;
+}
+
+static bool max98088_volatile_register(struct device *dev, unsigned int reg)
{
return max98088_access[reg].vol;
}
+static const struct regmap_config max98088_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .readable_reg = max98088_readable_register,
+ .volatile_reg = max98088_volatile_register,
+ .max_register = 0xff,
+
+ .reg_defaults = max98088_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98088_reg),
+ .cache_type = REGCACHE_RBTREE,
+};
/*
* Load equalizer DSP coefficient configurations registers
@@ -621,8 +568,9 @@ static void m98088_eq_band(struct snd_soc_codec *codec, unsigned int dai,
unsigned int eq_reg;
unsigned int i;
- BUG_ON(band > 4);
- BUG_ON(dai > 1);
+ if (WARN_ON(band > 4) ||
+ WARN_ON(dai > 1))
+ return;
/* Load the base register address */
eq_reg = dai ? M98088_REG_84_DAI2_EQ_BASE : M98088_REG_52_DAI1_EQ_BASE;
@@ -962,7 +910,8 @@ static int max98088_line_pga(struct snd_soc_dapm_widget *w,
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
u8 *state;
- BUG_ON(!((channel == 1) || (channel == 2)));
+ if (WARN_ON(!(channel == 1 || channel == 2)))
+ return -EINVAL;
switch (line) {
case LINE_INA:
@@ -1284,12 +1233,12 @@ static int max98088_dai1_hw_params(struct snd_pcm_substream *substream,
rate = params_rate(params);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
M98088_DAI_WS, 0);
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
snd_soc_update_bits(codec, M98088_REG_14_DAI1_FORMAT,
M98088_DAI_WS, M98088_DAI_WS);
break;
@@ -1610,58 +1559,34 @@ static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
return 0;
}
-static void max98088_sync_cache(struct snd_soc_codec *codec)
-{
- u8 *reg_cache = codec->reg_cache;
- int i;
-
- if (!codec->cache_sync)
- return;
-
- codec->cache_only = 0;
-
- /* write back cached values if they're writeable and
- * different from the hardware default.
- */
- for (i = 1; i < codec->driver->reg_cache_size; i++) {
- if (!max98088_access[i].writable)
- continue;
-
- if (reg_cache[i] == max98088_reg[i])
- continue;
-
- snd_soc_write(codec, i, reg_cache[i]);
- }
-
- codec->cache_sync = 0;
-}
-
static int max98088_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- switch (level) {
- case SND_SOC_BIAS_ON:
- break;
-
- case SND_SOC_BIAS_PREPARE:
- break;
-
- case SND_SOC_BIAS_STANDBY:
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
- max98088_sync_cache(codec);
-
- snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
- M98088_MBEN, M98088_MBEN);
- break;
-
- case SND_SOC_BIAS_OFF:
- snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
- M98088_MBEN, 0);
- codec->cache_sync = 1;
- break;
- }
- codec->dapm.bias_level = level;
- return 0;
+ struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ regcache_sync(max98088->regmap);
+
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, M98088_MBEN);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
+ M98088_MBEN, 0);
+ regcache_mark_dirty(max98088->regmap);
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
}
#define MAX98088_RATES SNDRV_PCM_RATE_8000_96000
@@ -1988,9 +1913,9 @@ static int max98088_probe(struct snd_soc_codec *codec)
struct max98088_cdata *cdata;
int ret = 0;
- codec->cache_sync = 1;
+ regcache_mark_dirty(max98088->regmap);
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -2048,9 +1973,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
max98088_handle_pdata(codec);
- snd_soc_add_codec_controls(codec, max98088_snd_controls,
- ARRAY_SIZE(max98088_snd_controls));
-
err_access:
return ret;
}
@@ -2066,15 +1988,13 @@ static int max98088_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
- .probe = max98088_probe,
- .remove = max98088_remove,
- .suspend = max98088_suspend,
- .resume = max98088_resume,
- .set_bias_level = max98088_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(max98088_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = max98088_reg,
- .volatile_register = max98088_volatile_register,
+ .probe = max98088_probe,
+ .remove = max98088_remove,
+ .suspend = max98088_suspend,
+ .resume = max98088_resume,
+ .set_bias_level = max98088_set_bias_level,
+ .controls = max98088_snd_controls,
+ .num_controls = ARRAY_SIZE(max98088_snd_controls),
.dapm_widgets = max98088_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
.dapm_routes = max98088_audio_map,
@@ -2082,7 +2002,7 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
};
static int max98088_i2c_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct max98088_priv *max98088;
int ret;
@@ -2092,6 +2012,10 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
if (max98088 == NULL)
return -ENOMEM;
+ max98088->regmap = devm_regmap_init_i2c(i2c, &max98088_regmap);
+ if (IS_ERR(max98088->regmap))
+ return PTR_ERR(max98088->regmap);
+
max98088->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98088);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 0569a4c3ae00..9f714ea86613 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg)
case M98090_REG_RECORD_TDM_SLOT:
case M98090_REG_SAMPLE_RATE:
case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E:
+ case M98090_REG_REVISION_ID:
return true;
default:
return false;
@@ -1769,16 +1770,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
- if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = regcache_sync(max98090->regmap);
-
- if (ret != 0) {
- dev_err(codec->dev,
- "Failed to sync cache: %d\n", ret);
- return ret;
- }
- }
-
if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
/*
* Set to normal bias level.
@@ -1792,6 +1783,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ ret = regcache_sync(max98090->regmap);
+ if (ret != 0) {
+ dev_err(codec->dev,
+ "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+ }
+ break;
+
case SND_SOC_BIAS_OFF:
/* Set internal pull-up to lowest power mode */
snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
@@ -1840,8 +1841,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
max98090->lrclk = params_rate(params);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
snd_soc_update_bits(codec, M98090_REG_INTERFACE_FORMAT,
M98090_WS_MASK, 0);
break;
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 41cdd1642970..3ba1170ebb53 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -39,6 +39,7 @@ struct max98095_cdata {
};
struct max98095_priv {
+ struct regmap *regmap;
enum max98095_type devtype;
struct max98095_pdata *pdata;
unsigned int sysclk;
@@ -56,263 +57,145 @@ struct max98095_priv {
struct snd_soc_jack *mic_jack;
};
-static const u8 max98095_reg_def[M98095_REG_CNT] = {
- 0x00, /* 00 */
- 0x00, /* 01 */
- 0x00, /* 02 */
- 0x00, /* 03 */
- 0x00, /* 04 */
- 0x00, /* 05 */
- 0x00, /* 06 */
- 0x00, /* 07 */
- 0x00, /* 08 */
- 0x00, /* 09 */
- 0x00, /* 0A */
- 0x00, /* 0B */
- 0x00, /* 0C */
- 0x00, /* 0D */
- 0x00, /* 0E */
- 0x00, /* 0F */
- 0x00, /* 10 */
- 0x00, /* 11 */
- 0x00, /* 12 */
- 0x00, /* 13 */
- 0x00, /* 14 */
- 0x00, /* 15 */
- 0x00, /* 16 */
- 0x00, /* 17 */
- 0x00, /* 18 */
- 0x00, /* 19 */
- 0x00, /* 1A */
- 0x00, /* 1B */
- 0x00, /* 1C */
- 0x00, /* 1D */
- 0x00, /* 1E */
- 0x00, /* 1F */
- 0x00, /* 20 */
- 0x00, /* 21 */
- 0x00, /* 22 */
- 0x00, /* 23 */
- 0x00, /* 24 */
- 0x00, /* 25 */
- 0x00, /* 26 */
- 0x00, /* 27 */
- 0x00, /* 28 */
- 0x00, /* 29 */
- 0x00, /* 2A */
- 0x00, /* 2B */
- 0x00, /* 2C */
- 0x00, /* 2D */
- 0x00, /* 2E */
- 0x00, /* 2F */
- 0x00, /* 30 */
- 0x00, /* 31 */
- 0x00, /* 32 */
- 0x00, /* 33 */
- 0x00, /* 34 */
- 0x00, /* 35 */
- 0x00, /* 36 */
- 0x00, /* 37 */
- 0x00, /* 38 */
- 0x00, /* 39 */
- 0x00, /* 3A */
- 0x00, /* 3B */
- 0x00, /* 3C */
- 0x00, /* 3D */
- 0x00, /* 3E */
- 0x00, /* 3F */
- 0x00, /* 40 */
- 0x00, /* 41 */
- 0x00, /* 42 */
- 0x00, /* 43 */
- 0x00, /* 44 */
- 0x00, /* 45 */
- 0x00, /* 46 */
- 0x00, /* 47 */
- 0x00, /* 48 */
- 0x00, /* 49 */
- 0x00, /* 4A */
- 0x00, /* 4B */
- 0x00, /* 4C */
- 0x00, /* 4D */
- 0x00, /* 4E */
- 0x00, /* 4F */
- 0x00, /* 50 */
- 0x00, /* 51 */
- 0x00, /* 52 */
- 0x00, /* 53 */
- 0x00, /* 54 */
- 0x00, /* 55 */
- 0x00, /* 56 */
- 0x00, /* 57 */
- 0x00, /* 58 */
- 0x00, /* 59 */
- 0x00, /* 5A */
- 0x00, /* 5B */
- 0x00, /* 5C */
- 0x00, /* 5D */
- 0x00, /* 5E */
- 0x00, /* 5F */
- 0x00, /* 60 */
- 0x00, /* 61 */
- 0x00, /* 62 */
- 0x00, /* 63 */
- 0x00, /* 64 */
- 0x00, /* 65 */
- 0x00, /* 66 */
- 0x00, /* 67 */
- 0x00, /* 68 */
- 0x00, /* 69 */
- 0x00, /* 6A */
- 0x00, /* 6B */
- 0x00, /* 6C */
- 0x00, /* 6D */
- 0x00, /* 6E */
- 0x00, /* 6F */
- 0x00, /* 70 */
- 0x00, /* 71 */
- 0x00, /* 72 */
- 0x00, /* 73 */
- 0x00, /* 74 */
- 0x00, /* 75 */
- 0x00, /* 76 */
- 0x00, /* 77 */
- 0x00, /* 78 */
- 0x00, /* 79 */
- 0x00, /* 7A */
- 0x00, /* 7B */
- 0x00, /* 7C */
- 0x00, /* 7D */
- 0x00, /* 7E */
- 0x00, /* 7F */
- 0x00, /* 80 */
- 0x00, /* 81 */
- 0x00, /* 82 */
- 0x00, /* 83 */
- 0x00, /* 84 */
- 0x00, /* 85 */
- 0x00, /* 86 */
- 0x00, /* 87 */
- 0x00, /* 88 */
- 0x00, /* 89 */
- 0x00, /* 8A */
- 0x00, /* 8B */
- 0x00, /* 8C */
- 0x00, /* 8D */
- 0x00, /* 8E */
- 0x00, /* 8F */
- 0x00, /* 90 */
- 0x00, /* 91 */
- 0x30, /* 92 */
- 0xF0, /* 93 */
- 0x00, /* 94 */
- 0x00, /* 95 */
- 0x3F, /* 96 */
- 0x00, /* 97 */
- 0x00, /* 98 */
- 0x00, /* 99 */
- 0x00, /* 9A */
- 0x00, /* 9B */
- 0x00, /* 9C */
- 0x00, /* 9D */
- 0x00, /* 9E */
- 0x00, /* 9F */
- 0x00, /* A0 */
- 0x00, /* A1 */
- 0x00, /* A2 */
- 0x00, /* A3 */
- 0x00, /* A4 */
- 0x00, /* A5 */
- 0x00, /* A6 */
- 0x00, /* A7 */
- 0x00, /* A8 */
- 0x00, /* A9 */
- 0x00, /* AA */
- 0x00, /* AB */
- 0x00, /* AC */
- 0x00, /* AD */
- 0x00, /* AE */
- 0x00, /* AF */
- 0x00, /* B0 */
- 0x00, /* B1 */
- 0x00, /* B2 */
- 0x00, /* B3 */
- 0x00, /* B4 */
- 0x00, /* B5 */
- 0x00, /* B6 */
- 0x00, /* B7 */
- 0x00, /* B8 */
- 0x00, /* B9 */
- 0x00, /* BA */
- 0x00, /* BB */
- 0x00, /* BC */
- 0x00, /* BD */
- 0x00, /* BE */
- 0x00, /* BF */
- 0x00, /* C0 */
- 0x00, /* C1 */
- 0x00, /* C2 */
- 0x00, /* C3 */
- 0x00, /* C4 */
- 0x00, /* C5 */
- 0x00, /* C6 */
- 0x00, /* C7 */
- 0x00, /* C8 */
- 0x00, /* C9 */
- 0x00, /* CA */
- 0x00, /* CB */
- 0x00, /* CC */
- 0x00, /* CD */
- 0x00, /* CE */
- 0x00, /* CF */
- 0x00, /* D0 */
- 0x00, /* D1 */
- 0x00, /* D2 */
- 0x00, /* D3 */
- 0x00, /* D4 */
- 0x00, /* D5 */
- 0x00, /* D6 */
- 0x00, /* D7 */
- 0x00, /* D8 */
- 0x00, /* D9 */
- 0x00, /* DA */
- 0x00, /* DB */
- 0x00, /* DC */
- 0x00, /* DD */
- 0x00, /* DE */
- 0x00, /* DF */
- 0x00, /* E0 */
- 0x00, /* E1 */
- 0x00, /* E2 */
- 0x00, /* E3 */
- 0x00, /* E4 */
- 0x00, /* E5 */
- 0x00, /* E6 */
- 0x00, /* E7 */
- 0x00, /* E8 */
- 0x00, /* E9 */
- 0x00, /* EA */
- 0x00, /* EB */
- 0x00, /* EC */
- 0x00, /* ED */
- 0x00, /* EE */
- 0x00, /* EF */
- 0x00, /* F0 */
- 0x00, /* F1 */
- 0x00, /* F2 */
- 0x00, /* F3 */
- 0x00, /* F4 */
- 0x00, /* F5 */
- 0x00, /* F6 */
- 0x00, /* F7 */
- 0x00, /* F8 */
- 0x00, /* F9 */
- 0x00, /* FA */
- 0x00, /* FB */
- 0x00, /* FC */
- 0x00, /* FD */
- 0x00, /* FE */
- 0x00, /* FF */
+static const struct reg_default max98095_reg_def[] = {
+ { 0xf, 0x00 }, /* 0F */
+ { 0x10, 0x00 }, /* 10 */
+ { 0x11, 0x00 }, /* 11 */
+ { 0x12, 0x00 }, /* 12 */
+ { 0x13, 0x00 }, /* 13 */
+ { 0x14, 0x00 }, /* 14 */
+ { 0x15, 0x00 }, /* 15 */
+ { 0x16, 0x00 }, /* 16 */
+ { 0x17, 0x00 }, /* 17 */
+ { 0x18, 0x00 }, /* 18 */
+ { 0x19, 0x00 }, /* 19 */
+ { 0x1a, 0x00 }, /* 1A */
+ { 0x1b, 0x00 }, /* 1B */
+ { 0x1c, 0x00 }, /* 1C */
+ { 0x1d, 0x00 }, /* 1D */
+ { 0x1e, 0x00 }, /* 1E */
+ { 0x1f, 0x00 }, /* 1F */
+ { 0x20, 0x00 }, /* 20 */
+ { 0x21, 0x00 }, /* 21 */
+ { 0x22, 0x00 }, /* 22 */
+ { 0x23, 0x00 }, /* 23 */
+ { 0x24, 0x00 }, /* 24 */
+ { 0x25, 0x00 }, /* 25 */
+ { 0x26, 0x00 }, /* 26 */
+ { 0x27, 0x00 }, /* 27 */
+ { 0x28, 0x00 }, /* 28 */
+ { 0x29, 0x00 }, /* 29 */
+ { 0x2a, 0x00 }, /* 2A */
+ { 0x2b, 0x00 }, /* 2B */
+ { 0x2c, 0x00 }, /* 2C */
+ { 0x2d, 0x00 }, /* 2D */
+ { 0x2e, 0x00 }, /* 2E */
+ { 0x2f, 0x00 }, /* 2F */
+ { 0x30, 0x00 }, /* 30 */
+ { 0x31, 0x00 }, /* 31 */
+ { 0x32, 0x00 }, /* 32 */
+ { 0x33, 0x00 }, /* 33 */
+ { 0x34, 0x00 }, /* 34 */
+ { 0x35, 0x00 }, /* 35 */
+ { 0x36, 0x00 }, /* 36 */
+ { 0x37, 0x00 }, /* 37 */
+ { 0x38, 0x00 }, /* 38 */
+ { 0x39, 0x00 }, /* 39 */
+ { 0x3a, 0x00 }, /* 3A */
+ { 0x3b, 0x00 }, /* 3B */
+ { 0x3c, 0x00 }, /* 3C */
+ { 0x3d, 0x00 }, /* 3D */
+ { 0x3e, 0x00 }, /* 3E */
+ { 0x3f, 0x00 }, /* 3F */
+ { 0x40, 0x00 }, /* 40 */
+ { 0x41, 0x00 }, /* 41 */
+ { 0x42, 0x00 }, /* 42 */
+ { 0x43, 0x00 }, /* 43 */
+ { 0x44, 0x00 }, /* 44 */
+ { 0x45, 0x00 }, /* 45 */
+ { 0x46, 0x00 }, /* 46 */
+ { 0x47, 0x00 }, /* 47 */
+ { 0x48, 0x00 }, /* 48 */
+ { 0x49, 0x00 }, /* 49 */
+ { 0x4a, 0x00 }, /* 4A */
+ { 0x4b, 0x00 }, /* 4B */
+ { 0x4c, 0x00 }, /* 4C */
+ { 0x4d, 0x00 }, /* 4D */
+ { 0x4e, 0x00 }, /* 4E */
+ { 0x4f, 0x00 }, /* 4F */
+ { 0x50, 0x00 }, /* 50 */
+ { 0x51, 0x00 }, /* 51 */
+ { 0x52, 0x00 }, /* 52 */
+ { 0x53, 0x00 }, /* 53 */
+ { 0x54, 0x00 }, /* 54 */
+ { 0x55, 0x00 }, /* 55 */
+ { 0x56, 0x00 }, /* 56 */
+ { 0x57, 0x00 }, /* 57 */
+ { 0x58, 0x00 }, /* 58 */
+ { 0x59, 0x00 }, /* 59 */
+ { 0x5a, 0x00 }, /* 5A */
+ { 0x5b, 0x00 }, /* 5B */
+ { 0x5c, 0x00 }, /* 5C */
+ { 0x5d, 0x00 }, /* 5D */
+ { 0x5e, 0x00 }, /* 5E */
+ { 0x5f, 0x00 }, /* 5F */
+ { 0x60, 0x00 }, /* 60 */
+ { 0x61, 0x00 }, /* 61 */
+ { 0x62, 0x00 }, /* 62 */
+ { 0x63, 0x00 }, /* 63 */
+ { 0x64, 0x00 }, /* 64 */
+ { 0x65, 0x00 }, /* 65 */
+ { 0x66, 0x00 }, /* 66 */
+ { 0x67, 0x00 }, /* 67 */
+ { 0x68, 0x00 }, /* 68 */
+ { 0x69, 0x00 }, /* 69 */
+ { 0x6a, 0x00 }, /* 6A */
+ { 0x6b, 0x00 }, /* 6B */
+ { 0x6c, 0x00 }, /* 6C */
+ { 0x6d, 0x00 }, /* 6D */
+ { 0x6e, 0x00 }, /* 6E */
+ { 0x6f, 0x00 }, /* 6F */
+ { 0x70, 0x00 }, /* 70 */
+ { 0x71, 0x00 }, /* 71 */
+ { 0x72, 0x00 }, /* 72 */
+ { 0x73, 0x00 }, /* 73 */
+ { 0x74, 0x00 }, /* 74 */
+ { 0x75, 0x00 }, /* 75 */
+ { 0x76, 0x00 }, /* 76 */
+ { 0x77, 0x00 }, /* 77 */
+ { 0x78, 0x00 }, /* 78 */
+ { 0x79, 0x00 }, /* 79 */
+ { 0x7a, 0x00 }, /* 7A */
+ { 0x7b, 0x00 }, /* 7B */
+ { 0x7c, 0x00 }, /* 7C */
+ { 0x7d, 0x00 }, /* 7D */
+ { 0x7e, 0x00 }, /* 7E */
+ { 0x7f, 0x00 }, /* 7F */
+ { 0x80, 0x00 }, /* 80 */
+ { 0x81, 0x00 }, /* 81 */
+ { 0x82, 0x00 }, /* 82 */
+ { 0x83, 0x00 }, /* 83 */
+ { 0x84, 0x00 }, /* 84 */
+ { 0x85, 0x00 }, /* 85 */
+ { 0x86, 0x00 }, /* 86 */
+ { 0x87, 0x00 }, /* 87 */
+ { 0x88, 0x00 }, /* 88 */
+ { 0x89, 0x00 }, /* 89 */
+ { 0x8a, 0x00 }, /* 8A */
+ { 0x8b, 0x00 }, /* 8B */
+ { 0x8c, 0x00 }, /* 8C */
+ { 0x8d, 0x00 }, /* 8D */
+ { 0x8e, 0x00 }, /* 8E */
+ { 0x8f, 0x00 }, /* 8F */
+ { 0x90, 0x00 }, /* 90 */
+ { 0x91, 0x00 }, /* 91 */
+ { 0x92, 0x30 }, /* 92 */
+ { 0x93, 0xF0 }, /* 93 */
+ { 0x94, 0x00 }, /* 94 */
+ { 0x95, 0x00 }, /* 95 */
+ { 0x96, 0x3F }, /* 96 */
+ { 0x97, 0x00 }, /* 97 */
+ { 0xff, 0x00 }, /* FF */
};
static struct {
@@ -577,14 +460,14 @@ static struct {
{ 0xFF, 0x00 }, /* FF */
};
-static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg)
+static bool max98095_readable(struct device *dev, unsigned int reg)
{
if (reg >= M98095_REG_CNT)
return 0;
return max98095_access[reg].readable != 0;
}
-static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
+static bool max98095_volatile(struct device *dev, unsigned int reg)
{
if (reg > M98095_REG_MAX_CACHED)
return 1;
@@ -611,22 +494,18 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
return 0;
}
-/*
- * Filter coefficients are in a separate register segment
- * and they share the address space of the normal registers.
- * The coefficient registers do not need or share the cache.
- */
-static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- int ret;
+static const struct regmap_config max98095_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
- codec->cache_bypass = 1;
- ret = snd_soc_write(codec, reg, value);
- codec->cache_bypass = 0;
+ .reg_defaults = max98095_reg_def,
+ .num_reg_defaults = ARRAY_SIZE(max98095_reg_def),
+ .max_register = M98095_0FF_REV_ID,
+ .cache_type = REGCACHE_RBTREE,
- return ret ? -EIO : 0;
-}
+ .readable_reg = max98095_readable,
+ .volatile_reg = max98095_volatile,
+};
/*
* Load equalizer DSP coefficient configurations registers
@@ -637,8 +516,9 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
unsigned int eq_reg;
unsigned int i;
- BUG_ON(band > 4);
- BUG_ON(dai > 1);
+ if (WARN_ON(band > 4) ||
+ WARN_ON(dai > 1))
+ return;
/* Load the base register address */
eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE;
@@ -648,8 +528,8 @@ static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
/* Step through the registers and coefs */
for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
- max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
- max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
+ snd_soc_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
+ snd_soc_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
}
}
@@ -662,8 +542,9 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
unsigned int bq_reg;
unsigned int i;
- BUG_ON(band > 1);
- BUG_ON(dai > 1);
+ if (WARN_ON(band > 1) ||
+ WARN_ON(dai > 1))
+ return;
/* Load the base register address */
bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE;
@@ -673,8 +554,8 @@ static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
/* Step through the registers and coefs */
for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
- max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
- max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
+ snd_soc_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
+ snd_soc_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
}
}
@@ -1011,7 +892,8 @@ static int max98095_line_pga(struct snd_soc_dapm_widget *w,
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
u8 *state;
- BUG_ON(!((channel == 1) || (channel == 2)));
+ if (WARN_ON(!(channel == 1 || channel == 2)))
+ return -EINVAL;
state = &max98095->lin_state;
@@ -1285,14 +1167,6 @@ static const struct snd_soc_dapm_route max98095_audio_map[] = {
{"MIC2 Input", NULL, "MIC2"},
};
-static int max98095_add_widgets(struct snd_soc_codec *codec)
-{
- snd_soc_add_codec_controls(codec, max98095_snd_controls,
- ARRAY_SIZE(max98095_snd_controls));
-
- return 0;
-}
-
/* codec mclk clock divider coefficients */
static const struct {
u32 rate;
@@ -1339,12 +1213,12 @@ static int max98095_dai1_hw_params(struct snd_pcm_substream *substream,
rate = params_rate(params);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
M98095_DAI_WS, 0);
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
M98095_DAI_WS, M98095_DAI_WS);
break;
@@ -1748,6 +1622,7 @@ static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
static int max98095_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) {
@@ -1759,7 +1634,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_cache_sync(codec);
+ ret = regcache_sync(max98095->regmap);
if (ret != 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
@@ -1774,7 +1649,7 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF:
snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
M98095_MBEN, 0);
- codec->cache_sync = 1;
+ regcache_mark_dirty(max98095->regmap);
break;
}
codec->dapm.bias_level = level;
@@ -1863,12 +1738,13 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_eq_channel(kcontrol->id.name);
struct max98095_cdata *cdata;
- int sel = ucontrol->value.integer.value[0];
+ unsigned int sel = ucontrol->value.integer.value[0];
struct max98095_eq_cfg *coef_set;
int fs, best, best_val, i;
int regmask, regsave;
- BUG_ON(channel > 1);
+ if (WARN_ON(channel > 1))
+ return -EINVAL;
if (!pdata || !max98095->eq_textcnt)
return 0;
@@ -2016,7 +1892,7 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata;
- int sel = ucontrol->value.integer.value[0];
+ unsigned int sel = ucontrol->value.integer.value[0];
struct max98095_biquad_cfg *coef_set;
int fs, best, best_val, i;
int regmask, regsave;
@@ -2341,7 +2217,7 @@ static int max98095_reset(struct snd_soc_codec *codec)
/* Reset to hardware default for registers, as there is not
* a soft reset hardware control register */
for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
- ret = snd_soc_write(codec, i, max98095_reg_def[i]);
+ ret = snd_soc_write(codec, i, snd_soc_read(codec, i));
if (ret < 0) {
dev_err(codec->dev, "Failed to reset: %d\n", ret);
return ret;
@@ -2358,7 +2234,7 @@ static int max98095_probe(struct snd_soc_codec *codec)
struct i2c_client *client;
int ret = 0;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -2447,8 +2323,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,
M98095_SHDNRUN);
- max98095_add_widgets(codec);
-
return 0;
err_irq:
@@ -2480,11 +2354,8 @@ static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
.suspend = max98095_suspend,
.resume = max98095_resume,
.set_bias_level = max98095_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(max98095_reg_def),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = max98095_reg_def,
- .readable_register = max98095_readable,
- .volatile_register = max98095_volatile,
+ .controls = max98095_snd_controls,
+ .num_controls = ARRAY_SIZE(max98095_snd_controls),
.dapm_widgets = max98095_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
.dapm_routes = max98095_audio_map,
@@ -2502,6 +2373,13 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
if (max98095 == NULL)
return -ENOMEM;
+ max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
+ if (IS_ERR(max98095->regmap)) {
+ ret = PTR_ERR(max98095->regmap);
+ dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
max98095->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98095);
max98095->pdata = i2c->dev.platform_data;
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 58c38a5b481c..82757ebf0301 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -27,18 +28,26 @@
#include "max9850.h"
struct max9850_priv {
+ struct regmap *regmap;
unsigned int sysclk;
};
/* max9850 register cache */
-static const u8 max9850_reg[MAX9850_CACHEREGNUM] = {
- 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+static const struct reg_default max9850_reg[] = {
+ { 2, 0x0c },
+ { 3, 0x00 },
+ { 4, 0x00 },
+ { 5, 0x00 },
+ { 6, 0x00 },
+ { 7, 0x00 },
+ { 8, 0x00 },
+ { 9, 0x00 },
+ { 10, 0x00 },
};
/* these registers are not used at the moment but provided for the sake of
* completeness */
-static int max9850_volatile_register(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool max9850_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX9850_STATUSA:
@@ -49,6 +58,15 @@ static int max9850_volatile_register(struct snd_soc_codec *codec,
}
}
+static const struct regmap_config max9850_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = MAX9850_DIGITAL_AUDIO,
+ .volatile_reg = max9850_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static const unsigned int max9850_tlv[] = {
TLV_DB_RANGE_HEAD(4),
0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0),
@@ -131,14 +149,14 @@ static int max9850_hw_params(struct snd_pcm_substream *substream,
snd_soc_write(codec, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f);
snd_soc_write(codec, MAX9850_LRCLK_LSB, lrclk_div & 0xff);
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
+ switch (params_width(params)) {
+ case 16:
da = 0;
break;
- case SNDRV_PCM_FORMAT_S20_3LE:
+ case 20:
da = 0x2;
break;
- case SNDRV_PCM_FORMAT_S24_LE:
+ case 24:
da = 0x3;
break;
default:
@@ -225,6 +243,7 @@ static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
static int max9850_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) {
@@ -234,7 +253,7 @@ static int max9850_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_cache_sync(codec);
+ ret = regcache_sync(max9850->regmap);
if (ret) {
dev_err(codec->dev,
"Failed to sync cache: %d\n", ret);
@@ -295,7 +314,7 @@ static int max9850_probe(struct snd_soc_codec *codec)
{
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -316,10 +335,6 @@ static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
.suspend = max9850_suspend,
.resume = max9850_resume,
.set_bias_level = max9850_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(max9850_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = max9850_reg,
- .volatile_register = max9850_volatile_register,
.controls = max9850_controls,
.num_controls = ARRAY_SIZE(max9850_controls),
@@ -340,6 +355,10 @@ static int max9850_i2c_probe(struct i2c_client *i2c,
if (max9850 == NULL)
return -ENOMEM;
+ max9850->regmap = devm_regmap_init_i2c(i2c, &max9850_regmap);
+ if (IS_ERR(max9850->regmap))
+ return PTR_ERR(max9850->regmap);
+
i2c_set_clientdata(i2c, max9850);
ret = snd_soc_register_codec(&i2c->dev,
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
index ea141e1d6f28..582c2bbd42cb 100644
--- a/sound/soc/codecs/mc13783.c
+++ b/sound/soc/codecs/mc13783.c
@@ -30,16 +30,10 @@
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/soc-dapm.h>
+#include <linux/regmap.h>
#include "mc13783.h"
-#define MC13783_AUDIO_RX0 36
-#define MC13783_AUDIO_RX1 37
-#define MC13783_AUDIO_TX 38
-#define MC13783_SSI_NETWORK 39
-#define MC13783_AUDIO_CODEC 40
-#define MC13783_AUDIO_DAC 41
-
#define AUDIO_RX0_ALSPEN (1 << 5)
#define AUDIO_RX0_ALSPSEL (1 << 7)
#define AUDIO_RX0_ADDCDC (1 << 21)
@@ -95,45 +89,12 @@
struct mc13783_priv {
struct mc13xxx *mc13xxx;
+ struct regmap *regmap;
enum mc13783_ssi_port adc_ssi_port;
enum mc13783_ssi_port dac_ssi_port;
};
-static unsigned int mc13783_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- unsigned int value = 0;
-
- mc13xxx_lock(priv->mc13xxx);
-
- mc13xxx_reg_read(priv->mc13xxx, reg, &value);
-
- mc13xxx_unlock(priv->mc13xxx);
-
- return value;
-}
-
-static int mc13783_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
-{
- struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- mc13xxx_lock(priv->mc13xxx);
-
- ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
-
- /* include errata fix for spi audio problems */
- if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC)
- ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
-
- mc13xxx_unlock(priv->mc13xxx);
-
- return ret;
-}
-
/* Mapping between sample rates and register value */
static unsigned int mc13783_rates[] = {
8000, 11025, 12000, 16000,
@@ -382,7 +343,7 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
break;
default:
return -EINVAL;
- };
+ }
snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
@@ -466,6 +427,29 @@ static const struct snd_kcontrol_new right_input_mux =
static const struct snd_kcontrol_new samp_ctl =
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 3, 1, 0);
+static const char * const speaker_amp_source_text[] = {
+ "CODEC", "Right"
+};
+static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4,
+ speaker_amp_source_text);
+static const struct snd_kcontrol_new speaker_amp_source_mux =
+ SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source);
+
+static const char * const headset_amp_source_text[] = {
+ "CODEC", "Mixer"
+};
+
+static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11,
+ headset_amp_source_text);
+static const struct snd_kcontrol_new headset_amp_source_mux =
+ SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source);
+
+static const struct snd_kcontrol_new cdcout_ctl =
+ SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 18, 1, 0);
+
+static const struct snd_kcontrol_new adc_bypass_ctl =
+ SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_CODEC, 16, 1, 0);
+
static const struct snd_kcontrol_new lamp_ctl =
SOC_DAPM_SINGLE("Switch", MC13783_AUDIO_RX0, 5, 1, 0);
@@ -503,12 +487,22 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
&right_input_mux),
+ SND_SOC_DAPM_MUX("Speaker Amp Source MUX", SND_SOC_NOPM, 0, 0,
+ &speaker_amp_source_mux),
+
+ SND_SOC_DAPM_MUX("Headset Amp Source MUX", SND_SOC_NOPM, 0, 0,
+ &headset_amp_source_mux),
+
SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_ADC("ADC", "Capture", MC13783_AUDIO_CODEC, 11, 0),
SND_SOC_DAPM_SUPPLY("ADC_Reset", MC13783_AUDIO_CODEC, 15, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Voice CODEC PGA", MC13783_AUDIO_RX1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SWITCH("Voice CODEC Bypass", MC13783_AUDIO_CODEC, 16, 0,
+ &adc_bypass_ctl),
+
/* Output */
SND_SOC_DAPM_SUPPLY("DAC_E", MC13783_AUDIO_DAC, 11, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DAC_Reset", MC13783_AUDIO_DAC, 15, 0, NULL, 0),
@@ -516,10 +510,15 @@ static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("RXOUTR"),
SND_SOC_DAPM_OUTPUT("HSL"),
SND_SOC_DAPM_OUTPUT("HSR"),
+ SND_SOC_DAPM_OUTPUT("LSPL"),
SND_SOC_DAPM_OUTPUT("LSP"),
SND_SOC_DAPM_OUTPUT("SP"),
+ SND_SOC_DAPM_OUTPUT("CDCOUT"),
- SND_SOC_DAPM_SWITCH("Speaker Amp", MC13783_AUDIO_RX0, 3, 0, &samp_ctl),
+ SND_SOC_DAPM_SWITCH("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 0,
+ &cdcout_ctl),
+ SND_SOC_DAPM_SWITCH("Speaker Amp Switch", MC13783_AUDIO_RX0, 3, 0,
+ &samp_ctl),
SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
SND_SOC_DAPM_SWITCH("Headset Amp Left", MC13783_AUDIO_RX0, 10, 0,
&hlamp_ctl),
@@ -554,20 +553,28 @@ static struct snd_soc_dapm_route mc13783_routes[] = {
{ "ADC", NULL, "PGA Right Input"},
{ "ADC", NULL, "ADC_Reset"},
+ { "Voice CODEC PGA", "Voice CODEC Bypass", "ADC" },
+
+ { "Speaker Amp Source MUX", "CODEC", "Voice CODEC PGA"},
+ { "Speaker Amp Source MUX", "Right", "DAC PGA"},
+
+ { "Headset Amp Source MUX", "CODEC", "Voice CODEC PGA"},
+ { "Headset Amp Source MUX", "Mixer", "DAC PGA"},
+
/* Output */
{ "HSL", NULL, "Headset Amp Left" },
{ "HSR", NULL, "Headset Amp Right"},
{ "RXOUTL", NULL, "Line out Amp Left"},
{ "RXOUTR", NULL, "Line out Amp Right"},
- { "SP", NULL, "Speaker Amp"},
- { "Speaker Amp", NULL, "DAC PGA"},
- { "LSP", NULL, "DAC PGA"},
- { "Headset Amp Left", NULL, "DAC PGA"},
- { "Headset Amp Right", NULL, "DAC PGA"},
+ { "SP", "Speaker Amp Switch", "Speaker Amp Source MUX"},
+ { "LSP", "Loudspeaker Amp", "Speaker Amp Source MUX"},
+ { "HSL", "Headset Amp Left", "Headset Amp Source MUX"},
+ { "HSR", "Headset Amp Right", "Headset Amp Source MUX"},
{ "Line out Amp Left", NULL, "DAC PGA"},
{ "Line out Amp Right", NULL, "DAC PGA"},
{ "DAC PGA", NULL, "DAC"},
{ "DAC", NULL, "DAC_E"},
+ { "CDCOUT", "CDCOUT Switch", "Voice CODEC PGA"},
};
static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
@@ -580,15 +587,39 @@ static const struct soc_enum mc13783_enum_3d_mixer =
static struct snd_kcontrol_new mc13783_control_list[] = {
SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
+ SOC_SINGLE("PCM Playback Switch", MC13783_AUDIO_RX1, 5, 1, 0),
SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
+
+ SOC_SINGLE("CDCOUT Switch", MC13783_AUDIO_RX0, 18, 1, 0),
+ SOC_SINGLE("Earpiece Amp Switch", MC13783_AUDIO_RX0, 3, 1, 0),
+ SOC_DOUBLE("Headset Amp Switch", MC13783_AUDIO_RX0, 10, 9, 1, 0),
+ SOC_DOUBLE("Line out Amp Switch", MC13783_AUDIO_RX0, 16, 15, 1, 0),
+
+ SOC_SINGLE("PCM Capture Mixin Switch", MC13783_AUDIO_RX0, 22, 1, 0),
+ SOC_SINGLE("Line in Capture Mixin Switch", MC13783_AUDIO_RX0, 23, 1, 0),
+
+ SOC_SINGLE("CODEC Capture Volume", MC13783_AUDIO_RX1, 1, 15, 0),
+ SOC_SINGLE("CODEC Capture Mixin Switch", MC13783_AUDIO_RX0, 21, 1, 0),
+
+ SOC_SINGLE("Line in Capture Volume", MC13783_AUDIO_RX1, 12, 15, 0),
+ SOC_SINGLE("Line in Capture Switch", MC13783_AUDIO_RX1, 10, 1, 0),
+
+ SOC_SINGLE("MC1 Capture Bias Switch", MC13783_AUDIO_TX, 0, 1, 0),
+ SOC_SINGLE("MC2 Capture Bias Switch", MC13783_AUDIO_TX, 1, 1, 0),
};
static int mc13783_probe(struct snd_soc_codec *codec)
{
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
- mc13xxx_lock(priv->mc13xxx);
+ codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 24, SND_SOC_REGMAP);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
/* these are the reset values */
mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
@@ -612,8 +643,6 @@ static int mc13783_probe(struct snd_soc_codec *codec)
mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
0, AUDIO_SSI_SEL);
- mc13xxx_unlock(priv->mc13xxx);
-
return 0;
}
@@ -621,13 +650,9 @@ static int mc13783_remove(struct snd_soc_codec *codec)
{
struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
- mc13xxx_lock(priv->mc13xxx);
-
/* Make sure VAUDIOON is off */
mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
- mc13xxx_unlock(priv->mc13xxx);
-
return 0;
}
@@ -717,8 +742,6 @@ static struct snd_soc_dai_driver mc13783_dai_sync[] = {
static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
.probe = mc13783_probe,
.remove = mc13783_remove,
- .read = mc13783_read,
- .write = mc13783_write,
.controls = mc13783_control_list,
.num_controls = ARRAY_SIZE(mc13783_control_list),
.dapm_widgets = mc13783_dapm_widgets,
@@ -727,30 +750,26 @@ static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
.num_dapm_routes = ARRAY_SIZE(mc13783_routes),
};
-static int mc13783_codec_probe(struct platform_device *pdev)
+static int __init mc13783_codec_probe(struct platform_device *pdev)
{
- struct mc13xxx *mc13xxx;
struct mc13783_priv *priv;
struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
int ret;
- mc13xxx = dev_get_drvdata(pdev->dev.parent);
-
-
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (priv == NULL)
+ if (!priv)
return -ENOMEM;
- dev_set_drvdata(&pdev->dev, priv);
- priv->mc13xxx = mc13xxx;
if (pdata) {
priv->adc_ssi_port = pdata->adc_ssi_port;
priv->dac_ssi_port = pdata->dac_ssi_port;
} else {
- priv->adc_ssi_port = MC13783_SSI1_PORT;
- priv->dac_ssi_port = MC13783_SSI2_PORT;
+ return -ENOSYS;
}
+ dev_set_drvdata(&pdev->dev, priv);
+ priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
+
if (priv->adc_ssi_port == priv->dac_ssi_port)
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
@@ -758,14 +777,6 @@ static int mc13783_codec_probe(struct platform_device *pdev)
ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
- if (ret)
- goto err_register_codec;
-
- return 0;
-
-err_register_codec:
- dev_err(&pdev->dev, "register codec failed with %d\n", ret);
-
return ret;
}
@@ -778,14 +789,12 @@ static int mc13783_codec_remove(struct platform_device *pdev)
static struct platform_driver mc13783_codec_driver = {
.driver = {
- .name = "mc13783-codec",
- .owner = THIS_MODULE,
- },
- .probe = mc13783_codec_probe,
+ .name = "mc13783-codec",
+ .owner = THIS_MODULE,
+ },
.remove = mc13783_codec_remove,
};
-
-module_platform_driver(mc13783_codec_driver);
+module_platform_driver_probe(mc13783_codec_driver, mc13783_codec_probe);
MODULE_DESCRIPTION("ASoC MC13783 driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 26118828782b..185fa3bc3052 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -342,6 +342,8 @@ static int ml26124_hw_params(struct snd_pcm_substream *substream,
struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
int i = get_coeff(priv->mclk, params_rate(hw_params));
+ if (i < 0)
+ return i;
priv->substream = substream;
priv->rate = params_rate(hw_params);
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index 651ce0923675..73f9c3630e2c 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -21,6 +21,7 @@
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
+#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
@@ -270,7 +271,7 @@ MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
static const struct regmap_config pcm1681_regmap = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = ARRAY_SIZE(pcm1681_reg_defaults) + 1,
+ .max_register = 0x13,
.reg_defaults = pcm1681_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(pcm1681_reg_defaults),
.writeable_reg = pcm1681_writeable_reg,
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
index 2a8eccf64c76..7146653a8e16 100644
--- a/sound/soc/codecs/pcm1792a.c
+++ b/sound/soc/codecs/pcm1792a.c
@@ -28,6 +28,7 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/tlv.h>
+#include <linux/of.h>
#include <linux/of_device.h>
#include "pcm1792a.h"
@@ -188,7 +189,7 @@ MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
static const struct regmap_config pcm1792a_regmap = {
.reg_bits = 8,
.val_bits = 8,
- .max_register = 24,
+ .max_register = 23,
.reg_defaults = pcm1792a_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults),
.writeable_reg = pcm1792a_writeable_reg,
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index c26a8f814b18..886924934aa5 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -21,6 +21,7 @@
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -926,7 +927,7 @@ static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
return 0;
}
-void hp_amp_power_on(struct snd_soc_codec *codec)
+static void hp_amp_power_on(struct snd_soc_codec *codec)
{
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1603,13 +1604,14 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- unsigned int val_len = 0, val_clk, mask_clk, dai_sel;
- int pre_div, bclk_ms, frame_size;
+ unsigned int val_len = 0, val_clk, mask_clk;
+ int dai_sel, pre_div, bclk_ms, frame_size;
rt5640->lrck[dai->id] = params_rate(params);
pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
if (pre_div < 0) {
- dev_err(codec->dev, "Unsupported clock setting\n");
+ dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n",
+ rt5640->lrck[dai->id], dai->id);
return -EINVAL;
}
frame_size = snd_soc_params_to_frame_size(params);
@@ -1673,7 +1675,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
- unsigned int reg_val = 0, dai_sel;
+ unsigned int reg_val = 0;
+ int dai_sel;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
@@ -1977,13 +1980,20 @@ static int rt5640_suspend(struct snd_soc_codec *codec)
rt5640_reset(codec);
regcache_cache_only(rt5640->regmap, true);
regcache_mark_dirty(rt5640->regmap);
+ if (gpio_is_valid(rt5640->pdata.ldo1_en))
+ gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 0);
return 0;
}
static int rt5640_resume(struct snd_soc_codec *codec)
{
- rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+ if (gpio_is_valid(rt5640->pdata.ldo1_en)) {
+ gpio_set_value_cansleep(rt5640->pdata.ldo1_en, 1);
+ msleep(400);
+ }
return 0;
}
@@ -2080,6 +2090,15 @@ static const struct i2c_device_id rt5640_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt5640_acpi_match[] = {
+ { "INT33CA", 0 },
+ { "10EC5640", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
+#endif
+
static int rt5640_parse_dt(struct rt5640_priv *rt5640, struct device_node *np)
{
rt5640->pdata.in1_diff = of_property_read_bool(np,
@@ -2199,6 +2218,7 @@ static struct i2c_driver rt5640_i2c_driver = {
.driver = {
.name = "rt5640",
.owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(rt5640_acpi_match),
},
.probe = rt5640_i2c_probe,
.remove = rt5640_i2c_remove,
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 1f4093f3f3a1..0fcbe90f3ef2 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -115,6 +115,7 @@ struct sgtl5000_priv {
struct ldo_regulator *ldo;
struct regmap *regmap;
struct clk *mclk;
+ int revision;
};
/*
@@ -1285,41 +1286,45 @@ static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec)
sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME;
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
-
- if (ret) {
- ldo_regulator_remove(codec);
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- return ret;
- }
-
dev_info(codec->dev, "Using internal LDO instead of VDDD\n");
return 0;
}
static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
{
- int reg;
int ret;
- int rev;
int i;
int external_vddd = 0;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
+ struct regulator *vddd;
for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++)
sgtl5000->supplies[i].supply = supply_names[i];
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
- if (!ret)
- external_vddd = 1;
- else {
+ /* External VDDD only works before revision 0x11 */
+ if (sgtl5000->revision < 0x11) {
+ vddd = regulator_get_optional(codec->dev, "VDDD");
+ if (IS_ERR(vddd)) {
+ /* See if it's just not registered yet */
+ if (PTR_ERR(vddd) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ } else {
+ external_vddd = 1;
+ regulator_put(vddd);
+ }
+ }
+
+ if (!external_vddd) {
ret = sgtl5000_replace_vddd_with_ldo(codec);
if (ret)
return ret;
}
+ ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies),
+ sgtl5000->supplies);
+ if (ret)
+ goto err_ldo_remove;
+
ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
if (ret)
@@ -1328,47 +1333,13 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec)
/* wait for all power rails bring up */
udelay(10);
- /*
- * workaround for revision 0x11 and later,
- * roll back to use internal LDO
- */
-
- ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
- if (ret)
- goto err_regulator_disable;
-
- rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
-
- if (external_vddd && rev >= 0x11) {
- /* disable all regulator first */
- regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
- /* free VDDD regulator */
- regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
-
- ret = sgtl5000_replace_vddd_with_ldo(codec);
- if (ret)
- return ret;
-
- ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
- if (ret)
- goto err_regulator_free;
-
- /* wait for all power rails bring up */
- udelay(10);
- }
-
return 0;
-err_regulator_disable:
- regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies),
- sgtl5000->supplies);
err_regulator_free:
regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies),
sgtl5000->supplies);
- if (external_vddd)
+err_ldo_remove:
+ if (!external_vddd)
ldo_regulator_remove(codec);
return ret;
@@ -1566,6 +1537,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
+ sgtl5000->revision = rev;
i2c_set_clientdata(client, sgtl5000);
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c
index 38f3b105c17d..52e7cb08434b 100644
--- a/sound/soc/codecs/si476x.c
+++ b/sound/soc/codecs/si476x.c
@@ -60,48 +60,6 @@ enum si476x_pcm_format {
SI476X_PCM_FORMAT_S24_LE = 6,
};
-static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- int err;
- unsigned int val;
- struct si476x_core *core = codec->control_data;
-
- si476x_core_lock(core);
- if (!si476x_core_is_powered_up(core))
- regcache_cache_only(core->regmap, true);
-
- err = regmap_read(core->regmap, reg, &val);
-
- if (!si476x_core_is_powered_up(core))
- regcache_cache_only(core->regmap, false);
- si476x_core_unlock(core);
-
- if (err < 0)
- return err;
-
- return val;
-}
-
-static int si476x_codec_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int val)
-{
- int err;
- struct si476x_core *core = codec->control_data;
-
- si476x_core_lock(core);
- if (!si476x_core_is_powered_up(core))
- regcache_cache_only(core->regmap, true);
-
- err = regmap_write(core->regmap, reg, val);
-
- if (!si476x_core_is_powered_up(core))
- regcache_cache_only(core->regmap, false);
- si476x_core_unlock(core);
-
- return err;
-}
-
static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("LOUT"),
SND_SOC_DAPM_OUTPUT("ROUT"),
@@ -115,6 +73,7 @@ static const struct snd_soc_dapm_route si476x_dapm_routes[] = {
static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
+ struct si476x_core *core = i2c_mfd_cell_to_core(codec_dai->dev);
int err;
u16 format = 0;
@@ -178,9 +137,14 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
+ si476x_core_lock(core);
+
err = snd_soc_update_bits(codec_dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK,
format);
+
+ si476x_core_unlock(core);
+
if (err < 0) {
dev_err(codec_dai->codec->dev, "Failed to set output format\n");
return err;
@@ -193,6 +157,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct si476x_core *core = i2c_mfd_cell_to_core(dai->dev);
int rate, width, err;
rate = params_rate(params);
@@ -218,11 +183,13 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ si476x_core_lock(core);
+
err = snd_soc_write(dai->codec, SI476X_DIGITAL_IO_OUTPUT_SAMPLE_RATE,
rate);
if (err < 0) {
dev_err(dai->codec->dev, "Failed to set sample rate\n");
- return err;
+ goto out;
}
err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
@@ -231,15 +198,18 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
(width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
if (err < 0) {
dev_err(dai->codec->dev, "Failed to set output width\n");
- return err;
+ goto out;
}
- return 0;
+out:
+ si476x_core_unlock(core);
+
+ return err;
}
static int si476x_codec_probe(struct snd_soc_codec *codec)
{
- codec->control_data = i2c_mfd_cell_to_core(codec->dev);
+ codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
return 0;
}
@@ -268,8 +238,6 @@ static struct snd_soc_dai_driver si476x_dai = {
static struct snd_soc_codec_driver soc_codec_dev_si476x = {
.probe = si476x_codec_probe,
- .read = si476x_codec_read,
- .write = si476x_codec_write,
.dapm_widgets = si476x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
.dapm_routes = si476x_dapm_routes,
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index dba26e63844e..13045f2af4d3 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -164,30 +164,28 @@ static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
}
/*end - adc helper functions */
-static inline unsigned int sn95031_read(struct snd_soc_codec *codec,
- unsigned int reg)
+static int sn95031_read(void *ctx, unsigned int reg, unsigned int *val)
{
u8 value = 0;
int ret;
ret = intel_scu_ipc_ioread8(reg, &value);
- if (ret)
- pr_err("read of %x failed, err %d\n", reg, ret);
- return value;
+ if (ret == 0)
+ *val = value;
+ return ret;
}
-static inline int sn95031_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
+static int sn95031_write(void *ctx, unsigned int reg, unsigned int value)
{
- int ret;
-
- ret = intel_scu_ipc_iowrite8(reg, value);
- if (ret)
- pr_err("write of %x failed, err %d\n", reg, ret);
- return ret;
+ return intel_scu_ipc_iowrite8(reg, value);
}
+static const struct regmap_config sn95031_regmap = {
+ .reg_read = sn95031_read,
+ .reg_write = sn95031_write,
+};
+
static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
@@ -827,6 +825,8 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
{
pr_debug("codec_probe called\n");
+ snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
+
/* PCM interface config
* This sets the pcm rx slot conguration to max 6 slots
* for max 4 dais (2 stereo and 2 mono)
@@ -886,8 +886,6 @@ static int sn95031_codec_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver sn95031_codec = {
.probe = sn95031_codec_probe,
.remove = sn95031_codec_remove,
- .read = sn95031_read,
- .write = sn95031_write,
.set_bias_level = sn95031_set_vaud_bias,
.idle_bias_off = true,
.dapm_widgets = sn95031_dapm_widgets,
@@ -898,7 +896,14 @@ static struct snd_soc_codec_driver sn95031_codec = {
static int sn95031_device_probe(struct platform_device *pdev)
{
+ struct regmap *regmap;
+
pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev));
+
+ regmap = devm_regmap_init(&pdev->dev, NULL, NULL, &sn95031_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
return snd_soc_register_codec(&pdev->dev, &sn95031_codec,
sn95031_dais, ARRAY_SIZE(sn95031_dais));
}
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c
index 95aed552139a..cc8debce752f 100644
--- a/sound/soc/codecs/ssm2518.c
+++ b/sound/soc/codecs/ssm2518.c
@@ -549,13 +549,13 @@ static int ssm2518_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
right_slot = 0;
} else {
/* We assume the left channel < right channel */
- left_slot = ffs(tx_mask);
- tx_mask &= ~(1 << tx_mask);
+ left_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << left_slot);
if (tx_mask == 0) {
right_slot = left_slot;
} else {
- right_slot = ffs(tx_mask);
- tx_mask &= ~(1 << tx_mask);
+ right_slot = __ffs(tx_mask);
+ tx_mask &= ~(1 << right_slot);
}
}
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 492644e67ace..af76bbd1b24f 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -53,8 +53,6 @@ enum ssm2602_type {
struct ssm2602_priv {
unsigned int sysclk;
struct snd_pcm_hw_constraint_list *sysclk_constraints;
- struct snd_pcm_substream *master_substream;
- struct snd_pcm_substream *slave_substream;
struct regmap *regmap;
@@ -196,7 +194,7 @@ static const struct snd_soc_dapm_route ssm2604_routes[] = {
};
static const unsigned int ssm2602_rates_12288000[] = {
- 8000, 32000, 48000, 96000,
+ 8000, 16000, 32000, 48000, 96000,
};
static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
@@ -233,6 +231,11 @@ static const struct ssm2602_coeff ssm2602_coeff_table[] = {
{18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
{12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
+ /* 16k */
+ {12288000, 16000, SSM2602_COEFF_SRATE(0x5, 0x0, 0x0)},
+ {18432000, 16000, SSM2602_COEFF_SRATE(0x5, 0x1, 0x0)},
+ {12000000, 16000, SSM2602_COEFF_SRATE(0xa, 0x0, 0x1)},
+
/* 8k */
{12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
{18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
@@ -277,11 +280,6 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
unsigned int iface;
- if (substream == ssm2602->slave_substream) {
- dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
- return 0;
- }
-
if (srate < 0)
return srate;
@@ -314,33 +312,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
{
struct snd_soc_codec *codec = dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- struct snd_pcm_runtime *master_runtime;
-
- /* The DAI has shared clocks so if we already have a playback or
- * capture going then constrain this substream to match it.
- * TODO: the ssm2602 allows pairs of non-matching PB/REC rates
- */
- if (ssm2602->master_substream) {
- master_runtime = ssm2602->master_substream->runtime;
- dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
- master_runtime->sample_bits,
- master_runtime->rate);
-
- if (master_runtime->rate != 0)
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- master_runtime->rate,
- master_runtime->rate);
-
- if (master_runtime->sample_bits != 0)
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- master_runtime->sample_bits,
- master_runtime->sample_bits);
-
- ssm2602->slave_substream = substream;
- } else
- ssm2602->master_substream = substream;
if (ssm2602->sysclk_constraints) {
snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -351,19 +322,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
return 0;
}
-static void ssm2602_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-
- if (ssm2602->master_substream == substream)
- ssm2602->master_substream = ssm2602->slave_substream;
-
- ssm2602->slave_substream = NULL;
-}
-
-
static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
@@ -520,9 +478,10 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_32000 |\
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+#define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
+ SNDRV_PCM_RATE_96000)
#define SSM2602_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
@@ -530,7 +489,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
static const struct snd_soc_dai_ops ssm2602_dai_ops = {
.startup = ssm2602_startup,
.hw_params = ssm2602_hw_params,
- .shutdown = ssm2602_shutdown,
.digital_mute = ssm2602_mute,
.set_sysclk = ssm2602_set_dai_sysclk,
.set_fmt = ssm2602_set_dai_fmt,
@@ -551,6 +509,8 @@ static struct snd_soc_dai_driver ssm2602_dai = {
.rates = SSM2602_RATES,
.formats = SSM2602_FORMATS,},
.ops = &ssm2602_dai_ops,
+ .symmetric_rates = 1,
+ .symmetric_samplebits = 1,
};
static int ssm2602_suspend(struct snd_soc_codec *codec)
@@ -730,7 +690,7 @@ static struct spi_driver ssm2602_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
/*
* ssm2602 2 wire address is determined by GPIO5
* state during powerup.
@@ -797,7 +757,7 @@ static int __init ssm2602_modinit(void)
return ret;
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&ssm2602_i2c_driver);
if (ret)
return ret;
@@ -813,7 +773,7 @@ static void __exit ssm2602_exit(void)
spi_unregister_driver(&ssm2602_spi_driver);
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&ssm2602_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
index 6d31d88f7204..a895a5e4bdf2 100644
--- a/sound/soc/codecs/tas5086.c
+++ b/sound/soc/codecs/tas5086.c
@@ -37,6 +37,7 @@
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
+#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
@@ -244,6 +245,8 @@ struct tas5086_private {
unsigned int mclk, sclk;
unsigned int format;
bool deemph;
+ unsigned int charge_period;
+ unsigned int pwm_start_mid_z;
/* Current sample rate for de-emphasis control */
int rate;
/* GPIO driving Reset pin, if any */
@@ -429,7 +432,7 @@ static int tas5086_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(codec->dev, "Invalid bit width\n");
return -EINVAL;
- };
+ }
ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
if (ret < 0)
@@ -456,6 +459,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
}
+static void tas5086_reset(struct tas5086_private *priv)
+{
+ if (gpio_is_valid(priv->gpio_nreset)) {
+ /* Reset codec - minimum assertion time is 400ns */
+ gpio_direction_output(priv->gpio_nreset, 0);
+ udelay(1);
+ gpio_set_value(priv->gpio_nreset, 1);
+
+ /* Codec needs ~15ms to wake up */
+ msleep(15);
+ }
+}
+
+/* charge period values in microseconds */
+static const int tas5086_charge_period[] = {
+ 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
+ 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
+ 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
+};
+
+static int tas5086_init(struct device *dev, struct tas5086_private *priv)
+{
+ int ret, i;
+
+ /*
+ * If any of the channels is configured to start in Mid-Z mode,
+ * configure 'part 1' of the PWM starts to use Mid-Z, and tell
+ * all configured mid-z channels to start start under 'part 1'.
+ */
+ if (priv->pwm_start_mid_z)
+ regmap_write(priv->regmap, TAS5086_PWM_START,
+ TAS5086_PWM_START_MIDZ_FOR_START_1 |
+ priv->pwm_start_mid_z);
+
+ /* lookup and set split-capacitor charge period */
+ if (priv->charge_period == 0) {
+ regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
+ } else {
+ i = index_in_array(tas5086_charge_period,
+ ARRAY_SIZE(tas5086_charge_period),
+ priv->charge_period);
+ if (i >= 0)
+ regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
+ i + 0x08);
+ else
+ dev_warn(dev,
+ "Invalid split-cap charge period of %d ns.\n",
+ priv->charge_period);
+ }
+
+ /* enable factory trim */
+ ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
+ if (ret < 0)
+ return ret;
+
+ /* start all channels */
+ ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+ if (ret < 0)
+ return ret;
+
+ /* mute all channels for now */
+ ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
+ TAS5086_SOFT_MUTE_ALL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
/* TAS5086 controls */
static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
@@ -691,14 +763,39 @@ static struct snd_soc_dai_driver tas5086_dai = {
};
#ifdef CONFIG_PM
+static int tas5086_soc_suspend(struct snd_soc_codec *codec)
+{
+ struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ /* Shut down all channels */
+ ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int tas5086_soc_resume(struct snd_soc_codec *codec)
{
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ tas5086_reset(priv);
+ regcache_mark_dirty(priv->regmap);
+
+ ret = tas5086_init(codec->dev, priv);
+ if (ret < 0)
+ return ret;
+
+ ret = regcache_sync(priv->regmap);
+ if (ret < 0)
+ return ret;
- /* Restore codec state */
- return regcache_sync(priv->regmap);
+ return 0;
}
#else
+#define tas5086_soc_suspend NULL
#define tas5086_soc_resume NULL
#endif /* CONFIG_PM */
@@ -710,23 +807,19 @@ static const struct of_device_id tas5086_dt_ids[] = {
MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
#endif
-/* charge period values in microseconds */
-static const int tas5086_charge_period[] = {
- 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200,
- 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000,
- 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
-};
-
static int tas5086_probe(struct snd_soc_codec *codec)
{
struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
- int charge_period = 1300000; /* hardware default is 1300 ms */
- u8 pwm_start_mid_z = 0;
int i, ret;
+ priv->pwm_start_mid_z = 0;
+ priv->charge_period = 1300000; /* hardware default is 1300 ms */
+
if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
struct device_node *of_node = codec->dev->of_node;
- of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+
+ of_property_read_u32(of_node, "ti,charge-period",
+ &priv->charge_period);
for (i = 0; i < 6; i++) {
char name[25];
@@ -735,43 +828,11 @@ static int tas5086_probe(struct snd_soc_codec *codec)
"ti,mid-z-channel-%d", i + 1);
if (of_get_property(of_node, name, NULL) != NULL)
- pwm_start_mid_z |= 1 << i;
+ priv->pwm_start_mid_z |= 1 << i;
}
}
- /*
- * If any of the channels is configured to start in Mid-Z mode,
- * configure 'part 1' of the PWM starts to use Mid-Z, and tell
- * all configured mid-z channels to start start under 'part 1'.
- */
- if (pwm_start_mid_z)
- regmap_write(priv->regmap, TAS5086_PWM_START,
- TAS5086_PWM_START_MIDZ_FOR_START_1 |
- pwm_start_mid_z);
-
- /* lookup and set split-capacitor charge period */
- if (charge_period == 0) {
- regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
- } else {
- i = index_in_array(tas5086_charge_period,
- ARRAY_SIZE(tas5086_charge_period),
- charge_period);
- if (i >= 0)
- regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
- i + 0x08);
- else
- dev_warn(codec->dev,
- "Invalid split-cap charge period of %d ns.\n",
- charge_period);
- }
-
- /* enable factory trim */
- ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
- if (ret < 0)
- return ret;
-
- /* start all channels */
- ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+ ret = tas5086_init(codec->dev, priv);
if (ret < 0)
return ret;
@@ -780,12 +841,6 @@ static int tas5086_probe(struct snd_soc_codec *codec)
if (ret < 0)
return ret;
- /* mute all channels for now */
- ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
- TAS5086_SOFT_MUTE_ALL);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -803,6 +858,7 @@ static int tas5086_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
.probe = tas5086_probe,
.remove = tas5086_remove,
+ .suspend = tas5086_soc_suspend,
.resume = tas5086_soc_resume,
.controls = tas5086_controls,
.num_controls = ARRAY_SIZE(tas5086_controls),
@@ -862,17 +918,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c,
if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
gpio_nreset = -EINVAL;
- if (gpio_is_valid(gpio_nreset)) {
- /* Reset codec - minimum assertion time is 400ns */
- gpio_direction_output(gpio_nreset, 0);
- udelay(1);
- gpio_set_value(gpio_nreset, 1);
-
- /* Codec needs ~15ms to wake up */
- msleep(15);
- }
-
priv->gpio_nreset = gpio_nreset;
+ tas5086_reset(priv);
/* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index 31762ebdd774..5d430cc56f51 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -37,11 +38,27 @@
/*
* AIC23 register cache
*/
-static const u16 tlv320aic23_reg[] = {
- 0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */
- 0x001A, 0x0004, 0x0007, 0x0001, /* 4 */
- 0x0020, 0x0000, 0x0000, 0x0000, /* 8 */
- 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
+static const struct reg_default tlv320aic23_reg[] = {
+ { 0, 0x0097 },
+ { 1, 0x0097 },
+ { 2, 0x00F9 },
+ { 3, 0x00F9 },
+ { 4, 0x001A },
+ { 5, 0x0004 },
+ { 6, 0x0007 },
+ { 7, 0x0001 },
+ { 8, 0x0020 },
+ { 9, 0x0000 },
+};
+
+static const struct regmap_config tlv320aic23_regmap = {
+ .reg_bits = 7,
+ .val_bits = 9,
+
+ .max_register = TLV320AIC23_RESET,
+ .reg_defaults = tlv320aic23_reg,
+ .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg),
+ .cache_type = REGCACHE_RBTREE,
};
static const char *rec_src_text[] = { "Line", "Mic" };
@@ -171,7 +188,7 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
/* AIC23 driver data */
struct aic23 {
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
int mclk;
int requested_adc;
int requested_dac;
@@ -532,7 +549,9 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec)
static int tlv320aic23_resume(struct snd_soc_codec *codec)
{
- snd_soc_cache_sync(codec);
+ struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
+ regcache_mark_dirty(aic23->regmap);
+ regcache_sync(aic23->regmap);
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
@@ -540,10 +559,9 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
static int tlv320aic23_probe(struct snd_soc_codec *codec)
{
- struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -552,16 +570,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
/* Reset codec */
snd_soc_write(codec, TLV320AIC23_RESET, 0);
- /* Write the register default value to cache for reserved registers,
- * so the write to the these registers are suppressed by the cache
- * restore code when it skips writes of default registers.
- */
- snd_soc_cache_write(codec, 0x0A, 0);
- snd_soc_cache_write(codec, 0x0B, 0);
- snd_soc_cache_write(codec, 0x0C, 0);
- snd_soc_cache_write(codec, 0x0D, 0);
- snd_soc_cache_write(codec, 0x0E, 0);
-
/* power on device */
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -586,9 +594,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1);
- snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls,
- ARRAY_SIZE(tlv320aic23_snd_controls));
-
return 0;
}
@@ -599,21 +604,19 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
- .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = tlv320aic23_reg,
.probe = tlv320aic23_probe,
.remove = tlv320aic23_remove,
.suspend = tlv320aic23_suspend,
.resume = tlv320aic23_resume,
.set_bias_level = tlv320aic23_set_bias_level,
+ .controls = tlv320aic23_snd_controls,
+ .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),
.dapm_widgets = tlv320aic23_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
.dapm_routes = tlv320aic23_intercon,
.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
* If the i2c layer weren't so broken, we could pass this kind of data
* around
@@ -631,8 +634,11 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
if (aic23 == NULL)
return -ENOMEM;
+ aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap);
+ if (IS_ERR(aic23->regmap))
+ return PTR_ERR(aic23->regmap);
+
i2c_set_clientdata(i2c, aic23);
- aic23->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1);
@@ -660,29 +666,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = {
.id_table = tlv320aic23_id,
};
-#endif
-
-static int __init tlv320aic23_modinit(void)
-{
- int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- ret = i2c_add_driver(&tlv320aic23_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n",
- ret);
- }
-#endif
- return ret;
-}
-module_init(tlv320aic23_modinit);
-
-static void __exit tlv320aic23_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_del_driver(&tlv320aic23_i2c_driver);
-#endif
-}
-module_exit(tlv320aic23_exit);
+module_i2c_driver(tlv320aic23_i2c_driver);
MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver");
MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>");
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 7b8f3d965f43..94a658fa6d97 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
/* AIC26 driver private data */
struct aic26 {
struct spi_device *spi;
+ struct regmap *regmap;
struct snd_soc_codec *codec;
int master;
int datfm;
@@ -40,85 +41,6 @@ struct aic26 {
int keyclick_len;
};
-/* ---------------------------------------------------------------------
- * Register access routines
- */
-static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
- u16 *cache = codec->reg_cache;
- u16 cmd, value;
- u8 buffer[2];
- int rc;
-
- if (reg >= AIC26_NUM_REGS) {
- WARN_ON_ONCE(1);
- return 0;
- }
-
- /* Do SPI transfer; first 16bits are command; remaining is
- * register contents */
- cmd = AIC26_READ_COMMAND_WORD(reg);
- buffer[0] = (cmd >> 8) & 0xff;
- buffer[1] = cmd & 0xff;
- rc = spi_write_then_read(aic26->spi, buffer, 2, buffer, 2);
- if (rc) {
- dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
- return -EIO;
- }
- value = (buffer[0] << 8) | buffer[1];
-
- /* Update the cache before returning with the value */
- cache[reg] = value;
- return value;
-}
-
-static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
-
- if (reg >= AIC26_NUM_REGS) {
- WARN_ON_ONCE(1);
- return 0;
- }
-
- return cache[reg];
-}
-
-static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
- struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
- u16 *cache = codec->reg_cache;
- u16 cmd;
- u8 buffer[4];
- int rc;
-
- if (reg >= AIC26_NUM_REGS) {
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
-
- /* Do SPI transfer; first 16bits are command; remaining is data
- * to write into register */
- cmd = AIC26_WRITE_COMMAND_WORD(reg);
- buffer[0] = (cmd >> 8) & 0xff;
- buffer[1] = cmd & 0xff;
- buffer[2] = value >> 8;
- buffer[3] = value;
- rc = spi_write(aic26->spi, buffer, 4);
- if (rc) {
- dev_err(&aic26->spi->dev, "AIC26 reg read error\n");
- return -EIO;
- }
-
- /* update cache before returning */
- cache[reg] = value;
- return 0;
-}
-
static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("MICIN"),
SND_SOC_DAPM_INPUT("AUX"),
@@ -195,19 +117,15 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg);
/* Audio Control 3 (master mode, fsref rate) */
- reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
- reg &= ~0xf800;
if (aic26->master)
- reg |= 0x0800;
+ reg = 0x0800;
if (fsref == 48000)
- reg |= 0x2000;
- snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+ reg = 0x2000;
+ snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL3, 0xf800, reg);
/* Audio Control 1 (FSref divisor) */
- reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
- reg &= ~0x0fff;
- reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
- snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+ reg = wlen | aic26->datfm | (divisor << 3) | divisor;
+ snd_soc_update_bits(codec, AIC26_REG_AUDIO_CTRL1, 0xfff, reg);
return 0;
}
@@ -219,16 +137,16 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
- u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
+ u16 reg;
dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
dai, mute);
if (mute)
- reg |= 0x8080;
+ reg = 0x8080;
else
- reg &= ~0x8080;
- snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg);
+ reg = 0;
+ snd_soc_update_bits(codec, AIC26_REG_DAC_GAIN, 0x8000, reg);
return 0;
}
@@ -346,7 +264,7 @@ static ssize_t aic26_keyclick_show(struct device *dev,
struct aic26 *aic26 = dev_get_drvdata(dev);
int val, amp, freq, len;
- val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
+ val = snd_soc_read(aic26->codec, AIC26_REG_AUDIO_CTRL2);
amp = (val >> 12) & 0x7;
freq = (125 << ((val >> 8) & 0x7)) >> 1;
len = 2 * (1 + ((val >> 4) & 0xf));
@@ -360,11 +278,9 @@ static ssize_t aic26_keyclick_set(struct device *dev,
const char *buf, size_t count)
{
struct aic26 *aic26 = dev_get_drvdata(dev);
- int val;
- val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
- val |= 0x8000;
- snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+ snd_soc_update_bits(aic26->codec, AIC26_REG_AUDIO_CTRL2,
+ 0x8000, 0x800);
return count;
}
@@ -377,7 +293,9 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
static int aic26_probe(struct snd_soc_codec *codec)
{
struct aic26 *aic26 = dev_get_drvdata(codec->dev);
- int ret, err, i, reg;
+ int ret, reg;
+
+ snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
aic26->codec = codec;
@@ -393,37 +311,30 @@ static int aic26_probe(struct snd_soc_codec *codec)
reg |= 0x0800; /* set master mode */
snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
- /* Fill register cache */
- for (i = 0; i < codec->driver->reg_cache_size; i++)
- snd_soc_read(codec, i);
-
/* Register the sysfs files for debugging */
/* Create SysFS files */
ret = device_create_file(codec->dev, &dev_attr_keyclick);
if (ret)
dev_info(codec->dev, "error creating sysfs files\n");
- /* register controls */
- dev_dbg(codec->dev, "Registering controls\n");
- err = snd_soc_add_codec_controls(codec, aic26_snd_controls,
- ARRAY_SIZE(aic26_snd_controls));
- WARN_ON(err < 0);
-
return 0;
}
static struct snd_soc_codec_driver aic26_soc_codec_dev = {
.probe = aic26_probe,
- .read = aic26_reg_read,
- .write = aic26_reg_write,
- .reg_cache_size = AIC26_NUM_REGS,
- .reg_word_size = sizeof(u16),
+ .controls = aic26_snd_controls,
+ .num_controls = ARRAY_SIZE(aic26_snd_controls),
.dapm_widgets = tlv320aic26_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets),
.dapm_routes = tlv320aic26_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes),
};
+static const struct regmap_config aic26_regmap = {
+ .reg_bits = 16,
+ .val_bits = 16,
+};
+
/* ---------------------------------------------------------------------
* SPI device portion of driver: probe and release routines and SPI
* driver registration.
@@ -440,6 +351,10 @@ static int aic26_spi_probe(struct spi_device *spi)
if (!aic26)
return -ENOMEM;
+ aic26->regmap = devm_regmap_init_spi(spi, &aic26_regmap);
+ if (IS_ERR(aic26->regmap))
+ return PTR_ERR(aic26->regmap);
+
/* Initialize the driver data */
aic26->spi = spi;
dev_set_drvdata(&spi->dev, aic26);
diff --git a/sound/soc/codecs/tlv320aic26.h b/sound/soc/codecs/tlv320aic26.h
index 67f19c3bebe6..629b85e75409 100644
--- a/sound/soc/codecs/tlv320aic26.h
+++ b/sound/soc/codecs/tlv320aic26.h
@@ -9,10 +9,7 @@
#define _TLV320AIC16_H_
/* AIC26 Registers */
-#define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5))
-#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
-#define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset)
-#define AIC26_NUM_REGS AIC26_PAGE_ADDR(3, 0)
+#define AIC26_PAGE_ADDR(page, offset) ((page << 11) | offset << 5)
/* Page 0: Auxiliary data registers */
#define AIC26_REG_BAT1 AIC26_PAGE_ADDR(0, 0x05)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 2ed57d4aa445..688151ba309a 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -60,9 +60,8 @@ struct aic32x4_rate_divs {
};
struct aic32x4_priv {
+ struct regmap *regmap;
u32 sysclk;
- u8 page_no;
- void *control_data;
u32 power_cfg;
u32 micpga_routing;
bool swapdacs;
@@ -262,67 +261,25 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
{"Right ADC", NULL, "Right Input Mixer"},
};
-static inline int aic32x4_change_page(struct snd_soc_codec *codec,
- unsigned int new_page)
-{
- struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
- u8 data[2];
- int ret;
-
- data[0] = 0x00;
- data[1] = new_page & 0xff;
-
- ret = codec->hw_write(codec->control_data, data, 2);
- if (ret == 2) {
- aic32x4->page_no = new_page;
- return 0;
- } else {
- return ret;
- }
-}
-
-static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int val)
-{
- struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
- unsigned int page = reg / 128;
- unsigned int fixed_reg = reg % 128;
- u8 data[2];
- int ret;
-
- /* A write to AIC32X4_PSEL is really a non-explicit page change */
- if (reg == AIC32X4_PSEL)
- return aic32x4_change_page(codec, val);
-
- if (aic32x4->page_no != page) {
- ret = aic32x4_change_page(codec, page);
- if (ret != 0)
- return ret;
- }
-
- data[0] = fixed_reg & 0xff;
- data[1] = val & 0xff;
-
- if (codec->hw_write(codec->control_data, data, 2) == 2)
- return 0;
- else
- return -EIO;
-}
+static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
+ {
+ .selector_reg = 0,
+ .selector_mask = 0xff,
+ .window_start = 0,
+ .window_len = 128,
+ .range_min = 0,
+ .range_max = AIC32X4_RMICPGAVOL,
+ },
+};
-static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg)
-{
- struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
- unsigned int page = reg / 128;
- unsigned int fixed_reg = reg % 128;
- int ret;
+static const struct regmap_config aic32x4_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
- if (aic32x4->page_no != page) {
- ret = aic32x4_change_page(codec, page);
- if (ret != 0)
- return ret;
- }
- return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff);
-}
+ .max_register = AIC32X4_RMICPGAVOL,
+ .ranges = aic32x4_regmap_pages,
+ .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
+};
static inline int aic32x4_get_divs(int mclk, int rate)
{
@@ -493,6 +450,17 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
}
snd_soc_write(codec, AIC32X4_IFACE1, data);
+ if (params_channels(params) == 1) {
+ data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
+ } else {
+ if (aic32x4->swapdacs)
+ data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
+ else
+ data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
+ }
+ snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK,
+ data);
+
return 0;
}
@@ -617,16 +585,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
{
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
u32 tmp_reg;
- int ret;
- codec->hw_write = (hw_write_t) i2c_master_send;
- codec->control_data = aic32x4->control_data;
+ snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (aic32x4->rstn_gpio >= 0) {
- ret = devm_gpio_request_one(codec->dev, aic32x4->rstn_gpio,
- GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
- if (ret != 0)
- return ret;
ndelay(10);
gpio_set_value(aic32x4->rstn_gpio, 1);
}
@@ -655,20 +617,15 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
}
snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg);
- /* Do DACs need to be swapped? */
- if (aic32x4->swapdacs) {
- snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2RCHN | AIC32X4_RDAC2LCHN);
- } else {
- snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN);
- }
-
/* Mic PGA routing */
- if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) {
+ if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K);
- }
- if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) {
+ else
+ snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_CM1L_10K);
+ if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K);
- }
+ else
+ snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_CM1R_10K);
aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -692,8 +649,6 @@ static int aic32x4_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
- .read = aic32x4_read,
- .write = aic32x4_write,
.probe = aic32x4_probe,
.remove = aic32x4_remove,
.suspend = aic32x4_suspend,
@@ -720,7 +675,10 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
if (aic32x4 == NULL)
return -ENOMEM;
- aic32x4->control_data = i2c;
+ aic32x4->regmap = devm_regmap_init_i2c(i2c, &aic32x4_regmap);
+ if (IS_ERR(aic32x4->regmap))
+ return PTR_ERR(aic32x4->regmap);
+
i2c_set_clientdata(i2c, aic32x4);
if (pdata) {
@@ -735,6 +693,13 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c,
aic32x4->rstn_gpio = -1;
}
+ if (aic32x4->rstn_gpio >= 0) {
+ ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio,
+ GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
+ if (ret != 0)
+ return ret;
+ }
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aic32x4, &aic32x4_dai, 1);
return ret;
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index 35774223fd91..995f033a855d 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -120,7 +120,9 @@
#define AIC32X4_MICBIAS_2075V 0x60
#define AIC32X4_LMICPGANIN_IN2R_10K 0x10
+#define AIC32X4_LMICPGANIN_CM1L_10K 0x40
#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
+#define AIC32X4_RMICPGANIN_CM1R_10K 0x40
#define AIC32X4_LMICPGAVOL_NOGAIN 0x80
#define AIC32X4_RMICPGAVOL_NOGAIN 0x80
@@ -138,6 +140,7 @@
#define AIC32X4_LDAC2RCHN (0x02 << 4)
#define AIC32X4_LDAC2LCHN (0x01 << 4)
#define AIC32X4_RDAC2RCHN (0x01 << 2)
+#define AIC32X4_DAC_CHAN_MASK 0x3c
#define AIC32X4_SSTEP2WCLK 0x01
#define AIC32X4_MUTEON 0x0C
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 6e3f269243e0..470fbfb4b386 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -40,6 +40,7 @@
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <sound/core.h>
@@ -72,9 +73,9 @@ struct aic3x_disable_nb {
/* codec private data */
struct aic3x_priv {
struct snd_soc_codec *codec;
+ struct regmap *regmap;
struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
- enum snd_soc_control_type control_type;
struct aic3x_setup_data *setup;
unsigned int sysclk;
struct list_head list;
@@ -90,41 +91,45 @@ struct aic3x_priv {
enum aic3x_micbias_voltage micbias_vg;
};
-/*
- * AIC3X register cache
- * We can't read the AIC3X register space when we are
- * using 2 wire for device control, so we cache them instead.
- * There is no point in caching the reset register
- */
-static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
- 0x00, 0x00, 0x00, 0x10, /* 0 */
- 0x04, 0x00, 0x00, 0x00, /* 4 */
- 0x00, 0x00, 0x00, 0x01, /* 8 */
- 0x00, 0x00, 0x00, 0x80, /* 12 */
- 0x80, 0xff, 0xff, 0x78, /* 16 */
- 0x78, 0x78, 0x78, 0x78, /* 20 */
- 0x78, 0x00, 0x00, 0xfe, /* 24 */
- 0x00, 0x00, 0xfe, 0x00, /* 28 */
- 0x18, 0x18, 0x00, 0x00, /* 32 */
- 0x00, 0x00, 0x00, 0x00, /* 36 */
- 0x00, 0x00, 0x00, 0x80, /* 40 */
- 0x80, 0x00, 0x00, 0x00, /* 44 */
- 0x00, 0x00, 0x00, 0x04, /* 48 */
- 0x00, 0x00, 0x00, 0x00, /* 52 */
- 0x00, 0x00, 0x04, 0x00, /* 56 */
- 0x00, 0x00, 0x00, 0x00, /* 60 */
- 0x00, 0x04, 0x00, 0x00, /* 64 */
- 0x00, 0x00, 0x00, 0x00, /* 68 */
- 0x04, 0x00, 0x00, 0x00, /* 72 */
- 0x00, 0x00, 0x00, 0x00, /* 76 */
- 0x00, 0x00, 0x00, 0x00, /* 80 */
- 0x00, 0x00, 0x00, 0x00, /* 84 */
- 0x00, 0x00, 0x00, 0x00, /* 88 */
- 0x00, 0x00, 0x00, 0x00, /* 92 */
- 0x00, 0x00, 0x00, 0x00, /* 96 */
- 0x00, 0x00, 0x02, 0x00, /* 100 */
- 0x00, 0x00, 0x00, 0x00, /* 104 */
- 0x00, 0x00, /* 108 */
+static const struct reg_default aic3x_reg[] = {
+ { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, { 3, 0x10 },
+ { 4, 0x04 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 },
+ { 8, 0x00 }, { 9, 0x00 }, { 10, 0x00 }, { 11, 0x01 },
+ { 12, 0x00 }, { 13, 0x00 }, { 14, 0x00 }, { 15, 0x80 },
+ { 16, 0x80 }, { 17, 0xff }, { 18, 0xff }, { 19, 0x78 },
+ { 20, 0x78 }, { 21, 0x78 }, { 22, 0x78 }, { 23, 0x78 },
+ { 24, 0x78 }, { 25, 0x00 }, { 26, 0x00 }, { 27, 0xfe },
+ { 28, 0x00 }, { 29, 0x00 }, { 30, 0xfe }, { 31, 0x00 },
+ { 32, 0x18 }, { 33, 0x18 }, { 34, 0x00 }, { 35, 0x00 },
+ { 36, 0x00 }, { 37, 0x00 }, { 38, 0x00 }, { 39, 0x00 },
+ { 40, 0x00 }, { 41, 0x00 }, { 42, 0x00 }, { 43, 0x80 },
+ { 44, 0x80 }, { 45, 0x00 }, { 46, 0x00 }, { 47, 0x00 },
+ { 48, 0x00 }, { 49, 0x00 }, { 50, 0x00 }, { 51, 0x04 },
+ { 52, 0x00 }, { 53, 0x00 }, { 54, 0x00 }, { 55, 0x00 },
+ { 56, 0x00 }, { 57, 0x00 }, { 58, 0x04 }, { 59, 0x00 },
+ { 60, 0x00 }, { 61, 0x00 }, { 62, 0x00 }, { 63, 0x00 },
+ { 64, 0x00 }, { 65, 0x04 }, { 66, 0x00 }, { 67, 0x00 },
+ { 68, 0x00 }, { 69, 0x00 }, { 70, 0x00 }, { 71, 0x00 },
+ { 72, 0x04 }, { 73, 0x00 }, { 74, 0x00 }, { 75, 0x00 },
+ { 76, 0x00 }, { 77, 0x00 }, { 78, 0x00 }, { 79, 0x00 },
+ { 80, 0x00 }, { 81, 0x00 }, { 82, 0x00 }, { 83, 0x00 },
+ { 84, 0x00 }, { 85, 0x00 }, { 86, 0x00 }, { 87, 0x00 },
+ { 88, 0x00 }, { 89, 0x00 }, { 90, 0x00 }, { 91, 0x00 },
+ { 92, 0x00 }, { 93, 0x00 }, { 94, 0x00 }, { 95, 0x00 },
+ { 96, 0x00 }, { 97, 0x00 }, { 98, 0x00 }, { 99, 0x00 },
+ { 100, 0x00 }, { 101, 0x00 }, { 102, 0x02 }, { 103, 0x00 },
+ { 104, 0x00 }, { 105, 0x00 }, { 106, 0x00 }, { 107, 0x00 },
+ { 108, 0x00 }, { 109, 0x00 },
+};
+
+static const struct regmap_config aic3x_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = DAC_ICC_ADJ,
+ .reg_defaults = aic3x_reg,
+ .num_reg_defaults = ARRAY_SIZE(aic3x_reg),
+ .cache_type = REGCACHE_RBTREE,
};
#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
@@ -345,16 +350,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
- LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
- PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
- SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
- DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
- 0, 118, 1, output_stage_tlv),
-
SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
0, 118, 1, output_stage_tlv),
@@ -378,7 +373,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
/* Output pin mute controls */
SOC_DOUBLE_R("Line Playback Switch", LLOPM_CTRL, RLOPM_CTRL, 3,
0x01, 0),
- SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
SOC_DOUBLE_R("HP Playback Switch", HPLOUT_CTRL, HPROUT_CTRL, 3,
0x01, 0),
SOC_DOUBLE_R("HPCOM Playback Switch", HPLCOM_CTRL, HPRCOM_CTRL, 3,
@@ -407,6 +401,20 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
};
+static const struct snd_kcontrol_new aic3x_mono_controls[] = {
+ SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
+ LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Mono PGA Bypass Volume",
+ PGAL_2_MONOLOPM_VOL, PGAR_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+ SOC_DOUBLE_R_TLV("Mono DAC Playback Volume",
+ DACL1_2_MONOLOPM_VOL, DACR1_2_MONOLOPM_VOL,
+ 0, 118, 1, output_stage_tlv),
+
+ SOC_SINGLE("Mono Playback Switch", MONOLOPM_CTRL, 3, 0x01, 0),
+};
+
/*
* Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
*/
@@ -560,9 +568,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Right HP Out", HPROUT_CTRL, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right HP Com", HPRCOM_CTRL, 0, 0, NULL, 0),
- /* Mono Output */
- SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
-
/* Inputs to Left ADC */
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
@@ -621,9 +626,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
&aic3x_right_line_mixer_controls[0],
ARRAY_SIZE(aic3x_right_line_mixer_controls)),
- SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
- &aic3x_mono_mixer_controls[0],
- ARRAY_SIZE(aic3x_mono_mixer_controls)),
SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
&aic3x_left_hp_mixer_controls[0],
ARRAY_SIZE(aic3x_left_hp_mixer_controls)),
@@ -639,7 +641,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("LLOUT"),
SND_SOC_DAPM_OUTPUT("RLOUT"),
- SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
SND_SOC_DAPM_OUTPUT("HPLOUT"),
SND_SOC_DAPM_OUTPUT("HPROUT"),
SND_SOC_DAPM_OUTPUT("HPLCOM"),
@@ -661,6 +662,17 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("Detection"),
};
+static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
+ /* Mono Output */
+ SND_SOC_DAPM_PGA("Mono Out", MONOLOPM_CTRL, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
+ &aic3x_mono_mixer_controls[0],
+ ARRAY_SIZE(aic3x_mono_mixer_controls)),
+
+ SND_SOC_DAPM_OUTPUT("MONO_LOUT"),
+};
+
static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
/* Class-D outputs */
SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
@@ -674,6 +686,8 @@ static const struct snd_soc_dapm_route intercon[] = {
/* Left Input */
{"Left Line1L Mux", "single-ended", "LINE1L"},
{"Left Line1L Mux", "differential", "LINE1L"},
+ {"Left Line1R Mux", "single-ended", "LINE1R"},
+ {"Left Line1R Mux", "differential", "LINE1R"},
{"Left Line2L Mux", "single-ended", "LINE2L"},
{"Left Line2L Mux", "differential", "LINE2L"},
@@ -690,6 +704,8 @@ static const struct snd_soc_dapm_route intercon[] = {
/* Right Input */
{"Right Line1R Mux", "single-ended", "LINE1R"},
{"Right Line1R Mux", "differential", "LINE1R"},
+ {"Right Line1L Mux", "single-ended", "LINE1L"},
+ {"Right Line1L Mux", "differential", "LINE1L"},
{"Right Line2R Mux", "single-ended", "LINE2R"},
{"Right Line2R Mux", "differential", "LINE2R"},
@@ -745,17 +761,6 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Right Line Out", NULL, "Right DAC Mux"},
{"RLOUT", NULL, "Right Line Out"},
- /* Mono Output */
- {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
- {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
- {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
- {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
- {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
- {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
-
- {"Mono Out", NULL, "Mono Mixer"},
- {"MONO_LOUT", NULL, "Mono Out"},
-
/* Left HP Output */
{"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
{"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
@@ -811,6 +816,18 @@ static const struct snd_soc_dapm_route intercon[] = {
{"HPRCOM", NULL, "Right HP Com"},
};
+static const struct snd_soc_dapm_route intercon_mono[] = {
+ /* Mono Output */
+ {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+ {"Mono Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
+ {"Mono Mixer", "DACL1 Switch", "Left DAC Mux"},
+ {"Mono Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+ {"Mono Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
+ {"Mono Mixer", "DACR1 Switch", "Right DAC Mux"},
+ {"Mono Out", NULL, "Mono Mixer"},
+ {"MONO_LOUT", NULL, "Mono Out"},
+};
+
static const struct snd_soc_dapm_route intercon_3007[] = {
/* Class-D outputs */
{"Left Class-D Out", NULL, "Left Line Out"},
@@ -824,17 +841,20 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
- snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
- ARRAY_SIZE(aic3x_dapm_widgets));
-
- /* set up audio path interconnects */
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
- if (aic3x->model == AIC3X_MODEL_3007) {
+ switch (aic3x->model) {
+ case AIC3X_MODEL_3X:
+ case AIC3X_MODEL_33:
+ snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
+ ARRAY_SIZE(aic3x_dapm_mono_widgets));
+ snd_soc_dapm_add_routes(dapm, intercon_mono,
+ ARRAY_SIZE(intercon_mono));
+ break;
+ case AIC3X_MODEL_3007:
snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
ARRAY_SIZE(aic3007_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon_3007,
ARRAY_SIZE(intercon_3007));
+ break;
}
return 0;
@@ -1078,29 +1098,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-static int aic3x_init_3007(struct snd_soc_codec *codec)
-{
- u8 tmp1, tmp2, *cache = codec->reg_cache;
-
- /*
- * There is no need to cache writes to undocumented page 0xD but
- * respective page 0 register cache entries must be preserved
- */
- tmp1 = cache[0xD];
- tmp2 = cache[0x8];
- /* Class-D speaker driver init; datasheet p. 46 */
- snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x0D);
- snd_soc_write(codec, 0xD, 0x0D);
- snd_soc_write(codec, 0x8, 0x5C);
- snd_soc_write(codec, 0x8, 0x5D);
- snd_soc_write(codec, 0x8, 0x5C);
- snd_soc_write(codec, AIC3X_PAGE_SELECT, 0x00);
- cache[0xD] = tmp1;
- cache[0x8] = tmp2;
-
- return 0;
-}
-
static int aic3x_regulator_event(struct notifier_block *nb,
unsigned long event, void *data)
{
@@ -1115,7 +1112,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
*/
if (gpio_is_valid(aic3x->gpio_reset))
gpio_set_value(aic3x->gpio_reset, 0);
- aic3x->codec->cache_sync = 1;
+ regcache_mark_dirty(aic3x->regmap);
}
return 0;
@@ -1124,8 +1121,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
static int aic3x_set_power(struct snd_soc_codec *codec, int power)
{
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
- int i, ret;
- u8 *cache = codec->reg_cache;
+ int ret;
if (power) {
ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
@@ -1133,12 +1129,6 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
if (ret)
goto out;
aic3x->power = 1;
- /*
- * Reset release and cache sync is necessary only if some
- * supply was off or if there were cached writes
- */
- if (!codec->cache_sync)
- goto out;
if (gpio_is_valid(aic3x->gpio_reset)) {
udelay(1);
@@ -1146,12 +1136,8 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
}
/* Sync reg_cache with the hardware */
- codec->cache_only = 0;
- for (i = AIC3X_SAMPLE_RATE_SEL_REG; i < ARRAY_SIZE(aic3x_reg); i++)
- snd_soc_write(codec, i, cache[i]);
- if (aic3x->model == AIC3X_MODEL_3007)
- aic3x_init_3007(codec);
- codec->cache_sync = 0;
+ regcache_cache_only(aic3x->regmap, false);
+ regcache_sync(aic3x->regmap);
} else {
/*
* Do soft reset to this codec instance in order to clear
@@ -1159,10 +1145,10 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
* remain on
*/
snd_soc_write(codec, AIC3X_RESET, SOFT_RESET);
- codec->cache_sync = 1;
+ regcache_mark_dirty(aic3x->regmap);
aic3x->power = 0;
/* HW writes are needless when bias is off */
- codec->cache_only = 1;
+ regcache_cache_only(aic3x->regmap, true);
ret = regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
}
@@ -1249,6 +1235,24 @@ static int aic3x_resume(struct snd_soc_codec *codec)
return 0;
}
+static void aic3x_mono_init(struct snd_soc_codec *codec)
+{
+ /* DAC to Mono Line Out default volume and route to Output mixer */
+ snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+ snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
+
+ /* unmute all outputs */
+ snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
+
+ /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
+ snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
+
+ /* Line2 to Mono Out default volume, disconnect from Output Mixer */
+ snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
+ snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
+}
+
/*
* initialise the AIC3X driver
* register the mixer and dsp interfaces with the kernel
@@ -1272,14 +1276,10 @@ static int aic3x_init(struct snd_soc_codec *codec)
/* DAC to Line Out default volume and route to Output mixer */
snd_soc_write(codec, DACL1_2_LLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
snd_soc_write(codec, DACR1_2_RLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
- /* DAC to Mono Line Out default volume and route to Output mixer */
- snd_soc_write(codec, DACL1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
- snd_soc_write(codec, DACR1_2_MONOLOPM_VOL, DEFAULT_VOL | ROUTE_ON);
/* unmute all outputs */
snd_soc_update_bits(codec, LLOPM_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, RLOPM_CTRL, UNMUTE, UNMUTE);
- snd_soc_update_bits(codec, MONOLOPM_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, HPLOUT_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, HPROUT_CTRL, UNMUTE, UNMUTE);
snd_soc_update_bits(codec, HPLCOM_CTRL, UNMUTE, UNMUTE);
@@ -1300,9 +1300,6 @@ static int aic3x_init(struct snd_soc_codec *codec)
/* PGA to Line Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, PGAL_2_LLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, PGAR_2_RLOPM_VOL, DEFAULT_VOL);
- /* PGA to Mono Line Out default volume, disconnect from Output Mixer */
- snd_soc_write(codec, PGAL_2_MONOLOPM_VOL, DEFAULT_VOL);
- snd_soc_write(codec, PGAR_2_MONOLOPM_VOL, DEFAULT_VOL);
/* Line2 to HP Bypass default volume, disconnect from Output Mixer */
snd_soc_write(codec, LINE2L_2_HPLOUT_VOL, DEFAULT_VOL);
@@ -1312,13 +1309,15 @@ static int aic3x_init(struct snd_soc_codec *codec)
/* Line2 Line Out default volume, disconnect from Output Mixer */
snd_soc_write(codec, LINE2L_2_LLOPM_VOL, DEFAULT_VOL);
snd_soc_write(codec, LINE2R_2_RLOPM_VOL, DEFAULT_VOL);
- /* Line2 to Mono Out default volume, disconnect from Output Mixer */
- snd_soc_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
- snd_soc_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
- if (aic3x->model == AIC3X_MODEL_3007) {
- aic3x_init_3007(codec);
+ switch (aic3x->model) {
+ case AIC3X_MODEL_3X:
+ case AIC3X_MODEL_33:
+ aic3x_mono_init(codec);
+ break;
+ case AIC3X_MODEL_3007:
snd_soc_write(codec, CLASSD_CTRL, 0);
+ break;
}
return 0;
@@ -1345,29 +1344,12 @@ static int aic3x_probe(struct snd_soc_codec *codec)
INIT_LIST_HEAD(&aic3x->list);
aic3x->codec = codec;
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x)) {
- ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
- if (ret != 0)
- goto err_gpio;
- gpio_direction_output(aic3x->gpio_reset, 0);
- }
-
- for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
- aic3x->supplies[i].supply = aic3x_supply_names[i];
-
- ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
- aic3x->supplies);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
- goto err_get;
- }
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) {
aic3x->disable_nb[i].nb.notifier_call = aic3x_regulator_event;
aic3x->disable_nb[i].aic3x = aic3x;
@@ -1381,7 +1363,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
}
}
- codec->cache_only = 1;
+ regcache_mark_dirty(aic3x->regmap);
aic3x_init(codec);
if (aic3x->setup) {
@@ -1392,10 +1374,17 @@ static int aic3x_probe(struct snd_soc_codec *codec)
(aic3x->setup->gpio_func[1] & 0xf) << 4);
}
- snd_soc_add_codec_controls(codec, aic3x_snd_controls,
- ARRAY_SIZE(aic3x_snd_controls));
- if (aic3x->model == AIC3X_MODEL_3007)
- snd_soc_add_codec_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
+ switch (aic3x->model) {
+ case AIC3X_MODEL_3X:
+ case AIC3X_MODEL_33:
+ snd_soc_add_codec_controls(codec, aic3x_mono_controls,
+ ARRAY_SIZE(aic3x_mono_controls));
+ break;
+ case AIC3X_MODEL_3007:
+ snd_soc_add_codec_controls(codec,
+ &aic3x_classd_amp_gain_ctrl, 1);
+ break;
+ }
/* set mic bias voltage */
switch (aic3x->micbias_vg) {
@@ -1424,12 +1413,6 @@ err_notif:
while (i--)
regulator_unregister_notifier(aic3x->supplies[i].consumer,
&aic3x->disable_nb[i].nb);
- regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
-err_get:
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x))
- gpio_free(aic3x->gpio_reset);
-err_gpio:
return ret;
}
@@ -1440,15 +1423,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
list_del(&aic3x->list);
- if (gpio_is_valid(aic3x->gpio_reset) &&
- !aic3x_is_shared_reset(aic3x)) {
- gpio_set_value(aic3x->gpio_reset, 0);
- gpio_free(aic3x->gpio_reset);
- }
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
regulator_unregister_notifier(aic3x->supplies[i].consumer,
&aic3x->disable_nb[i].nb);
- regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
return 0;
}
@@ -1456,13 +1433,16 @@ static int aic3x_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
.set_bias_level = aic3x_set_bias_level,
.idle_bias_off = true,
- .reg_cache_size = ARRAY_SIZE(aic3x_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = aic3x_reg,
.probe = aic3x_probe,
.remove = aic3x_remove,
.suspend = aic3x_suspend,
.resume = aic3x_resume,
+ .controls = aic3x_snd_controls,
+ .num_controls = ARRAY_SIZE(aic3x_snd_controls),
+ .dapm_widgets = aic3x_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic3x_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
};
/*
@@ -1479,6 +1459,16 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
+static const struct reg_default aic3007_class_d[] = {
+ /* Class-D speaker driver init; datasheet p. 46 */
+ { AIC3X_PAGE_SELECT, 0x0D },
+ { 0xD, 0x0D },
+ { 0x8, 0x5C },
+ { 0x8, 0x5D },
+ { 0x8, 0x5C },
+ { AIC3X_PAGE_SELECT, 0x00 },
+};
+
/*
* If the i2c layer weren't so broken, we could pass this kind of data
* around
@@ -1490,7 +1480,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
struct aic3x_priv *aic3x;
struct aic3x_setup_data *ai3x_setup;
struct device_node *np = i2c->dev.of_node;
- int ret;
+ int ret, i;
u32 value;
aic3x = devm_kzalloc(&i2c->dev, sizeof(struct aic3x_priv), GFP_KERNEL);
@@ -1499,7 +1489,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
}
- aic3x->control_type = SND_SOC_I2C;
+ aic3x->regmap = devm_regmap_init_i2c(i2c, &aic3x_regmap);
+ if (IS_ERR(aic3x->regmap)) {
+ ret = PTR_ERR(aic3x->regmap);
+ return ret;
+ }
+
+ regcache_cache_only(aic3x->regmap, true);
i2c_set_clientdata(i2c, aic3x);
if (pdata) {
@@ -1551,14 +1547,54 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
aic3x->model = id->driver_data;
+ if (gpio_is_valid(aic3x->gpio_reset) &&
+ !aic3x_is_shared_reset(aic3x)) {
+ ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
+ if (ret != 0)
+ goto err;
+ gpio_direction_output(aic3x->gpio_reset, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
+ aic3x->supplies[i].supply = aic3x_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(aic3x->supplies),
+ aic3x->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ goto err_gpio;
+ }
+
+ if (aic3x->model == AIC3X_MODEL_3007) {
+ ret = regmap_register_patch(aic3x->regmap, aic3007_class_d,
+ ARRAY_SIZE(aic3007_class_d));
+ if (ret != 0)
+ dev_err(&i2c->dev, "Failed to init class D: %d\n",
+ ret);
+ }
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aic3x, &aic3x_dai, 1);
return ret;
+
+err_gpio:
+ if (gpio_is_valid(aic3x->gpio_reset) &&
+ !aic3x_is_shared_reset(aic3x))
+ gpio_free(aic3x->gpio_reset);
+err:
+ return ret;
}
static int aic3x_i2c_remove(struct i2c_client *client)
{
+ struct aic3x_priv *aic3x = i2c_get_clientdata(client);
+
snd_soc_unregister_codec(&client->dev);
+ if (gpio_is_valid(aic3x->gpio_reset) &&
+ !aic3x_is_shared_reset(aic3x)) {
+ gpio_set_value(aic3x->gpio_reset, 0);
+ gpio_free(aic3x->gpio_reset);
+ }
return 0;
}
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index c58bee8346ce..b27c396037d4 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -30,6 +30,7 @@
#include <sound/tpa6130a2-plat.h>
#include <sound/soc.h>
#include <sound/tlv.h>
+#include <linux/of_gpio.h>
#include "tpa6130a2.h"
@@ -55,7 +56,8 @@ static int tpa6130a2_i2c_read(int reg)
struct tpa6130a2_data *data;
int val;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
/* If powered off, return the cached value */
@@ -77,7 +79,8 @@ static int tpa6130a2_i2c_write(int reg, u8 value)
struct tpa6130a2_data *data;
int val = 0;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
if (data->power_state) {
@@ -98,7 +101,8 @@ static u8 tpa6130a2_read(int reg)
{
struct tpa6130a2_data *data;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return 0;
data = i2c_get_clientdata(tpa6130a2_client);
return data->regs[reg];
@@ -109,7 +113,8 @@ static int tpa6130a2_initialize(void)
struct tpa6130a2_data *data;
int i, ret = 0;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
for (i = 1; i < TPA6130A2_REG_VERSION; i++) {
@@ -127,7 +132,8 @@ static int tpa6130a2_power(u8 power)
u8 val;
int ret = 0;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
mutex_lock(&data->mutex);
@@ -193,7 +199,8 @@ static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
mutex_lock(&data->mutex);
@@ -223,7 +230,8 @@ static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val = (ucontrol->value.integer.value[0] & mask);
unsigned int val_reg;
- BUG_ON(tpa6130a2_client == NULL);
+ if (WARN_ON(!tpa6130a2_client))
+ return -EINVAL;
data = i2c_get_clientdata(tpa6130a2_client);
if (invert)
@@ -364,30 +372,33 @@ static int tpa6130a2_probe(struct i2c_client *client,
{
struct device *dev;
struct tpa6130a2_data *data;
- struct tpa6130a2_platform_data *pdata;
+ struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
+ struct device_node *np = client->dev.of_node;
const char *regulator;
int ret;
dev = &client->dev;
- if (client->dev.platform_data == NULL) {
- dev_err(dev, "Platform data not set\n");
- dump_stack();
- return -ENODEV;
- }
-
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (data == NULL) {
dev_err(dev, "Can not allocate memory\n");
return -ENOMEM;
}
+ if (pdata) {
+ data->power_gpio = pdata->power_gpio;
+ } else if (np) {
+ data->power_gpio = of_get_named_gpio(np, "power-gpio", 0);
+ } else {
+ dev_err(dev, "Platform data not set\n");
+ dump_stack();
+ return -ENODEV;
+ }
+
tpa6130a2_client = client;
i2c_set_clientdata(tpa6130a2_client, data);
- pdata = client->dev.platform_data;
- data->power_gpio = pdata->power_gpio;
data->id = id->driver_data;
mutex_init(&data->mutex);
@@ -466,10 +477,20 @@ static const struct i2c_device_id tpa6130a2_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id tpa6130a2_of_match[] = {
+ { .compatible = "ti,tpa6130a2", },
+ { .compatible = "ti,tpa6140a2" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tpa6130a2_of_match);
+#endif
+
static struct i2c_driver tpa6130a2_i2c_driver = {
.driver = {
.name = "tpa6130a2",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(tpa6130a2_of_match),
},
.probe = tpa6130a2_probe,
.remove = tpa6130a2_remove,
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 1e3884d6b3fb..00665ada23e2 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -46,94 +46,7 @@
/* TWL4030 PMBR1 Register GPIO6 mux bits */
#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
-/* Shadow register used by the audio driver */
-#define TWL4030_REG_SW_SHADOW 0x4A
-#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
-
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
-#define TWL4030_HFL_EN 0x01
-#define TWL4030_HFR_EN 0x02
-
-/*
- * twl4030 register cache & default register settings
- */
-static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
- 0x00, /* this register not used */
- 0x00, /* REG_CODEC_MODE (0x1) */
- 0x00, /* REG_OPTION (0x2) */
- 0x00, /* REG_UNKNOWN (0x3) */
- 0x00, /* REG_MICBIAS_CTL (0x4) */
- 0x00, /* REG_ANAMICL (0x5) */
- 0x00, /* REG_ANAMICR (0x6) */
- 0x00, /* REG_AVADC_CTL (0x7) */
- 0x00, /* REG_ADCMICSEL (0x8) */
- 0x00, /* REG_DIGMIXING (0x9) */
- 0x0f, /* REG_ATXL1PGA (0xA) */
- 0x0f, /* REG_ATXR1PGA (0xB) */
- 0x0f, /* REG_AVTXL2PGA (0xC) */
- 0x0f, /* REG_AVTXR2PGA (0xD) */
- 0x00, /* REG_AUDIO_IF (0xE) */
- 0x00, /* REG_VOICE_IF (0xF) */
- 0x3f, /* REG_ARXR1PGA (0x10) */
- 0x3f, /* REG_ARXL1PGA (0x11) */
- 0x3f, /* REG_ARXR2PGA (0x12) */
- 0x3f, /* REG_ARXL2PGA (0x13) */
- 0x25, /* REG_VRXPGA (0x14) */
- 0x00, /* REG_VSTPGA (0x15) */
- 0x00, /* REG_VRX2ARXPGA (0x16) */
- 0x00, /* REG_AVDAC_CTL (0x17) */
- 0x00, /* REG_ARX2VTXPGA (0x18) */
- 0x32, /* REG_ARXL1_APGA_CTL (0x19) */
- 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */
- 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */
- 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */
- 0x00, /* REG_ATX2ARXPGA (0x1D) */
- 0x00, /* REG_BT_IF (0x1E) */
- 0x55, /* REG_BTPGA (0x1F) */
- 0x00, /* REG_BTSTPGA (0x20) */
- 0x00, /* REG_EAR_CTL (0x21) */
- 0x00, /* REG_HS_SEL (0x22) */
- 0x00, /* REG_HS_GAIN_SET (0x23) */
- 0x00, /* REG_HS_POPN_SET (0x24) */
- 0x00, /* REG_PREDL_CTL (0x25) */
- 0x00, /* REG_PREDR_CTL (0x26) */
- 0x00, /* REG_PRECKL_CTL (0x27) */
- 0x00, /* REG_PRECKR_CTL (0x28) */
- 0x00, /* REG_HFL_CTL (0x29) */
- 0x00, /* REG_HFR_CTL (0x2A) */
- 0x05, /* REG_ALC_CTL (0x2B) */
- 0x00, /* REG_ALC_SET1 (0x2C) */
- 0x00, /* REG_ALC_SET2 (0x2D) */
- 0x00, /* REG_BOOST_CTL (0x2E) */
- 0x00, /* REG_SOFTVOL_CTL (0x2F) */
- 0x13, /* REG_DTMF_FREQSEL (0x30) */
- 0x00, /* REG_DTMF_TONEXT1H (0x31) */
- 0x00, /* REG_DTMF_TONEXT1L (0x32) */
- 0x00, /* REG_DTMF_TONEXT2H (0x33) */
- 0x00, /* REG_DTMF_TONEXT2L (0x34) */
- 0x79, /* REG_DTMF_TONOFF (0x35) */
- 0x11, /* REG_DTMF_WANONOFF (0x36) */
- 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */
- 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */
- 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */
- 0x06, /* REG_APLL_CTL (0x3A) */
- 0x00, /* REG_DTMF_CTL (0x3B) */
- 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */
- 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */
- 0x00, /* REG_MISC_SET_1 (0x3E) */
- 0x00, /* REG_PCMBTMUX (0x3F) */
- 0x00, /* not used (0x40) */
- 0x00, /* not used (0x41) */
- 0x00, /* not used (0x42) */
- 0x00, /* REG_RX_PATH_SEL (0x43) */
- 0x32, /* REG_VDL_APGA_CTL (0x44) */
- 0x00, /* REG_VIBRA_CTL (0x45) */
- 0x00, /* REG_VIBRA_SET (0x46) */
- 0x00, /* REG_VIBRA_PWM_SET (0x47) */
- 0x00, /* REG_ANAMIC_GAIN (0x48) */
- 0x00, /* REG_MISC_SET_2 (0x49) */
- 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */
-};
+#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1)
/* codec private data */
struct twl4030_priv {
@@ -157,83 +70,109 @@ struct twl4030_priv {
u8 earpiece_enabled;
u8 predrivel_enabled, predriver_enabled;
u8 carkitl_enabled, carkitr_enabled;
+ u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1];
struct twl4030_codec_data *pdata;
};
-/*
- * read twl4030 register cache
- */
-static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
+static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030)
+{
+ int i;
+ u8 byte;
+
+ for (i = TWL4030_REG_EAR_CTL; i <= TWL4030_REG_PRECKR_CTL; i++) {
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, i);
+ twl4030->ctl_cache[i - TWL4030_REG_EAR_CTL] = byte;
+ }
+}
+
+static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg)
{
- u8 *cache = codec->reg_cache;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+ u8 value = 0;
if (reg >= TWL4030_CACHEREGNUM)
return -EIO;
- return cache[reg];
+ switch (reg) {
+ case TWL4030_REG_EAR_CTL:
+ case TWL4030_REG_PREDL_CTL:
+ case TWL4030_REG_PREDR_CTL:
+ case TWL4030_REG_PRECKL_CTL:
+ case TWL4030_REG_PRECKR_CTL:
+ case TWL4030_REG_HS_GAIN_SET:
+ value = twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL];
+ break;
+ default:
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg);
+ break;
+ }
+
+ return value;
}
-/*
- * write twl4030 register cache
- */
-static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
- u8 reg, u8 value)
+static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030,
+ unsigned int reg)
{
- u8 *cache = codec->reg_cache;
+ bool write_to_reg = false;
- if (reg >= TWL4030_CACHEREGNUM)
- return;
- cache[reg] = value;
+ /* Decide if the given register can be written */
+ switch (reg) {
+ case TWL4030_REG_EAR_CTL:
+ if (twl4030->earpiece_enabled)
+ write_to_reg = true;
+ break;
+ case TWL4030_REG_PREDL_CTL:
+ if (twl4030->predrivel_enabled)
+ write_to_reg = true;
+ break;
+ case TWL4030_REG_PREDR_CTL:
+ if (twl4030->predriver_enabled)
+ write_to_reg = true;
+ break;
+ case TWL4030_REG_PRECKL_CTL:
+ if (twl4030->carkitl_enabled)
+ write_to_reg = true;
+ break;
+ case TWL4030_REG_PRECKR_CTL:
+ if (twl4030->carkitr_enabled)
+ write_to_reg = true;
+ break;
+ case TWL4030_REG_HS_GAIN_SET:
+ if (twl4030->hsl_enabled || twl4030->hsr_enabled)
+ write_to_reg = true;
+ break;
+ default:
+ /* All other register can be written */
+ write_to_reg = true;
+ break;
+ }
+
+ return write_to_reg;
}
-/*
- * write to the twl4030 register space
- */
-static int twl4030_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
+static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- int write_to_reg = 0;
-
- twl4030_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL4030_REG_SW_SHADOW)) {
- /* Decide if the given register can be written */
- switch (reg) {
- case TWL4030_REG_EAR_CTL:
- if (twl4030->earpiece_enabled)
- write_to_reg = 1;
- break;
- case TWL4030_REG_PREDL_CTL:
- if (twl4030->predrivel_enabled)
- write_to_reg = 1;
- break;
- case TWL4030_REG_PREDR_CTL:
- if (twl4030->predriver_enabled)
- write_to_reg = 1;
- break;
- case TWL4030_REG_PRECKL_CTL:
- if (twl4030->carkitl_enabled)
- write_to_reg = 1;
- break;
- case TWL4030_REG_PRECKR_CTL:
- if (twl4030->carkitr_enabled)
- write_to_reg = 1;
- break;
- case TWL4030_REG_HS_GAIN_SET:
- if (twl4030->hsl_enabled || twl4030->hsr_enabled)
- write_to_reg = 1;
- break;
- default:
- /* All other register can be written */
- write_to_reg = 1;
- break;
- }
- if (write_to_reg)
- return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
- value, reg);
+
+ /* Update the ctl cache */
+ switch (reg) {
+ case TWL4030_REG_EAR_CTL:
+ case TWL4030_REG_PREDL_CTL:
+ case TWL4030_REG_PREDR_CTL:
+ case TWL4030_REG_PRECKL_CTL:
+ case TWL4030_REG_PRECKR_CTL:
+ case TWL4030_REG_HS_GAIN_SET:
+ twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL] = value;
+ break;
+ default:
+ break;
}
+
+ if (twl4030_can_write_to_chip(twl4030, reg))
+ return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
+
return 0;
}
@@ -260,46 +199,14 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
else
mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
- if (mode >= 0) {
- twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode);
+ if (mode >= 0)
twl4030->codec_powered = enable;
- }
/* REVISIT: this delay is present in TI sample drivers */
/* but there seems to be no TRM requirement for it */
udelay(10);
}
-static inline void twl4030_check_defaults(struct snd_soc_codec *codec)
-{
- int i, difference = 0;
- u8 val;
-
- dev_dbg(codec->dev, "Checking TWL audio default configuration\n");
- for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) {
- twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i);
- if (val != twl4030_reg[i]) {
- difference++;
- dev_dbg(codec->dev,
- "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n",
- i, val, twl4030_reg[i]);
- }
- }
- dev_dbg(codec->dev, "Found %d non-matching registers. %s\n",
- difference, difference ? "Not OK" : "OK");
-}
-
-static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
-{
- int i;
-
- /* set all audio section registers to reasonable defaults */
- for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
- if (i != TWL4030_REG_APLL_CTL)
- twl4030_write(codec, i, twl4030_reg[i]);
-
-}
-
static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata,
struct device_node *node)
{
@@ -380,27 +287,17 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
}
}
- /* Check defaults, if instructed before anything else */
- if (pdata && pdata->check_defaults)
- twl4030_check_defaults(codec);
-
- /* Reset registers, if no setup data or if instructed to do so */
- if (!pdata || (pdata && pdata->reset_registers))
- twl4030_reset_registers(codec);
-
- /* Refresh APLL_CTL register from HW */
- twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
- TWL4030_REG_APLL_CTL);
- twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
+ /* Initialize the local ctl register cache */
+ tw4030_init_ctl_cache(twl4030);
/* anti-pop when changing analog gain */
- reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+ reg = twl4030_read(codec, TWL4030_REG_MISC_SET_1);
twl4030_write(codec, TWL4030_REG_MISC_SET_1,
- reg | TWL4030_SMOOTH_ANAVOL_EN);
+ reg | TWL4030_SMOOTH_ANAVOL_EN);
twl4030_write(codec, TWL4030_REG_OPTION,
- TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
- TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
+ TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
+ TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
/* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
@@ -411,19 +308,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
twl4030->pdata = pdata;
- reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+ reg = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
reg &= ~TWL4030_RAMP_DELAY;
reg |= (pdata->ramp_delay_value << 2);
- twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
+ twl4030_write(codec, TWL4030_REG_HS_POPN_SET, reg);
/* initiate offset cancellation */
twl4030_codec_enable(codec, 1);
- reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+ reg = twl4030_read(codec, TWL4030_REG_ANAMICL);
reg &= ~TWL4030_OFFSET_CNCL_SEL;
reg |= pdata->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
- reg | TWL4030_CNCL_OFFSET_START);
+ reg | TWL4030_CNCL_OFFSET_START);
/*
* Wait for offset cancellation to complete.
@@ -433,15 +330,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
msleep(20);
do {
usleep_range(1000, 2000);
+ twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, true);
twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
- TWL4030_REG_ANAMICL);
+ TWL4030_REG_ANAMICL);
+ twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, false);
} 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);
-
twl4030_codec_enable(codec, 0);
}
@@ -461,9 +357,6 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
status = twl4030_audio_disable_resource(
TWL4030_AUDIO_RES_APLL);
}
-
- if (status >= 0)
- twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
}
/* Earpiece */
@@ -532,7 +425,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
/* Handsfree Left virtual mute */
static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
- SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0);
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Handsfree Right */
static const char *twl4030_handsfreer_texts[] =
@@ -548,7 +441,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
/* Handsfree Right virtual mute */
static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
- SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0);
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Vibra */
/* Vibra audio path selection */
@@ -679,20 +572,18 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
*/
#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
- struct snd_kcontrol *kcontrol, int event) \
+ struct snd_kcontrol *kcontrol, int event) \
{ \
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
\
switch (event) { \
case SND_SOC_DAPM_POST_PMU: \
twl4030->pin_name##_enabled = 1; \
- twl4030_write(w->codec, reg, \
- twl4030_read_reg_cache(w->codec, reg)); \
+ twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \
break; \
case SND_SOC_DAPM_POST_PMD: \
twl4030->pin_name##_enabled = 0; \
- twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
- 0, reg); \
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 0, reg); \
break; \
} \
return 0; \
@@ -708,7 +599,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
{
unsigned char hs_ctl;
- hs_ctl = twl4030_read_reg_cache(codec, reg);
+ hs_ctl = twl4030_read(codec, reg);
if (ramp) {
/* HF ramp-up */
@@ -735,7 +626,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
}
static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -749,7 +640,7 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
}
static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -763,14 +654,14 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
}
static int vibramux_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
return 0;
}
static int apll_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -784,11 +675,11 @@ static int apll_event(struct snd_soc_dapm_widget *w,
}
static int aif_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
u8 audio_if;
- audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF);
+ audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Enable AIF */
@@ -796,12 +687,12 @@ static int aif_event(struct snd_soc_dapm_widget *w,
twl4030_apll_enable(w->codec, 1);
twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
- audio_if | TWL4030_AIF_EN);
+ audio_if | TWL4030_AIF_EN);
break;
case SND_SOC_DAPM_POST_PMD:
/* disable the DAI before we stop it's source PLL */
twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
- audio_if & ~TWL4030_AIF_EN);
+ audio_if & ~TWL4030_AIF_EN);
twl4030_apll_enable(w->codec, 0);
break;
}
@@ -818,8 +709,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
8388608, 16777216, 33554432, 67108864};
unsigned int delay;
- hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
- hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+ hs_gain = twl4030_read(codec, TWL4030_REG_HS_GAIN_SET);
+ hs_pop = twl4030_read(codec, TWL4030_REG_HS_POPN_SET);
delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
twl4030->sysclk) + 1;
@@ -839,9 +730,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
hs_pop |= TWL4030_VMID_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Actually write to the register */
- twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
- hs_gain,
- TWL4030_REG_HS_GAIN_SET);
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain,
+ TWL4030_REG_HS_GAIN_SET);
hs_pop |= TWL4030_RAMP_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Wait ramp delay time + 1, so the VMID can settle */
@@ -854,9 +744,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
/* Wait ramp delay time + 1, so the VMID can settle */
twl4030_wait_ms(delay);
/* Bypass the reg_cache to mute the headset */
- twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
- hs_gain & (~0x0f),
- TWL4030_REG_HS_GAIN_SET);
+ twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f),
+ TWL4030_REG_HS_GAIN_SET);
hs_pop &= ~TWL4030_VMID_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
@@ -874,7 +763,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
}
static int headsetlpga_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
@@ -898,7 +787,7 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
}
static int headsetrpga_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
@@ -922,7 +811,7 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
}
static int digimic_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
struct twl4030_codec_data *pdata = twl4030->pdata;
@@ -943,7 +832,7 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
* Custom volsw and volsw_2r get/put functions to handle these gain bits.
*/
static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -972,7 +861,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
}
static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -1001,7 +890,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol,
}
static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -1028,7 +917,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
}
static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
@@ -1759,11 +1648,11 @@ static void twl4030_constraints(struct twl4030_priv *twl4030,
/* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for
* capture has to be enabled/disabled. */
static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
- int enable)
+ int enable)
{
u8 reg, mask;
- reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+ reg = twl4030_read(codec, TWL4030_REG_OPTION);
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN;
@@ -1792,14 +1681,14 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
if (twl4030->configured)
twl4030_constraints(twl4030, twl4030->master_substream);
} else {
- if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) &
+ if (!(twl4030_read(codec, TWL4030_REG_CODEC_MODE) &
TWL4030_OPTION_1)) {
/* In option2 4 channel is not supported, set the
* constraint for the first stream for channels, the
* second stream will 'inherit' this cosntraint */
snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- 2, 2);
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 2, 2);
}
twl4030->master_substream = substream;
}
@@ -1831,8 +1720,8 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
}
static int twl4030_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_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -1840,8 +1729,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
/* If the substream has 4 channel, do the necessary setup */
if (params_channels(params) == 4) {
- format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
- mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
+ format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
+ mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE);
/* Safety check: are we in the correct operating mode and
* the interface is in TDM mode? */
@@ -1857,8 +1746,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return 0;
/* bit rate */
- old_mode = twl4030_read_reg_cache(codec,
- TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
+ old_mode = twl4030_read(codec,
+ TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
mode = old_mode & ~TWL4030_APLL_RATE;
switch (params_rate(params)) {
@@ -1899,7 +1788,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
}
/* sample size */
- old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+ old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
format = old_format;
format &= ~TWL4030_DATA_WIDTH;
switch (params_format(params)) {
@@ -1948,8 +1837,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
+static int twl4030_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 twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -1974,15 +1863,14 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}
-static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
+static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_format, format;
/* get format */
- old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+ old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
format = old_format;
/* set master/slave audio interface */
@@ -2032,7 +1920,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
- u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
+ u8 reg = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
if (tristate)
reg |= TWL4030_AIF_TRI_EN;
@@ -2045,11 +1933,11 @@ static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate)
/* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R
* (VTXL, VTXR) for uplink has to be enabled/disabled. */
static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
- int enable)
+ int enable)
{
u8 reg, mask;
- reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION);
+ reg = twl4030_read(codec, TWL4030_REG_OPTION);
if (direction == SNDRV_PCM_STREAM_PLAYBACK)
mask = TWL4030_ARXL1_VRX_EN;
@@ -2065,7 +1953,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
}
static int twl4030_voice_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -2084,7 +1972,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
/* If the codec mode is not option2, the voice PCM interface is not
* available.
*/
- mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
+ mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE)
& TWL4030_OPT_MODE;
if (mode != TWL4030_OPTION_2) {
@@ -2097,7 +1985,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
}
static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+ struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
@@ -2106,7 +1994,8 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
}
static int twl4030_voice_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_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -2116,8 +2005,8 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
twl4030_voice_enable(codec, substream->stream, 1);
/* bit rate */
- old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE)
- & ~(TWL4030_CODECPDZ);
+ old_mode = twl4030_read(codec,
+ TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
mode = old_mode;
switch (params_rate(params)) {
@@ -2151,7 +2040,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
}
static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
+ int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@@ -2172,14 +2061,14 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
}
static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
+ unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_format, format;
/* get format */
- old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+ old_format = twl4030_read(codec, TWL4030_REG_VOICE_IF);
format = old_format;
/* set master/slave audio interface */
@@ -2226,7 +2115,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
{
struct snd_soc_codec *codec = dai->codec;
- u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF);
+ u8 reg = twl4030_read(codec, TWL4030_REG_VOICE_IF);
if (tristate)
reg |= TWL4030_VIF_TRI_EN;
@@ -2318,8 +2207,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_codec_data *pdata = twl4030->pdata;
- /* Reset registers to their chip default before leaving */
- twl4030_reset_registers(codec);
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
@@ -2331,13 +2218,10 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
.probe = twl4030_soc_probe,
.remove = twl4030_soc_remove,
- .read = twl4030_read_reg_cache,
+ .read = twl4030_read,
.write = twl4030_write,
.set_bias_level = twl4030_set_bias_level,
.idle_bias_off = true,
- .reg_cache_size = sizeof(twl4030_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = twl4030_reg,
.controls = twl4030_snd_controls,
.num_controls = ARRAY_SIZE(twl4030_snd_controls),
@@ -2350,7 +2234,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
static int twl4030_codec_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030,
- twl4030_dai, ARRAY_SIZE(twl4030_dai));
+ twl4030_dai, ARRAY_SIZE(twl4030_dai));
}
static int twl4030_codec_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 3c79dbb6c323..0afe8bef6765 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -54,12 +54,7 @@ enum twl6040_dai_id {
#define TWL6040_OUTHF_0dB 0x03
#define TWL6040_OUTHF_M52dB 0x1D
-/* Shadow register used by the driver */
-#define TWL6040_REG_SW_SHADOW 0x2F
-#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
-
-/* TWL6040_REG_SW_SHADOW (0x2F) fields */
-#define TWL6040_EAR_PATH_ENABLE 0x01
+#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
struct twl6040_jack_data {
struct snd_soc_jack *jack;
@@ -77,6 +72,7 @@ struct twl6040_data {
int hs_power_mode_locked;
bool dl1_unmuted;
bool dl2_unmuted;
+ u8 dl12_cache[TWL6040_REG_HFRCTL - TWL6040_REG_HSLCTL + 1];
unsigned int clk_in;
unsigned int sysclk;
struct twl6040_jack_data hs_jack;
@@ -84,77 +80,6 @@ struct twl6040_data {
struct mutex mutex;
};
-/*
- * twl6040 register cache & default register settings
- */
-static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
- 0x00, /* not used 0x00 */
- 0x4B, /* REG_ASICID 0x01 (ro) */
- 0x00, /* REG_ASICREV 0x02 (ro) */
- 0x00, /* REG_INTID 0x03 */
- 0x00, /* REG_INTMR 0x04 */
- 0x00, /* REG_NCPCTRL 0x05 */
- 0x00, /* REG_LDOCTL 0x06 */
- 0x60, /* REG_HPPLLCTL 0x07 */
- 0x00, /* REG_LPPLLCTL 0x08 */
- 0x4A, /* REG_LPPLLDIV 0x09 */
- 0x00, /* REG_AMICBCTL 0x0A */
- 0x00, /* REG_DMICBCTL 0x0B */
- 0x00, /* REG_MICLCTL 0x0C */
- 0x00, /* REG_MICRCTL 0x0D */
- 0x00, /* REG_MICGAIN 0x0E */
- 0x1B, /* REG_LINEGAIN 0x0F */
- 0x00, /* REG_HSLCTL 0x10 */
- 0x00, /* REG_HSRCTL 0x11 */
- 0x00, /* REG_HSGAIN 0x12 */
- 0x00, /* REG_EARCTL 0x13 */
- 0x00, /* REG_HFLCTL 0x14 */
- 0x00, /* REG_HFLGAIN 0x15 */
- 0x00, /* REG_HFRCTL 0x16 */
- 0x00, /* REG_HFRGAIN 0x17 */
- 0x00, /* REG_VIBCTLL 0x18 */
- 0x00, /* REG_VIBDATL 0x19 */
- 0x00, /* REG_VIBCTLR 0x1A */
- 0x00, /* REG_VIBDATR 0x1B */
- 0x00, /* REG_HKCTL1 0x1C */
- 0x00, /* REG_HKCTL2 0x1D */
- 0x00, /* REG_GPOCTL 0x1E */
- 0x00, /* REG_ALB 0x1F */
- 0x00, /* REG_DLB 0x20 */
- 0x00, /* not used 0x21 */
- 0x00, /* not used 0x22 */
- 0x00, /* not used 0x23 */
- 0x00, /* not used 0x24 */
- 0x00, /* not used 0x25 */
- 0x00, /* not used 0x26 */
- 0x00, /* not used 0x27 */
- 0x00, /* REG_TRIM1 0x28 */
- 0x00, /* REG_TRIM2 0x29 */
- 0x00, /* REG_TRIM3 0x2A */
- 0x00, /* REG_HSOTRIM 0x2B */
- 0x00, /* REG_HFOTRIM 0x2C */
- 0x09, /* REG_ACCCTL 0x2D */
- 0x00, /* REG_STATUS 0x2E (ro) */
-
- 0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */
-};
-
-/* List of registers to be restored after power up */
-static const int twl6040_restore_list[] = {
- TWL6040_REG_MICLCTL,
- TWL6040_REG_MICRCTL,
- TWL6040_REG_MICGAIN,
- TWL6040_REG_LINEGAIN,
- TWL6040_REG_HSLCTL,
- TWL6040_REG_HSRCTL,
- TWL6040_REG_HSGAIN,
- TWL6040_REG_EARCTL,
- TWL6040_REG_HFLCTL,
- TWL6040_REG_HFLGAIN,
- TWL6040_REG_HFRCTL,
- TWL6040_REG_HFRGAIN,
-};
-
/* set of rates for each pll: low-power and high-performance */
static unsigned int lp_rates[] = {
8000,
@@ -181,57 +106,33 @@ static struct snd_pcm_hw_constraint_list sysclk_constraints[] = {
{ .count = ARRAY_SIZE(hp_rates), .list = hp_rates, },
};
-/*
- * read twl6040 register cache
- */
-static inline unsigned int twl6040_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u8 *cache = codec->reg_cache;
-
- if (reg >= TWL6040_CACHEREGNUM)
- return -EIO;
-
- return cache[reg];
-}
-
-/*
- * write twl6040 register cache
- */
-static inline void twl6040_write_reg_cache(struct snd_soc_codec *codec,
- u8 reg, u8 value)
-{
- u8 *cache = codec->reg_cache;
-
- if (reg >= TWL6040_CACHEREGNUM)
- return;
- cache[reg] = value;
-}
-
-/*
- * read from twl6040 hardware register
- */
-static int twl6040_read_reg_volatile(struct snd_soc_codec *codec,
- unsigned int reg)
+static unsigned int twl6040_read(struct snd_soc_codec *codec, unsigned int reg)
{
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
struct twl6040 *twl6040 = codec->control_data;
u8 value;
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
- if (likely(reg < TWL6040_REG_SW_SHADOW)) {
+ switch (reg) {
+ case TWL6040_REG_HSLCTL:
+ case TWL6040_REG_HSRCTL:
+ case TWL6040_REG_EARCTL:
+ case TWL6040_REG_HFLCTL:
+ case TWL6040_REG_HFRCTL:
+ value = priv->dl12_cache[reg - TWL6040_REG_HSLCTL];
+ break;
+ default:
value = twl6040_reg_read(twl6040, reg);
- twl6040_write_reg_cache(codec, reg, value);
- } else {
- value = twl6040_read_reg_cache(codec, reg);
+ break;
}
return value;
}
-static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool twl6040_can_write_to_chip(struct snd_soc_codec *codec,
+ unsigned int reg)
{
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
@@ -246,12 +147,27 @@ static bool twl6040_is_path_unmuted(struct snd_soc_codec *codec,
return priv->dl2_unmuted;
default:
return 1;
- };
+ }
+}
+
+static inline void twl6040_update_dl12_cache(struct snd_soc_codec *codec,
+ u8 reg, u8 value)
+{
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (reg) {
+ case TWL6040_REG_HSLCTL:
+ case TWL6040_REG_HSRCTL:
+ case TWL6040_REG_EARCTL:
+ case TWL6040_REG_HFLCTL:
+ case TWL6040_REG_HFRCTL:
+ priv->dl12_cache[reg - TWL6040_REG_HSLCTL] = value;
+ break;
+ default:
+ break;
+ }
}
-/*
- * write to the twl6040 register space
- */
static int twl6040_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
@@ -260,9 +176,8 @@ static int twl6040_write(struct snd_soc_codec *codec,
if (reg >= TWL6040_CACHEREGNUM)
return -EIO;
- twl6040_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL6040_REG_SW_SHADOW) &&
- twl6040_is_path_unmuted(codec, reg))
+ twl6040_update_dl12_cache(codec, reg, value);
+ if (twl6040_can_write_to_chip(codec, reg))
return twl6040_reg_write(twl6040, reg, value);
else
return 0;
@@ -270,45 +185,27 @@ static int twl6040_write(struct snd_soc_codec *codec,
static void twl6040_init_chip(struct snd_soc_codec *codec)
{
- struct twl6040 *twl6040 = codec->control_data;
- u8 val;
-
- /* Update reg_cache: ASICREV, and TRIM values */
- val = twl6040_get_revid(twl6040);
- twl6040_write_reg_cache(codec, TWL6040_REG_ASICREV, val);
-
- twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM1);
- twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM2);
- twl6040_read_reg_volatile(codec, TWL6040_REG_TRIM3);
- twl6040_read_reg_volatile(codec, TWL6040_REG_HSOTRIM);
- twl6040_read_reg_volatile(codec, TWL6040_REG_HFOTRIM);
+ twl6040_read(codec, TWL6040_REG_TRIM1);
+ twl6040_read(codec, TWL6040_REG_TRIM2);
+ twl6040_read(codec, TWL6040_REG_TRIM3);
+ twl6040_read(codec, TWL6040_REG_HSOTRIM);
+ twl6040_read(codec, TWL6040_REG_HFOTRIM);
/* Change chip defaults */
/* No imput selected for microphone amplifiers */
- twl6040_write_reg_cache(codec, TWL6040_REG_MICLCTL, 0x18);
- twl6040_write_reg_cache(codec, TWL6040_REG_MICRCTL, 0x18);
+ twl6040_write(codec, TWL6040_REG_MICLCTL, 0x18);
+ twl6040_write(codec, TWL6040_REG_MICRCTL, 0x18);
/*
* We need to lower the default gain values, so the ramp code
* can work correctly for the first playback.
* This reduces the pop noise heard at the first playback.
*/
- twl6040_write_reg_cache(codec, TWL6040_REG_HSGAIN, 0xff);
- twl6040_write_reg_cache(codec, TWL6040_REG_EARCTL, 0x1e);
- twl6040_write_reg_cache(codec, TWL6040_REG_HFLGAIN, 0x1d);
- twl6040_write_reg_cache(codec, TWL6040_REG_HFRGAIN, 0x1d);
- twl6040_write_reg_cache(codec, TWL6040_REG_LINEGAIN, 0);
-}
-
-static void twl6040_restore_regs(struct snd_soc_codec *codec)
-{
- u8 *cache = codec->reg_cache;
- int reg, i;
-
- for (i = 0; i < ARRAY_SIZE(twl6040_restore_list); i++) {
- reg = twl6040_restore_list[i];
- twl6040_write(codec, reg, cache[reg]);
- }
+ twl6040_write(codec, TWL6040_REG_HSGAIN, 0xff);
+ twl6040_write(codec, TWL6040_REG_EARCTL, 0x1e);
+ twl6040_write(codec, TWL6040_REG_HFLGAIN, 0x1d);
+ twl6040_write(codec, TWL6040_REG_HFRGAIN, 0x1d);
+ twl6040_write(codec, TWL6040_REG_LINEGAIN, 0);
}
/* set headset dac and driver power mode */
@@ -317,8 +214,8 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
int hslctl, hsrctl;
int mask = TWL6040_HSDRVMODE | TWL6040_HSDACMODE;
- hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
- hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+ hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
+ hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
if (high_perf) {
hslctl &= ~mask;
@@ -345,8 +242,8 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
* Both HS DAC need to be turned on (before the HS driver) and off at
* the same time.
*/
- hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
- hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
+ hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
+ hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
if (SND_SOC_DAPM_EVENT_ON(event)) {
hslctl |= TWL6040_HSDACENA;
hsrctl |= TWL6040_HSDACENA;
@@ -391,7 +288,7 @@ static void twl6040_hs_jack_report(struct snd_soc_codec *codec,
mutex_lock(&priv->mutex);
/* Sync status */
- status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS);
+ status = twl6040_read(codec, TWL6040_REG_STATUS);
if (status & TWL6040_PLUGCOMP)
snd_soc_jack_report(jack, report, report);
else
@@ -443,7 +340,7 @@ static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
unsigned int val;
/* Do not allow changes while Input/FF efect is running */
- val = twl6040_read_reg_volatile(codec, e->reg);
+ val = twl6040_read(codec, e->reg);
if (val & TWL6040_VIBENA && !(val & TWL6040_VIBSEL))
return -EBUSY;
@@ -555,7 +452,7 @@ static const struct snd_kcontrol_new hfr_mux_controls =
SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
static const struct snd_kcontrol_new ep_path_enable_control =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0);
+ SOC_DAPM_SINGLE_VIRT("Switch", 1);
static const struct snd_kcontrol_new auxl_switch_control =
SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
@@ -668,7 +565,7 @@ int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim)
if (unlikely(trim >= TWL6040_TRIM_INVAL))
return -EINVAL;
- return twl6040_read_reg_cache(codec, TWL6040_REG_TRIM1 + trim);
+ return twl6040_read(codec, TWL6040_REG_TRIM1 + trim);
}
EXPORT_SYMBOL_GPL(twl6040_get_trim_value);
@@ -943,8 +840,6 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
priv->codec_powered = 1;
- twl6040_restore_regs(codec);
-
/* Set external boost GPO */
twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
break;
@@ -1065,9 +960,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
switch (id) {
case TWL6040_DAI_DL1:
- hslctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSLCTL);
- hsrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HSRCTL);
- earctl = twl6040_read_reg_cache(codec, TWL6040_REG_EARCTL);
+ hslctl = twl6040_read(codec, TWL6040_REG_HSLCTL);
+ hsrctl = twl6040_read(codec, TWL6040_REG_HSRCTL);
+ earctl = twl6040_read(codec, TWL6040_REG_EARCTL);
if (mute) {
/* Power down drivers and DACs */
@@ -1083,8 +978,8 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
priv->dl1_unmuted = !mute;
break;
case TWL6040_DAI_DL2:
- hflctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFLCTL);
- hfrctl = twl6040_read_reg_cache(codec, TWL6040_REG_HFRCTL);
+ hflctl = twl6040_read(codec, TWL6040_REG_HFLCTL);
+ hfrctl = twl6040_read(codec, TWL6040_REG_HFRCTL);
if (mute) {
/* Power down drivers and DACs */
@@ -1100,7 +995,7 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i
break;
default:
break;
- };
+ }
}
static int twl6040_digital_mute(struct snd_soc_dai *dai, int mute)
@@ -1221,6 +1116,7 @@ static int twl6040_resume(struct snd_soc_codec *codec)
static int twl6040_probe(struct snd_soc_codec *codec)
{
struct twl6040_data *priv;
+ struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent);
struct platform_device *pdev = container_of(codec->dev,
struct platform_device, dev);
int ret = 0;
@@ -1232,7 +1128,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, priv);
priv->codec = codec;
- codec->control_data = dev_get_drvdata(codec->dev->parent);
+ codec->control_data = twl6040;
priv->plug_irq = platform_get_irq(pdev, 0);
if (priv->plug_irq < 0) {
@@ -1252,10 +1148,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)
return ret;
}
+ twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
twl6040_init_chip(codec);
- /* power on device */
- return twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
}
static int twl6040_remove(struct snd_soc_codec *codec)
@@ -1273,12 +1169,9 @@ static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
.remove = twl6040_remove,
.suspend = twl6040_suspend,
.resume = twl6040_resume,
- .read = twl6040_read_reg_cache,
+ .read = twl6040_read,
.write = twl6040_write,
.set_bias_level = twl6040_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(twl6040_reg),
- .reg_word_size = sizeof(u8),
- .reg_cache_default = twl6040_reg,
.ignore_pmdown_time = true,
.controls = twl6040_snd_controls,
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index fd0a314bc209..726df6d43c2b 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -794,7 +794,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
.num_dapm_routes = ARRAY_SIZE(uda1380_dapm_routes),
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int uda1380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -840,7 +840,7 @@ static struct i2c_driver uda1380_i2c_driver = {
static int __init uda1380_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&uda1380_i2c_driver);
if (ret != 0)
pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
@@ -851,7 +851,7 @@ module_init(uda1380_modinit);
static void __exit uda1380_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&uda1380_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index d5ebcb00019b..71ce3159a62e 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -372,7 +372,8 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
offset = 0;
dsp = inforec->dsp_target;
wm0010->boot_failed = false;
- BUG_ON(!list_empty(&xfer_list));
+ if (WARN_ON(!list_empty(&xfer_list)))
+ return -EINVAL;
init_completion(&done);
/* First record should be INFO */
@@ -793,11 +794,11 @@ static int wm0010_set_sysclk(struct snd_soc_codec *codec, int source,
wm0010->max_spi_freq = 0;
} else {
for (i = 0; i < ARRAY_SIZE(pll_clock_map); i++)
- if (freq >= pll_clock_map[i].max_sysclk)
+ if (freq >= pll_clock_map[i].max_sysclk) {
+ wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed;
+ wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;
break;
-
- wm0010->max_spi_freq = pll_clock_map[i].max_pll_spi_speed;
- wm0010->pll_clkctrl1 = pll_clock_map[i].pll_clkctrl1;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 7fefd766b582..8ae50274ea8f 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -137,7 +137,8 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
unsigned long rate;
int ret;
- BUG_ON(wm2000->anc_mode != ANC_OFF);
+ if (WARN_ON(wm2000->anc_mode != ANC_OFF))
+ return -EINVAL;
dev_dbg(&i2c->dev, "Beginning power up\n");
@@ -277,7 +278,8 @@ static int wm2000_enter_bypass(struct i2c_client *i2c, int analogue)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
- BUG_ON(wm2000->anc_mode != ANC_ACTIVE);
+ if (WARN_ON(wm2000->anc_mode != ANC_ACTIVE))
+ return -EINVAL;
if (analogue) {
wm2000_write(i2c, WM2000_REG_SYS_MODE_CNTRL,
@@ -315,7 +317,8 @@ static int wm2000_exit_bypass(struct i2c_client *i2c, int analogue)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
- BUG_ON(wm2000->anc_mode != ANC_BYPASS);
+ if (WARN_ON(wm2000->anc_mode != ANC_BYPASS))
+ return -EINVAL;
wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0);
@@ -349,7 +352,8 @@ static int wm2000_enter_standby(struct i2c_client *i2c, int analogue)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
- BUG_ON(wm2000->anc_mode != ANC_ACTIVE);
+ if (WARN_ON(wm2000->anc_mode != ANC_ACTIVE))
+ return -EINVAL;
if (analogue) {
wm2000_write(i2c, WM2000_REG_ANA_VMID_PD_TIME, 248 / 4);
@@ -392,7 +396,8 @@ static int wm2000_exit_standby(struct i2c_client *i2c, int analogue)
{
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
- BUG_ON(wm2000->anc_mode != ANC_STANDBY);
+ if (WARN_ON(wm2000->anc_mode != ANC_STANDBY))
+ return -EINVAL;
wm2000_write(i2c, WM2000_REG_SYS_CTL1, 0);
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index ac1745d030d6..4e3e31aaf509 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -14,6 +14,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/pm.h>
#include <linux/gcd.h>
#include <linux/gpio.h>
@@ -1972,7 +1973,8 @@ static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)
{
struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];
- BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes));
+ if (WARN_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes)))
+ return;
gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1,
@@ -2140,6 +2142,7 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
return 0;
}
+EXPORT_SYMBOL_GPL(wm5100_detect);
static irqreturn_t wm5100_irq(int irq, void *data)
{
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 8bbddc151aa8..ce9c8e14d4bd 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -601,8 +601,8 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
if (patch)
for (i = 0; i < patch_size; i++)
- regmap_write(regmap, patch[i].reg,
- patch[i].def);
+ regmap_write_async(regmap, patch[i].reg,
+ patch[i].def);
break;
default:
@@ -685,13 +685,13 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21,
+SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21,
+SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21,
+SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21,
+SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
ARIZONA_EQ4_ENA_MASK),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index bbd64384ca1c..2c3c962d9a85 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -30,13 +30,140 @@
#include <linux/mfd/arizona/registers.h>
#include "arizona.h"
+#include "wm_adsp.h"
#include "wm5110.h"
+#define WM5110_NUM_ADSP 4
+
struct wm5110_priv {
struct arizona_priv core;
struct arizona_fll fll[2];
};
+static const struct wm_adsp_region wm5110_dsp1_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x100000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x180000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x190000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x1a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp2_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x200000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x280000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x290000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x2a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp3_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x300000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x380000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x390000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x3a8000 },
+};
+
+static const struct wm_adsp_region wm5110_dsp4_regions[] = {
+ { .type = WMFW_ADSP2_PM, .base = 0x400000 },
+ { .type = WMFW_ADSP2_ZM, .base = 0x480000 },
+ { .type = WMFW_ADSP2_XM, .base = 0x490000 },
+ { .type = WMFW_ADSP2_YM, .base = 0x4a8000 },
+};
+
+static const struct wm_adsp_region *wm5110_dsp_regions[] = {
+ wm5110_dsp1_regions,
+ wm5110_dsp2_regions,
+ wm5110_dsp3_regions,
+ wm5110_dsp4_regions,
+};
+
+static const struct reg_default wm5110_sysclk_revd_patch[] = {
+ { 0x3093, 0x1001 },
+ { 0x30E3, 0x1301 },
+ { 0x3133, 0x1201 },
+ { 0x3183, 0x1501 },
+ { 0x31D3, 0x1401 },
+ { 0x0049, 0x01ea },
+ { 0x004a, 0x01f2 },
+ { 0x0057, 0x01e7 },
+ { 0x0058, 0x01fb },
+ { 0x33ce, 0xc4f5 },
+ { 0x33cf, 0x1361 },
+ { 0x33d0, 0x0402 },
+ { 0x33d1, 0x4700 },
+ { 0x33d2, 0x026d },
+ { 0x33d3, 0xff00 },
+ { 0x33d4, 0x026d },
+ { 0x33d5, 0x0101 },
+ { 0x33d6, 0xc4f5 },
+ { 0x33d7, 0x0361 },
+ { 0x33d8, 0x0402 },
+ { 0x33d9, 0x6701 },
+ { 0x33da, 0xc4f5 },
+ { 0x33db, 0x136f },
+ { 0x33dc, 0xc4f5 },
+ { 0x33dd, 0x134f },
+ { 0x33de, 0xc4f5 },
+ { 0x33df, 0x131f },
+ { 0x33e0, 0x026d },
+ { 0x33e1, 0x4f01 },
+ { 0x33e2, 0x026d },
+ { 0x33e3, 0xf100 },
+ { 0x33e4, 0x026d },
+ { 0x33e5, 0x0001 },
+ { 0x33e6, 0xc4f5 },
+ { 0x33e7, 0x0361 },
+ { 0x33e8, 0x0402 },
+ { 0x33e9, 0x6601 },
+ { 0x33ea, 0xc4f5 },
+ { 0x33eb, 0x136f },
+ { 0x33ec, 0xc4f5 },
+ { 0x33ed, 0x134f },
+ { 0x33ee, 0xc4f5 },
+ { 0x33ef, 0x131f },
+ { 0x33f0, 0x026d },
+ { 0x33f1, 0x4e01 },
+ { 0x33f2, 0x026d },
+ { 0x33f3, 0xf000 },
+ { 0x33f6, 0xc4f5 },
+ { 0x33f7, 0x1361 },
+ { 0x33f8, 0x0402 },
+ { 0x33f9, 0x4600 },
+ { 0x33fa, 0x026d },
+ { 0x33fb, 0xfe00 },
+};
+
+static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+ struct regmap *regmap = codec->control_data;
+ const struct reg_default *patch = NULL;
+ int i, patch_size;
+
+ switch (arizona->rev) {
+ case 3:
+ patch = wm5110_sysclk_revd_patch;
+ patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch);
+ break;
+ default:
+ return 0;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (patch)
+ for (i = 0; i < patch_size; i++)
+ regmap_write_async(regmap, patch[i].reg,
+ patch[i].def);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
@@ -76,6 +203,25 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL,
SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL,
ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum),
+
+SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL,
+ ARIZONA_IN1L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL,
+ ARIZONA_IN1R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL,
+ ARIZONA_IN2L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL,
+ ARIZONA_IN2R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL,
+ ARIZONA_IN3L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL,
+ ARIZONA_IN3R_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL,
+ ARIZONA_IN4L_HPF_SHIFT, 1, 0),
+SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL,
+ ARIZONA_IN4R_HPF_SHIFT, 1, 0),
+
SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
@@ -101,13 +247,13 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21,
+SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21,
+SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21,
+SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21,
+SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
ARIZONA_EQ4_ENA_MASK),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
@@ -179,6 +325,14 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+SOC_VALUE_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]),
+SOC_VALUE_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]),
+SOC_VALUE_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
+SOC_VALUE_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
+SOC_VALUE_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+
ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
@@ -207,18 +361,12 @@ ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT2L", ARIZONA_OUT6LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SPKDAT2R", ARIZONA_OUT6RMIX_INPUT_1_SOURCE),
-SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,
- ARIZONA_OUT1_OSR_SHIFT, 1, 0),
-SOC_SINGLE("HPOUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,
- ARIZONA_OUT2_OSR_SHIFT, 1, 0),
-SOC_SINGLE("HPOUT3 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
- ARIZONA_OUT3_OSR_SHIFT, 1, 0),
-SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
- ARIZONA_OUT4_OSR_SHIFT, 1, 0),
-SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
- ARIZONA_OUT5_OSR_SHIFT, 1, 0),
-SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L,
- ARIZONA_OUT6_OSR_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL,
+ ARIZONA_HP1_SC_ENA_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT2 SC Protect Switch", ARIZONA_HP2_SHORT_CIRCUIT_CTRL,
+ ARIZONA_HP2_SC_ENA_SHIFT, 1, 0),
+SOC_SINGLE("HPOUT3 SC Protect Switch", ARIZONA_HP3_SHORT_CIRCUIT_CTRL,
+ ARIZONA_HP3_SC_ENA_SHIFT, 1, 0),
SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
@@ -252,23 +400,18 @@ SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_6L,
ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_VOL_SHIFT,
0xbf, 0, digital_tlv),
-SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L,
- ARIZONA_OUTPUT_PATH_CONFIG_1R,
- ARIZONA_OUT1L_PGA_VOL_SHIFT,
- 0x34, 0x40, 0, ana_tlv),
-SOC_DOUBLE_R_RANGE_TLV("HPOUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,
- ARIZONA_OUTPUT_PATH_CONFIG_2R,
- ARIZONA_OUT2L_PGA_VOL_SHIFT,
- 0x34, 0x40, 0, ana_tlv),
-SOC_DOUBLE_R_RANGE_TLV("HPOUT3 Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
- ARIZONA_OUTPUT_PATH_CONFIG_3R,
- ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
-
SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT,
ARIZONA_SPK2R_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE,
+ ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE,
+ ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0),
+SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE,
+ ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0),
+
SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
@@ -302,6 +445,10 @@ ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
@@ -331,6 +478,22 @@ ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1L, ARIZONA_DSP1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP1R, ARIZONA_DSP1RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP1, ARIZONA_DSP1AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DSP4L, ARIZONA_DSP4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DSP4R, ARIZONA_DSP4RMIX_INPUT_1_SOURCE);
+ARIZONA_DSP_AUX_ENUMS(DSP4, ARIZONA_DSP4AUX1MIX_INPUT_1_SOURCE);
+
ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
@@ -361,6 +524,10 @@ ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE);
ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE);
@@ -379,6 +546,36 @@ ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE);
+
static const char *wm5110_aec_loopback_texts[] = {
"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
@@ -400,7 +597,7 @@ static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
- 0, NULL, 0),
+ 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
@@ -519,6 +716,65 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
NULL, 0),
+WM_ADSP2("DSP1", 0),
+WM_ADSP2("DSP2", 1),
+WM_ADSP2("DSP3", 2),
+WM_ADSP2("DSP4", 3),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3,
+ ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3,
+ ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3,
+ ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0),
+
SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5110_aec_loopback_mux),
@@ -561,11 +817,27 @@ SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0,
+ ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0,
+ ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
@@ -703,6 +975,10 @@ ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"),
+ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"),
+ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"),
+ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"),
ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"),
ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"),
@@ -721,6 +997,41 @@ ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"),
ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"),
ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"),
+ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
+ARIZONA_DSP_WIDGETS(DSP2, "DSP2"),
+ARIZONA_DSP_WIDGETS(DSP3, "DSP3"),
+ARIZONA_DSP_WIDGETS(DSP4, "DSP4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"),
+ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"),
+ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"),
+ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"),
+
+ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"),
+ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"),
+ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"),
+ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"),
+
SND_SOC_DAPM_OUTPUT("HPOUT1L"),
SND_SOC_DAPM_OUTPUT("HPOUT1R"),
SND_SOC_DAPM_OUTPUT("HPOUT2L"),
@@ -764,6 +1075,10 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
{ name, "AIF1RX8", "AIF1RX8" }, \
{ name, "AIF2RX1", "AIF2RX1" }, \
{ name, "AIF2RX2", "AIF2RX2" }, \
+ { name, "AIF2RX3", "AIF2RX3" }, \
+ { name, "AIF2RX4", "AIF2RX4" }, \
+ { name, "AIF2RX5", "AIF2RX5" }, \
+ { name, "AIF2RX6", "AIF2RX6" }, \
{ name, "AIF3RX1", "AIF3RX1" }, \
{ name, "AIF3RX2", "AIF3RX2" }, \
{ name, "SLIMRX1", "SLIMRX1" }, \
@@ -789,7 +1104,55 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"),
{ name, "ASRC1L", "ASRC1L" }, \
{ name, "ASRC1R", "ASRC1R" }, \
{ name, "ASRC2L", "ASRC2L" }, \
- { name, "ASRC2R", "ASRC2R" }
+ { name, "ASRC2R", "ASRC2R" }, \
+ { name, "ISRC1DEC1", "ISRC1DEC1" }, \
+ { name, "ISRC1DEC2", "ISRC1DEC2" }, \
+ { name, "ISRC1DEC3", "ISRC1DEC3" }, \
+ { name, "ISRC1DEC4", "ISRC1DEC4" }, \
+ { name, "ISRC1INT1", "ISRC1INT1" }, \
+ { name, "ISRC1INT2", "ISRC1INT2" }, \
+ { name, "ISRC1INT3", "ISRC1INT3" }, \
+ { name, "ISRC1INT4", "ISRC1INT4" }, \
+ { name, "ISRC2DEC1", "ISRC2DEC1" }, \
+ { name, "ISRC2DEC2", "ISRC2DEC2" }, \
+ { name, "ISRC2DEC3", "ISRC2DEC3" }, \
+ { name, "ISRC2DEC4", "ISRC2DEC4" }, \
+ { name, "ISRC2INT1", "ISRC2INT1" }, \
+ { name, "ISRC2INT2", "ISRC2INT2" }, \
+ { name, "ISRC2INT3", "ISRC2INT3" }, \
+ { name, "ISRC2INT4", "ISRC2INT4" }, \
+ { name, "ISRC3DEC1", "ISRC3DEC1" }, \
+ { name, "ISRC3DEC2", "ISRC3DEC2" }, \
+ { name, "ISRC3DEC3", "ISRC3DEC3" }, \
+ { name, "ISRC3DEC4", "ISRC3DEC4" }, \
+ { name, "ISRC3INT1", "ISRC3INT1" }, \
+ { name, "ISRC3INT2", "ISRC3INT2" }, \
+ { name, "ISRC3INT3", "ISRC3INT3" }, \
+ { name, "ISRC3INT4", "ISRC3INT4" }, \
+ { name, "DSP1.1", "DSP1" }, \
+ { name, "DSP1.2", "DSP1" }, \
+ { name, "DSP1.3", "DSP1" }, \
+ { name, "DSP1.4", "DSP1" }, \
+ { name, "DSP1.5", "DSP1" }, \
+ { name, "DSP1.6", "DSP1" }, \
+ { name, "DSP2.1", "DSP2" }, \
+ { name, "DSP2.2", "DSP2" }, \
+ { name, "DSP2.3", "DSP2" }, \
+ { name, "DSP2.4", "DSP2" }, \
+ { name, "DSP2.5", "DSP2" }, \
+ { name, "DSP2.6", "DSP2" }, \
+ { name, "DSP3.1", "DSP3" }, \
+ { name, "DSP3.2", "DSP3" }, \
+ { name, "DSP3.3", "DSP3" }, \
+ { name, "DSP3.4", "DSP3" }, \
+ { name, "DSP3.5", "DSP3" }, \
+ { name, "DSP3.6", "DSP3" }, \
+ { name, "DSP4.1", "DSP4" }, \
+ { name, "DSP4.2", "DSP4" }, \
+ { name, "DSP4.3", "DSP4" }, \
+ { name, "DSP4.4", "DSP4" }, \
+ { name, "DSP4.5", "DSP4" }, \
+ { name, "DSP4.6", "DSP4" }
static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "AIF2 Capture", NULL, "DBVDD2" },
@@ -861,9 +1224,17 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "AIF2 Capture", NULL, "AIF2TX1" },
{ "AIF2 Capture", NULL, "AIF2TX2" },
+ { "AIF2 Capture", NULL, "AIF2TX3" },
+ { "AIF2 Capture", NULL, "AIF2TX4" },
+ { "AIF2 Capture", NULL, "AIF2TX5" },
+ { "AIF2 Capture", NULL, "AIF2TX6" },
{ "AIF2RX1", NULL, "AIF2 Playback" },
{ "AIF2RX2", NULL, "AIF2 Playback" },
+ { "AIF2RX3", NULL, "AIF2 Playback" },
+ { "AIF2RX4", NULL, "AIF2 Playback" },
+ { "AIF2RX5", NULL, "AIF2 Playback" },
+ { "AIF2RX6", NULL, "AIF2 Playback" },
{ "AIF3 Capture", NULL, "AIF3TX1" },
{ "AIF3 Capture", NULL, "AIF3TX2" },
@@ -947,6 +1318,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+ ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"),
+ ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"),
+ ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"),
+ ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"),
ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"),
ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"),
@@ -983,24 +1358,71 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
+ ARIZONA_DSP_ROUTES("DSP1"),
+ ARIZONA_DSP_ROUTES("DSP2"),
+ ARIZONA_DSP_ROUTES("DSP3"),
+ ARIZONA_DSP_ROUTES("DSP4"),
+
+ ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+ ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
+ ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"),
+ ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"),
+
+ ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+ ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+ ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"),
+ ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"),
+
+ ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+ ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+ ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"),
+ ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"),
+
+ ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+ ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+ ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"),
+ ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"),
+
+ ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"),
+ ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"),
+ ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"),
+ ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"),
+
+ ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"),
+ ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"),
+ ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"),
+ ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"),
+
+ { "AEC Loopback", "HPOUT1L", "OUT1L" },
+ { "AEC Loopback", "HPOUT1R", "OUT1R" },
{ "HPOUT1L", NULL, "OUT1L" },
{ "HPOUT1R", NULL, "OUT1R" },
+ { "AEC Loopback", "HPOUT2L", "OUT2L" },
+ { "AEC Loopback", "HPOUT2R", "OUT2R" },
{ "HPOUT2L", NULL, "OUT2L" },
{ "HPOUT2R", NULL, "OUT2R" },
+ { "AEC Loopback", "HPOUT3L", "OUT3L" },
+ { "AEC Loopback", "HPOUT3R", "OUT3R" },
{ "HPOUT3L", NULL, "OUT3L" },
- { "HPOUT3R", NULL, "OUT3L" },
+ { "HPOUT3R", NULL, "OUT3R" },
+ { "AEC Loopback", "SPKOUTL", "OUT4L" },
{ "SPKOUTLN", NULL, "OUT4L" },
{ "SPKOUTLP", NULL, "OUT4L" },
+ { "AEC Loopback", "SPKOUTR", "OUT4R" },
{ "SPKOUTRN", NULL, "OUT4R" },
{ "SPKOUTRP", NULL, "OUT4R" },
+ { "AEC Loopback", "SPKDAT1L", "OUT5L" },
+ { "AEC Loopback", "SPKDAT1R", "OUT5R" },
{ "SPKDAT1L", NULL, "OUT5L" },
{ "SPKDAT1R", NULL, "OUT5R" },
+ { "AEC Loopback", "SPKDAT2L", "OUT6L" },
+ { "AEC Loopback", "SPKDAT2R", "OUT6R" },
{ "SPKDAT2L", NULL, "OUT6L" },
{ "SPKDAT2R", NULL, "OUT6R" },
@@ -1067,14 +1489,14 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
.playback = {
.stream_name = "AIF2 Playback",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 6,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
.capture = {
.stream_name = "AIF2 Capture",
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 6,
.rates = WM5110_RATES,
.formats = WM5110_FORMATS,
},
@@ -1176,6 +1598,10 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
arizona_init_spk(codec);
arizona_init_gpio(codec);
+ ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 8);
+ if (ret != 0)
+ return ret;
+
snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
priv->core.arizona->dapm = &codec->dapm;
@@ -1230,7 +1656,7 @@ static int wm5110_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
struct wm5110_priv *wm5110;
- int i;
+ int i, ret;
wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv),
GFP_KERNEL);
@@ -1241,6 +1667,24 @@ static int wm5110_probe(struct platform_device *pdev)
wm5110->core.arizona = arizona;
wm5110->core.num_inputs = 8;
+ for (i = 0; i < WM5110_NUM_ADSP; i++) {
+ wm5110->core.adsp[i].part = "wm5110";
+ wm5110->core.adsp[i].num = i + 1;
+ wm5110->core.adsp[i].type = WMFW_ADSP2;
+ wm5110->core.adsp[i].dev = arizona->dev;
+ wm5110->core.adsp[i].regmap = arizona->regmap;
+
+ wm5110->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1
+ + (0x100 * i);
+ wm5110->core.adsp[i].mem = wm5110_dsp_regions[i];
+ wm5110->core.adsp[i].num_mems
+ = ARRAY_SIZE(wm5110_dsp1_regions);
+
+ ret = wm_adsp2_init(&wm5110->core.adsp[i], false);
+ if (ret != 0)
+ return ret;
+ }
+
for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
wm5110->fll[i].vco_mult = 3;
@@ -1251,6 +1695,12 @@ static int wm5110_probe(struct platform_device *pdev)
ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
&wm5110->fll[1]);
+ /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+ regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+ ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+ regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+ ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++)
arizona_init_dai(&wm5110->core, i);
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index af1318ddb062..a183dcf3d5c1 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -274,7 +274,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Invalid shift %d\n", w->shift);
return -1;
}
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index d2a092850283..48dc7d2fee36 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -32,13 +32,6 @@
#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",
@@ -74,32 +67,6 @@ struct wm8400_priv {
int fll_in, fll_out;
};
-static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
-
- 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 = snd_soc_codec_get_drvdata(codec);
-
- 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 = snd_soc_codec_get_drvdata(codec);
@@ -352,32 +319,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
* _DAPM_ Controls
*/
-static int inmixer_event (struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- u16 reg, fakepower;
-
- reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2);
- fakepower = snd_soc_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_AINR_ENA;
- }
- snd_soc_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)
{
@@ -658,27 +599,26 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8400_POWER_MANAGEMENT_2,
0, &wm8400_dapm_rin34_pga_controls[0],
ARRAY_SIZE(wm8400_dapm_rin34_pga_controls)),
+SND_SOC_DAPM_SUPPLY("INL", WM8400_POWER_MANAGEMENT_2, WM8400_AINL_ENA_SHIFT,
+ 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("INR", WM8400_POWER_MANAGEMENT_2, WM8400_AINR_ENA_SHIFT,
+ 0, NULL, 0),
+
/* INMIXL */
-SND_SOC_DAPM_MIXER_E("INMIXL", WM8400_INTDRIVBITS, WM8400_INMIXL_PWR, 0,
+SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
&wm8400_dapm_inmixl_controls[0],
- ARRAY_SIZE(wm8400_dapm_inmixl_controls),
- inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ ARRAY_SIZE(wm8400_dapm_inmixl_controls)),
/* 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),
+SND_SOC_DAPM_MUX("AILNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainlmux_controls),
/* INMIXR */
-SND_SOC_DAPM_MIXER_E("INMIXR", WM8400_INTDRIVBITS, WM8400_INMIXR_PWR, 0,
+SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
&wm8400_dapm_inmixr_controls[0],
- ARRAY_SIZE(wm8400_dapm_inmixr_controls),
- inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ ARRAY_SIZE(wm8400_dapm_inmixr_controls)),
/* 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),
+SND_SOC_DAPM_MUX("AIRNMUX", SND_SOC_NOPM, 0, 0, &wm8400_dapm_ainrmux_controls),
/* Output Side */
/* DACs */
@@ -789,11 +729,13 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
{"LIN34 PGA", "LIN3 Switch", "LIN3"},
{"LIN34 PGA", "LIN4 Switch", "LIN4/RXN"},
/* INMIXL */
+ {"INMIXL", NULL, "INL"},
{"INMIXL", "Record Left Volume", "LOMIX"},
{"INMIXL", "LIN2 Volume", "LIN2"},
{"INMIXL", "LINPGA12 Switch", "LIN12 PGA"},
{"INMIXL", "LINPGA34 Switch", "LIN34 PGA"},
/* AILNMUX */
+ {"AILNMUX", NULL, "INL"},
{"AILNMUX", "INMIXL Mix", "INMIXL"},
{"AILNMUX", "DIFFINL Mix", "LIN12 PGA"},
{"AILNMUX", "DIFFINL Mix", "LIN34 PGA"},
@@ -808,12 +750,14 @@ static const struct snd_soc_dapm_route wm8400_dapm_routes[] = {
/* RIN34 PGA */
{"RIN34 PGA", "RIN3 Switch", "RIN3"},
{"RIN34 PGA", "RIN4 Switch", "RIN4/RXP"},
- /* INMIXL */
+ /* INMIXR */
+ {"INMIXR", NULL, "INR"},
{"INMIXR", "Record Right Volume", "ROMIX"},
{"INMIXR", "RIN2 Volume", "RIN2"},
{"INMIXR", "RINPGA12 Switch", "RIN12 PGA"},
{"INMIXR", "RINPGA34 Switch", "RIN34 PGA"},
/* AIRNMUX */
+ {"AIRNMUX", NULL, "INR"},
{"AIRNMUX", "INMIXR Mix", "INMIXR"},
{"AIRNMUX", "DIFFINR Mix", "RIN12 PGA"},
{"AIRNMUX", "DIFFINR Mix", "RIN34 PGA"},
@@ -1365,9 +1309,12 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
return -ENOMEM;
snd_soc_codec_set_drvdata(codec, priv);
- codec->control_data = priv->wm8400 = wm8400;
+ priv->wm8400 = wm8400;
+ codec->control_data = wm8400->regmap;
priv->codec = codec;
+ snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
+
ret = devm_regulator_bulk_get(wm8400->dev,
ARRAY_SIZE(power), &power[0]);
if (ret != 0) {
@@ -1414,8 +1361,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
.remove = wm8400_codec_remove,
.suspend = wm8400_suspend,
.resume = wm8400_resume,
- .read = snd_soc_read,
- .write = wm8400_write,
.set_bias_level = wm8400_set_bias_level,
.controls = wm8400_snd_controls,
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 6ed5433943ea..7df7d4572755 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -684,7 +684,7 @@ static struct spi_driver wm8510_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8510_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -735,7 +735,7 @@ static struct i2c_driver wm8510_i2c_driver = {
static int __init wm8510_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8510_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n",
@@ -755,7 +755,7 @@ module_init(wm8510_modinit);
static void __exit wm8510_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8510_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 139bf9ac9407..74d106dc7667 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -452,7 +452,7 @@ static const struct regmap_config wm8523_regmap = {
.volatile_reg = wm8523_volatile_register,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8523_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -555,7 +555,7 @@ static struct i2c_driver wm8523_i2c_driver = {
static int __init wm8523_modinit(void)
{
int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8523_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n",
@@ -568,7 +568,7 @@ module_init(wm8523_modinit);
static void __exit wm8523_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8523_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 5e9c40fa7eb2..318989acbbe5 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -736,7 +736,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
break;
default:
- BUG_ON("Unknown DAI driver ID\n");
+ WARN(1, "Unknown DAI driver ID\n");
return -EINVAL;
}
@@ -941,7 +941,7 @@ static const struct regmap_config wm8580_regmap = {
.volatile_reg = wm8580_volatile,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8580_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1003,7 +1003,7 @@ static int __init wm8580_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8580_i2c_driver);
if (ret != 0) {
pr_err("Failed to register WM8580 I2C driver: %d\n", ret);
@@ -1016,7 +1016,7 @@ module_init(wm8580_modinit);
static void __exit wm8580_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8580_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 5b428b060d41..d99f948c513c 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -469,7 +469,7 @@ static struct spi_driver wm8711_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8711_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -520,7 +520,7 @@ static struct i2c_driver wm8711_i2c_driver = {
static int __init wm8711_modinit(void)
{
int ret;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8711_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8711 I2C driver: %d\n",
@@ -540,7 +540,7 @@ module_init(wm8711_modinit);
static void __exit wm8711_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8711_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index c6a292dcded0..cd89033e84c0 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -320,7 +320,7 @@ static struct spi_driver wm8728_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8728_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -371,7 +371,7 @@ static struct i2c_driver wm8728_i2c_driver = {
static int __init wm8728_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8728_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8728 I2C driver: %d\n",
@@ -391,7 +391,7 @@ module_init(wm8728_modinit);
static void __exit wm8728_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8728_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 456bb8c6d759..029720366ff8 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -447,10 +447,10 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface |= 0x0001;
break;
case SND_SOC_DAIFMT_DSP_A:
- iface |= 0x0003;
+ iface |= 0x0013;
break;
case SND_SOC_DAIFMT_DSP_B:
- iface |= 0x0013;
+ iface |= 0x0003;
break;
default:
return -EINVAL;
@@ -732,7 +732,7 @@ static struct spi_driver wm8731_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8731_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -791,7 +791,7 @@ static struct i2c_driver wm8731_i2c_driver = {
static int __init wm8731_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8731_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
@@ -811,7 +811,7 @@ module_init(wm8731_modinit);
static void __exit wm8731_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8731_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index b18813cc7ba9..2895c8d3b5e4 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -500,7 +500,7 @@ static const struct regmap_config wm8741_regmap = {
.readable_reg = wm8741_readable,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8741_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -617,7 +617,7 @@ static int __init wm8741_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8741_i2c_driver);
if (ret != 0)
pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
@@ -639,7 +639,7 @@ static void __exit wm8741_exit(void)
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8741_spi_driver);
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8741_i2c_driver);
#endif
}
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 50d5ff616232..78616a638a55 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -816,7 +816,7 @@ static struct spi_driver wm8750_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8750_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -868,7 +868,7 @@ static struct i2c_driver wm8750_i2c_driver = {
static int __init wm8750_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8750_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8750 I2C driver: %d\n",
@@ -888,7 +888,7 @@ module_init(wm8750_modinit);
static void __exit wm8750_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8750_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index d96ebf52d953..be85da93a268 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -1596,7 +1596,7 @@ static struct spi_driver wm8753_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8753_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1653,7 +1653,7 @@ static struct i2c_driver wm8753_i2c_driver = {
static int __init wm8753_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8753_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
@@ -1673,7 +1673,7 @@ module_init(wm8753_modinit);
static void __exit wm8753_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8753_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index f31017ed1381..ef8246725232 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -325,7 +325,8 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
struct snd_soc_codec *codec = dai->codec;
struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
- BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
+ if (WARN_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk)))
+ return -EINVAL;
wm8776->sysclk[dai->driver->id] = freq;
@@ -531,7 +532,7 @@ static struct spi_driver wm8776_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8776_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -583,7 +584,7 @@ static struct i2c_driver wm8776_i2c_driver = {
static int __init wm8776_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8776_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
@@ -603,7 +604,7 @@ module_init(wm8776_modinit);
static void __exit wm8776_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8776_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 1704b1e119cb..9bc8206a6807 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -739,7 +739,7 @@ static struct spi_driver wm8804_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8804_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -791,7 +791,7 @@ static int __init wm8804_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8804_i2c_driver);
if (ret) {
printk(KERN_ERR "Failed to register wm8804 I2C driver: %d\n",
@@ -811,7 +811,7 @@ module_init(wm8804_modinit);
static void __exit wm8804_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8804_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 7c8257c5a17b..e98bc7038a08 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -279,7 +279,8 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
+ break;
}
return 0;
@@ -691,7 +692,8 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
unsigned int K, Ndiv, Nmod, target;
unsigned int div;
- BUG_ON(!Fout);
+ if (WARN_ON(!Fout))
+ return -EINVAL;
/* The FLL must run at 90-100MHz which is then scaled down to
* the output value by FLLCLK_DIV. */
@@ -742,8 +744,9 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
/* Move down to proper range now rounding is done */
fll_div->k = K / 10;
- BUG_ON(target != Fout * (fll_div->fllclk_div << 2));
- BUG_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n);
+ if (WARN_ON(target != Fout * (fll_div->fllclk_div << 2)) ||
+ WARN_ON(!K && target != Fref * fll_div->fll_ratio * fll_div->n))
+ return -EINVAL;
return 0;
}
@@ -1285,7 +1288,7 @@ static struct spi_driver wm8900_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8900_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1335,7 +1338,7 @@ static struct i2c_driver wm8900_i2c_driver = {
static int __init wm8900_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8900_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register wm8900 I2C driver: %d\n",
@@ -1355,7 +1358,7 @@ module_init(wm8900_modinit);
static void __exit wm8900_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8900_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 4dfa8dceeabf..53bbfac6a83a 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -658,7 +658,8 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8904_EQ6, 0, 24, 0, eq_tlv),
static int cp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- BUG_ON(event != SND_SOC_DAPM_POST_PMU);
+ if (WARN_ON(event != SND_SOC_DAPM_POST_PMU))
+ return -EINVAL;
/* Maximum startup time */
udelay(500);
@@ -740,7 +741,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
dcs_r = 3;
break;
default:
- BUG();
+ WARN(1, "Invalid reg %d\n", reg);
return -EINVAL;
}
@@ -1443,7 +1444,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
- aif1 |= WM8904_AIF_LRCLK_INV;
+ aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;
case SND_SOC_DAIFMT_DSP_A:
aif1 |= 0x3;
break;
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index b1591c61c254..b404c26c1753 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -28,7 +28,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -41,78 +41,116 @@
struct wm8940_priv {
unsigned int sysclk;
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
};
-static int wm8940_volatile_register(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool wm8940_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8940_SOFTRESET:
- return 1;
+ return true;
default:
- return 0;
+ return false;
+ }
+}
+
+static bool wm8940_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8940_SOFTRESET:
+ case WM8940_POWER1:
+ case WM8940_POWER2:
+ case WM8940_POWER3:
+ case WM8940_IFACE:
+ case WM8940_COMPANDINGCTL:
+ case WM8940_CLOCK:
+ case WM8940_ADDCNTRL:
+ case WM8940_GPIO:
+ case WM8940_CTLINT:
+ case WM8940_DAC:
+ case WM8940_DACVOL:
+ case WM8940_ADC:
+ case WM8940_ADCVOL:
+ case WM8940_NOTCH1:
+ case WM8940_NOTCH2:
+ case WM8940_NOTCH3:
+ case WM8940_NOTCH4:
+ case WM8940_NOTCH5:
+ case WM8940_NOTCH6:
+ case WM8940_NOTCH7:
+ case WM8940_NOTCH8:
+ case WM8940_DACLIM1:
+ case WM8940_DACLIM2:
+ case WM8940_ALC1:
+ case WM8940_ALC2:
+ case WM8940_ALC3:
+ case WM8940_NOISEGATE:
+ case WM8940_PLLN:
+ case WM8940_PLLK1:
+ case WM8940_PLLK2:
+ case WM8940_PLLK3:
+ case WM8940_ALC4:
+ case WM8940_INPUTCTL:
+ case WM8940_PGAGAIN:
+ case WM8940_ADCBOOST:
+ case WM8940_OUTPUTCTL:
+ case WM8940_SPKMIX:
+ case WM8940_SPKVOL:
+ case WM8940_MONOMIX:
+ return true;
+ default:
+ return false;
}
}
-static u16 wm8940_reg_defaults[] = {
- 0x8940, /* Soft Reset */
- 0x0000, /* Power 1 */
- 0x0000, /* Power 2 */
- 0x0000, /* Power 3 */
- 0x0010, /* Interface Control */
- 0x0000, /* Companding Control */
- 0x0140, /* Clock Control */
- 0x0000, /* Additional Controls */
- 0x0000, /* GPIO Control */
- 0x0002, /* Auto Increment Control */
- 0x0000, /* DAC Control */
- 0x00FF, /* DAC Volume */
- 0,
- 0,
- 0x0100, /* ADC Control */
- 0x00FF, /* ADC Volume */
- 0x0000, /* Notch Filter 1 Control 1 */
- 0x0000, /* Notch Filter 1 Control 2 */
- 0x0000, /* Notch Filter 2 Control 1 */
- 0x0000, /* Notch Filter 2 Control 2 */
- 0x0000, /* Notch Filter 3 Control 1 */
- 0x0000, /* Notch Filter 3 Control 2 */
- 0x0000, /* Notch Filter 4 Control 1 */
- 0x0000, /* Notch Filter 4 Control 2 */
- 0x0032, /* DAC Limit Control 1 */
- 0x0000, /* DAC Limit Control 2 */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0x0038, /* ALC Control 1 */
- 0x000B, /* ALC Control 2 */
- 0x0032, /* ALC Control 3 */
- 0x0000, /* Noise Gate */
- 0x0041, /* PLLN */
- 0x000C, /* PLLK1 */
- 0x0093, /* PLLK2 */
- 0x00E9, /* PLLK3 */
- 0,
- 0,
- 0x0030, /* ALC Control 4 */
- 0,
- 0x0002, /* Input Control */
- 0x0050, /* PGA Gain */
- 0,
- 0x0002, /* ADC Boost Control */
- 0,
- 0x0002, /* Output Control */
- 0x0000, /* Speaker Mixer Control */
- 0,
- 0,
- 0,
- 0x0079, /* Speaker Volume */
- 0,
- 0x0000, /* Mono Mixer Control */
+static const struct reg_default wm8940_reg_defaults[] = {
+ { 0x1, 0x0000 }, /* Power 1 */
+ { 0x2, 0x0000 }, /* Power 2 */
+ { 0x3, 0x0000 }, /* Power 3 */
+ { 0x4, 0x0010 }, /* Interface Control */
+ { 0x5, 0x0000 }, /* Companding Control */
+ { 0x6, 0x0140 }, /* Clock Control */
+ { 0x7, 0x0000 }, /* Additional Controls */
+ { 0x8, 0x0000 }, /* GPIO Control */
+ { 0x9, 0x0002 }, /* Auto Increment Control */
+ { 0xa, 0x0000 }, /* DAC Control */
+ { 0xb, 0x00FF }, /* DAC Volume */
+
+ { 0xe, 0x0100 }, /* ADC Control */
+ { 0xf, 0x00FF }, /* ADC Volume */
+ { 0x10, 0x0000 }, /* Notch Filter 1 Control 1 */
+ { 0x11, 0x0000 }, /* Notch Filter 1 Control 2 */
+ { 0x12, 0x0000 }, /* Notch Filter 2 Control 1 */
+ { 0x13, 0x0000 }, /* Notch Filter 2 Control 2 */
+ { 0x14, 0x0000 }, /* Notch Filter 3 Control 1 */
+ { 0x15, 0x0000 }, /* Notch Filter 3 Control 2 */
+ { 0x16, 0x0000 }, /* Notch Filter 4 Control 1 */
+ { 0x17, 0x0000 }, /* Notch Filter 4 Control 2 */
+ { 0x18, 0x0032 }, /* DAC Limit Control 1 */
+ { 0x19, 0x0000 }, /* DAC Limit Control 2 */
+
+ { 0x20, 0x0038 }, /* ALC Control 1 */
+ { 0x21, 0x000B }, /* ALC Control 2 */
+ { 0x22, 0x0032 }, /* ALC Control 3 */
+ { 0x23, 0x0000 }, /* Noise Gate */
+ { 0x24, 0x0041 }, /* PLLN */
+ { 0x25, 0x000C }, /* PLLK1 */
+ { 0x26, 0x0093 }, /* PLLK2 */
+ { 0x27, 0x00E9 }, /* PLLK3 */
+
+ { 0x2a, 0x0030 }, /* ALC Control 4 */
+
+ { 0x2c, 0x0002 }, /* Input Control */
+ { 0x2d, 0x0050 }, /* PGA Gain */
+
+ { 0x2f, 0x0002 }, /* ADC Boost Control */
+
+ { 0x31, 0x0002 }, /* Output Control */
+ { 0x32, 0x0000 }, /* Speaker Mixer Control */
+
+ { 0x36, 0x0079 }, /* Speaker Volume */
+
+ { 0x38, 0x0000 }, /* Mono Mixer Control */
};
static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" };
@@ -264,7 +302,7 @@ static const struct snd_soc_dapm_widget wm8940_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AUX"),
};
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
/* Mono output mixer */
{"Mono Mixer", "PCM Playback Switch", "DAC"},
{"Mono Mixer", "Aux Playback Switch", "Aux Input"},
@@ -296,21 +334,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"ADC", NULL, "Boost Mixer"},
};
-static int wm8940_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
-
- ret = snd_soc_dapm_new_controls(dapm, wm8940_dapm_widgets,
- ARRAY_SIZE(wm8940_dapm_widgets));
- if (ret)
- goto error_ret;
- ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-error_ret:
- return ret;
-}
-
#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0);
static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -446,6 +469,7 @@ static int wm8940_mute(struct snd_soc_dai *dai, int mute)
static int wm8940_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
u16 val;
u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0;
int ret = 0;
@@ -469,7 +493,7 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_cache_sync(codec);
+ ret = regcache_sync(wm8940->regmap);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
return ret;
@@ -684,12 +708,11 @@ static int wm8940_resume(struct snd_soc_codec *codec)
static int wm8940_probe(struct snd_soc_codec *codec)
{
- struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
struct wm8940_setup_data *pdata = codec->dev->platform_data;
int ret;
u16 reg;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -716,11 +739,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
return ret;
}
- ret = snd_soc_add_codec_controls(codec, wm8940_snd_controls,
- ARRAY_SIZE(wm8940_snd_controls));
- if (ret)
- return ret;
- ret = wm8940_add_widgets(codec);
return ret;
}
@@ -736,10 +754,24 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
.suspend = wm8940_suspend,
.resume = wm8940_resume,
.set_bias_level = wm8940_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = wm8940_reg_defaults,
- .volatile_register = wm8940_volatile_register,
+ .controls = wm8940_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8940_snd_controls),
+ .dapm_widgets = wm8940_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8940_dapm_widgets),
+ .dapm_routes = wm8940_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8940_dapm_routes),
+};
+
+static const struct regmap_config wm8940_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = WM8940_MONOMIX,
+ .reg_defaults = wm8940_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8940_reg_defaults),
+
+ .readable_reg = wm8940_readable_register,
+ .volatile_reg = wm8940_volatile_register,
};
static int wm8940_i2c_probe(struct i2c_client *i2c,
@@ -753,8 +785,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
if (wm8940 == NULL)
return -ENOMEM;
+ wm8940->regmap = devm_regmap_init_i2c(i2c, &wm8940_regmap);
+ if (IS_ERR(wm8940->regmap))
+ return PTR_ERR(wm8940->regmap);
+
i2c_set_clientdata(i2c, wm8940);
- wm8940->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8940, &wm8940_dai, 1);
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index b0710d817a65..b7488f190d2b 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -348,7 +348,7 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
aif = 1;
break;
default:
- BUG();
+ WARN(1, "Invalid path %d\n", path);
return;
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 11d80f3b6137..97db3b45b411 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -74,7 +74,7 @@ struct wm8962_priv {
struct regulator_bulk_data supplies[WM8962_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8962_NUM_SUPPLIES];
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
struct input_dev *beep;
struct work_struct beep_work;
int beep_rate;
@@ -1758,6 +1758,9 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv),
SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
+SND_SOC_BYTES("EQL Coefficients", WM8962_EQ4, 18),
+SND_SOC_BYTES("EQR Coefficients", WM8962_EQ24, 18),
+
SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
@@ -1775,6 +1778,11 @@ WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),
WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30),
+
+SOC_DOUBLE("ALC Switch", WM8962_ALC1, WM8962_ALCL_ENA_SHIFT,
+ WM8962_ALCR_ENA_SHIFT, 1, 0),
+SND_SOC_BYTES_MASK("ALC Coefficients", WM8962_ALC1, 4,
+ WM8962_ALCL_ENA_MASK | WM8962_ALCR_ENA_MASK),
};
static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -1845,7 +1853,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
return -EINVAL;
}
@@ -1937,7 +1945,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
return -EINVAL;
}
@@ -1966,7 +1974,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
reg = WM8962_SPKOUTL_VOLUME;
break;
default:
- BUG();
+ WARN(1, "Invalid shift %d\n", w->shift);
return -EINVAL;
}
@@ -1974,7 +1982,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
return -EINVAL;
}
}
@@ -1997,7 +2005,7 @@ static int dsp2_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
return -EINVAL;
}
@@ -2431,7 +2439,20 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8962_CLOCKING_4,
WM8962_SYSCLK_RATE_MASK, clocking4);
+ /* DSPCLK_DIV can be only generated correctly after enabling SYSCLK.
+ * So we here provisionally enable it and then disable it afterward
+ * if current bias_level hasn't reached SND_SOC_BIAS_ON.
+ */
+ if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_SYSCLK_ENA_MASK, WM8962_SYSCLK_ENA);
+
dspclk = snd_soc_read(codec, WM8962_CLOCKING1);
+
+ if (codec->dapm.bias_level != SND_SOC_BIAS_ON)
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_SYSCLK_ENA_MASK, 0);
+
if (dspclk < 0) {
dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk);
return;
@@ -3100,7 +3121,7 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
}
EXPORT_SYMBOL_GPL(wm8962_mic_detect);
-#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+#if IS_ENABLED(CONFIG_INPUT)
static int beep_rates[] = {
500, 1000, 2000, 4000,
};
@@ -3242,7 +3263,7 @@ static void wm8962_free_beep(struct snd_soc_codec *codec)
}
#endif
-static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
+static void wm8962_set_gpio_mode(struct wm8962_priv *wm8962, int gpio)
{
int mask = 0;
int val = 0;
@@ -3263,8 +3284,8 @@ static void wm8962_set_gpio_mode(struct snd_soc_codec *codec, int gpio)
}
if (mask)
- snd_soc_update_bits(codec, WM8962_ANALOGUE_CLOCKING1,
- mask, val);
+ regmap_update_bits(wm8962->regmap, WM8962_ANALOGUE_CLOCKING1,
+ mask, val);
}
#ifdef CONFIG_GPIOLIB
@@ -3276,7 +3297,6 @@ static inline struct wm8962_priv *gpio_to_wm8962(struct gpio_chip *chip)
static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct wm8962_priv *wm8962 = gpio_to_wm8962(chip);
- struct snd_soc_codec *codec = wm8962->codec;
/* The WM8962 GPIOs aren't linearly numbered. For simplicity
* we export linear numbers and error out if the unsupported
@@ -3292,7 +3312,7 @@ static int wm8962_gpio_request(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
- wm8962_set_gpio_mode(codec, offset + 1);
+ wm8962_set_gpio_mode(wm8962, offset + 1);
return 0;
}
@@ -3376,8 +3396,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
{
int ret;
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
- struct wm8962_pdata *pdata = &wm8962->pdata;
- int i, trigger, irq_pol;
+ int i;
bool dmicclk, dmicdat;
wm8962->codec = codec;
@@ -3409,75 +3428,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
}
}
- /* SYSCLK defaults to on; make sure it is off so we can safely
- * write to registers if the device is declocked.
- */
- snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
-
- /* Ensure we have soft control over all registers */
- snd_soc_update_bits(codec, WM8962_CLOCKING2,
- WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
-
- /* Ensure that the oscillator and PLLs are disabled */
- snd_soc_update_bits(codec, WM8962_PLL2,
- WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
- 0);
-
- /* Apply static configuration for GPIOs */
- for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
- if (pdata->gpio_init[i]) {
- wm8962_set_gpio_mode(codec, i + 1);
- snd_soc_write(codec, 0x200 + i,
- pdata->gpio_init[i] & 0xffff);
- }
-
-
- /* Put the speakers into mono mode? */
- if (pdata->spk_mono)
- snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2,
- WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
-
- /* Micbias setup, detection enable and detection
- * threasholds. */
- if (pdata->mic_cfg)
- snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
- WM8962_MICDET_ENA |
- WM8962_MICDET_THR_MASK |
- WM8962_MICSHORT_THR_MASK |
- WM8962_MICBIAS_LVL,
- pdata->mic_cfg);
-
- /* Latch volume update bits */
- snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME,
- WM8962_IN_VU, WM8962_IN_VU);
- snd_soc_update_bits(codec, WM8962_RIGHT_INPUT_VOLUME,
- WM8962_IN_VU, WM8962_IN_VU);
- snd_soc_update_bits(codec, WM8962_LEFT_ADC_VOLUME,
- WM8962_ADC_VU, WM8962_ADC_VU);
- snd_soc_update_bits(codec, WM8962_RIGHT_ADC_VOLUME,
- WM8962_ADC_VU, WM8962_ADC_VU);
- snd_soc_update_bits(codec, WM8962_LEFT_DAC_VOLUME,
- WM8962_DAC_VU, WM8962_DAC_VU);
- snd_soc_update_bits(codec, WM8962_RIGHT_DAC_VOLUME,
- WM8962_DAC_VU, WM8962_DAC_VU);
- snd_soc_update_bits(codec, WM8962_SPKOUTL_VOLUME,
- WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
- snd_soc_update_bits(codec, WM8962_SPKOUTR_VOLUME,
- WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
- snd_soc_update_bits(codec, WM8962_HPOUTL_VOLUME,
- WM8962_HPOUT_VU, WM8962_HPOUT_VU);
- snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME,
- WM8962_HPOUT_VU, WM8962_HPOUT_VU);
-
- /* Stereo control for EQ */
- snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0);
-
- /* Don't debouce interrupts so we don't need SYSCLK */
- snd_soc_update_bits(codec, WM8962_IRQ_DEBOUNCE,
- WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
- WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
- 0);
-
wm8962_add_widgets(codec);
/* Save boards having to disable DMIC when not in use */
@@ -3506,36 +3456,6 @@ static int wm8962_probe(struct snd_soc_codec *codec)
wm8962_init_beep(codec);
wm8962_init_gpio(codec);
- if (wm8962->irq) {
- if (pdata->irq_active_low) {
- trigger = IRQF_TRIGGER_LOW;
- irq_pol = WM8962_IRQ_POL;
- } else {
- trigger = IRQF_TRIGGER_HIGH;
- irq_pol = 0;
- }
-
- snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL,
- WM8962_IRQ_POL, irq_pol);
-
- ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq,
- trigger | IRQF_ONESHOT,
- "wm8962", codec->dev);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
- wm8962->irq, ret);
- wm8962->irq = 0;
- /* Non-fatal */
- } else {
- /* Enable some IRQs by default */
- snd_soc_update_bits(codec,
- WM8962_INTERRUPT_STATUS_2_MASK,
- WM8962_FLL_LOCK_EINT |
- WM8962_TEMP_SHUT_EINT |
- WM8962_FIFOS_ERR_EINT, 0);
- }
- }
-
return 0;
}
@@ -3544,9 +3464,6 @@ static int wm8962_remove(struct snd_soc_codec *codec)
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int i;
- if (wm8962->irq)
- free_irq(wm8962->irq, codec);
-
cancel_delayed_work_sync(&wm8962->mic_work);
wm8962_free_gpio(codec);
@@ -3619,7 +3536,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
struct wm8962_pdata *pdata = dev_get_platdata(&i2c->dev);
struct wm8962_priv *wm8962;
unsigned int reg;
- int ret, i;
+ int ret, i, irq_pol, trigger;
wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv),
GFP_KERNEL);
@@ -3704,6 +3621,77 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
goto err_enable;
}
+ /* SYSCLK defaults to on; make sure it is off so we can safely
+ * write to registers if the device is declocked.
+ */
+ regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+ WM8962_SYSCLK_ENA, 0);
+
+ /* Ensure we have soft control over all registers */
+ regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+ WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
+ /* Ensure that the oscillator and PLLs are disabled */
+ regmap_update_bits(wm8962->regmap, WM8962_PLL2,
+ WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+ 0);
+
+ /* Apply static configuration for GPIOs */
+ for (i = 0; i < ARRAY_SIZE(wm8962->pdata.gpio_init); i++)
+ if (wm8962->pdata.gpio_init[i]) {
+ wm8962_set_gpio_mode(wm8962, i + 1);
+ regmap_write(wm8962->regmap, 0x200 + i,
+ wm8962->pdata.gpio_init[i] & 0xffff);
+ }
+
+
+ /* Put the speakers into mono mode? */
+ if (wm8962->pdata.spk_mono)
+ regmap_update_bits(wm8962->regmap, WM8962_CLASS_D_CONTROL_2,
+ WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
+
+ /* Micbias setup, detection enable and detection
+ * threasholds. */
+ if (wm8962->pdata.mic_cfg)
+ regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
+ WM8962_MICDET_ENA |
+ WM8962_MICDET_THR_MASK |
+ WM8962_MICSHORT_THR_MASK |
+ WM8962_MICBIAS_LVL,
+ wm8962->pdata.mic_cfg);
+
+ /* Latch volume update bits */
+ regmap_update_bits(wm8962->regmap, WM8962_LEFT_INPUT_VOLUME,
+ WM8962_IN_VU, WM8962_IN_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_RIGHT_INPUT_VOLUME,
+ WM8962_IN_VU, WM8962_IN_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_LEFT_ADC_VOLUME,
+ WM8962_ADC_VU, WM8962_ADC_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_RIGHT_ADC_VOLUME,
+ WM8962_ADC_VU, WM8962_ADC_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_LEFT_DAC_VOLUME,
+ WM8962_DAC_VU, WM8962_DAC_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_RIGHT_DAC_VOLUME,
+ WM8962_DAC_VU, WM8962_DAC_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_SPKOUTL_VOLUME,
+ WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_SPKOUTR_VOLUME,
+ WM8962_SPKOUT_VU, WM8962_SPKOUT_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_HPOUTL_VOLUME,
+ WM8962_HPOUT_VU, WM8962_HPOUT_VU);
+ regmap_update_bits(wm8962->regmap, WM8962_HPOUTR_VOLUME,
+ WM8962_HPOUT_VU, WM8962_HPOUT_VU);
+
+ /* Stereo control for EQ */
+ regmap_update_bits(wm8962->regmap, WM8962_EQ1,
+ WM8962_EQ_SHARED_COEFF, 0);
+
+ /* Don't debouce interrupts so we don't need SYSCLK */
+ regmap_update_bits(wm8962->regmap, WM8962_IRQ_DEBOUNCE,
+ WM8962_FLL_LOCK_DB | WM8962_PLL3_LOCK_DB |
+ WM8962_PLL2_LOCK_DB | WM8962_TEMP_SHUT_DB,
+ 0);
+
if (wm8962->pdata.in4_dc_measure) {
ret = regmap_register_patch(wm8962->regmap,
wm8962_dc_measure,
@@ -3714,6 +3702,37 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
ret);
}
+ if (wm8962->irq) {
+ if (wm8962->pdata.irq_active_low) {
+ trigger = IRQF_TRIGGER_LOW;
+ irq_pol = WM8962_IRQ_POL;
+ } else {
+ trigger = IRQF_TRIGGER_HIGH;
+ irq_pol = 0;
+ }
+
+ regmap_update_bits(wm8962->regmap, WM8962_INTERRUPT_CONTROL,
+ WM8962_IRQ_POL, irq_pol);
+
+ ret = devm_request_threaded_irq(&i2c->dev, wm8962->irq, NULL,
+ wm8962_irq,
+ trigger | IRQF_ONESHOT,
+ "wm8962", &i2c->dev);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+ wm8962->irq, ret);
+ wm8962->irq = 0;
+ /* Non-fatal */
+ } else {
+ /* Enable some IRQs by default */
+ regmap_update_bits(wm8962->regmap,
+ WM8962_INTERRUPT_STATUS_2_MASK,
+ WM8962_FLL_LOCK_EINT |
+ WM8962_TEMP_SHUT_EINT |
+ WM8962_FIFOS_ERR_EINT, 0);
+ }
+ }
+
pm_runtime_enable(&i2c->dev);
pm_request_idle(&i2c->dev);
@@ -3722,6 +3741,8 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
goto err_enable;
+ regcache_cache_only(wm8962->regmap, true);
+
/* The drivers should power up as needed */
regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index a2d01d10a5dd..15f45c7bd833 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -27,22 +28,22 @@
#include "wm8974.h"
-static const u16 wm8974_reg[WM8974_CACHEREGNUM] = {
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0050, 0x0000, 0x0140, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x00ff,
- 0x0000, 0x0000, 0x0100, 0x00ff,
- 0x0000, 0x0000, 0x012c, 0x002c,
- 0x002c, 0x002c, 0x002c, 0x0000,
- 0x0032, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0038, 0x000b, 0x0032, 0x0000,
- 0x0008, 0x000c, 0x0093, 0x00e9,
- 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0003, 0x0010, 0x0000, 0x0000,
- 0x0000, 0x0002, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0039, 0x0000,
- 0x0000,
+static const struct reg_default wm8974_reg_defaults[] = {
+ { 0, 0x0000 }, { 1, 0x0000 }, { 2, 0x0000 }, { 3, 0x0000 },
+ { 4, 0x0050 }, { 5, 0x0000 }, { 6, 0x0140 }, { 7, 0x0000 },
+ { 8, 0x0000 }, { 9, 0x0000 }, { 10, 0x0000 }, { 11, 0x00ff },
+ { 12, 0x0000 }, { 13, 0x0000 }, { 14, 0x0100 }, { 15, 0x00ff },
+ { 16, 0x0000 }, { 17, 0x0000 }, { 18, 0x012c }, { 19, 0x002c },
+ { 20, 0x002c }, { 21, 0x002c }, { 22, 0x002c }, { 23, 0x0000 },
+ { 24, 0x0032 }, { 25, 0x0000 }, { 26, 0x0000 }, { 27, 0x0000 },
+ { 28, 0x0000 }, { 29, 0x0000 }, { 30, 0x0000 }, { 31, 0x0000 },
+ { 32, 0x0038 }, { 33, 0x000b }, { 34, 0x0032 }, { 35, 0x0000 },
+ { 36, 0x0008 }, { 37, 0x000c }, { 38, 0x0093 }, { 39, 0x00e9 },
+ { 40, 0x0000 }, { 41, 0x0000 }, { 42, 0x0000 }, { 43, 0x0000 },
+ { 44, 0x0003 }, { 45, 0x0010 }, { 46, 0x0000 }, { 47, 0x0000 },
+ { 48, 0x0000 }, { 49, 0x0002 }, { 50, 0x0000 }, { 51, 0x0000 },
+ { 52, 0x0000 }, { 53, 0x0000 }, { 54, 0x0039 }, { 55, 0x0000 },
+ { 56, 0x0000 },
};
#define WM8974_POWER1_BIASEN 0x08
@@ -514,7 +515,7 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- snd_soc_cache_sync(codec);
+ regcache_sync(dev_get_regmap(codec->dev, NULL));
/* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
@@ -579,11 +580,20 @@ static int wm8974_resume(struct snd_soc_codec *codec)
return 0;
}
+static const struct regmap_config wm8974_regmap = {
+ .reg_bits = 7,
+ .val_bits = 9,
+
+ .max_register = WM8974_MONOMIX,
+ .reg_defaults = wm8974_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
+};
+
static int wm8974_probe(struct snd_soc_codec *codec)
{
int ret = 0;
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -613,9 +623,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
.suspend = wm8974_suspend,
.resume = wm8974_resume,
.set_bias_level = wm8974_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(wm8974_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = wm8974_reg,
.controls = wm8974_snd_controls,
.num_controls = ARRAY_SIZE(wm8974_snd_controls),
@@ -628,8 +635,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
static int wm8974_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ struct regmap *regmap;
int ret;
+ regmap = devm_regmap_init_i2c(i2c, &wm8974_regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8974, &wm8974_dai, 1);
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 18f2babe1090..271b517911a4 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -1148,7 +1148,7 @@ static struct spi_driver wm8985_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8985_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1201,7 +1201,7 @@ static int __init wm8985_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8985_i2c_driver);
if (ret) {
printk(KERN_ERR "Failed to register wm8985 I2C driver: %d\n",
@@ -1221,7 +1221,7 @@ module_init(wm8985_modinit);
static void __exit wm8985_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8985_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 39b9acceb595..a55e1c2c382e 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -912,7 +912,7 @@ static struct spi_driver wm8988_spi_driver = {
};
#endif /* CONFIG_SPI_MASTER */
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8988_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -964,7 +964,7 @@ static struct i2c_driver wm8988_i2c_driver = {
static int __init wm8988_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8988_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8988 I2C driver: %d\n",
@@ -984,7 +984,7 @@ module_init(wm8988_modinit);
static void __exit wm8988_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8988_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 253c88bb7a4c..0ccd4d8d043b 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -30,13 +31,12 @@
/* codec private data */
struct wm8990_priv {
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
unsigned int sysclk;
unsigned int pcmclk;
};
-static int wm8990_volatile_register(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8990_RESET:
@@ -46,71 +46,69 @@ static int wm8990_volatile_register(struct snd_soc_codec *codec,
}
}
-static const u16 wm8990_reg[] = {
- 0x8990, /* R0 - Reset */
- 0x0000, /* R1 - Power Management (1) */
- 0x6000, /* R2 - Power Management (2) */
- 0x0000, /* R3 - Power Management (3) */
- 0x4050, /* R4 - Audio Interface (1) */
- 0x4000, /* R5 - Audio Interface (2) */
- 0x01C8, /* R6 - Clocking (1) */
- 0x0000, /* R7 - Clocking (2) */
- 0x0040, /* R8 - Audio Interface (3) */
- 0x0040, /* R9 - Audio Interface (4) */
- 0x0004, /* R10 - DAC CTRL */
- 0x00C0, /* R11 - Left DAC Digital Volume */
- 0x00C0, /* R12 - Right DAC Digital Volume */
- 0x0000, /* R13 - Digital Side Tone */
- 0x0100, /* R14 - ADC CTRL */
- 0x00C0, /* R15 - Left ADC Digital Volume */
- 0x00C0, /* R16 - Right ADC Digital Volume */
- 0x0000, /* R17 */
- 0x0000, /* R18 - GPIO CTRL 1 */
- 0x1000, /* R19 - GPIO1 & GPIO2 */
- 0x1010, /* R20 - GPIO3 & GPIO4 */
- 0x1010, /* R21 - GPIO5 & GPIO6 */
- 0x8000, /* R22 - GPIOCTRL 2 */
- 0x0800, /* R23 - GPIO_POL */
- 0x008B, /* R24 - Left Line Input 1&2 Volume */
- 0x008B, /* R25 - Left Line Input 3&4 Volume */
- 0x008B, /* R26 - Right Line Input 1&2 Volume */
- 0x008B, /* R27 - Right Line Input 3&4 Volume */
- 0x0000, /* R28 - Left Output Volume */
- 0x0000, /* R29 - Right Output Volume */
- 0x0066, /* R30 - Line Outputs Volume */
- 0x0022, /* R31 - Out3/4 Volume */
- 0x0079, /* R32 - Left OPGA Volume */
- 0x0079, /* R33 - Right OPGA Volume */
- 0x0003, /* R34 - Speaker Volume */
- 0x0003, /* R35 - ClassD1 */
- 0x0000, /* R36 */
- 0x0100, /* R37 - ClassD3 */
- 0x0079, /* R38 - ClassD4 */
- 0x0000, /* R39 - Input Mixer1 */
- 0x0000, /* R40 - Input Mixer2 */
- 0x0000, /* R41 - Input Mixer3 */
- 0x0000, /* R42 - Input Mixer4 */
- 0x0000, /* R43 - Input Mixer5 */
- 0x0000, /* R44 - Input Mixer6 */
- 0x0000, /* R45 - Output Mixer1 */
- 0x0000, /* R46 - Output Mixer2 */
- 0x0000, /* R47 - Output Mixer3 */
- 0x0000, /* R48 - Output Mixer4 */
- 0x0000, /* R49 - Output Mixer5 */
- 0x0000, /* R50 - Output Mixer6 */
- 0x0180, /* R51 - Out3/4 Mixer */
- 0x0000, /* R52 - Line Mixer1 */
- 0x0000, /* R53 - Line Mixer2 */
- 0x0000, /* R54 - Speaker Mixer */
- 0x0000, /* R55 - Additional Control */
- 0x0000, /* R56 - AntiPOP1 */
- 0x0000, /* R57 - AntiPOP2 */
- 0x0000, /* R58 - MICBIAS */
- 0x0000, /* R59 */
- 0x0008, /* R60 - PLL1 */
- 0x0031, /* R61 - PLL2 */
- 0x0026, /* R62 - PLL3 */
- 0x0000, /* R63 - Driver internal */
+static const struct reg_default wm8990_reg_defaults[] = {
+ { 1, 0x0000 }, /* R1 - Power Management (1) */
+ { 2, 0x6000 }, /* R2 - Power Management (2) */
+ { 3, 0x0000 }, /* R3 - Power Management (3) */
+ { 4, 0x4050 }, /* R4 - Audio Interface (1) */
+ { 5, 0x4000 }, /* R5 - Audio Interface (2) */
+ { 6, 0x01C8 }, /* R6 - Clocking (1) */
+ { 7, 0x0000 }, /* R7 - Clocking (2) */
+ { 8, 0x0040 }, /* R8 - Audio Interface (3) */
+ { 9, 0x0040 }, /* R9 - Audio Interface (4) */
+ { 10, 0x0004 }, /* R10 - DAC CTRL */
+ { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */
+ { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */
+ { 13, 0x0000 }, /* R13 - Digital Side Tone */
+ { 14, 0x0100 }, /* R14 - ADC CTRL */
+ { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */
+ { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */
+
+ { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */
+ { 19, 0x1000 }, /* R19 - GPIO1 & GPIO2 */
+ { 20, 0x1010 }, /* R20 - GPIO3 & GPIO4 */
+ { 21, 0x1010 }, /* R21 - GPIO5 & GPIO6 */
+ { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */
+ { 23, 0x0800 }, /* R23 - GPIO_POL */
+ { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
+ { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
+ { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
+ { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
+ { 28, 0x0000 }, /* R28 - Left Output Volume */
+ { 29, 0x0000 }, /* R29 - Right Output Volume */
+ { 30, 0x0066 }, /* R30 - Line Outputs Volume */
+ { 31, 0x0022 }, /* R31 - Out3/4 Volume */
+ { 32, 0x0079 }, /* R32 - Left OPGA Volume */
+ { 33, 0x0079 }, /* R33 - Right OPGA Volume */
+ { 34, 0x0003 }, /* R34 - Speaker Volume */
+ { 35, 0x0003 }, /* R35 - ClassD1 */
+
+ { 37, 0x0100 }, /* R37 - ClassD3 */
+ { 38, 0x0079 }, /* R38 - ClassD4 */
+ { 39, 0x0000 }, /* R39 - Input Mixer1 */
+ { 40, 0x0000 }, /* R40 - Input Mixer2 */
+ { 41, 0x0000 }, /* R41 - Input Mixer3 */
+ { 42, 0x0000 }, /* R42 - Input Mixer4 */
+ { 43, 0x0000 }, /* R43 - Input Mixer5 */
+ { 44, 0x0000 }, /* R44 - Input Mixer6 */
+ { 45, 0x0000 }, /* R45 - Output Mixer1 */
+ { 46, 0x0000 }, /* R46 - Output Mixer2 */
+ { 47, 0x0000 }, /* R47 - Output Mixer3 */
+ { 48, 0x0000 }, /* R48 - Output Mixer4 */
+ { 49, 0x0000 }, /* R49 - Output Mixer5 */
+ { 50, 0x0000 }, /* R50 - Output Mixer6 */
+ { 51, 0x0180 }, /* R51 - Out3/4 Mixer */
+ { 52, 0x0000 }, /* R52 - Line Mixer1 */
+ { 53, 0x0000 }, /* R53 - Line Mixer2 */
+ { 54, 0x0000 }, /* R54 - Speaker Mixer */
+ { 55, 0x0000 }, /* R55 - Additional Control */
+ { 56, 0x0000 }, /* R56 - AntiPOP1 */
+ { 57, 0x0000 }, /* R57 - AntiPOP2 */
+ { 58, 0x0000 }, /* R58 - MICBIAS */
+
+ { 60, 0x0008 }, /* R60 - PLL1 */
+ { 61, 0x0031 }, /* R61 - PLL2 */
+ { 62, 0x0026 }, /* R62 - PLL3 */
};
#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0)
@@ -376,32 +374,6 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
* _DAPM_ Controls
*/
-static int inmixer_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- u16 reg, fakepower;
-
- reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2);
- fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS);
-
- if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) |
- (1 << WM8990_AINLMUX_PWR_BIT))) {
- reg |= WM8990_AINL_ENA;
- } else {
- reg &= ~WM8990_AINL_ENA;
- }
-
- if (fakepower & ((1 << WM8990_INMIXR_PWR_BIT) |
- (1 << WM8990_AINRMUX_PWR_BIT))) {
- reg |= WM8990_AINR_ENA;
- } else {
- reg &= ~WM8990_AINR_ENA;
- }
- snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
-
- return 0;
-}
-
static int outmixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -656,6 +628,11 @@ SND_SOC_DAPM_INPUT("RIN1"),
SND_SOC_DAPM_INPUT("RIN2"),
SND_SOC_DAPM_INPUT("Internal ADC Source"),
+SND_SOC_DAPM_SUPPLY("INL", WM8990_POWER_MANAGEMENT_2, WM8990_AINL_ENA_BIT, 0,
+ NULL, 0),
+SND_SOC_DAPM_SUPPLY("INR", WM8990_POWER_MANAGEMENT_2, WM8990_AINR_ENA_BIT, 0,
+ NULL, 0),
+
/* DACs */
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8990_POWER_MANAGEMENT_2,
WM8990_ADCL_ENA_BIT, 0),
@@ -677,26 +654,20 @@ SND_SOC_DAPM_MIXER("RIN34 PGA", WM8990_POWER_MANAGEMENT_2, WM8990_RIN34_ENA_BIT,
ARRAY_SIZE(wm8990_dapm_rin34_pga_controls)),
/* INMIXL */
-SND_SOC_DAPM_MIXER_E("INMIXL", WM8990_INTDRIVBITS, WM8990_INMIXL_PWR_BIT, 0,
+SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
&wm8990_dapm_inmixl_controls[0],
- ARRAY_SIZE(wm8990_dapm_inmixl_controls),
- inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ ARRAY_SIZE(wm8990_dapm_inmixl_controls)),
/* AINLMUX */
-SND_SOC_DAPM_MUX_E("AINLMUX", WM8990_INTDRIVBITS, WM8990_AINLMUX_PWR_BIT, 0,
- &wm8990_dapm_ainlmux_controls, inmixer_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainlmux_controls),
/* INMIXR */
-SND_SOC_DAPM_MIXER_E("INMIXR", WM8990_INTDRIVBITS, WM8990_INMIXR_PWR_BIT, 0,
+SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
&wm8990_dapm_inmixr_controls[0],
- ARRAY_SIZE(wm8990_dapm_inmixr_controls),
- inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ ARRAY_SIZE(wm8990_dapm_inmixr_controls)),
/* AINRMUX */
-SND_SOC_DAPM_MUX_E("AINRMUX", WM8990_INTDRIVBITS, WM8990_AINRMUX_PWR_BIT, 0,
- &wm8990_dapm_ainrmux_controls, inmixer_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0, &wm8990_dapm_ainrmux_controls),
/* Output Side */
/* DACs */
@@ -787,7 +758,7 @@ SND_SOC_DAPM_OUTPUT("RON"),
SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
};
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8990_dapm_routes[] = {
/* 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"},
@@ -796,6 +767,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Left ADC", NULL, "Internal ADC Source"},
{"Right ADC", NULL, "Internal ADC Source"},
+ {"AINLMUX", NULL, "INL"},
+ {"INMIXL", NULL, "INL"},
+ {"AINRMUX", NULL, "INR"},
+ {"INMIXR", NULL, "INR"},
+
/* Input Side */
/* LIN12 PGA */
{"LIN12 PGA", "LIN1 Switch", "LIN1"},
@@ -912,18 +888,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"RON", NULL, "RONMIX"},
};
-static int wm8990_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, wm8990_dapm_widgets,
- ARRAY_SIZE(wm8990_dapm_widgets));
- /* set up the WM8990 audio map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
- return 0;
-}
-
/* PLL divisors */
struct _pll_div {
u32 div2;
@@ -1148,6 +1112,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
static int wm8990_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) {
@@ -1162,7 +1127,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- ret = snd_soc_cache_sync(codec);
+ ret = regcache_sync(wm8990->regmap);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
return ret;
@@ -1259,6 +1224,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write(codec, WM8990_ANTIPOP2, 0x0);
+
+ regcache_mark_dirty(wm8990->regmap);
break;
}
@@ -1327,7 +1294,7 @@ static int wm8990_probe(struct snd_soc_codec *codec)
{
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret < 0) {
printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret);
return ret;
@@ -1350,10 +1317,6 @@ static int wm8990_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
- snd_soc_add_codec_controls(codec, wm8990_snd_controls,
- ARRAY_SIZE(wm8990_snd_controls));
- wm8990_add_widgets(codec);
-
return 0;
}
@@ -1370,13 +1333,25 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
.suspend = wm8990_suspend,
.resume = wm8990_resume,
.set_bias_level = wm8990_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(wm8990_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = wm8990_reg,
- .volatile_register = wm8990_volatile_register,
+ .controls = wm8990_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8990_snd_controls),
+ .dapm_widgets = wm8990_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8990_dapm_widgets),
+ .dapm_routes = wm8990_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8990_dapm_routes),
+};
+
+static const struct regmap_config wm8990_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = WM8990_PLL3,
+ .volatile_reg = wm8990_volatile_register,
+ .reg_defaults = wm8990_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8990_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1418,29 +1393,8 @@ static struct i2c_driver wm8990_i2c_driver = {
.remove = wm8990_i2c_remove,
.id_table = wm8990_i2c_id,
};
-#endif
-static int __init wm8990_modinit(void)
-{
- int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- ret = i2c_add_driver(&wm8990_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "Failed to register wm8990 I2C driver: %d\n",
- ret);
- }
-#endif
- return ret;
-}
-module_init(wm8990_modinit);
-
-static void __exit wm8990_exit(void)
-{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_del_driver(&wm8990_i2c_driver);
-#endif
-}
-module_exit(wm8990_exit);
+module_i2c_driver(wm8990_i2c_driver);
MODULE_DESCRIPTION("ASoC WM8990 driver");
MODULE_AUTHOR("Liam Girdwood");
diff --git a/sound/soc/codecs/wm8990.h b/sound/soc/codecs/wm8990.h
index 77c98a4bfe9c..0e9c78040c4c 100644
--- a/sound/soc/codecs/wm8990.h
+++ b/sound/soc/codecs/wm8990.h
@@ -78,7 +78,6 @@
#define WM8990_PLL1 0x3C
#define WM8990_PLL2 0x3D
#define WM8990_PLL3 0x3E
-#define WM8990_INTDRIVBITS 0x3F
#define WM8990_EXT_ACCESS_ENA 0x75
#define WM8990_EXT_CTL1 0x7a
@@ -818,14 +817,6 @@
*/
#define WM8990_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */
-/*
- * R63 (0x3F) - Internal Driver Bits
- */
-#define WM8990_INMIXL_PWR_BIT 0
-#define WM8990_AINLMUX_PWR_BIT 1
-#define WM8990_INMIXR_PWR_BIT 2
-#define WM8990_AINRMUX_PWR_BIT 3
-
#define WM8990_MCLK_DIV 0
#define WM8990_DACCLK_DIV 1
#define WM8990_ADCCLK_DIV 2
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 3a39df7a3829..dba0306c42a5 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -31,77 +32,84 @@
#include "wm8991.h"
struct wm8991_priv {
- enum snd_soc_control_type control_type;
+ struct regmap *regmap;
unsigned int pcmclk;
};
-static const u16 wm8991_reg_defs[] = {
- 0x8991, /* R0 - Reset */
- 0x0000, /* R1 - Power Management (1) */
- 0x6000, /* R2 - Power Management (2) */
- 0x0000, /* R3 - Power Management (3) */
- 0x4050, /* R4 - Audio Interface (1) */
- 0x4000, /* R5 - Audio Interface (2) */
- 0x01C8, /* R6 - Clocking (1) */
- 0x0000, /* R7 - Clocking (2) */
- 0x0040, /* R8 - Audio Interface (3) */
- 0x0040, /* R9 - Audio Interface (4) */
- 0x0004, /* R10 - DAC CTRL */
- 0x00C0, /* R11 - Left DAC Digital Volume */
- 0x00C0, /* R12 - Right DAC Digital Volume */
- 0x0000, /* R13 - Digital Side Tone */
- 0x0100, /* R14 - ADC CTRL */
- 0x00C0, /* R15 - Left ADC Digital Volume */
- 0x00C0, /* R16 - Right ADC Digital Volume */
- 0x0000, /* R17 */
- 0x0000, /* R18 - GPIO CTRL 1 */
- 0x1000, /* R19 - GPIO1 & GPIO2 */
- 0x1010, /* R20 - GPIO3 & GPIO4 */
- 0x1010, /* R21 - GPIO5 & GPIO6 */
- 0x8000, /* R22 - GPIOCTRL 2 */
- 0x0800, /* R23 - GPIO_POL */
- 0x008B, /* R24 - Left Line Input 1&2 Volume */
- 0x008B, /* R25 - Left Line Input 3&4 Volume */
- 0x008B, /* R26 - Right Line Input 1&2 Volume */
- 0x008B, /* R27 - Right Line Input 3&4 Volume */
- 0x0000, /* R28 - Left Output Volume */
- 0x0000, /* R29 - Right Output Volume */
- 0x0066, /* R30 - Line Outputs Volume */
- 0x0022, /* R31 - Out3/4 Volume */
- 0x0079, /* R32 - Left OPGA Volume */
- 0x0079, /* R33 - Right OPGA Volume */
- 0x0003, /* R34 - Speaker Volume */
- 0x0003, /* R35 - ClassD1 */
- 0x0000, /* R36 */
- 0x0100, /* R37 - ClassD3 */
- 0x0000, /* R38 */
- 0x0000, /* R39 - Input Mixer1 */
- 0x0000, /* R40 - Input Mixer2 */
- 0x0000, /* R41 - Input Mixer3 */
- 0x0000, /* R42 - Input Mixer4 */
- 0x0000, /* R43 - Input Mixer5 */
- 0x0000, /* R44 - Input Mixer6 */
- 0x0000, /* R45 - Output Mixer1 */
- 0x0000, /* R46 - Output Mixer2 */
- 0x0000, /* R47 - Output Mixer3 */
- 0x0000, /* R48 - Output Mixer4 */
- 0x0000, /* R49 - Output Mixer5 */
- 0x0000, /* R50 - Output Mixer6 */
- 0x0180, /* R51 - Out3/4 Mixer */
- 0x0000, /* R52 - Line Mixer1 */
- 0x0000, /* R53 - Line Mixer2 */
- 0x0000, /* R54 - Speaker Mixer */
- 0x0000, /* R55 - Additional Control */
- 0x0000, /* R56 - AntiPOP1 */
- 0x0000, /* R57 - AntiPOP2 */
- 0x0000, /* R58 - MICBIAS */
- 0x0000, /* R59 */
- 0x0008, /* R60 - PLL1 */
- 0x0031, /* R61 - PLL2 */
- 0x0026, /* R62 - PLL3 */
+static const struct reg_default wm8991_reg_defaults[] = {
+ { 1, 0x0000 }, /* R1 - Power Management (1) */
+ { 2, 0x6000 }, /* R2 - Power Management (2) */
+ { 3, 0x0000 }, /* R3 - Power Management (3) */
+ { 4, 0x4050 }, /* R4 - Audio Interface (1) */
+ { 5, 0x4000 }, /* R5 - Audio Interface (2) */
+ { 6, 0x01C8 }, /* R6 - Clocking (1) */
+ { 7, 0x0000 }, /* R7 - Clocking (2) */
+ { 8, 0x0040 }, /* R8 - Audio Interface (3) */
+ { 9, 0x0040 }, /* R9 - Audio Interface (4) */
+ { 10, 0x0004 }, /* R10 - DAC CTRL */
+ { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */
+ { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */
+ { 13, 0x0000 }, /* R13 - Digital Side Tone */
+ { 14, 0x0100 }, /* R14 - ADC CTRL */
+ { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */
+ { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */
+
+ { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */
+ { 19, 0x1000 }, /* R19 - GPIO1 & GPIO2 */
+ { 20, 0x1010 }, /* R20 - GPIO3 & GPIO4 */
+ { 21, 0x1010 }, /* R21 - GPIO5 & GPIO6 */
+ { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */
+ { 23, 0x0800 }, /* R23 - GPIO_POL */
+ { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
+ { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
+ { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
+ { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
+ { 28, 0x0000 }, /* R28 - Left Output Volume */
+ { 29, 0x0000 }, /* R29 - Right Output Volume */
+ { 30, 0x0066 }, /* R30 - Line Outputs Volume */
+ { 31, 0x0022 }, /* R31 - Out3/4 Volume */
+ { 32, 0x0079 }, /* R32 - Left OPGA Volume */
+ { 33, 0x0079 }, /* R33 - Right OPGA Volume */
+ { 34, 0x0003 }, /* R34 - Speaker Volume */
+ { 35, 0x0003 }, /* R35 - ClassD1 */
+
+ { 37, 0x0100 }, /* R37 - ClassD3 */
+
+ { 39, 0x0000 }, /* R39 - Input Mixer1 */
+ { 40, 0x0000 }, /* R40 - Input Mixer2 */
+ { 41, 0x0000 }, /* R41 - Input Mixer3 */
+ { 42, 0x0000 }, /* R42 - Input Mixer4 */
+ { 43, 0x0000 }, /* R43 - Input Mixer5 */
+ { 44, 0x0000 }, /* R44 - Input Mixer6 */
+ { 45, 0x0000 }, /* R45 - Output Mixer1 */
+ { 46, 0x0000 }, /* R46 - Output Mixer2 */
+ { 47, 0x0000 }, /* R47 - Output Mixer3 */
+ { 48, 0x0000 }, /* R48 - Output Mixer4 */
+ { 49, 0x0000 }, /* R49 - Output Mixer5 */
+ { 50, 0x0000 }, /* R50 - Output Mixer6 */
+ { 51, 0x0180 }, /* R51 - Out3/4 Mixer */
+ { 52, 0x0000 }, /* R52 - Line Mixer1 */
+ { 53, 0x0000 }, /* R53 - Line Mixer2 */
+ { 54, 0x0000 }, /* R54 - Speaker Mixer */
+ { 55, 0x0000 }, /* R55 - Additional Control */
+ { 56, 0x0000 }, /* R56 - AntiPOP1 */
+ { 57, 0x0000 }, /* R57 - AntiPOP2 */
+ { 58, 0x0000 }, /* R58 - MICBIAS */
+
+ { 60, 0x0008 }, /* R60 - PLL1 */
+ { 61, 0x0031 }, /* R61 - PLL2 */
+ { 62, 0x0026 }, /* R62 - PLL3 */
};
-#define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0)
+static bool wm8991_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8991_RESET:
+ return true;
+ default:
+ return false;
+ }
+}
static const unsigned int rec_mix_tlv[] = {
TLV_DB_RANGE_HEAD(1),
@@ -374,30 +382,6 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
/*
* _DAPM_ Controls
*/
-static int inmixer_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- u16 reg, fakepower;
-
- reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2);
- fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS);
-
- if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) |
- (1 << WM8991_AINLMUX_PWR_BIT)))
- reg |= WM8991_AINL_ENA;
- else
- reg &= ~WM8991_AINL_ENA;
-
- if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) |
- (1 << WM8991_AINRMUX_PWR_BIT)))
- reg |= WM8991_AINR_ENA;
- else
- reg &= ~WM8991_AINR_ENA;
-
- snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
- return 0;
-}
-
static int outmixer_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -655,6 +639,11 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("RIN2"),
SND_SOC_DAPM_INPUT("Internal ADC Source"),
+ SND_SOC_DAPM_SUPPLY("INL", WM8991_POWER_MANAGEMENT_2,
+ WM8991_AINL_ENA_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("INR", WM8991_POWER_MANAGEMENT_2,
+ WM8991_AINR_ENA_BIT, 0, NULL, 0),
+
/* DACs */
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2,
WM8991_ADCL_ENA_BIT, 0),
@@ -676,26 +665,22 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)),
/* INMIXL */
- SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0,
+ SND_SOC_DAPM_MIXER("INMIXL", SND_SOC_NOPM, 0, 0,
&wm8991_dapm_inmixl_controls[0],
- ARRAY_SIZE(wm8991_dapm_inmixl_controls),
- inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ ARRAY_SIZE(wm8991_dapm_inmixl_controls)),
/* AINLMUX */
- SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0,
- &wm8991_dapm_ainlmux_controls, inmixer_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("AINLMUX", SND_SOC_NOPM, 0, 0,
+ &wm8991_dapm_ainlmux_controls),
/* INMIXR */
- SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0,
+ SND_SOC_DAPM_MIXER("INMIXR", SND_SOC_NOPM, 0, 0,
&wm8991_dapm_inmixr_controls[0],
- ARRAY_SIZE(wm8991_dapm_inmixr_controls),
- inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ ARRAY_SIZE(wm8991_dapm_inmixr_controls)),
/* AINRMUX */
- SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0,
- &wm8991_dapm_ainrmux_controls, inmixer_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("AINRMUX", SND_SOC_NOPM, 0, 0,
+ &wm8991_dapm_ainrmux_controls),
/* Output Side */
/* DACs */
@@ -787,7 +772,7 @@ static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
};
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm8991_dapm_routes[] = {
/* 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"},
@@ -797,6 +782,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Right ADC", NULL, "Internal ADC Source"},
/* Input Side */
+ {"INMIXL", NULL, "INL"},
+ {"AINLMUX", NULL, "INL"},
+ {"INMIXR", NULL, "INR"},
+ {"AINRMUX", NULL, "INR"},
/* LIN12 PGA */
{"LIN12 PGA", "LIN1 Switch", "LIN1"},
{"LIN12 PGA", "LIN2 Switch", "LIN2"},
@@ -1129,6 +1118,7 @@ static int wm8991_mute(struct snd_soc_dai *dai, int mute)
static int wm8991_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct wm8991_priv *wm8991 = snd_soc_codec_get_drvdata(codec);
u16 val;
switch (level) {
@@ -1144,7 +1134,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
- snd_soc_cache_sync(codec);
+ regcache_sync(wm8991->regmap);
/* Enable all output discharge bits */
snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE |
WM8991_DIS_RLINE | WM8991_DIS_OUT3 |
@@ -1232,7 +1222,7 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
snd_soc_write(codec, WM8991_ANTIPOP2, 0x0);
- codec->cache_sync = 1;
+ regcache_mark_dirty(wm8991->regmap);
break;
}
@@ -1266,44 +1256,14 @@ static int wm8991_probe(struct snd_soc_codec *codec)
wm8991 = snd_soc_codec_get_drvdata(codec);
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type);
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret);
return ret;
}
- ret = wm8991_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
- }
-
wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4,
- WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
-
- snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2,
- WM8991_GPIO1_SEL_MASK, 1);
-
- snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1,
- WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
- WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
-
- snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2,
- WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
-
- snd_soc_write(codec, WM8991_DAC_CTRL, 0);
- snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
- snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
-
- snd_soc_add_codec_controls(codec, wm8991_snd_controls,
- ARRAY_SIZE(wm8991_snd_controls));
-
- snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets,
- ARRAY_SIZE(wm8991_dapm_widgets));
- snd_soc_dapm_add_routes(&codec->dapm, audio_map,
- ARRAY_SIZE(audio_map));
return 0;
}
@@ -1352,24 +1312,77 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
.suspend = wm8991_suspend,
.resume = wm8991_resume,
.set_bias_level = wm8991_set_bias_level,
- .reg_cache_size = WM8991_MAX_REGISTER + 1,
- .reg_word_size = sizeof(u16),
- .reg_cache_default = wm8991_reg_defs
+ .controls = wm8991_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8991_snd_controls),
+ .dapm_widgets = wm8991_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8991_dapm_widgets),
+ .dapm_routes = wm8991_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(wm8991_dapm_routes),
+};
+
+static const struct regmap_config wm8991_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = WM8991_PLL3,
+ .volatile_reg = wm8991_volatile,
+ .reg_defaults = wm8991_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8991_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
};
static int wm8991_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8991_priv *wm8991;
+ unsigned int val;
int ret;
wm8991 = devm_kzalloc(&i2c->dev, sizeof(*wm8991), GFP_KERNEL);
if (!wm8991)
return -ENOMEM;
- wm8991->control_type = SND_SOC_I2C;
+ wm8991->regmap = devm_regmap_init_i2c(i2c, &wm8991_regmap);
+ if (IS_ERR(wm8991->regmap))
+ return PTR_ERR(wm8991->regmap);
+
i2c_set_clientdata(i2c, wm8991);
+ ret = regmap_read(wm8991->regmap, WM8991_RESET, &val);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to read device ID: %d\n", ret);
+ return ret;
+ }
+ if (val != 0x8991) {
+ dev_err(&i2c->dev, "Device with ID %x is not a WM8991\n", val);
+ return -EINVAL;
+ }
+
+ ret = regmap_write(wm8991->regmap, WM8991_RESET, 0);
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret);
+ return ret;
+ }
+
+ regmap_update_bits(wm8991->regmap, WM8991_AUDIO_INTERFACE_4,
+ WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
+
+ regmap_update_bits(wm8991->regmap, WM8991_GPIO1_GPIO2,
+ WM8991_GPIO1_SEL_MASK, 1);
+
+ regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_1,
+ WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
+ WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
+
+ regmap_update_bits(wm8991->regmap, WM8991_POWER_MANAGEMENT_2,
+ WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
+
+ regmap_write(wm8991->regmap, WM8991_DAC_CTRL, 0);
+ regmap_write(wm8991->regmap, WM8991_LEFT_OUTPUT_VOLUME,
+ 0x50 | (1<<8));
+ regmap_write(wm8991->regmap, WM8991_RIGHT_OUTPUT_VOLUME,
+ 0x50 | (1<<8));
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8991, &wm8991_dai, 1);
diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h
index 07707d8d7e20..08ed383303c0 100644
--- a/sound/soc/codecs/wm8991.h
+++ b/sound/soc/codecs/wm8991.h
@@ -76,7 +76,6 @@
#define WM8991_PLL1 0x3C
#define WM8991_PLL2 0x3D
#define WM8991_PLL3 0x3E
-#define WM8991_INTDRIVBITS 0x3F
#define WM8991_REGISTER_COUNT 60
#define WM8991_MAX_REGISTER 0x3F
@@ -807,14 +806,6 @@
*/
#define WM8991_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */
-/*
- * R63 (0x3F) - Internal Driver Bits
- */
-#define WM8991_INMIXL_PWR_BIT 0
-#define WM8991_AINLMUX_PWR_BIT 1
-#define WM8991_INMIXR_PWR_BIT 2
-#define WM8991_AINRMUX_PWR_BIT 3
-
#define WM8991_MCLK_DIV 0
#define WM8991_DACCLK_DIV 1
#define WM8991_ADCCLK_DIV 2
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 86426a117b07..b9be9cbc4603 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4077,12 +4077,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_TEMP_SHUT,
wm8994_temp_shut, "Thermal shutdown", codec);
- ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
- wm_hubs_dcs_done, "DC servo done",
- &wm8994->hubs);
- if (ret == 0)
- wm8994->hubs.dcs_done_irq = true;
-
switch (control->type) {
case WM8994:
if (wm8994->micdet_irq) {
@@ -4313,6 +4307,11 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
}
wm_hubs_add_analogue_routes(codec, 0, 0);
+ ret = wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_DCS_DONE,
+ wm_hubs_dcs_done, "DC servo done",
+ &wm8994->hubs);
+ if (ret == 0)
+ wm8994->hubs.dcs_done_irq = true;
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
switch (control->type) {
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index da2899e6c401..4300caff1783 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -2293,7 +2293,7 @@ static struct spi_driver wm8995_spi_driver = {
};
#endif
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm8995_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -2350,7 +2350,7 @@ static int __init wm8995_modinit(void)
{
int ret = 0;
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
ret = i2c_add_driver(&wm8995_i2c_driver);
if (ret) {
printk(KERN_ERR "Failed to register wm8995 I2C driver: %d\n",
@@ -2371,7 +2371,7 @@ module_init(wm8995_modinit);
static void __exit wm8995_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
i2c_del_driver(&wm8995_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 46fe83d2b224..1a7655b0aa22 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -438,6 +438,8 @@ static int wm8996_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
int block = wm8996_get_retune_mobile_block(kcontrol->id.name);
+ if (block < 0)
+ return block;
ucontrol->value.enumerated.item[0] = wm8996->retune_mobile_cfg[block];
return 0;
@@ -608,7 +610,7 @@ static int bg_event(struct snd_soc_dapm_widget *w,
wm8996_bg_disable(codec);
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
ret = -EINVAL;
}
@@ -625,7 +627,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
msleep(5);
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
ret = -EINVAL;
}
@@ -646,7 +648,7 @@ static int rmv_short_event(struct snd_soc_dapm_widget *w,
wm8996->hpout_pending |= w->shift;
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
return -EINVAL;
}
@@ -767,7 +769,7 @@ static int dcs_start(struct snd_soc_dapm_widget *w,
wm8996->dcs_pending |= 1 << w->shift;
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
return -EINVAL;
}
@@ -1656,7 +1658,7 @@ static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
lrclk_rx_reg = WM8996_AIF2_RX_LRCLK_2;
break;
default:
- BUG();
+ WARN(1, "Invalid dai id %d\n", dai->id);
return -EINVAL;
}
@@ -1768,7 +1770,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
dsp_shift = WM8996_DSP2_DIV_SHIFT;
break;
default:
- BUG();
+ WARN(1, "Invalid dai id %d\n", dai->id);
return -EINVAL;
}
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
index 6ec3de3efa4f..555115ee2159 100644
--- a/sound/soc/codecs/wm8997.c
+++ b/sound/soc/codecs/wm8997.c
@@ -103,8 +103,8 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
if (patch)
for (i = 0; i < patch_size; i++)
- regmap_write(regmap, patch[i].reg,
- patch[i].def);
+ regmap_write_async(regmap, patch[i].reg,
+ patch[i].def);
break;
default:
break;
@@ -170,13 +170,13 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
-SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21,
+SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21,
ARIZONA_EQ1_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21,
+SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21,
ARIZONA_EQ2_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21,
+SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21,
ARIZONA_EQ3_ENA_MASK),
-SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21,
+SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21,
ARIZONA_EQ4_ENA_MASK),
SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
@@ -887,7 +887,7 @@ static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {
ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
- ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC2INT2"),
+ ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 630b3d776ec2..0982c1d38ec4 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1326,7 +1326,7 @@ static const struct regmap_config wm9081_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if IS_ENABLED(CONFIG_I2C)
static int wm9081_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index a53e175c015a..acea8927905b 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -221,7 +221,8 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = w->codec;
u16 status, rate;
- BUG_ON(event != SND_SOC_DAPM_PRE_PMD);
+ if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
+ return -EINVAL;
/* Gracefully shut down the voice interface. */
status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index b38f3506418f..444626fcab40 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -341,6 +341,8 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
unsigned int offset)
{
+ if (WARN_ON(!region))
+ return offset;
switch (region->type) {
case WMFW_ADSP1_PM:
return region->base + (offset * 3);
@@ -353,7 +355,7 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
case WMFW_ADSP1_ZM:
return region->base + (offset * 2);
default:
- WARN_ON(NULL != "Unknown memory region type");
+ WARN(1, "Unknown memory region type");
return offset;
}
}
@@ -396,11 +398,12 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
ret = regmap_raw_write(adsp->regmap, reg, scratch,
ctl->len);
if (ret) {
- adsp_err(adsp, "Failed to write %zu bytes to %x\n",
- ctl->len, reg);
+ adsp_err(adsp, "Failed to write %zu bytes to %x: %d\n",
+ ctl->len, reg, ret);
kfree(scratch);
return ret;
}
+ adsp_dbg(adsp, "Wrote %zu bytes to %x\n", ctl->len, reg);
kfree(scratch);
@@ -450,11 +453,12 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);
if (ret) {
- adsp_err(adsp, "Failed to read %zu bytes from %x\n",
- ctl->len, reg);
+ adsp_err(adsp, "Failed to read %zu bytes from %x: %d\n",
+ ctl->len, reg, ret);
kfree(scratch);
return ret;
}
+ adsp_dbg(adsp, "Read %zu bytes from %x\n", ctl->len, reg);
memcpy(buf, scratch, ctl->len);
kfree(scratch);
@@ -568,6 +572,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
file, header->ver);
goto out_fw;
}
+ adsp_info(dsp, "Firmware version: %d\n", header->ver);
if (header->core != dsp->type) {
adsp_err(dsp, "%s: invalid core %d != %d\n",
@@ -602,7 +607,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
break;
default:
- BUG_ON(NULL == "Unknown DSP type");
+ WARN(1, "Unknown DSP type");
goto out_fw;
}
@@ -642,27 +647,22 @@ static int wm_adsp_load(struct wm_adsp *dsp)
reg = offset;
break;
case WMFW_ADSP1_PM:
- BUG_ON(!mem);
region_name = "PM";
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP1_DM:
- BUG_ON(!mem);
region_name = "DM";
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP2_XM:
- BUG_ON(!mem);
region_name = "XM";
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP2_YM:
- BUG_ON(!mem);
region_name = "YM";
reg = wm_adsp_region_to_reg(mem, offset);
break;
case WMFW_ADSP1_ZM:
- BUG_ON(!mem);
region_name = "ZM";
reg = wm_adsp_region_to_reg(mem, offset);
break;
@@ -689,7 +689,8 @@ static int wm_adsp_load(struct wm_adsp *dsp)
&buf_list);
if (!buf) {
adsp_err(dsp, "Out of memory\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_fw;
}
ret = regmap_raw_write_async(regmap, reg, buf->buf,
@@ -901,10 +902,8 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
break;
}
- if (mem == NULL) {
- BUG_ON(mem != NULL);
+ if (WARN_ON(!mem))
return -EINVAL;
- }
switch (dsp->type) {
case WMFW_ADSP1:
@@ -998,7 +997,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
break;
default:
- BUG_ON(NULL == "Unknown DSP type");
+ WARN(1, "Unknown DSP type");
return -EINVAL;
}
@@ -1062,6 +1061,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
region->len -= be32_to_cpu(adsp1_alg[i].dm);
+ region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
@@ -1079,6 +1079,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
region->len -= be32_to_cpu(adsp1_alg[i].zm);
+ region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
@@ -1108,6 +1109,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
region->len -= be32_to_cpu(adsp2_alg[i].xm);
+ region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
@@ -1125,6 +1127,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
region->len -= be32_to_cpu(adsp2_alg[i].ym);
+ region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
@@ -1142,6 +1145,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
if (i + 1 < algs) {
region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
region->len -= be32_to_cpu(adsp2_alg[i].zm);
+ region->len *= 4;
wm_adsp_create_control(dsp, region);
} else {
adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
@@ -1282,6 +1286,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
reg = wm_adsp_region_to_reg(mem,
reg);
reg += offset;
+ break;
}
}
@@ -1313,8 +1318,8 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
le32_to_cpu(blk->len));
if (ret != 0) {
adsp_err(dsp,
- "%s.%d: Failed to write to %x in %s\n",
- file, blocks, reg, region_name);
+ "%s.%d: Failed to write to %x in %s: %d\n",
+ file, blocks, reg, region_name, ret);
}
}
@@ -1358,6 +1363,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_soc_codec *codec = w->codec;
struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
struct wm_adsp *dsp = &dsps[w->shift];
+ struct wm_adsp_alg_region *alg_region;
struct wm_coeff_ctl *ctl;
int ret;
int val;
@@ -1435,6 +1441,14 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
list_for_each_entry(ctl, &dsp->ctl_list, list)
ctl->enabled = 0;
+
+ while (!list_empty(&dsp->alg_regions)) {
+ alg_region = list_first_entry(&dsp->alg_regions,
+ struct wm_adsp_alg_region,
+ list);
+ list_del(&alg_region->list);
+ kfree(alg_region);
+ }
break;
default:
@@ -1455,19 +1469,23 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
unsigned int val;
int ret, count;
- ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
- ADSP2_SYS_ENA, ADSP2_SYS_ENA);
+ ret = regmap_update_bits_async(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA, ADSP2_SYS_ENA);
if (ret != 0)
return ret;
/* Wait for the RAM to start, should be near instantaneous */
- count = 0;
- do {
+ for (count = 0; count < 10; ++count) {
ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1,
&val);
if (ret != 0)
return ret;
- } while (!(val & ADSP2_RAM_RDY) && ++count < 10);
+
+ if (val & ADSP2_RAM_RDY)
+ break;
+
+ msleep(1);
+ }
if (!(val & ADSP2_RAM_RDY)) {
adsp_err(dsp, "Failed to start DSP RAM\n");
@@ -1475,112 +1493,153 @@ static int wm_adsp2_ena(struct wm_adsp *dsp)
}
adsp_dbg(dsp, "RAM ready after %d polls\n", count);
- adsp_info(dsp, "RAM ready after %d polls\n", count);
return 0;
}
-int wm_adsp2_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static void wm_adsp2_boot_work(struct work_struct *work)
{
- struct snd_soc_codec *codec = w->codec;
- struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
- struct wm_adsp *dsp = &dsps[w->shift];
- struct wm_adsp_alg_region *alg_region;
- struct wm_coeff_ctl *ctl;
- unsigned int val;
+ struct wm_adsp *dsp = container_of(work,
+ struct wm_adsp,
+ boot_work);
int ret;
+ unsigned int val;
- dsp->card = codec->card;
+ /*
+ * For simplicity set the DSP clock rate to be the
+ * SYSCLK rate rather than making it configurable.
+ */
+ ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret);
+ return;
+ }
+ val = (val & ARIZONA_SYSCLK_FREQ_MASK)
+ >> ARIZONA_SYSCLK_FREQ_SHIFT;
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- /*
- * For simplicity set the DSP clock rate to be the
- * SYSCLK rate rather than making it configurable.
- */
- ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val);
- if (ret != 0) {
- adsp_err(dsp, "Failed to read SYSCLK state: %d\n",
- ret);
- return ret;
- }
- val = (val & ARIZONA_SYSCLK_FREQ_MASK)
- >> ARIZONA_SYSCLK_FREQ_SHIFT;
+ ret = regmap_update_bits_async(dsp->regmap,
+ dsp->base + ADSP2_CLOCKING,
+ ADSP2_CLK_SEL_MASK, val);
+ if (ret != 0) {
+ adsp_err(dsp, "Failed to set clock rate: %d\n", ret);
+ return;
+ }
- ret = regmap_update_bits(dsp->regmap,
- dsp->base + ADSP2_CLOCKING,
- ADSP2_CLK_SEL_MASK, val);
+ if (dsp->dvfs) {
+ ret = regmap_read(dsp->regmap,
+ dsp->base + ADSP2_CLOCKING, &val);
if (ret != 0) {
- adsp_err(dsp, "Failed to set clock rate: %d\n",
- ret);
- return ret;
+ dev_err(dsp->dev, "Failed to read clocking: %d\n", ret);
+ return;
}
- if (dsp->dvfs) {
- ret = regmap_read(dsp->regmap,
- dsp->base + ADSP2_CLOCKING, &val);
+ if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
+ ret = regulator_enable(dsp->dvfs);
if (ret != 0) {
dev_err(dsp->dev,
- "Failed to read clocking: %d\n", ret);
- return ret;
+ "Failed to enable supply: %d\n",
+ ret);
+ return;
}
- if ((val & ADSP2_CLK_SEL_MASK) >= 3) {
- ret = regulator_enable(dsp->dvfs);
- if (ret != 0) {
- dev_err(dsp->dev,
- "Failed to enable supply: %d\n",
- ret);
- return ret;
- }
-
- ret = regulator_set_voltage(dsp->dvfs,
- 1800000,
- 1800000);
- if (ret != 0) {
- dev_err(dsp->dev,
- "Failed to raise supply: %d\n",
- ret);
- return ret;
- }
+ ret = regulator_set_voltage(dsp->dvfs,
+ 1800000,
+ 1800000);
+ if (ret != 0) {
+ dev_err(dsp->dev,
+ "Failed to raise supply: %d\n",
+ ret);
+ return;
}
}
+ }
- ret = wm_adsp2_ena(dsp);
- if (ret != 0)
- return ret;
+ ret = wm_adsp2_ena(dsp);
+ if (ret != 0)
+ return;
- ret = wm_adsp_load(dsp);
- if (ret != 0)
- goto err;
+ ret = wm_adsp_load(dsp);
+ if (ret != 0)
+ goto err;
- ret = wm_adsp_setup_algs(dsp);
- if (ret != 0)
- goto err;
+ ret = wm_adsp_setup_algs(dsp);
+ if (ret != 0)
+ goto err;
- ret = wm_adsp_load_coeff(dsp);
- if (ret != 0)
- goto err;
+ ret = wm_adsp_load_coeff(dsp);
+ if (ret != 0)
+ goto err;
- /* Initialize caches for enabled and unset controls */
- ret = wm_coeff_init_control_caches(dsp);
- if (ret != 0)
- goto err;
+ /* Initialize caches for enabled and unset controls */
+ ret = wm_coeff_init_control_caches(dsp);
+ if (ret != 0)
+ goto err;
- /* Sync set controls */
- ret = wm_coeff_sync_controls(dsp);
- if (ret != 0)
- goto err;
+ /* Sync set controls */
+ ret = wm_coeff_sync_controls(dsp);
+ if (ret != 0)
+ goto err;
+
+ ret = regmap_update_bits_async(dsp->regmap,
+ dsp->base + ADSP2_CONTROL,
+ ADSP2_CORE_ENA,
+ ADSP2_CORE_ENA);
+ if (ret != 0)
+ goto err;
+
+ dsp->running = true;
+
+ return;
+
+err:
+ regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL,
+ ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0);
+}
+
+int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+ struct wm_adsp *dsp = &dsps[w->shift];
+
+ dsp->card = codec->card;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ queue_work(system_unbound_wq, &dsp->boot_work);
+ break;
+ default:
+ break;
+ };
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
+
+int wm_adsp2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
+ struct wm_adsp *dsp = &dsps[w->shift];
+ struct wm_adsp_alg_region *alg_region;
+ struct wm_coeff_ctl *ctl;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ flush_work(&dsp->boot_work);
+
+ if (!dsp->running)
+ return -EIO;
ret = regmap_update_bits(dsp->regmap,
dsp->base + ADSP2_CONTROL,
- ADSP2_CORE_ENA | ADSP2_START,
- ADSP2_CORE_ENA | ADSP2_START);
+ ADSP2_START,
+ ADSP2_START);
if (ret != 0)
goto err;
-
- dsp->running = true;
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -1651,6 +1710,7 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
INIT_LIST_HEAD(&adsp->alg_regions);
INIT_LIST_HEAD(&adsp->ctl_list);
+ INIT_WORK(&adsp->boot_work, wm_adsp2_boot_work);
if (dvfs) {
adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index d018dea6254d..a4f6b64deb61 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -59,6 +59,8 @@ struct wm_adsp {
struct regulator *dvfs;
struct list_head ctl_list;
+
+ struct work_struct boot_work;
};
#define WM_ADSP1(wname, num) \
@@ -66,8 +68,12 @@ struct wm_adsp {
wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
#define WM_ADSP2(wname, num) \
- SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \
- wm_adsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \
+ .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_early_event, \
+ .event_flags = SND_SOC_DAPM_PRE_PMU }, \
+{ .id = snd_soc_dapm_out_drv, .name = wname, \
+ .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
+ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
@@ -76,6 +82,8 @@ int wm_adsp1_init(struct wm_adsp *adsp);
int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
int wm_adsp1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
+int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
int wm_adsp2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 8b50e5958de5..b371066dd5bc 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -530,6 +530,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
hubs->hp_startup_mode);
break;
}
+ break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
@@ -610,7 +611,7 @@ static int earpiece_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Invalid event %d\n", event);
break;
}
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index c82f89c9475b..a8ec1fc3e4d0 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -1,10 +1,6 @@
config SND_DAVINCI_SOC
- tristate "SoC Audio for the TI DAVINCI chip"
- depends on ARCH_DAVINCI
- help
- Say Y or M if you want to add support for codecs attached to
- the DAVINCI AC97 or I2S interface. You will also need
- to select the audio interfaces to support below.
+ tristate "SoC Audio for TI DAVINCI or AM33XX/AM43XX chips"
+ depends on ARCH_DAVINCI || SOC_AM33XX || SOC_AM43XX
config SND_DAVINCI_SOC_I2S
tristate
@@ -15,12 +11,26 @@ config SND_DAVINCI_SOC_MCASP
config SND_DAVINCI_SOC_VCIF
tristate
+config SND_DAVINCI_SOC_GENERIC_EVM
+ tristate
+ select SND_SOC_TLV320AIC3X
+ select SND_DAVINCI_SOC_MCASP
+
+config SND_AM33XX_SOC_EVM
+ tristate "SoC Audio for the AM33XX chip based boards"
+ depends on SND_DAVINCI_SOC && SOC_AM33XX
+ select SND_DAVINCI_SOC_GENERIC_EVM
+ help
+ Say Y or M if you want to add support for SoC audio on AM33XX
+ boards using McASP and TLV320AIC3X codec. For example AM335X-EVM,
+ AM335X-EVMSK, and BeagelBone with AudioCape boards have this
+ setup.
+
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_DAVINCI_SOC
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
- select SND_DAVINCI_SOC_I2S
- select SND_SOC_TLV320AIC3X
+ select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DaVinci DM6446, DM355 or DM365 EVM platforms.
@@ -47,8 +57,7 @@ endchoice
config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DM6467_EVM
- select SND_DAVINCI_SOC_MCASP
- select SND_SOC_TLV320AIC3X
+ select SND_DAVINCI_SOC_GENERIC_EVM
select SND_SOC_SPDIF
help
@@ -57,8 +66,7 @@ config SND_DM6467_SOC_EVM
config SND_DA830_SOC_EVM
tristate "SoC Audio support for DA830/OMAP-L137 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM
- select SND_DAVINCI_SOC_MCASP
- select SND_SOC_TLV320AIC3X
+ select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
@@ -67,8 +75,7 @@ config SND_DA830_SOC_EVM
config SND_DA850_SOC_EVM
tristate "SoC Audio support for DA850/OMAP-L138 EVM"
depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA850_EVM
- select SND_DAVINCI_SOC_MCASP
- select SND_SOC_TLV320AIC3X
+ select SND_DAVINCI_SOC_GENERIC_EVM
help
Say Y if you want to add support for SoC audio on TI
DA850/OMAP-L138 EVM
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index a396ab6d6d5e..744d4d9a0184 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -9,10 +9,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
-# DAVINCI Machine Support
+# Generic DAVINCI/AM33xx Machine Support
snd-soc-evm-objs := davinci-evm.o
-obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o
-obj-$(CONFIG_SND_DA850_SOC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index fd7c45b9ed5a..5e3bc3c6801a 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/platform_data/edma.h>
#include <linux/i2c.h>
+#include <linux/of_platform.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -23,49 +24,26 @@
#include <asm/dma.h>
#include <asm/mach-types.h>
+#include <linux/edma.h>
+
#include "davinci-pcm.h"
#include "davinci-i2s.h"
-#include "davinci-mcasp.h"
-#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
- SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
+struct snd_soc_card_drvdata_davinci {
+ unsigned sysclk;
+};
+
static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *soc_card = codec->card;
int ret = 0;
- unsigned sysclk;
-
- /* ASP1 on DM355 EVM is clocked by an external oscillator */
- if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() ||
- machine_is_davinci_dm365_evm())
- sysclk = 27000000;
-
- /* ASP0 in DM6446 EVM is clocked by U55, as configured by
- * board-dm644x-evm.c using GPIOs from U18. There are six
- * options; here we "know" we use a 48 KHz sample rate.
- */
- else if (machine_is_davinci_evm())
- sysclk = 12288000;
-
- else if (machine_is_davinci_da830_evm() ||
- machine_is_davinci_da850_evm())
- sysclk = 24576000;
-
- else
- return -EINVAL;
-
- /* set codec DAI configuration */
- ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
- if (ret < 0)
- return ret;
-
- /* set cpu DAI configuration */
- ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
- if (ret < 0)
- return ret;
+ unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
+ snd_soc_card_get_drvdata(soc_card))->sysclk;
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
@@ -80,24 +58,10 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
- /* set cpu DAI configuration */
- return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
-}
-
static struct snd_soc_ops evm_ops = {
.hw_params = evm_hw_params,
};
-static struct snd_soc_ops evm_spdif_ops = {
- .hw_params = evm_spdif_hw_params,
-};
-
/* davinci-evm machine dapm widgets */
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -133,13 +97,22 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
+ struct device_node *np = codec->card->dev->of_node;
+ int ret;
/* Add davinci-evm specific widgets */
snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
- /* Set up davinci-evm specific audio path audio_map */
- snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ if (np) {
+ ret = snd_soc_of_parse_audio_routing(codec->card,
+ "ti,audio-routing");
+ if (ret)
+ return ret;
+ } else {
+ /* Set up davinci-evm specific audio path audio_map */
+ snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ }
/* not connected */
snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
@@ -165,6 +138,8 @@ static struct snd_soc_dai_link dm6446_evm_dai = {
.platform_name = "davinci-mcbsp",
.init = evm_aic3x_init,
.ops = &evm_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
};
static struct snd_soc_dai_link dm355_evm_dai = {
@@ -176,6 +151,8 @@ static struct snd_soc_dai_link dm355_evm_dai = {
.platform_name = "davinci-mcbsp.1",
.init = evm_aic3x_init,
.ops = &evm_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
};
static struct snd_soc_dai_link dm365_evm_dai = {
@@ -184,10 +161,12 @@ static struct snd_soc_dai_link dm365_evm_dai = {
.stream_name = "AIC3X",
.cpu_dai_name = "davinci-mcbsp",
.codec_dai_name = "tlv320aic3x-hifi",
- .init = evm_aic3x_init,
.codec_name = "tlv320aic3x-codec.1-0018",
- .ops = &evm_ops,
.platform_name = "davinci-mcbsp",
+ .init = evm_aic3x_init,
+ .ops = &evm_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
.name = "Voice Codec - CQ93VC",
.stream_name = "CQ93",
@@ -208,6 +187,8 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
.codec_name = "tlv320aic3x-codec.0-001a",
.init = evm_aic3x_init,
.ops = &evm_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
},
{
.name = "McASP",
@@ -216,7 +197,8 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
.codec_dai_name = "dit-hifi",
.codec_name = "spdif_dit",
.platform_name = "davinci-mcasp.1",
- .ops = &evm_spdif_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
},
};
@@ -229,6 +211,8 @@ static struct snd_soc_dai_link da830_evm_dai = {
.platform_name = "davinci-mcasp.1",
.init = evm_aic3x_init,
.ops = &evm_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
};
static struct snd_soc_dai_link da850_evm_dai = {
@@ -240,38 +224,70 @@ static struct snd_soc_dai_link da850_evm_dai = {
.platform_name = "davinci-mcasp.0",
.init = evm_aic3x_init,
.ops = &evm_ops,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
};
/* davinci dm6446 evm audio machine driver */
+/*
+ * ASP0 in DM6446 EVM is clocked by U55, as configured by
+ * board-dm644x-evm.c using GPIOs from U18. There are six
+ * options; here we "know" we use a 48 KHz sample rate.
+ */
+static struct snd_soc_card_drvdata_davinci dm6446_snd_soc_card_drvdata = {
+ .sysclk = 12288000,
+};
+
static struct snd_soc_card dm6446_snd_soc_card_evm = {
.name = "DaVinci DM6446 EVM",
.owner = THIS_MODULE,
.dai_link = &dm6446_evm_dai,
.num_links = 1,
+ .drvdata = &dm6446_snd_soc_card_drvdata,
};
/* davinci dm355 evm audio machine driver */
+/* ASP1 on DM355 EVM is clocked by an external oscillator */
+static struct snd_soc_card_drvdata_davinci dm355_snd_soc_card_drvdata = {
+ .sysclk = 27000000,
+};
+
static struct snd_soc_card dm355_snd_soc_card_evm = {
.name = "DaVinci DM355 EVM",
.owner = THIS_MODULE,
.dai_link = &dm355_evm_dai,
.num_links = 1,
+ .drvdata = &dm355_snd_soc_card_drvdata,
};
/* davinci dm365 evm audio machine driver */
+static struct snd_soc_card_drvdata_davinci dm365_snd_soc_card_drvdata = {
+ .sysclk = 27000000,
+};
+
static struct snd_soc_card dm365_snd_soc_card_evm = {
.name = "DaVinci DM365 EVM",
.owner = THIS_MODULE,
.dai_link = &dm365_evm_dai,
.num_links = 1,
+ .drvdata = &dm365_snd_soc_card_drvdata,
};
/* davinci dm6467 evm audio machine driver */
+static struct snd_soc_card_drvdata_davinci dm6467_snd_soc_card_drvdata = {
+ .sysclk = 27000000,
+};
+
static struct snd_soc_card dm6467_snd_soc_card_evm = {
.name = "DaVinci DM6467 EVM",
.owner = THIS_MODULE,
.dai_link = dm6467_evm_dai,
.num_links = ARRAY_SIZE(dm6467_evm_dai),
+ .drvdata = &dm6467_snd_soc_card_drvdata,
+};
+
+static struct snd_soc_card_drvdata_davinci da830_snd_soc_card_drvdata = {
+ .sysclk = 24576000,
};
static struct snd_soc_card da830_snd_soc_card = {
@@ -279,6 +295,11 @@ static struct snd_soc_card da830_snd_soc_card = {
.owner = THIS_MODULE,
.dai_link = &da830_evm_dai,
.num_links = 1,
+ .drvdata = &da830_snd_soc_card_drvdata,
+};
+
+static struct snd_soc_card_drvdata_davinci da850_snd_soc_card_drvdata = {
+ .sysclk = 24576000,
};
static struct snd_soc_card da850_snd_soc_card = {
@@ -286,7 +307,103 @@ static struct snd_soc_card da850_snd_soc_card = {
.owner = THIS_MODULE,
.dai_link = &da850_evm_dai,
.num_links = 1,
+ .drvdata = &da850_snd_soc_card_drvdata,
+};
+
+#if defined(CONFIG_OF)
+
+/*
+ * The struct is used as place holder. It will be completely
+ * filled with data from dt node.
+ */
+static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
+ .name = "TLV320AIC3X",
+ .stream_name = "AIC3X",
+ .codec_dai_name = "tlv320aic3x-hifi",
+ .ops = &evm_ops,
+ .init = evm_aic3x_init,
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_IB_NF,
+};
+
+static const struct of_device_id davinci_evm_dt_ids[] = {
+ {
+ .compatible = "ti,da830-evm-audio",
+ .data = (void *) &evm_dai_tlv320aic3x,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
+
+/* davinci evm audio machine driver */
+static struct snd_soc_card evm_soc_card = {
+ .owner = THIS_MODULE,
+ .num_links = 1,
+};
+
+static int davinci_evm_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match =
+ of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
+ struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
+ struct snd_soc_card_drvdata_davinci *drvdata = NULL;
+ int ret = 0;
+
+ evm_soc_card.dai_link = dai;
+
+ dai->codec_of_node = of_parse_phandle(np, "ti,audio-codec", 0);
+ if (!dai->codec_of_node)
+ return -EINVAL;
+
+ dai->cpu_of_node = of_parse_phandle(np, "ti,mcasp-controller", 0);
+ if (!dai->cpu_of_node)
+ return -EINVAL;
+
+ dai->platform_of_node = dai->cpu_of_node;
+
+ evm_soc_card.dev = &pdev->dev;
+ ret = snd_soc_of_parse_card_name(&evm_soc_card, "ti,model");
+ if (ret)
+ return ret;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
+ if (ret < 0)
+ return -EINVAL;
+
+ snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
+ ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
+
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int davinci_evm_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static struct platform_driver davinci_evm_driver = {
+ .probe = davinci_evm_probe,
+ .remove = davinci_evm_remove,
+ .driver = {
+ .name = "davinci_evm",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = of_match_ptr(davinci_evm_dt_ids),
+ },
};
+#endif
static struct platform_device *evm_snd_device;
@@ -296,6 +413,15 @@ static int __init evm_init(void)
int index;
int ret;
+ /*
+ * If dtb is there, the devices will be created dynamically.
+ * Only register platfrom driver structure.
+ */
+#if defined(CONFIG_OF)
+ if (of_have_populated_dt())
+ return platform_driver_register(&davinci_evm_driver);
+#endif
+
if (machine_is_davinci_evm()) {
evm_snd_dev_data = &dm6446_snd_soc_card_evm;
index = 0;
@@ -331,6 +457,13 @@ static int __init evm_init(void)
static void __exit evm_exit(void)
{
+#if defined(CONFIG_OF)
+ if (of_have_populated_dt()) {
+ platform_driver_unregister(&davinci_evm_driver);
+ return;
+ }
+#endif
+
platform_device_unregister(evm_snd_device);
}
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 32ddb7fe5034..670afa29e30d 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -31,351 +32,147 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
#include "davinci-pcm.h"
#include "davinci-mcasp.h"
-/*
- * McASP register definitions
- */
-#define DAVINCI_MCASP_PID_REG 0x00
-#define DAVINCI_MCASP_PWREMUMGT_REG 0x04
-
-#define DAVINCI_MCASP_PFUNC_REG 0x10
-#define DAVINCI_MCASP_PDIR_REG 0x14
-#define DAVINCI_MCASP_PDOUT_REG 0x18
-#define DAVINCI_MCASP_PDSET_REG 0x1c
-
-#define DAVINCI_MCASP_PDCLR_REG 0x20
-
-#define DAVINCI_MCASP_TLGC_REG 0x30
-#define DAVINCI_MCASP_TLMR_REG 0x34
-
-#define DAVINCI_MCASP_GBLCTL_REG 0x44
-#define DAVINCI_MCASP_AMUTE_REG 0x48
-#define DAVINCI_MCASP_LBCTL_REG 0x4c
-
-#define DAVINCI_MCASP_TXDITCTL_REG 0x50
-
-#define DAVINCI_MCASP_GBLCTLR_REG 0x60
-#define DAVINCI_MCASP_RXMASK_REG 0x64
-#define DAVINCI_MCASP_RXFMT_REG 0x68
-#define DAVINCI_MCASP_RXFMCTL_REG 0x6c
-
-#define DAVINCI_MCASP_ACLKRCTL_REG 0x70
-#define DAVINCI_MCASP_AHCLKRCTL_REG 0x74
-#define DAVINCI_MCASP_RXTDM_REG 0x78
-#define DAVINCI_MCASP_EVTCTLR_REG 0x7c
-
-#define DAVINCI_MCASP_RXSTAT_REG 0x80
-#define DAVINCI_MCASP_RXTDMSLOT_REG 0x84
-#define DAVINCI_MCASP_RXCLKCHK_REG 0x88
-#define DAVINCI_MCASP_REVTCTL_REG 0x8c
-
-#define DAVINCI_MCASP_GBLCTLX_REG 0xa0
-#define DAVINCI_MCASP_TXMASK_REG 0xa4
-#define DAVINCI_MCASP_TXFMT_REG 0xa8
-#define DAVINCI_MCASP_TXFMCTL_REG 0xac
-
-#define DAVINCI_MCASP_ACLKXCTL_REG 0xb0
-#define DAVINCI_MCASP_AHCLKXCTL_REG 0xb4
-#define DAVINCI_MCASP_TXTDM_REG 0xb8
-#define DAVINCI_MCASP_EVTCTLX_REG 0xbc
-
-#define DAVINCI_MCASP_TXSTAT_REG 0xc0
-#define DAVINCI_MCASP_TXTDMSLOT_REG 0xc4
-#define DAVINCI_MCASP_TXCLKCHK_REG 0xc8
-#define DAVINCI_MCASP_XEVTCTL_REG 0xcc
-
-/* Left(even TDM Slot) Channel Status Register File */
-#define DAVINCI_MCASP_DITCSRA_REG 0x100
-/* Right(odd TDM slot) Channel Status Register File */
-#define DAVINCI_MCASP_DITCSRB_REG 0x118
-/* Left(even TDM slot) User Data Register File */
-#define DAVINCI_MCASP_DITUDRA_REG 0x130
-/* Right(odd TDM Slot) User Data Register File */
-#define DAVINCI_MCASP_DITUDRB_REG 0x148
-
-/* Serializer n Control Register */
-#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
-#define DAVINCI_MCASP_XRSRCTL_REG(n) (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
- (n << 2))
-
-/* Transmit Buffer for Serializer n */
-#define DAVINCI_MCASP_TXBUF_REG 0x200
-/* Receive Buffer for Serializer n */
-#define DAVINCI_MCASP_RXBUF_REG 0x280
-
-/* McASP FIFO Registers */
-#define DAVINCI_MCASP_WFIFOCTL (0x1010)
-#define DAVINCI_MCASP_WFIFOSTS (0x1014)
-#define DAVINCI_MCASP_RFIFOCTL (0x1018)
-#define DAVINCI_MCASP_RFIFOSTS (0x101C)
-#define MCASP_VER3_WFIFOCTL (0x1000)
-#define MCASP_VER3_WFIFOSTS (0x1004)
-#define MCASP_VER3_RFIFOCTL (0x1008)
-#define MCASP_VER3_RFIFOSTS (0x100C)
-
-/*
- * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
- * Register Bits
- */
-#define MCASP_FREE BIT(0)
-#define MCASP_SOFT BIT(1)
-
-/*
- * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
- */
-#define AXR(n) (1<<n)
-#define PFUNC_AMUTE BIT(25)
-#define ACLKX BIT(26)
-#define AHCLKX BIT(27)
-#define AFSX BIT(28)
-#define ACLKR BIT(29)
-#define AHCLKR BIT(30)
-#define AFSR BIT(31)
-
-/*
- * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
- */
-#define AXR(n) (1<<n)
-#define PDIR_AMUTE BIT(25)
-#define ACLKX BIT(26)
-#define AHCLKX BIT(27)
-#define AFSX BIT(28)
-#define ACLKR BIT(29)
-#define AHCLKR BIT(30)
-#define AFSR BIT(31)
-
-/*
- * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
- */
-#define DITEN BIT(0) /* Transmit DIT mode enable/disable */
-#define VA BIT(2)
-#define VB BIT(3)
-
-/*
- * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
- */
-#define TXROT(val) (val)
-#define TXSEL BIT(3)
-#define TXSSZ(val) (val<<4)
-#define TXPBIT(val) (val<<8)
-#define TXPAD(val) (val<<13)
-#define TXORD BIT(15)
-#define FSXDLY(val) (val<<16)
-
-/*
- * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
- */
-#define RXROT(val) (val)
-#define RXSEL BIT(3)
-#define RXSSZ(val) (val<<4)
-#define RXPBIT(val) (val<<8)
-#define RXPAD(val) (val<<13)
-#define RXORD BIT(15)
-#define FSRDLY(val) (val<<16)
-
-/*
- * DAVINCI_MCASP_TXFMCTL_REG - Transmit Frame Control Register Bits
- */
-#define FSXPOL BIT(0)
-#define AFSXE BIT(1)
-#define FSXDUR BIT(4)
-#define FSXMOD(val) (val<<7)
-
-/*
- * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
- */
-#define FSRPOL BIT(0)
-#define AFSRE BIT(1)
-#define FSRDUR BIT(4)
-#define FSRMOD(val) (val<<7)
-
-/*
- * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
- */
-#define ACLKXDIV(val) (val)
-#define ACLKXE BIT(5)
-#define TX_ASYNC BIT(6)
-#define ACLKXPOL BIT(7)
-#define ACLKXDIV_MASK 0x1f
-
-/*
- * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
- */
-#define ACLKRDIV(val) (val)
-#define ACLKRE BIT(5)
-#define RX_ASYNC BIT(6)
-#define ACLKRPOL BIT(7)
-#define ACLKRDIV_MASK 0x1f
-
-/*
- * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
- * Register Bits
- */
-#define AHCLKXDIV(val) (val)
-#define AHCLKXPOL BIT(14)
-#define AHCLKXE BIT(15)
-#define AHCLKXDIV_MASK 0xfff
-
-/*
- * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
- * Register Bits
- */
-#define AHCLKRDIV(val) (val)
-#define AHCLKRPOL BIT(14)
-#define AHCLKRE BIT(15)
-#define AHCLKRDIV_MASK 0xfff
-
-/*
- * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits
- */
-#define MODE(val) (val)
-#define DISMOD (val)(val<<2)
-#define TXSTATE BIT(4)
-#define RXSTATE BIT(5)
-#define SRMOD_MASK 3
-#define SRMOD_INACTIVE 0
-
-/*
- * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
- */
-#define LBEN BIT(0)
-#define LBORD BIT(1)
-#define LBGENMODE(val) (val<<2)
-
-/*
- * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
- */
-#define TXTDMS(n) (1<<n)
-
-/*
- * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
- */
-#define RXTDMS(n) (1<<n)
-
-/*
- * DAVINCI_MCASP_GBLCTL_REG - Global Control Register Bits
- */
-#define RXCLKRST BIT(0) /* Receiver Clock Divider Reset */
-#define RXHCLKRST BIT(1) /* Receiver High Frequency Clock Divider */
-#define RXSERCLR BIT(2) /* Receiver Serializer Clear */
-#define RXSMRST BIT(3) /* Receiver State Machine Reset */
-#define RXFSRST BIT(4) /* Frame Sync Generator Reset */
-#define TXCLKRST BIT(8) /* Transmitter Clock Divider Reset */
-#define TXHCLKRST BIT(9) /* Transmitter High Frequency Clock Divider*/
-#define TXSERCLR BIT(10) /* Transmit Serializer Clear */
-#define TXSMRST BIT(11) /* Transmitter State Machine Reset */
-#define TXFSRST BIT(12) /* Frame Sync Generator Reset */
-
-/*
- * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits
- */
-#define MUTENA(val) (val)
-#define MUTEINPOL BIT(2)
-#define MUTEINENA BIT(3)
-#define MUTEIN BIT(4)
-#define MUTER BIT(5)
-#define MUTEX BIT(6)
-#define MUTEFSR BIT(7)
-#define MUTEFSX BIT(8)
-#define MUTEBADCLKR BIT(9)
-#define MUTEBADCLKX BIT(10)
-#define MUTERXDMAERR BIT(11)
-#define MUTETXDMAERR BIT(12)
-
-/*
- * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
- */
-#define RXDATADMADIS BIT(0)
-
-/*
- * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
- */
-#define TXDATADMADIS BIT(0)
-
-/*
- * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
- */
-#define FIFO_ENABLE BIT(16)
-#define NUMEVT_MASK (0xFF << 8)
-#define NUMDMA_MASK (0xFF)
-
-#define DAVINCI_MCASP_NUM_SERIALIZER 16
+struct davinci_mcasp {
+ struct davinci_pcm_dma_params dma_params[2];
+ struct snd_dmaengine_dai_dma_data dma_data[2];
+ void __iomem *base;
+ u32 fifo_base;
+ struct device *dev;
+
+ /* McASP specific data */
+ int tdm_slots;
+ u8 op_mode;
+ u8 num_serializer;
+ u8 *serial_dir;
+ u8 version;
+ u16 bclk_lrclk_ratio;
+ int streams;
+
+ /* McASP FIFO related */
+ u8 txnumevt;
+ u8 rxnumevt;
+
+ bool dat_port;
+
+#ifdef CONFIG_PM_SLEEP
+ struct {
+ u32 txfmtctl;
+ u32 rxfmtctl;
+ u32 txfmt;
+ u32 rxfmt;
+ u32 aclkxctl;
+ u32 aclkrctl;
+ u32 pdir;
+ } context;
+#endif
+};
-static inline void mcasp_set_bits(void __iomem *reg, u32 val)
+static inline void mcasp_set_bits(struct davinci_mcasp *mcasp, u32 offset,
+ u32 val)
{
+ void __iomem *reg = mcasp->base + offset;
__raw_writel(__raw_readl(reg) | val, reg);
}
-static inline void mcasp_clr_bits(void __iomem *reg, u32 val)
+static inline void mcasp_clr_bits(struct davinci_mcasp *mcasp, u32 offset,
+ u32 val)
{
+ void __iomem *reg = mcasp->base + offset;
__raw_writel((__raw_readl(reg) & ~(val)), reg);
}
-static inline void mcasp_mod_bits(void __iomem *reg, u32 val, u32 mask)
+static inline void mcasp_mod_bits(struct davinci_mcasp *mcasp, u32 offset,
+ u32 val, u32 mask)
{
+ void __iomem *reg = mcasp->base + offset;
__raw_writel((__raw_readl(reg) & ~mask) | val, reg);
}
-static inline void mcasp_set_reg(void __iomem *reg, u32 val)
+static inline void mcasp_set_reg(struct davinci_mcasp *mcasp, u32 offset,
+ u32 val)
{
- __raw_writel(val, reg);
+ __raw_writel(val, mcasp->base + offset);
}
-static inline u32 mcasp_get_reg(void __iomem *reg)
+static inline u32 mcasp_get_reg(struct davinci_mcasp *mcasp, u32 offset)
{
- return (unsigned int)__raw_readl(reg);
+ return (u32)__raw_readl(mcasp->base + offset);
}
-static inline void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
+static void mcasp_set_ctl_reg(struct davinci_mcasp *mcasp, u32 ctl_reg, u32 val)
{
int i = 0;
- mcasp_set_bits(regs, val);
+ mcasp_set_bits(mcasp, ctl_reg, val);
/* programming GBLCTL needs to read back from GBLCTL and verfiy */
/* loop count is to avoid the lock-up */
for (i = 0; i < 1000; i++) {
- if ((mcasp_get_reg(regs) & val) == val)
+ if ((mcasp_get_reg(mcasp, ctl_reg) & val) == val)
break;
}
- if (i == 1000 && ((mcasp_get_reg(regs) & val) != val))
+ if (i == 1000 && ((mcasp_get_reg(mcasp, ctl_reg) & val) != val))
printk(KERN_ERR "GBLCTL write error\n");
}
-static void mcasp_start_rx(struct davinci_audio_dev *dev)
+static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
{
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
+ u32 rxfmctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+ u32 aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+
+ return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
+}
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_RXBUF_REG, 0);
+static void mcasp_start_rx(struct davinci_mcasp *mcasp)
+{
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+ /*
+ * When ASYNC == 0 the transmit and receive sections operate
+ * synchronously from the transmit clock and frame sync. We need to make
+ * sure that the TX signlas are enabled when starting reception.
+ */
+ if (mcasp_is_synchronous(mcasp)) {
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ }
+
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
+
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
+
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+
+ if (mcasp_is_synchronous(mcasp))
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
}
-static void mcasp_start_tx(struct davinci_audio_dev *dev)
+static void mcasp_start_tx(struct davinci_mcasp *mcasp)
{
u8 offset = 0, i;
u32 cnt;
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
- mcasp_set_ctl_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
- for (i = 0; i < dev->num_serializer; i++) {
- if (dev->serial_dir[i] == TX_MODE) {
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
+ for (i = 0; i < mcasp->num_serializer; i++) {
+ if (mcasp->serial_dir[i] == TX_MODE) {
offset = i;
break;
}
@@ -383,223 +180,212 @@ static void mcasp_start_tx(struct davinci_audio_dev *dev)
/* wait for TX ready */
cnt = 0;
- while (!(mcasp_get_reg(dev->base + DAVINCI_MCASP_XRSRCTL_REG(offset)) &
+ while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) &
TXSTATE) && (cnt < 100000))
cnt++;
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXBUF_REG, 0);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
}
-static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
+static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
{
+ u32 reg;
+
+ mcasp->streams++;
+
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (dev->txnumevt) { /* enable FIFO */
- switch (dev->version) {
- case MCASP_VERSION_3:
- mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,
- FIFO_ENABLE);
- mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL,
- FIFO_ENABLE);
- break;
- default:
- mcasp_clr_bits(dev->base +
- DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
- mcasp_set_bits(dev->base +
- DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
- }
+ if (mcasp->txnumevt) { /* enable FIFO */
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
}
- mcasp_start_tx(dev);
+ mcasp_start_tx(mcasp);
} else {
- if (dev->rxnumevt) { /* enable FIFO */
- switch (dev->version) {
- case MCASP_VERSION_3:
- mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,
- FIFO_ENABLE);
- mcasp_set_bits(dev->base + MCASP_VER3_RFIFOCTL,
- FIFO_ENABLE);
- break;
- default:
- mcasp_clr_bits(dev->base +
- DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
- mcasp_set_bits(dev->base +
- DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
- }
+ if (mcasp->rxnumevt) { /* enable FIFO */
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
}
- mcasp_start_rx(dev);
+ mcasp_start_rx(mcasp);
}
}
-static void mcasp_stop_rx(struct davinci_audio_dev *dev)
+static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
{
- mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLR_REG, 0);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+ /*
+ * In synchronous mode stop the TX clocks if no other stream is
+ * running
+ */
+ if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, 0);
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
}
-static void mcasp_stop_tx(struct davinci_audio_dev *dev)
+static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
{
- mcasp_set_reg(dev->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+ u32 val = 0;
+
+ /*
+ * In synchronous mode keep TX clocks running if the capture stream is
+ * still running.
+ */
+ if (mcasp_is_synchronous(mcasp) && mcasp->streams)
+ val = TXHCLKRST | TXCLKRST | TXFSRST;
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
}
-static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)
+static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
{
+ u32 reg;
+
+ mcasp->streams--;
+
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (dev->txnumevt) { /* disable FIFO */
- switch (dev->version) {
- case MCASP_VERSION_3:
- mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,
- FIFO_ENABLE);
- break;
- default:
- mcasp_clr_bits(dev->base +
- DAVINCI_MCASP_WFIFOCTL, FIFO_ENABLE);
- }
+ if (mcasp->txnumevt) { /* disable FIFO */
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
}
- mcasp_stop_tx(dev);
+ mcasp_stop_tx(mcasp);
} else {
- if (dev->rxnumevt) { /* disable FIFO */
- switch (dev->version) {
- case MCASP_VERSION_3:
- mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,
- FIFO_ENABLE);
- break;
-
- default:
- mcasp_clr_bits(dev->base +
- DAVINCI_MCASP_RFIFOCTL, FIFO_ENABLE);
- }
+ if (mcasp->rxnumevt) { /* disable FIFO */
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
}
- mcasp_stop_rx(dev);
+ mcasp_stop_rx(mcasp);
}
}
static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
- void __iomem *base = dev->base;
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret = 0;
+ pm_runtime_get_sync(mcasp->dev);
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
case SND_SOC_DAIFMT_AC97:
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
break;
default:
/* configure a full-word SYNC pulse (LRCLK) */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
- mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
/* make 1st data bit occur one ACLK cycle after the frame sync */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
- mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, FSXDLY(1));
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
break;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* codec is clock and frame slave */
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
- mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
- mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
- ACLKX | ACLKR);
- mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
- AFSX | AFSR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
break;
case SND_SOC_DAIFMT_CBM_CFS:
/* codec is clock master and frame slave */
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
- mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
- mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG,
- ACLKX | ACLKR);
- mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
- AFSX | AFSR);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is clock and frame master */
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
- mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE);
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
- mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
- mcasp_clr_bits(base + DAVINCI_MCASP_PDIR_REG,
- ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
+ ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_IB_NF:
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
break;
case SND_SOC_DAIFMT_NB_IF:
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
break;
case SND_SOC_DAIFMT_IB_IF:
- mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
break;
case SND_SOC_DAIFMT_NB_NF:
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
- mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
- mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
- mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
-
- return 0;
+out:
+ pm_runtime_put_sync(mcasp->dev);
+ return ret;
}
static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
{
- struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
switch (div_id) {
case 0: /* MCLK divider */
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG,
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG,
AHCLKXDIV(div - 1), AHCLKXDIV_MASK);
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG,
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKRDIV(div - 1), AHCLKRDIV_MASK);
break;
case 1: /* BCLK divider */
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG,
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG,
ACLKXDIV(div - 1), ACLKXDIV_MASK);
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKRCTL_REG,
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG,
ACLKRDIV(div - 1), ACLKRDIV_MASK);
break;
case 2: /* BCLK/LRCLK ratio */
- dev->bclk_lrclk_ratio = div;
+ mcasp->bclk_lrclk_ratio = div;
break;
default:
@@ -612,22 +398,22 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div
static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
- struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
if (dir == SND_SOC_CLOCK_OUT) {
- mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
- mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
- mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
} else {
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
}
return 0;
}
-static int davinci_config_channel_size(struct davinci_audio_dev *dev,
+static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
int word_length)
{
u32 fmt;
@@ -644,71 +430,68 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
* both left and right channels), so it has to be divided by number of
* tdm-slots (for I2S - divided by 2).
*/
- if (dev->bclk_lrclk_ratio)
- word_length = dev->bclk_lrclk_ratio / dev->tdm_slots;
+ if (mcasp->bclk_lrclk_ratio)
+ word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
/* mapping of the XSSZ bit-field as described in the datasheet */
fmt = (word_length >> 1) - 1;
- if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
- RXSSZ(fmt), RXSSZ(0x0F));
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
- TXSSZ(fmt), TXSSZ(0x0F));
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
- TXROT(tx_rotate), TXROT(7));
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
- RXROT(rx_rotate), RXROT(7));
- mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
- mask);
+ if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt),
+ RXSSZ(0x0F));
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(fmt),
+ TXSSZ(0x0F));
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
+ TXROT(7));
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
+ RXROT(7));
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
}
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
return 0;
}
-static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
+static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
int channels)
{
int i;
u8 tx_ser = 0;
u8 rx_ser = 0;
u8 ser;
- u8 slots = dev->tdm_slots;
+ u8 slots = mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
+ u32 reg;
/* Default configuration */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
+ if (mcasp->version != MCASP_VERSION_4)
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
/* All PINS as McASP */
- mcasp_set_reg(dev->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_PFUNC_REG, 0x00000000);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG,
- TXDATADMADIS);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
} else {
- mcasp_set_reg(dev->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_REVTCTL_REG,
- RXDATADMADIS);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_REVTCTL_REG, RXDATADMADIS);
}
- for (i = 0; i < dev->num_serializer; i++) {
- mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
- dev->serial_dir[i]);
- if (dev->serial_dir[i] == TX_MODE &&
+ for (i = 0; i < mcasp->num_serializer; i++) {
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ mcasp->serial_dir[i]);
+ if (mcasp->serial_dir[i] == TX_MODE &&
tx_ser < max_active_serializers) {
- mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
- AXR(i));
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
tx_ser++;
- } else if (dev->serial_dir[i] == RX_MODE &&
+ } else if (mcasp->serial_dir[i] == RX_MODE &&
rx_ser < max_active_serializers) {
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
- AXR(i));
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AXR(i));
rx_ser++;
} else {
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
- SRMOD_INACTIVE, SRMOD_MASK);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i),
+ SRMOD_INACTIVE, SRMOD_MASK);
}
}
@@ -718,146 +501,130 @@ static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
ser = rx_ser;
if (ser < max_active_serializers) {
- dev_warn(dev->dev, "stream has more channels (%d) than are "
+ dev_warn(mcasp->dev, "stream has more channels (%d) than are "
"enabled in mcasp (%d)\n", channels, ser * slots);
return -EINVAL;
}
- if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (dev->txnumevt * tx_ser > 64)
- dev->txnumevt = 1;
+ if (mcasp->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (mcasp->txnumevt * tx_ser > 64)
+ mcasp->txnumevt = 1;
- switch (dev->version) {
- case MCASP_VERSION_3:
- mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, tx_ser,
- NUMDMA_MASK);
- mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL,
- ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
- break;
- default:
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
- tx_ser, NUMDMA_MASK);
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
- ((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK);
- }
+ reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+ mcasp_mod_bits(mcasp, reg, tx_ser, NUMDMA_MASK);
+ mcasp_mod_bits(mcasp, reg, ((mcasp->txnumevt * tx_ser) << 8),
+ NUMEVT_MASK);
}
- if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (dev->rxnumevt * rx_ser > 64)
- dev->rxnumevt = 1;
- switch (dev->version) {
- case MCASP_VERSION_3:
- mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, rx_ser,
- NUMDMA_MASK);
- mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL,
- ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
- break;
- default:
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
- rx_ser, NUMDMA_MASK);
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
- ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
- }
+ if (mcasp->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (mcasp->rxnumevt * rx_ser > 64)
+ mcasp->rxnumevt = 1;
+
+ reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+ mcasp_mod_bits(mcasp, reg, rx_ser, NUMDMA_MASK);
+ mcasp_mod_bits(mcasp, reg, ((mcasp->rxnumevt * rx_ser) << 8),
+ NUMEVT_MASK);
}
return 0;
}
-static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
{
int i, active_slots;
u32 mask = 0;
+ u32 busel = 0;
- active_slots = (dev->tdm_slots > 31) ? 32 : dev->tdm_slots;
+ if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
+ dev_err(mcasp->dev, "tdm slot %d not supported\n",
+ mcasp->tdm_slots);
+ return -EINVAL;
+ }
+
+ active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
for (i = 0; i < active_slots; i++)
mask |= (1 << i);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- /* bit stream is MSB first with no delay */
- /* DSP_B mode */
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask);
- mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD);
-
- if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32))
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
- FSXMOD(dev->tdm_slots), FSXMOD(0x1FF));
- else
- printk(KERN_ERR "playback tdm slot %d not supported\n",
- dev->tdm_slots);
- } else {
- /* bit stream is MSB first with no delay */
- /* DSP_B mode */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD);
- mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask);
-
- if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32))
- mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG,
- FSRMOD(dev->tdm_slots), FSRMOD(0x1FF));
- else
- printk(KERN_ERR "capture tdm slot %d not supported\n",
- dev->tdm_slots);
- }
+ if (!mcasp->dat_port)
+ busel = TXSEL;
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+ FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+ FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
+
+ return 0;
}
/* S/PDIF */
-static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
+static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
{
/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
and LSB first */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
- TXROT(6) | TXSSZ(15));
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXFMCTL_REG,
- AFSXE | FSXMOD(0x180));
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));
/* Set the TX tdm : for all the slots */
- mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);
/* Set the TX clock controls : div = 1 and internal */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG,
- ACLKXE | TX_ASYNC);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXE | TX_ASYNC);
- mcasp_clr_bits(dev->base + DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);
/* Only 44100 and 48000 are valid, both have the same setting */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));
/* Enable the DIT */
- mcasp_set_bits(dev->base + DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+
+ return 0;
}
static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
- struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
struct davinci_pcm_dma_params *dma_params =
- &dev->dma_params[substream->stream];
+ &mcasp->dma_params[substream->stream];
+ struct snd_dmaengine_dai_dma_data *dma_data =
+ &mcasp->dma_data[substream->stream];
int word_length;
u8 fifo_level;
- u8 slots = dev->tdm_slots;
+ u8 slots = mcasp->tdm_slots;
u8 active_serializers;
int channels;
+ int ret;
struct snd_interval *pcm_channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
channels = pcm_channels->min;
active_serializers = (channels + slots - 1) / slots;
- if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
+ if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL)
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- fifo_level = dev->txnumevt * active_serializers;
+ fifo_level = mcasp->txnumevt * active_serializers;
else
- fifo_level = dev->rxnumevt * active_serializers;
+ fifo_level = mcasp->rxnumevt * active_serializers;
- if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
- davinci_hw_dit_param(dev);
+ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+ ret = mcasp_dit_hw_param(mcasp);
else
- davinci_hw_param(dev, substream->stream);
+ ret = mcasp_i2s_hw_param(mcasp, substream->stream);
+
+ if (ret)
+ return ret;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_U8:
@@ -891,13 +658,15 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (dev->version == MCASP_VERSION_2 && !fifo_level)
+ if (mcasp->version == MCASP_VERSION_2 && !fifo_level)
dma_params->acnt = 4;
else
dma_params->acnt = dma_params->data_type;
dma_params->fifo_level = fifo_level;
- davinci_config_channel_size(dev, word_length);
+ dma_data->maxburst = fifo_level;
+
+ davinci_config_channel_size(mcasp, word_length);
return 0;
}
@@ -905,29 +674,19 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *cpu_dai)
{
- struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ret = pm_runtime_get_sync(dev->dev);
- if (IS_ERR_VALUE(ret))
- dev_err(dev->dev, "pm_runtime_get_sync() failed\n");
- davinci_mcasp_start(dev, substream->stream);
+ davinci_mcasp_start(mcasp, substream->stream);
break;
-
case SNDRV_PCM_TRIGGER_SUSPEND:
- davinci_mcasp_stop(dev, substream->stream);
- ret = pm_runtime_put_sync(dev->dev);
- if (IS_ERR_VALUE(ret))
- dev_err(dev->dev, "pm_runtime_put_sync() failed\n");
- break;
-
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- davinci_mcasp_stop(dev, substream->stream);
+ davinci_mcasp_stop(mcasp, substream->stream);
break;
default:
@@ -940,9 +699,14 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);
+
+ if (mcasp->version == MCASP_VERSION_4)
+ snd_soc_dai_set_dma_data(dai, substream,
+ &mcasp->dma_data[substream->stream]);
+ else
+ snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params);
- snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
return 0;
}
@@ -955,6 +719,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_sysclk = davinci_mcasp_set_sysclk,
};
+#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
+
#define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_U8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
@@ -985,7 +751,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
},
{
- "davinci-mcasp.1",
+ .name = "davinci-mcasp.1",
.playback = {
.channels_min = 1,
.channels_max = 384,
@@ -1001,23 +767,96 @@ static const struct snd_soc_component_driver davinci_mcasp_component = {
.name = "davinci-mcasp",
};
+/* Some HW specific values and defaults. The rest is filled in from DT. */
+static struct snd_platform_data dm646x_mcasp_pdata = {
+ .tx_dma_offset = 0x400,
+ .rx_dma_offset = 0x400,
+ .asp_chan_q = EVENTQ_0,
+ .version = MCASP_VERSION_1,
+};
+
+static struct snd_platform_data da830_mcasp_pdata = {
+ .tx_dma_offset = 0x2000,
+ .rx_dma_offset = 0x2000,
+ .asp_chan_q = EVENTQ_0,
+ .version = MCASP_VERSION_2,
+};
+
+static struct snd_platform_data am33xx_mcasp_pdata = {
+ .tx_dma_offset = 0,
+ .rx_dma_offset = 0,
+ .asp_chan_q = EVENTQ_0,
+ .version = MCASP_VERSION_3,
+};
+
+static struct snd_platform_data dra7_mcasp_pdata = {
+ .tx_dma_offset = 0x200,
+ .rx_dma_offset = 0x284,
+ .asp_chan_q = EVENTQ_0,
+ .version = MCASP_VERSION_4,
+};
+
static const struct of_device_id mcasp_dt_ids[] = {
{
.compatible = "ti,dm646x-mcasp-audio",
- .data = (void *)MCASP_VERSION_1,
+ .data = &dm646x_mcasp_pdata,
},
{
.compatible = "ti,da830-mcasp-audio",
- .data = (void *)MCASP_VERSION_2,
+ .data = &da830_mcasp_pdata,
},
{
- .compatible = "ti,omap2-mcasp-audio",
- .data = (void *)MCASP_VERSION_3,
+ .compatible = "ti,am33xx-mcasp-audio",
+ .data = &am33xx_mcasp_pdata,
+ },
+ {
+ .compatible = "ti,dra7-mcasp-audio",
+ .data = &dra7_mcasp_pdata,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mcasp_dt_ids);
+static int mcasp_reparent_fck(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct clk *gfclk, *parent_clk;
+ const char *parent_name;
+ int ret;
+
+ if (!node)
+ return 0;
+
+ parent_name = of_get_property(node, "fck_parent", NULL);
+ if (!parent_name)
+ return 0;
+
+ gfclk = clk_get(&pdev->dev, "fck");
+ if (IS_ERR(gfclk)) {
+ dev_err(&pdev->dev, "failed to get fck\n");
+ return PTR_ERR(gfclk);
+ }
+
+ parent_clk = clk_get(NULL, parent_name);
+ if (IS_ERR(parent_clk)) {
+ dev_err(&pdev->dev, "failed to get parent clock\n");
+ ret = PTR_ERR(parent_clk);
+ goto err1;
+ }
+
+ ret = clk_set_parent(gfclk, parent_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to reparent fck\n");
+ goto err2;
+ }
+
+err2:
+ clk_put(parent_clk);
+err1:
+ clk_put(gfclk);
+ return ret;
+}
+
static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
struct platform_device *pdev)
{
@@ -1025,9 +864,9 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
struct snd_platform_data *pdata = NULL;
const struct of_device_id *match =
of_match_device(mcasp_dt_ids, &pdev->dev);
+ struct of_phandle_args dma_spec;
const u32 *of_serial_dir32;
- u8 *of_serial_dir;
u32 val;
int i, ret = 0;
@@ -1035,20 +874,13 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
pdata = pdev->dev.platform_data;
return pdata;
} else if (match) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- ret = -ENOMEM;
- goto nodata;
- }
+ pdata = (struct snd_platform_data *) match->data;
} else {
/* control shouldn't reach here. something is wrong */
ret = -EINVAL;
goto nodata;
}
- if (match->data)
- pdata->version = (u8)((int)match->data);
-
ret = of_property_read_u32(np, "op-mode", &val);
if (ret >= 0)
pdata->op_mode = val;
@@ -1065,35 +897,46 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
pdata->tdm_slots = val;
}
- ret = of_property_read_u32(np, "num-serializer", &val);
- if (ret >= 0)
- pdata->num_serializer = val;
-
of_serial_dir32 = of_get_property(np, "serial-dir", &val);
val /= sizeof(u32);
- if (val != pdata->num_serializer) {
- dev_err(&pdev->dev,
- "num-serializer(%d) != serial-dir size(%d)\n",
- pdata->num_serializer, val);
- ret = -EINVAL;
- goto nodata;
- }
-
if (of_serial_dir32) {
- of_serial_dir = devm_kzalloc(&pdev->dev,
- (sizeof(*of_serial_dir) * val),
- GFP_KERNEL);
+ u8 *of_serial_dir = devm_kzalloc(&pdev->dev,
+ (sizeof(*of_serial_dir) * val),
+ GFP_KERNEL);
if (!of_serial_dir) {
ret = -ENOMEM;
goto nodata;
}
- for (i = 0; i < pdata->num_serializer; i++)
+ for (i = 0; i < val; i++)
of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]);
+ pdata->num_serializer = val;
pdata->serial_dir = of_serial_dir;
}
+ ret = of_property_match_string(np, "dma-names", "tx");
+ if (ret < 0)
+ goto nodata;
+
+ ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+ &dma_spec);
+ if (ret < 0)
+ goto nodata;
+
+ pdata->tx_dma_channel = dma_spec.args[0];
+
+ ret = of_property_match_string(np, "dma-names", "rx");
+ if (ret < 0)
+ goto nodata;
+
+ ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+ &dma_spec);
+ if (ret < 0)
+ goto nodata;
+
+ pdata->rx_dma_channel = dma_spec.args[0];
+
ret = of_property_read_u32(np, "tx-num-evt", &val);
if (ret >= 0)
pdata->txnumevt = val;
@@ -1124,9 +967,9 @@ nodata:
static int davinci_mcasp_probe(struct platform_device *pdev)
{
struct davinci_pcm_dma_params *dma_data;
- struct resource *mem, *ioarea, *res;
+ struct resource *mem, *ioarea, *res, *dat;
struct snd_platform_data *pdata;
- struct davinci_audio_dev *dev;
+ struct davinci_mcasp *mcasp;
int ret;
if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -1134,9 +977,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
return -EINVAL;
}
- dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),
+ mcasp = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcasp),
GFP_KERNEL);
- if (!dev)
+ if (!mcasp)
return -ENOMEM;
pdata = davinci_mcasp_set_pdata_from_of(pdev);
@@ -1145,10 +988,15 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
return -EINVAL;
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
+ dev_warn(mcasp->dev,
+ "\"mpu\" mem resource not found, using index 0\n");
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
}
ioarea = devm_request_mem_region(&pdev->dev, mem->start,
@@ -1166,67 +1014,93 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
return ret;
}
- dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!dev->base) {
+ mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (!mcasp->base) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
goto err_release_clk;
}
- dev->op_mode = pdata->op_mode;
- dev->tdm_slots = pdata->tdm_slots;
- dev->num_serializer = pdata->num_serializer;
- dev->serial_dir = pdata->serial_dir;
- dev->version = pdata->version;
- dev->txnumevt = pdata->txnumevt;
- dev->rxnumevt = pdata->rxnumevt;
- dev->dev = &pdev->dev;
+ mcasp->op_mode = pdata->op_mode;
+ mcasp->tdm_slots = pdata->tdm_slots;
+ mcasp->num_serializer = pdata->num_serializer;
+ mcasp->serial_dir = pdata->serial_dir;
+ mcasp->version = pdata->version;
+ mcasp->txnumevt = pdata->txnumevt;
+ mcasp->rxnumevt = pdata->rxnumevt;
- dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
+ mcasp->dev = &pdev->dev;
+
+ dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+ if (dat)
+ mcasp->dat_port = true;
+
+ dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
dma_data->asp_chan_q = pdata->asp_chan_q;
dma_data->ram_chan_q = pdata->ram_chan_q;
dma_data->sram_pool = pdata->sram_pool;
dma_data->sram_size = pdata->sram_size_playback;
- dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
- mem->start);
+ if (dat)
+ dma_data->dma_addr = dat->start;
+ else
+ dma_data->dma_addr = mem->start + pdata->tx_dma_offset;
- /* first TX, then RX */
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!res) {
- dev_err(&pdev->dev, "no DMA resource\n");
- ret = -ENODEV;
- goto err_release_clk;
- }
+ /* Unconditional dmaengine stuff */
+ mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr;
- dma_data->channel = res->start;
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (res)
+ dma_data->channel = res->start;
+ else
+ dma_data->channel = pdata->tx_dma_channel;
- dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+ dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
dma_data->asp_chan_q = pdata->asp_chan_q;
dma_data->ram_chan_q = pdata->ram_chan_q;
dma_data->sram_pool = pdata->sram_pool;
dma_data->sram_size = pdata->sram_size_capture;
- dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
- mem->start);
+ if (dat)
+ dma_data->dma_addr = dat->start;
+ else
+ dma_data->dma_addr = mem->start + pdata->rx_dma_offset;
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!res) {
- dev_err(&pdev->dev, "no DMA resource\n");
- ret = -ENODEV;
- goto err_release_clk;
+ /* Unconditional dmaengine stuff */
+ mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr;
+
+ if (mcasp->version < MCASP_VERSION_3) {
+ mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
+ /* dma_data->dma_addr is pointing to the data port address */
+ mcasp->dat_port = true;
+ } else {
+ mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
}
- dma_data->channel = res->start;
- dev_set_drvdata(&pdev->dev, dev);
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (res)
+ dma_data->channel = res->start;
+ else
+ dma_data->channel = pdata->rx_dma_channel;
+
+ /* Unconditional dmaengine stuff */
+ mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx";
+ mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx";
+
+ dev_set_drvdata(&pdev->dev, mcasp);
+
+ mcasp_reparent_fck(pdev);
+
ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
&davinci_mcasp_dai[pdata->op_mode], 1);
if (ret != 0)
goto err_release_clk;
- ret = davinci_soc_platform_register(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
- goto err_unregister_component;
+ if (mcasp->version != MCASP_VERSION_4) {
+ ret = davinci_soc_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+ goto err_unregister_component;
+ }
}
return 0;
@@ -1241,9 +1115,11 @@ err_release_clk:
static int davinci_mcasp_remove(struct platform_device *pdev)
{
+ struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
- davinci_soc_platform_unregister(&pdev->dev);
+ if (mcasp->version != MCASP_VERSION_4)
+ davinci_soc_platform_unregister(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1251,12 +1127,49 @@ static int davinci_mcasp_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int davinci_mcasp_suspend(struct device *dev)
+{
+ struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
+
+ mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG);
+ mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG);
+ mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG);
+ mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG);
+ mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG);
+ mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG);
+ mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG);
+
+ return 0;
+}
+
+static int davinci_mcasp_resume(struct device *dev)
+{
+ struct davinci_mcasp *mcasp = dev_get_drvdata(dev);
+
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl);
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir);
+
+ return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops,
+ davinci_mcasp_suspend,
+ davinci_mcasp_resume);
+
static struct platform_driver davinci_mcasp_driver = {
.probe = davinci_mcasp_probe,
.remove = davinci_mcasp_remove,
.driver = {
.name = "davinci-mcasp",
.owner = THIS_MODULE,
+ .pm = &davinci_mcasp_pm_ops,
.of_match_table = mcasp_dt_ids,
},
};
@@ -1266,4 +1179,3 @@ module_platform_driver(davinci_mcasp_driver);
MODULE_AUTHOR("Steve Chen");
MODULE_DESCRIPTION("TI DAVINCI McASP SoC Interface");
MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index a9ac0c11da71..8fed757d6087 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -18,31 +18,271 @@
#ifndef DAVINCI_MCASP_H
#define DAVINCI_MCASP_H
-#include <linux/io.h>
-#include <linux/platform_data/davinci_asp.h>
-
-#include "davinci-pcm.h"
-
-#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000
-#define DAVINCI_MCASP_I2S_DAI 0
-#define DAVINCI_MCASP_DIT_DAI 1
-
-struct davinci_audio_dev {
- struct davinci_pcm_dma_params dma_params[2];
- void __iomem *base;
- struct device *dev;
-
- /* McASP specific data */
- int tdm_slots;
- u8 op_mode;
- u8 num_serializer;
- u8 *serial_dir;
- u8 version;
- u16 bclk_lrclk_ratio;
-
- /* McASP FIFO related */
- u8 txnumevt;
- u8 rxnumevt;
-};
+/*
+ * McASP register definitions
+ */
+#define DAVINCI_MCASP_PID_REG 0x00
+#define DAVINCI_MCASP_PWREMUMGT_REG 0x04
+
+#define DAVINCI_MCASP_PFUNC_REG 0x10
+#define DAVINCI_MCASP_PDIR_REG 0x14
+#define DAVINCI_MCASP_PDOUT_REG 0x18
+#define DAVINCI_MCASP_PDSET_REG 0x1c
+
+#define DAVINCI_MCASP_PDCLR_REG 0x20
+
+#define DAVINCI_MCASP_TLGC_REG 0x30
+#define DAVINCI_MCASP_TLMR_REG 0x34
+
+#define DAVINCI_MCASP_GBLCTL_REG 0x44
+#define DAVINCI_MCASP_AMUTE_REG 0x48
+#define DAVINCI_MCASP_LBCTL_REG 0x4c
+
+#define DAVINCI_MCASP_TXDITCTL_REG 0x50
+
+#define DAVINCI_MCASP_GBLCTLR_REG 0x60
+#define DAVINCI_MCASP_RXMASK_REG 0x64
+#define DAVINCI_MCASP_RXFMT_REG 0x68
+#define DAVINCI_MCASP_RXFMCTL_REG 0x6c
+
+#define DAVINCI_MCASP_ACLKRCTL_REG 0x70
+#define DAVINCI_MCASP_AHCLKRCTL_REG 0x74
+#define DAVINCI_MCASP_RXTDM_REG 0x78
+#define DAVINCI_MCASP_EVTCTLR_REG 0x7c
+
+#define DAVINCI_MCASP_RXSTAT_REG 0x80
+#define DAVINCI_MCASP_RXTDMSLOT_REG 0x84
+#define DAVINCI_MCASP_RXCLKCHK_REG 0x88
+#define DAVINCI_MCASP_REVTCTL_REG 0x8c
+
+#define DAVINCI_MCASP_GBLCTLX_REG 0xa0
+#define DAVINCI_MCASP_TXMASK_REG 0xa4
+#define DAVINCI_MCASP_TXFMT_REG 0xa8
+#define DAVINCI_MCASP_TXFMCTL_REG 0xac
+
+#define DAVINCI_MCASP_ACLKXCTL_REG 0xb0
+#define DAVINCI_MCASP_AHCLKXCTL_REG 0xb4
+#define DAVINCI_MCASP_TXTDM_REG 0xb8
+#define DAVINCI_MCASP_EVTCTLX_REG 0xbc
+
+#define DAVINCI_MCASP_TXSTAT_REG 0xc0
+#define DAVINCI_MCASP_TXTDMSLOT_REG 0xc4
+#define DAVINCI_MCASP_TXCLKCHK_REG 0xc8
+#define DAVINCI_MCASP_XEVTCTL_REG 0xcc
+
+/* Left(even TDM Slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRA_REG 0x100
+/* Right(odd TDM slot) Channel Status Register File */
+#define DAVINCI_MCASP_DITCSRB_REG 0x118
+/* Left(even TDM slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRA_REG 0x130
+/* Right(odd TDM Slot) User Data Register File */
+#define DAVINCI_MCASP_DITUDRB_REG 0x148
+
+/* Serializer n Control Register */
+#define DAVINCI_MCASP_XRSRCTL_BASE_REG 0x180
+#define DAVINCI_MCASP_XRSRCTL_REG(n) (DAVINCI_MCASP_XRSRCTL_BASE_REG + \
+ (n << 2))
+
+/* Transmit Buffer for Serializer n */
+#define DAVINCI_MCASP_TXBUF_REG 0x200
+/* Receive Buffer for Serializer n */
+#define DAVINCI_MCASP_RXBUF_REG 0x280
+
+/* McASP FIFO Registers */
+#define DAVINCI_MCASP_V2_AFIFO_BASE (0x1010)
+#define DAVINCI_MCASP_V3_AFIFO_BASE (0x1000)
+
+/* FIFO register offsets from AFIFO base */
+#define MCASP_WFIFOCTL_OFFSET (0x0)
+#define MCASP_WFIFOSTS_OFFSET (0x4)
+#define MCASP_RFIFOCTL_OFFSET (0x8)
+#define MCASP_RFIFOSTS_OFFSET (0xc)
+
+/*
+ * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management
+ * Register Bits
+ */
+#define MCASP_FREE BIT(0)
+#define MCASP_SOFT BIT(1)
+
+/*
+ * DAVINCI_MCASP_PFUNC_REG - Pin Function / GPIO Enable Register Bits
+ */
+#define AXR(n) (1<<n)
+#define PFUNC_AMUTE BIT(25)
+#define ACLKX BIT(26)
+#define AHCLKX BIT(27)
+#define AFSX BIT(28)
+#define ACLKR BIT(29)
+#define AHCLKR BIT(30)
+#define AFSR BIT(31)
+
+/*
+ * DAVINCI_MCASP_PDIR_REG - Pin Direction Register Bits
+ */
+#define AXR(n) (1<<n)
+#define PDIR_AMUTE BIT(25)
+#define ACLKX BIT(26)
+#define AHCLKX BIT(27)
+#define AFSX BIT(28)
+#define ACLKR BIT(29)
+#define AHCLKR BIT(30)
+#define AFSR BIT(31)
+
+/*
+ * DAVINCI_MCASP_TXDITCTL_REG - Transmit DIT Control Register Bits
+ */
+#define DITEN BIT(0) /* Transmit DIT mode enable/disable */
+#define VA BIT(2)
+#define VB BIT(3)
+
+/*
+ * DAVINCI_MCASP_TXFMT_REG - Transmit Bitstream Format Register Bits
+ */
+#define TXROT(val) (val)
+#define TXSEL BIT(3)
+#define TXSSZ(val) (val<<4)
+#define TXPBIT(val) (val<<8)
+#define TXPAD(val) (val<<13)
+#define TXORD BIT(15)
+#define FSXDLY(val) (val<<16)
+
+/*
+ * DAVINCI_MCASP_RXFMT_REG - Receive Bitstream Format Register Bits
+ */
+#define RXROT(val) (val)
+#define RXSEL BIT(3)
+#define RXSSZ(val) (val<<4)
+#define RXPBIT(val) (val<<8)
+#define RXPAD(val) (val<<13)
+#define RXORD BIT(15)
+#define FSRDLY(val) (val<<16)
+
+/*
+ * DAVINCI_MCASP_TXFMCTL_REG - Transmit Frame Control Register Bits
+ */
+#define FSXPOL BIT(0)
+#define AFSXE BIT(1)
+#define FSXDUR BIT(4)
+#define FSXMOD(val) (val<<7)
+
+/*
+ * DAVINCI_MCASP_RXFMCTL_REG - Receive Frame Control Register Bits
+ */
+#define FSRPOL BIT(0)
+#define AFSRE BIT(1)
+#define FSRDUR BIT(4)
+#define FSRMOD(val) (val<<7)
+
+/*
+ * DAVINCI_MCASP_ACLKXCTL_REG - Transmit Clock Control Register Bits
+ */
+#define ACLKXDIV(val) (val)
+#define ACLKXE BIT(5)
+#define TX_ASYNC BIT(6)
+#define ACLKXPOL BIT(7)
+#define ACLKXDIV_MASK 0x1f
+
+/*
+ * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits
+ */
+#define ACLKRDIV(val) (val)
+#define ACLKRE BIT(5)
+#define RX_ASYNC BIT(6)
+#define ACLKRPOL BIT(7)
+#define ACLKRDIV_MASK 0x1f
+
+/*
+ * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control
+ * Register Bits
+ */
+#define AHCLKXDIV(val) (val)
+#define AHCLKXPOL BIT(14)
+#define AHCLKXE BIT(15)
+#define AHCLKXDIV_MASK 0xfff
+
+/*
+ * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control
+ * Register Bits
+ */
+#define AHCLKRDIV(val) (val)
+#define AHCLKRPOL BIT(14)
+#define AHCLKRE BIT(15)
+#define AHCLKRDIV_MASK 0xfff
+
+/*
+ * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits
+ */
+#define MODE(val) (val)
+#define DISMOD (val)(val<<2)
+#define TXSTATE BIT(4)
+#define RXSTATE BIT(5)
+#define SRMOD_MASK 3
+#define SRMOD_INACTIVE 0
+
+/*
+ * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
+ */
+#define LBEN BIT(0)
+#define LBORD BIT(1)
+#define LBGENMODE(val) (val<<2)
+
+/*
+ * DAVINCI_MCASP_TXTDMSLOT_REG - Transmit TDM Slot Register configuration
+ */
+#define TXTDMS(n) (1<<n)
+
+/*
+ * DAVINCI_MCASP_RXTDMSLOT_REG - Receive TDM Slot Register configuration
+ */
+#define RXTDMS(n) (1<<n)
+
+/*
+ * DAVINCI_MCASP_GBLCTL_REG - Global Control Register Bits
+ */
+#define RXCLKRST BIT(0) /* Receiver Clock Divider Reset */
+#define RXHCLKRST BIT(1) /* Receiver High Frequency Clock Divider */
+#define RXSERCLR BIT(2) /* Receiver Serializer Clear */
+#define RXSMRST BIT(3) /* Receiver State Machine Reset */
+#define RXFSRST BIT(4) /* Frame Sync Generator Reset */
+#define TXCLKRST BIT(8) /* Transmitter Clock Divider Reset */
+#define TXHCLKRST BIT(9) /* Transmitter High Frequency Clock Divider*/
+#define TXSERCLR BIT(10) /* Transmit Serializer Clear */
+#define TXSMRST BIT(11) /* Transmitter State Machine Reset */
+#define TXFSRST BIT(12) /* Frame Sync Generator Reset */
+
+/*
+ * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits
+ */
+#define MUTENA(val) (val)
+#define MUTEINPOL BIT(2)
+#define MUTEINENA BIT(3)
+#define MUTEIN BIT(4)
+#define MUTER BIT(5)
+#define MUTEX BIT(6)
+#define MUTEFSR BIT(7)
+#define MUTEFSX BIT(8)
+#define MUTEBADCLKR BIT(9)
+#define MUTEBADCLKX BIT(10)
+#define MUTERXDMAERR BIT(11)
+#define MUTETXDMAERR BIT(12)
+
+/*
+ * DAVINCI_MCASP_REVTCTL_REG - Receiver DMA Event Control Register bits
+ */
+#define RXDATADMADIS BIT(0)
+
+/*
+ * DAVINCI_MCASP_XEVTCTL_REG - Transmitter DMA Event Control Register bits
+ */
+#define TXDATADMADIS BIT(0)
+
+/*
+ * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
+ */
+#define FIFO_ENABLE BIT(16)
+#define NUMEVT_MASK (0xFF << 8)
+#define NUMDMA_MASK (0xFF)
#endif /* DAVINCI_MCASP_H */
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 8460edce1c3b..14145cdf8a11 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -46,33 +46,11 @@ static void print_buf_info(int slot, char *name)
}
#endif
-#define DAVINCI_PCM_FMTBITS (\
- SNDRV_PCM_FMTBIT_S8 |\
- SNDRV_PCM_FMTBIT_U8 |\
- SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S16_BE |\
- SNDRV_PCM_FMTBIT_U16_LE |\
- SNDRV_PCM_FMTBIT_U16_BE |\
- SNDRV_PCM_FMTBIT_S24_LE |\
- SNDRV_PCM_FMTBIT_S24_BE |\
- SNDRV_PCM_FMTBIT_U24_LE |\
- SNDRV_PCM_FMTBIT_U24_BE |\
- SNDRV_PCM_FMTBIT_S32_LE |\
- SNDRV_PCM_FMTBIT_S32_BE |\
- SNDRV_PCM_FMTBIT_U32_LE |\
- SNDRV_PCM_FMTBIT_U32_BE)
-
static struct snd_pcm_hardware pcm_hardware_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|
SNDRV_PCM_INFO_BATCH),
- .formats = DAVINCI_PCM_FMTBITS,
- .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
- .rate_min = 8000,
- .rate_max = 192000,
- .channels_min = 2,
- .channels_max = 384,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8 * 1024,
@@ -86,12 +64,6 @@ static struct snd_pcm_hardware pcm_hardware_capture = {
SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_BATCH),
- .formats = DAVINCI_PCM_FMTBITS,
- .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT,
- .rate_min = 8000,
- .rate_max = 192000,
- .channels_min = 2,
- .channels_max = 384,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8 * 1024,
@@ -238,7 +210,7 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
print_buf_info(prtd->ram_channel, "i ram_channel");
pr_debug("davinci_pcm: link=%d, status=0x%x\n", link, ch_status);
- if (unlikely(ch_status != DMA_COMPLETE))
+ if (unlikely(ch_status != EDMA_DMA_COMPLETE))
return;
if (snd_pcm_running(substream)) {
@@ -267,10 +239,9 @@ static int allocate_sram(struct snd_pcm_substream *substream,
return 0;
ppcm->period_bytes_max = size;
- iram_virt = (void *)gen_pool_alloc(sram_pool, size);
+ iram_virt = gen_pool_dma_alloc(sram_pool, size, &iram_phys);
if (!iram_virt)
goto exit1;
- iram_phys = gen_pool_virt_to_phys(sram_pool, (unsigned)iram_virt);
iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL);
if (!iram_dma)
goto exit2;
@@ -844,18 +815,15 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
}
}
-static u64 davinci_pcm_dmamask = DMA_BIT_MASK(32);
-
static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &davinci_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = davinci_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index b7ab71f2ccc1..07f8f141727d 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,9 +1,16 @@
+config SND_SOC_FSL_SAI
+ tristate
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+
config SND_SOC_FSL_SSI
tristate
config SND_SOC_FSL_SPDIF
tristate
+config SND_SOC_FSL_ESAI
+ tristate
+
config SND_SOC_FSL_UTILS
tristate
@@ -197,7 +204,6 @@ config SND_SOC_IMX_SPDIF
tristate "SoC Audio support for i.MX boards with S/PDIF"
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_SPDIF
- select SND_SOC_SPDIF
select REGMAP_MMIO
help
SoC Audio support for i.MX boards with S/PDIF
@@ -206,7 +212,7 @@ config SND_SOC_IMX_SPDIF
config SND_SOC_IMX_MC13783
tristate "SoC Audio support for I.MX boards with mc13783"
- depends on MFD_MC13783 && ARM
+ depends on MFD_MC13XXX && ARM
select SND_SOC_IMX_SSI
select SND_SOC_IMX_AUDMUX
select SND_SOC_MC13783
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8db705b0fdf9..b12ad4b9b4da 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -10,13 +10,17 @@ obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
snd-soc-p1022-rdk-objs := p1022_rdk.o
obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
-# Freescale PowerPC SSI/DMA Platform Support
+# Freescale SSI/DMA/SAI/SPDIF Support
+snd-soc-fsl-sai-objs := fsl_sai.o
snd-soc-fsl-ssi-objs := fsl_ssi.o
snd-soc-fsl-spdif-objs := fsl_spdif.o
+snd-soc-fsl-esai-objs := fsl_esai.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
+obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
+obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 9a4a0ca2c1de..5983740be123 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -42,7 +42,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret) {
- pr_err("%s: failed set cpu dai format\n", __func__);
+ dev_err(cpu_dai->dev,
+ "Failed to set the cpu dai format.\n");
return ret;
}
@@ -50,14 +51,16 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret) {
- pr_err("%s: failed set codec dai format\n", __func__);
+ dev_err(cpu_dai->dev,
+ "Failed to set the codec format.\n");
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, 0,
CODEC_CLOCK, SND_SOC_CLOCK_OUT);
if (ret) {
- pr_err("%s: failed setting codec sysclk\n", __func__);
+ dev_err(cpu_dai->dev,
+ "Failed to set the codec sysclk.\n");
return ret;
}
snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
@@ -65,7 +68,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
SND_SOC_CLOCK_IN);
if (ret) {
- pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
+ dev_err(cpu_dai->dev,
+ "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n");
return ret;
}
@@ -155,7 +159,8 @@ static struct platform_driver eukrea_tlv320_driver = {
.owner = THIS_MODULE,
},
.probe = eukrea_tlv320_probe,
- .remove = eukrea_tlv320_remove,};
+ .remove = eukrea_tlv320_remove,
+};
module_platform_driver(eukrea_tlv320_driver);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 9cc5c1f82f09..6bb0ea59284f 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -21,6 +21,8 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/gfp.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/list.h>
#include <linux/slab.h>
@@ -53,10 +55,6 @@
SNDRV_PCM_FMTBIT_S32_BE | \
SNDRV_PCM_FMTBIT_U32_LE | \
SNDRV_PCM_FMTBIT_U32_BE)
-
-#define FSLDMA_PCM_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
- SNDRV_PCM_RATE_CONTINUOUS)
-
struct dma_object {
struct snd_soc_platform_driver dai;
dma_addr_t ssi_stx_phys;
@@ -138,9 +136,6 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
SNDRV_PCM_INFO_JOINT_DUPLEX |
SNDRV_PCM_INFO_PAUSE,
.formats = FSLDMA_PCM_FORMATS,
- .rates = FSLDMA_PCM_RATES,
- .rate_min = 5512,
- .rate_max = 192000,
.period_bytes_min = 512, /* A reasonable limit */
.period_bytes_max = (u32) -1,
.periods_min = NUM_DMA_LINKS,
@@ -298,14 +293,11 @@ static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- static u64 fsl_dma_dmamask = DMA_BIT_MASK(36);
int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &fsl_dma_dmamask;
-
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = fsl_dma_dmamask;
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(36));
+ if (ret)
+ return ret;
/* Some codecs have separate DAIs for playback and capture, so we
* should allocate a DMA buffer only for the streams that are valid.
@@ -853,7 +845,7 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
}
/**
- * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ * find_ssi_node -- returns the SSI node that points to its DMA channel node
*
* Although this DMA driver attempts to operate independently of the other
* devices, it still needs to determine some information about the SSI device
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
new file mode 100644
index 000000000000..c84026c99134
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.c
@@ -0,0 +1,815 @@
+/*
+ * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_esai.h"
+#include "imx-pcm.h"
+
+#define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000
+#define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+/**
+ * fsl_esai: ESAI private data
+ *
+ * @dma_params_rx: DMA parameters for receive channel
+ * @dma_params_tx: DMA parameters for transmit channel
+ * @pdev: platform device pointer
+ * @regmap: regmap handler
+ * @coreclk: clock source to access register
+ * @extalclk: esai clock source to derive HCK, SCK and FS
+ * @fsysclk: system clock source to derive HCK, SCK and FS
+ * @fifo_depth: depth of tx/rx FIFO
+ * @slot_width: width of each DAI slot
+ * @hck_rate: clock rate of desired HCKx clock
+ * @sck_div: if using PSR/PM dividers for SCKx clock
+ * @slave_mode: if fully using DAI slave mode
+ * @synchronous: if using tx/rx synchronous mode
+ * @name: driver name
+ */
+struct fsl_esai {
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct clk *coreclk;
+ struct clk *extalclk;
+ struct clk *fsysclk;
+ u32 fifo_depth;
+ u32 slot_width;
+ u32 hck_rate[2];
+ bool sck_div[2];
+ bool slave_mode;
+ bool synchronous;
+ char name[32];
+};
+
+static irqreturn_t esai_isr(int irq, void *devid)
+{
+ struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
+ struct platform_device *pdev = esai_priv->pdev;
+ u32 esr;
+
+ regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
+
+ if (esr & ESAI_ESR_TINIT_MASK)
+ dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
+
+ if (esr & ESAI_ESR_RFF_MASK)
+ dev_warn(&pdev->dev, "isr: Receiving overrun\n");
+
+ if (esr & ESAI_ESR_TFE_MASK)
+ dev_warn(&pdev->dev, "isr: Transmition underrun\n");
+
+ if (esr & ESAI_ESR_TLS_MASK)
+ dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
+
+ if (esr & ESAI_ESR_TDE_MASK)
+ dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
+
+ if (esr & ESAI_ESR_TED_MASK)
+ dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
+
+ if (esr & ESAI_ESR_TD_MASK)
+ dev_dbg(&pdev->dev, "isr: Transmitting data\n");
+
+ if (esr & ESAI_ESR_RLS_MASK)
+ dev_dbg(&pdev->dev, "isr: Just received the last slot\n");
+
+ if (esr & ESAI_ESR_RDE_MASK)
+ dev_dbg(&pdev->dev, "isr: Receiving data exception\n");
+
+ if (esr & ESAI_ESR_RED_MASK)
+ dev_dbg(&pdev->dev, "isr: Receiving even slots\n");
+
+ if (esr & ESAI_ESR_RD_MASK)
+ dev_dbg(&pdev->dev, "isr: Receiving data\n");
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * This function is used to calculate the divisors of psr, pm, fp and it is
+ * supposed to be called in set_dai_sysclk() and set_bclk().
+ *
+ * @ratio: desired overall ratio for the paticipating dividers
+ * @usefp: for HCK setting, there is no need to set fp divider
+ * @fp: bypass other dividers by setting fp directly if fp != 0
+ * @tx: current setting is for playback or capture
+ */
+static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,
+ bool usefp, u32 fp)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
+
+ maxfp = usefp ? 16 : 1;
+
+ if (usefp && fp)
+ goto out_fp;
+
+ if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
+ dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
+ 2 * 8 * 256 * maxfp);
+ return -EINVAL;
+ } else if (ratio % 2) {
+ dev_err(dai->dev, "the raio must be even if using upper divider\n");
+ return -EINVAL;
+ }
+
+ ratio /= 2;
+
+ psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
+
+ /* Set the max fluctuation -- 0.1% of the max devisor */
+ savesub = (psr ? 1 : 8) * 256 * maxfp / 1000;
+
+ /* Find the best value for PM */
+ for (i = 1; i <= 256; i++) {
+ for (j = 1; j <= maxfp; j++) {
+ /* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
+ prod = (psr ? 1 : 8) * i * j;
+
+ if (prod == ratio)
+ sub = 0;
+ else if (prod / ratio == 1)
+ sub = prod - ratio;
+ else if (ratio / prod == 1)
+ sub = ratio - prod;
+ else
+ continue;
+
+ /* Calculate the fraction */
+ sub = sub * 1000 / ratio;
+ if (sub < savesub) {
+ savesub = sub;
+ pm = i;
+ fp = j;
+ }
+
+ /* We are lucky */
+ if (savesub == 0)
+ goto out;
+ }
+ }
+
+ if (pm == 999) {
+ dev_err(dai->dev, "failed to calculate proper divisors\n");
+ return -EINVAL;
+ }
+
+out:
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
+ ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
+ psr | ESAI_xCCR_xPM(pm));
+
+out_fp:
+ /* Bypass fp if not being required */
+ if (maxfp <= 1)
+ return 0;
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
+ ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
+
+ return 0;
+}
+
+/**
+ * This function mainly configures the clock frequency of MCLK (HCKT/HCKR)
+ *
+ * @Parameters:
+ * clk_id: The clock source of HCKT/HCKR
+ * (Input from outside; output from inside, FSYS or EXTAL)
+ * freq: The required clock rate of HCKT/HCKR
+ * dir: The clock direction of HCKT/HCKR
+ *
+ * Note: If the direction is input, we do not care about clk_id.
+ */
+static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ struct clk *clksrc = esai_priv->extalclk;
+ bool tx = clk_id <= ESAI_HCKT_EXTAL;
+ bool in = dir == SND_SOC_CLOCK_IN;
+ u32 ret, ratio, ecr = 0;
+ unsigned long clk_rate;
+
+ /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
+ esai_priv->sck_div[tx] = true;
+
+ /* Set the direction of HCKT/HCKR pins */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
+ ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
+
+ if (in)
+ goto out;
+
+ switch (clk_id) {
+ case ESAI_HCKT_FSYS:
+ case ESAI_HCKR_FSYS:
+ clksrc = esai_priv->fsysclk;
+ break;
+ case ESAI_HCKT_EXTAL:
+ ecr |= ESAI_ECR_ETI;
+ case ESAI_HCKR_EXTAL:
+ ecr |= ESAI_ECR_ERI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (IS_ERR(clksrc)) {
+ dev_err(dai->dev, "no assigned %s clock\n",
+ clk_id % 2 ? "extal" : "fsys");
+ return PTR_ERR(clksrc);
+ }
+ clk_rate = clk_get_rate(clksrc);
+
+ ratio = clk_rate / freq;
+ if (ratio * freq > clk_rate)
+ ret = ratio * freq - clk_rate;
+ else if (ratio * freq < clk_rate)
+ ret = clk_rate - ratio * freq;
+ else
+ ret = 0;
+
+ /* Block if clock source can not be divided into the required rate */
+ if (ret != 0 && clk_rate / ret < 1000) {
+ dev_err(dai->dev, "failed to derive required HCK%c rate\n",
+ tx ? 'T' : 'R');
+ return -EINVAL;
+ }
+
+ if (ratio == 1) {
+ /* Bypass all the dividers if not being needed */
+ ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
+ goto out;
+ }
+
+ ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
+ if (ret)
+ return ret;
+
+ esai_priv->sck_div[tx] = false;
+
+out:
+ esai_priv->hck_rate[tx] = freq;
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
+ tx ? ESAI_ECR_ETI | ESAI_ECR_ETO :
+ ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
+
+ return 0;
+}
+
+/**
+ * This function configures the related dividers according to the bclk rate
+ */
+static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ u32 hck_rate = esai_priv->hck_rate[tx];
+ u32 sub, ratio = hck_rate / freq;
+
+ /* Don't apply for fully slave mode*/
+ if (esai_priv->slave_mode)
+ return 0;
+
+ if (ratio * freq > hck_rate)
+ sub = ratio * freq - hck_rate;
+ else if (ratio * freq < hck_rate)
+ sub = hck_rate - ratio * freq;
+ else
+ sub = 0;
+
+ /* Block if clock source can not be divided into the required rate */
+ if (sub != 0 && hck_rate / sub < 1000) {
+ dev_err(dai->dev, "failed to derive required SCK%c rate\n",
+ tx ? 'T' : 'R');
+ return -EINVAL;
+ }
+
+ if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
+ dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
+ return -EINVAL;
+ }
+
+ return fsl_esai_divisor_cal(dai, tx, ratio, true,
+ esai_priv->sck_div[tx] ? 0 : ratio);
+}
+
+static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+ ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
+ ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
+ ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask));
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+ ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
+ ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
+ ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
+
+ esai_priv->slot_width = slot_width;
+
+ return 0;
+}
+
+static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ u32 xcr = 0, xccr = 0, mask;
+
+ /* DAI mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* Data on rising edge of bclk, frame low, 1clk before data */
+ xcr |= ESAI_xCR_xFSR;
+ xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* Data on rising edge of bclk, frame high */
+ xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* Data on rising edge of bclk, frame high, right aligned */
+ xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* Data on rising edge of bclk, frame high, 1clk before data */
+ xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+ xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /* Data on rising edge of bclk, frame high */
+ xcr |= ESAI_xCR_xFSL;
+ xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to do for both normal cases */
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Invert bit clock */
+ xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Invert frame clock */
+ xccr ^= ESAI_xCCR_xFSP;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert both clocks */
+ xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ esai_priv->slave_mode = false;
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ esai_priv->slave_mode = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ xccr |= ESAI_xCCR_xCKD;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ xccr |= ESAI_xCCR_xFSD;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR;
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);
+
+ mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |
+ ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA;
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);
+
+ return 0;
+}
+
+static int fsl_esai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+ /*
+ * Some platforms might use the same bit to gate all three or two of
+ * clocks, so keep all clocks open/close at the same time for safety
+ */
+ clk_prepare_enable(esai_priv->coreclk);
+ if (!IS_ERR(esai_priv->extalclk))
+ clk_prepare_enable(esai_priv->extalclk);
+ if (!IS_ERR(esai_priv->fsysclk))
+ clk_prepare_enable(esai_priv->fsysclk);
+
+ if (!dai->active) {
+ /* Reset Port C */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
+ ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
+ ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
+
+ /* Set synchronous mode */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
+ ESAI_SAICR_SYNC, esai_priv->synchronous ?
+ ESAI_SAICR_SYNC : 0);
+
+ /* Set a default slot number -- 2 */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
+ ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
+ ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
+ }
+
+ return 0;
+}
+
+static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u32 width = snd_pcm_format_width(params_format(params));
+ u32 channels = params_channels(params);
+ u32 bclk, mask, val, ret;
+
+ bclk = params_rate(params) * esai_priv->slot_width * 2;
+
+ ret = fsl_esai_set_bclk(dai, tx, bclk);
+ if (ret)
+ return ret;
+
+ /* Use Normal mode to support monaural audio */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+ ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?
+ ESAI_xCR_xMOD_NETWORK : 0);
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+ ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
+
+ mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
+ (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
+ val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
+ (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
+
+ mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
+ val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+
+ return 0;
+}
+
+static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+ if (!IS_ERR(esai_priv->fsysclk))
+ clk_disable_unprepare(esai_priv->fsysclk);
+ if (!IS_ERR(esai_priv->extalclk))
+ clk_disable_unprepare(esai_priv->extalclk);
+ clk_disable_unprepare(esai_priv->coreclk);
+}
+
+static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u8 i, channels = substream->runtime->channels;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+ ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
+
+ /* Write initial words reqiured by ESAI as normal procedure */
+ for (i = 0; tx && i < channels; i++)
+ regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+ tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
+ tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
+ tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
+
+ /* Disable and reset FIFO */
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+ ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
+ ESAI_xFCR_xFR, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+ .startup = fsl_esai_startup,
+ .shutdown = fsl_esai_shutdown,
+ .trigger = fsl_esai_trigger,
+ .hw_params = fsl_esai_hw_params,
+ .set_sysclk = fsl_esai_set_dai_sysclk,
+ .set_fmt = fsl_esai_set_dai_fmt,
+ .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
+static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
+{
+ struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,
+ &esai_priv->dma_params_rx);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+ .probe = fsl_esai_dai_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 12,
+ .rates = FSL_ESAI_RATES,
+ .formats = FSL_ESAI_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = FSL_ESAI_RATES,
+ .formats = FSL_ESAI_FORMATS,
+ },
+ .ops = &fsl_esai_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_esai_component = {
+ .name = "fsl-esai",
+};
+
+static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case REG_ESAI_ERDR:
+ case REG_ESAI_ECR:
+ case REG_ESAI_ESR:
+ case REG_ESAI_TFCR:
+ case REG_ESAI_TFSR:
+ case REG_ESAI_RFCR:
+ case REG_ESAI_RFSR:
+ case REG_ESAI_RX0:
+ case REG_ESAI_RX1:
+ case REG_ESAI_RX2:
+ case REG_ESAI_RX3:
+ case REG_ESAI_SAISR:
+ case REG_ESAI_SAICR:
+ case REG_ESAI_TCR:
+ case REG_ESAI_TCCR:
+ case REG_ESAI_RCR:
+ case REG_ESAI_RCCR:
+ case REG_ESAI_TSMA:
+ case REG_ESAI_TSMB:
+ case REG_ESAI_RSMA:
+ case REG_ESAI_RSMB:
+ case REG_ESAI_PRRC:
+ case REG_ESAI_PCRC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case REG_ESAI_ETDR:
+ case REG_ESAI_ECR:
+ case REG_ESAI_TFCR:
+ case REG_ESAI_RFCR:
+ case REG_ESAI_TX0:
+ case REG_ESAI_TX1:
+ case REG_ESAI_TX2:
+ case REG_ESAI_TX3:
+ case REG_ESAI_TX4:
+ case REG_ESAI_TX5:
+ case REG_ESAI_TSR:
+ case REG_ESAI_SAICR:
+ case REG_ESAI_TCR:
+ case REG_ESAI_TCCR:
+ case REG_ESAI_RCR:
+ case REG_ESAI_RCCR:
+ case REG_ESAI_TSMA:
+ case REG_ESAI_TSMB:
+ case REG_ESAI_RSMA:
+ case REG_ESAI_RSMB:
+ case REG_ESAI_PRRC:
+ case REG_ESAI_PCRC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config fsl_esai_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = REG_ESAI_PCRC,
+ .readable_reg = fsl_esai_readable_reg,
+ .writeable_reg = fsl_esai_writeable_reg,
+};
+
+static int fsl_esai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_esai *esai_priv;
+ struct resource *res;
+ const uint32_t *iprop;
+ void __iomem *regs;
+ int irq, ret;
+
+ esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);
+ if (!esai_priv)
+ return -ENOMEM;
+
+ esai_priv->pdev = pdev;
+ strcpy(esai_priv->name, np->name);
+
+ /* Get the addresses and IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+ "core", regs, &fsl_esai_regmap_config);
+ if (IS_ERR(esai_priv->regmap)) {
+ dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+ PTR_ERR(esai_priv->regmap));
+ return PTR_ERR(esai_priv->regmap);
+ }
+
+ esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(esai_priv->coreclk)) {
+ dev_err(&pdev->dev, "failed to get core clock: %ld\n",
+ PTR_ERR(esai_priv->coreclk));
+ return PTR_ERR(esai_priv->coreclk);
+ }
+
+ esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");
+ if (IS_ERR(esai_priv->extalclk))
+ dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",
+ PTR_ERR(esai_priv->extalclk));
+
+ esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");
+ if (IS_ERR(esai_priv->fsysclk))
+ dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
+ PTR_ERR(esai_priv->fsysclk));
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+ return irq;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
+ esai_priv->name, esai_priv);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+ return ret;
+ }
+
+ /* Set a default slot size */
+ esai_priv->slot_width = 32;
+
+ /* Set a default master/slave state */
+ esai_priv->slave_mode = true;
+
+ /* Determine the FIFO depth */
+ iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+ if (iprop)
+ esai_priv->fifo_depth = be32_to_cpup(iprop);
+ else
+ esai_priv->fifo_depth = 64;
+
+ esai_priv->dma_params_tx.maxburst = 16;
+ esai_priv->dma_params_rx.maxburst = 16;
+ esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;
+ esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;
+
+ esai_priv->synchronous =
+ of_property_read_bool(np, "fsl,esai-synchronous");
+
+ /* Implement full symmetry for synchronous mode */
+ if (esai_priv->synchronous) {
+ fsl_esai_dai.symmetric_rates = 1;
+ fsl_esai_dai.symmetric_channels = 1;
+ fsl_esai_dai.symmetric_samplebits = 1;
+ }
+
+ dev_set_drvdata(&pdev->dev, esai_priv);
+
+ /* Reset ESAI unit */
+ ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * We need to enable ESAI so as to access some of its registers.
+ * Otherwise, we would fail to dump regmap from user space.
+ */
+ ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
+ &fsl_esai_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+ return ret;
+ }
+
+ ret = imx_pcm_dma_init(pdev);
+ if (ret)
+ dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
+
+ return ret;
+}
+
+static const struct of_device_id fsl_esai_dt_ids[] = {
+ { .compatible = "fsl,imx35-esai", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
+
+static struct platform_driver fsl_esai_driver = {
+ .probe = fsl_esai_probe,
+ .driver = {
+ .name = "fsl-esai-dai",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_esai_dt_ids,
+ },
+};
+
+module_platform_driver(fsl_esai_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl-esai-dai");
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
new file mode 100644
index 000000000000..75e14033e8d8
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.h
@@ -0,0 +1,354 @@
+/*
+ * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_ESAI_DAI_H
+#define _FSL_ESAI_DAI_H
+
+/* ESAI Register Map */
+#define REG_ESAI_ETDR 0x00
+#define REG_ESAI_ERDR 0x04
+#define REG_ESAI_ECR 0x08
+#define REG_ESAI_ESR 0x0C
+#define REG_ESAI_TFCR 0x10
+#define REG_ESAI_TFSR 0x14
+#define REG_ESAI_RFCR 0x18
+#define REG_ESAI_RFSR 0x1C
+#define REG_ESAI_xFCR(tx) (tx ? REG_ESAI_TFCR : REG_ESAI_RFCR)
+#define REG_ESAI_xFSR(tx) (tx ? REG_ESAI_TFSR : REG_ESAI_RFSR)
+#define REG_ESAI_TX0 0x80
+#define REG_ESAI_TX1 0x84
+#define REG_ESAI_TX2 0x88
+#define REG_ESAI_TX3 0x8C
+#define REG_ESAI_TX4 0x90
+#define REG_ESAI_TX5 0x94
+#define REG_ESAI_TSR 0x98
+#define REG_ESAI_RX0 0xA0
+#define REG_ESAI_RX1 0xA4
+#define REG_ESAI_RX2 0xA8
+#define REG_ESAI_RX3 0xAC
+#define REG_ESAI_SAISR 0xCC
+#define REG_ESAI_SAICR 0xD0
+#define REG_ESAI_TCR 0xD4
+#define REG_ESAI_TCCR 0xD8
+#define REG_ESAI_RCR 0xDC
+#define REG_ESAI_RCCR 0xE0
+#define REG_ESAI_xCR(tx) (tx ? REG_ESAI_TCR : REG_ESAI_RCR)
+#define REG_ESAI_xCCR(tx) (tx ? REG_ESAI_TCCR : REG_ESAI_RCCR)
+#define REG_ESAI_TSMA 0xE4
+#define REG_ESAI_TSMB 0xE8
+#define REG_ESAI_RSMA 0xEC
+#define REG_ESAI_RSMB 0xF0
+#define REG_ESAI_xSMA(tx) (tx ? REG_ESAI_TSMA : REG_ESAI_RSMA)
+#define REG_ESAI_xSMB(tx) (tx ? REG_ESAI_TSMB : REG_ESAI_RSMB)
+#define REG_ESAI_PRRC 0xF8
+#define REG_ESAI_PCRC 0xFC
+
+/* ESAI Control Register -- REG_ESAI_ECR 0x8 */
+#define ESAI_ECR_ETI_SHIFT 19
+#define ESAI_ECR_ETI_MASK (1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETI (1 << ESAI_ECR_ETI_SHIFT)
+#define ESAI_ECR_ETO_SHIFT 18
+#define ESAI_ECR_ETO_MASK (1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ETO (1 << ESAI_ECR_ETO_SHIFT)
+#define ESAI_ECR_ERI_SHIFT 17
+#define ESAI_ECR_ERI_MASK (1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERI (1 << ESAI_ECR_ERI_SHIFT)
+#define ESAI_ECR_ERO_SHIFT 16
+#define ESAI_ECR_ERO_MASK (1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERO (1 << ESAI_ECR_ERO_SHIFT)
+#define ESAI_ECR_ERST_SHIFT 1
+#define ESAI_ECR_ERST_MASK (1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ERST (1 << ESAI_ECR_ERST_SHIFT)
+#define ESAI_ECR_ESAIEN_SHIFT 0
+#define ESAI_ECR_ESAIEN_MASK (1 << ESAI_ECR_ESAIEN_SHIFT)
+#define ESAI_ECR_ESAIEN (1 << ESAI_ECR_ESAIEN_SHIFT)
+
+/* ESAI Status Register -- REG_ESAI_ESR 0xC */
+#define ESAI_ESR_TINIT_SHIFT 10
+#define ESAI_ESR_TINIT_MASK (1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_TINIT (1 << ESAI_ESR_TINIT_SHIFT)
+#define ESAI_ESR_RFF_SHIFT 9
+#define ESAI_ESR_RFF_MASK (1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_RFF (1 << ESAI_ESR_RFF_SHIFT)
+#define ESAI_ESR_TFE_SHIFT 8
+#define ESAI_ESR_TFE_MASK (1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TFE (1 << ESAI_ESR_TFE_SHIFT)
+#define ESAI_ESR_TLS_SHIFT 7
+#define ESAI_ESR_TLS_MASK (1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TLS (1 << ESAI_ESR_TLS_SHIFT)
+#define ESAI_ESR_TDE_SHIFT 6
+#define ESAI_ESR_TDE_MASK (1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TDE (1 << ESAI_ESR_TDE_SHIFT)
+#define ESAI_ESR_TED_SHIFT 5
+#define ESAI_ESR_TED_MASK (1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TED (1 << ESAI_ESR_TED_SHIFT)
+#define ESAI_ESR_TD_SHIFT 4
+#define ESAI_ESR_TD_MASK (1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_TD (1 << ESAI_ESR_TD_SHIFT)
+#define ESAI_ESR_RLS_SHIFT 3
+#define ESAI_ESR_RLS_MASK (1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RLS (1 << ESAI_ESR_RLS_SHIFT)
+#define ESAI_ESR_RDE_SHIFT 2
+#define ESAI_ESR_RDE_MASK (1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RDE (1 << ESAI_ESR_RDE_SHIFT)
+#define ESAI_ESR_RED_SHIFT 1
+#define ESAI_ESR_RED_MASK (1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RED (1 << ESAI_ESR_RED_SHIFT)
+#define ESAI_ESR_RD_SHIFT 0
+#define ESAI_ESR_RD_MASK (1 << ESAI_ESR_RD_SHIFT)
+#define ESAI_ESR_RD (1 << ESAI_ESR_RD_SHIFT)
+
+/*
+ * Transmit FIFO Configuration Register -- REG_ESAI_TFCR 0x10
+ * Receive FIFO Configuration Register -- REG_ESAI_RFCR 0x18
+ */
+#define ESAI_xFCR_TIEN_SHIFT 19
+#define ESAI_xFCR_TIEN_MASK (1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_TIEN (1 << ESAI_xFCR_TIEN_SHIFT)
+#define ESAI_xFCR_REXT_SHIFT 19
+#define ESAI_xFCR_REXT_MASK (1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_REXT (1 << ESAI_xFCR_REXT_SHIFT)
+#define ESAI_xFCR_xWA_SHIFT 16
+#define ESAI_xFCR_xWA_WIDTH 3
+#define ESAI_xFCR_xWA_MASK (((1 << ESAI_xFCR_xWA_WIDTH) - 1) << ESAI_xFCR_xWA_SHIFT)
+#define ESAI_xFCR_xWA(v) (((8 - ((v) >> 2)) << ESAI_xFCR_xWA_SHIFT) & ESAI_xFCR_xWA_MASK)
+#define ESAI_xFCR_xFWM_SHIFT 8
+#define ESAI_xFCR_xFWM_WIDTH 8
+#define ESAI_xFCR_xFWM_MASK (((1 << ESAI_xFCR_xFWM_WIDTH) - 1) << ESAI_xFCR_xFWM_SHIFT)
+#define ESAI_xFCR_xFWM(v) ((((v) - 1) << ESAI_xFCR_xFWM_SHIFT) & ESAI_xFCR_xFWM_MASK)
+#define ESAI_xFCR_xE_SHIFT 2
+#define ESAI_xFCR_TE_WIDTH 6
+#define ESAI_xFCR_RE_WIDTH 4
+#define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
+#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
+#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
+#define ESAI_xFCR_xFR_SHIFT 1
+#define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT)
+#define ESAI_xFCR_xFEN_SHIFT 0
+#define ESAI_xFCR_xFEN_MASK (1 << ESAI_xFCR_xFEN_SHIFT)
+#define ESAI_xFCR_xFEN (1 << ESAI_xFCR_xFEN_SHIFT)
+
+/*
+ * Transmit FIFO Status Register -- REG_ESAI_TFSR 0x14
+ * Receive FIFO Status Register --REG_ESAI_RFSR 0x1C
+ */
+#define ESAI_xFSR_NTFO_SHIFT 12
+#define ESAI_xFSR_NRFI_SHIFT 12
+#define ESAI_xFSR_NTFI_SHIFT 8
+#define ESAI_xFSR_NRFO_SHIFT 8
+#define ESAI_xFSR_NTFx_WIDTH 3
+#define ESAI_xFSR_NRFx_WIDTH 2
+#define ESAI_xFSR_NTFO_MASK (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFO_SHIFT)
+#define ESAI_xFSR_NTFI_MASK (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFI_SHIFT)
+#define ESAI_xFSR_NRFO_MASK (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFO_SHIFT)
+#define ESAI_xFSR_NRFI_MASK (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFI_SHIFT)
+#define ESAI_xFSR_xFCNT_SHIFT 0
+#define ESAI_xFSR_xFCNT_WIDTH 8
+#define ESAI_xFSR_xFCNT_MASK (((1 << ESAI_xFSR_xFCNT_WIDTH) - 1) << ESAI_xFSR_xFCNT_SHIFT)
+
+/* ESAI Transmit Slot Register -- REG_ESAI_TSR 0x98 */
+#define ESAI_TSR_SHIFT 0
+#define ESAI_TSR_WIDTH 24
+#define ESAI_TSR_MASK (((1 << ESAI_TSR_WIDTH) - 1) << ESAI_TSR_SHIFT)
+
+/* Serial Audio Interface Status Register -- REG_ESAI_SAISR 0xCC */
+#define ESAI_SAISR_TODFE_SHIFT 17
+#define ESAI_SAISR_TODFE_MASK (1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TODFE (1 << ESAI_SAISR_TODFE_SHIFT)
+#define ESAI_SAISR_TEDE_SHIFT 16
+#define ESAI_SAISR_TEDE_MASK (1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TEDE (1 << ESAI_SAISR_TEDE_SHIFT)
+#define ESAI_SAISR_TDE_SHIFT 15
+#define ESAI_SAISR_TDE_MASK (1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TDE (1 << ESAI_SAISR_TDE_SHIFT)
+#define ESAI_SAISR_TUE_SHIFT 14
+#define ESAI_SAISR_TUE_MASK (1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TUE (1 << ESAI_SAISR_TUE_SHIFT)
+#define ESAI_SAISR_TFS_SHIFT 13
+#define ESAI_SAISR_TFS_MASK (1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_TFS (1 << ESAI_SAISR_TFS_SHIFT)
+#define ESAI_SAISR_RODF_SHIFT 10
+#define ESAI_SAISR_RODF_MASK (1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_RODF (1 << ESAI_SAISR_RODF_SHIFT)
+#define ESAI_SAISR_REDF_SHIFT 9
+#define ESAI_SAISR_REDF_MASK (1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_REDF (1 << ESAI_SAISR_REDF_SHIFT)
+#define ESAI_SAISR_RDF_SHIFT 8
+#define ESAI_SAISR_RDF_MASK (1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_RDF (1 << ESAI_SAISR_RDF_SHIFT)
+#define ESAI_SAISR_ROE_SHIFT 7
+#define ESAI_SAISR_ROE_MASK (1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_ROE (1 << ESAI_SAISR_ROE_SHIFT)
+#define ESAI_SAISR_RFS_SHIFT 6
+#define ESAI_SAISR_RFS_MASK (1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_RFS (1 << ESAI_SAISR_RFS_SHIFT)
+#define ESAI_SAISR_IF2_SHIFT 2
+#define ESAI_SAISR_IF2_MASK (1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF2 (1 << ESAI_SAISR_IF2_SHIFT)
+#define ESAI_SAISR_IF1_SHIFT 1
+#define ESAI_SAISR_IF1_MASK (1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF1 (1 << ESAI_SAISR_IF1_SHIFT)
+#define ESAI_SAISR_IF0_SHIFT 0
+#define ESAI_SAISR_IF0_MASK (1 << ESAI_SAISR_IF0_SHIFT)
+#define ESAI_SAISR_IF0 (1 << ESAI_SAISR_IF0_SHIFT)
+
+/* Serial Audio Interface Control Register -- REG_ESAI_SAICR 0xD0 */
+#define ESAI_SAICR_ALC_SHIFT 8
+#define ESAI_SAICR_ALC_MASK (1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_ALC (1 << ESAI_SAICR_ALC_SHIFT)
+#define ESAI_SAICR_TEBE_SHIFT 7
+#define ESAI_SAICR_TEBE_MASK (1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_TEBE (1 << ESAI_SAICR_TEBE_SHIFT)
+#define ESAI_SAICR_SYNC_SHIFT 6
+#define ESAI_SAICR_SYNC_MASK (1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_SYNC (1 << ESAI_SAICR_SYNC_SHIFT)
+#define ESAI_SAICR_OF2_SHIFT 2
+#define ESAI_SAICR_OF2_MASK (1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF2 (1 << ESAI_SAICR_OF2_SHIFT)
+#define ESAI_SAICR_OF1_SHIFT 1
+#define ESAI_SAICR_OF1_MASK (1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF1 (1 << ESAI_SAICR_OF1_SHIFT)
+#define ESAI_SAICR_OF0_SHIFT 0
+#define ESAI_SAICR_OF0_MASK (1 << ESAI_SAICR_OF0_SHIFT)
+#define ESAI_SAICR_OF0 (1 << ESAI_SAICR_OF0_SHIFT)
+
+/*
+ * Transmit Control Register -- REG_ESAI_TCR 0xD4
+ * Receive Control Register -- REG_ESAI_RCR 0xDC
+ */
+#define ESAI_xCR_xLIE_SHIFT 23
+#define ESAI_xCR_xLIE_MASK (1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xLIE (1 << ESAI_xCR_xLIE_SHIFT)
+#define ESAI_xCR_xIE_SHIFT 22
+#define ESAI_xCR_xIE_MASK (1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xIE (1 << ESAI_xCR_xIE_SHIFT)
+#define ESAI_xCR_xEDIE_SHIFT 21
+#define ESAI_xCR_xEDIE_MASK (1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEDIE (1 << ESAI_xCR_xEDIE_SHIFT)
+#define ESAI_xCR_xEIE_SHIFT 20
+#define ESAI_xCR_xEIE_MASK (1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xEIE (1 << ESAI_xCR_xEIE_SHIFT)
+#define ESAI_xCR_xPR_SHIFT 19
+#define ESAI_xCR_xPR_MASK (1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_xPR (1 << ESAI_xCR_xPR_SHIFT)
+#define ESAI_xCR_PADC_SHIFT 17
+#define ESAI_xCR_PADC_MASK (1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_PADC (1 << ESAI_xCR_PADC_SHIFT)
+#define ESAI_xCR_xFSR_SHIFT 16
+#define ESAI_xCR_xFSR_MASK (1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSR (1 << ESAI_xCR_xFSR_SHIFT)
+#define ESAI_xCR_xFSL_SHIFT 15
+#define ESAI_xCR_xFSL_MASK (1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xFSL (1 << ESAI_xCR_xFSL_SHIFT)
+#define ESAI_xCR_xSWS_SHIFT 10
+#define ESAI_xCR_xSWS_WIDTH 5
+#define ESAI_xCR_xSWS_MASK (((1 << ESAI_xCR_xSWS_WIDTH) - 1) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xSWS(s, w) ((w < 24 ? (s - w + ((w - 8) >> 2)) : (s < 32 ? 0x1e : 0x1f)) << ESAI_xCR_xSWS_SHIFT)
+#define ESAI_xCR_xMOD_SHIFT 8
+#define ESAI_xCR_xMOD_WIDTH 2
+#define ESAI_xCR_xMOD_MASK (((1 << ESAI_xCR_xMOD_WIDTH) - 1) << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_ONDEMAND (0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_NETWORK (0x1 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xMOD_AC97 (0x3 << ESAI_xCR_xMOD_SHIFT)
+#define ESAI_xCR_xWA_SHIFT 7
+#define ESAI_xCR_xWA_MASK (1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xWA (1 << ESAI_xCR_xWA_SHIFT)
+#define ESAI_xCR_xSHFD_SHIFT 6
+#define ESAI_xCR_xSHFD_MASK (1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xSHFD (1 << ESAI_xCR_xSHFD_SHIFT)
+#define ESAI_xCR_xE_SHIFT 0
+#define ESAI_xCR_TE_WIDTH 6
+#define ESAI_xCR_RE_WIDTH 4
+#define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
+#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
+#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
+
+/*
+ * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
+ * Receive Clock Control Register -- REG_ESAI_RCCR 0xE0
+ */
+#define ESAI_xCCR_xHCKD_SHIFT 23
+#define ESAI_xCCR_xHCKD_MASK (1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xHCKD (1 << ESAI_xCCR_xHCKD_SHIFT)
+#define ESAI_xCCR_xFSD_SHIFT 22
+#define ESAI_xCCR_xFSD_MASK (1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xFSD (1 << ESAI_xCCR_xFSD_SHIFT)
+#define ESAI_xCCR_xCKD_SHIFT 21
+#define ESAI_xCCR_xCKD_MASK (1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xCKD (1 << ESAI_xCCR_xCKD_SHIFT)
+#define ESAI_xCCR_xHCKP_SHIFT 20
+#define ESAI_xCCR_xHCKP_MASK (1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xHCKP (1 << ESAI_xCCR_xHCKP_SHIFT)
+#define ESAI_xCCR_xFSP_SHIFT 19
+#define ESAI_xCCR_xFSP_MASK (1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xFSP (1 << ESAI_xCCR_xFSP_SHIFT)
+#define ESAI_xCCR_xCKP_SHIFT 18
+#define ESAI_xCCR_xCKP_MASK (1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xCKP (1 << ESAI_xCCR_xCKP_SHIFT)
+#define ESAI_xCCR_xFP_SHIFT 14
+#define ESAI_xCCR_xFP_WIDTH 4
+#define ESAI_xCCR_xFP_MASK (((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT)
+#define ESAI_xCCR_xFP(v) ((((v) - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK)
+#define ESAI_xCCR_xDC_SHIFT 9
+#define ESAI_xCCR_xDC_WIDTH 4
+#define ESAI_xCCR_xDC_MASK (((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT)
+#define ESAI_xCCR_xDC(v) ((((v) - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK)
+#define ESAI_xCCR_xPSR_SHIFT 8
+#define ESAI_xCCR_xPSR_MASK (1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_BYPASS (1 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPSR_DIV8 (0 << ESAI_xCCR_xPSR_SHIFT)
+#define ESAI_xCCR_xPM_SHIFT 0
+#define ESAI_xCCR_xPM_WIDTH 8
+#define ESAI_xCCR_xPM_MASK (((1 << ESAI_xCCR_xPM_WIDTH) - 1) << ESAI_xCCR_xPM_SHIFT)
+#define ESAI_xCCR_xPM(v) ((((v) - 1) << ESAI_xCCR_xPM_SHIFT) & ESAI_xCCR_xPM_MASK)
+
+/* Transmit Slot Mask Register A/B -- REG_ESAI_TSMA/B 0xE4 ~ 0xF0 */
+#define ESAI_xSMA_xS_SHIFT 0
+#define ESAI_xSMA_xS_WIDTH 16
+#define ESAI_xSMA_xS_MASK (((1 << ESAI_xSMA_xS_WIDTH) - 1) << ESAI_xSMA_xS_SHIFT)
+#define ESAI_xSMA_xS(v) ((v) & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS_SHIFT 0
+#define ESAI_xSMB_xS_WIDTH 16
+#define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
+#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK)
+
+/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
+#define ESAI_PRRC_PDC_SHIFT 0
+#define ESAI_PRRC_PDC_WIDTH 12
+#define ESAI_PRRC_PDC_MASK (((1 << ESAI_PRRC_PDC_WIDTH) - 1) << ESAI_PRRC_PDC_SHIFT)
+#define ESAI_PRRC_PDC(v) ((v) & ESAI_PRRC_PDC_MASK)
+
+/* Port C Control Register -- REG_ESAI_PCRC 0xFC */
+#define ESAI_PCRC_PC_SHIFT 0
+#define ESAI_PCRC_PC_WIDTH 12
+#define ESAI_PCRC_PC_MASK (((1 << ESAI_PCRC_PC_WIDTH) - 1) << ESAI_PCRC_PC_SHIFT)
+#define ESAI_PCRC_PC(v) ((v) & ESAI_PCRC_PC_MASK)
+
+#define ESAI_GPIO 0xfff
+
+/* ESAI clock source */
+#define ESAI_HCKT_FSYS 0
+#define ESAI_HCKT_EXTAL 1
+#define ESAI_HCKR_FSYS 2
+#define ESAI_HCKR_EXTAL 3
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR 0
+#define ESAI_TX_DIV_PM 1
+#define ESAI_TX_DIV_FP 2
+#define ESAI_RX_DIV_PSR 3
+#define ESAI_RX_DIV_PM 4
+#define ESAI_RX_DIV_FP 5
+#endif /* _FSL_ESAI_DAI_H */
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
new file mode 100644
index 000000000000..cdd3fa830704
--- /dev/null
+++ b/sound/soc/fsl/fsl_sai.c
@@ -0,0 +1,459 @@
+/*
+ * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "fsl_sai.h"
+
+static inline u32 sai_readl(struct fsl_sai *sai,
+ const void __iomem *addr)
+{
+ u32 val;
+
+ val = __raw_readl(addr);
+
+ if (likely(sai->big_endian_regs))
+ val = be32_to_cpu(val);
+ else
+ val = le32_to_cpu(val);
+ rmb();
+
+ return val;
+}
+
+static inline void sai_writel(struct fsl_sai *sai,
+ u32 val, void __iomem *addr)
+{
+ wmb();
+ if (likely(sai->big_endian_regs))
+ val = cpu_to_be32(val);
+ else
+ val = cpu_to_le32(val);
+
+ __raw_writel(val, addr);
+}
+
+static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int fsl_dir)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 val_cr2, reg_cr2;
+
+ if (fsl_dir == FSL_FMT_TRANSMITTER)
+ reg_cr2 = FSL_SAI_TCR2;
+ else
+ reg_cr2 = FSL_SAI_RCR2;
+
+ val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK;
+
+ switch (clk_id) {
+ case FSL_SAI_CLK_BUS:
+ val_cr2 |= FSL_SAI_CR2_MSEL_BUS;
+ break;
+ case FSL_SAI_CLK_MAST1:
+ val_cr2 |= FSL_SAI_CR2_MSEL_MCLK1;
+ break;
+ case FSL_SAI_CLK_MAST2:
+ val_cr2 |= FSL_SAI_CR2_MSEL_MCLK2;
+ break;
+ case FSL_SAI_CLK_MAST3:
+ val_cr2 |= FSL_SAI_CR2_MSEL_MCLK3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sai_writel(sai, val_cr2, sai->base + reg_cr2);
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ if (dir == SND_SOC_CLOCK_IN)
+ return 0;
+
+ ret = clk_prepare_enable(sai->clk);
+ if (ret)
+ return ret;
+
+ ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+ FSL_FMT_TRANSMITTER);
+ if (ret) {
+ dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret);
+ goto err_clk;
+ }
+
+ ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq,
+ FSL_FMT_RECEIVER);
+ if (ret) {
+ dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
+ goto err_clk;
+ }
+
+err_clk:
+ clk_disable_unprepare(sai->clk);
+
+ return ret;
+}
+
+static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt, int fsl_dir)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 val_cr2, val_cr4, reg_cr2, reg_cr4;
+
+ if (fsl_dir == FSL_FMT_TRANSMITTER) {
+ reg_cr2 = FSL_SAI_TCR2;
+ reg_cr4 = FSL_SAI_TCR4;
+ } else {
+ reg_cr2 = FSL_SAI_RCR2;
+ reg_cr4 = FSL_SAI_RCR4;
+ }
+
+ val_cr2 = sai_readl(sai, sai->base + reg_cr2);
+ val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+
+ if (sai->big_endian_data)
+ val_cr4 &= ~FSL_SAI_CR4_MF;
+ else
+ val_cr4 |= FSL_SAI_CR4_MF;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val_cr4 |= FSL_SAI_CR4_FSE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ val_cr4 |= FSL_SAI_CR4_FSP;
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val_cr4 &= ~FSL_SAI_CR4_FSP;
+ val_cr2 &= ~FSL_SAI_CR2_BCP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val_cr4 |= FSL_SAI_CR4_FSP;
+ val_cr2 |= FSL_SAI_CR2_BCP;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ val_cr4 &= ~FSL_SAI_CR4_FSP;
+ val_cr2 |= FSL_SAI_CR2_BCP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR;
+ val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sai_writel(sai, val_cr2, sai->base + reg_cr2);
+ sai_writel(sai, val_cr4, sai->base + reg_cr4);
+
+ return 0;
+}
+
+static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ ret = clk_prepare_enable(sai->clk);
+ if (ret)
+ return ret;
+
+ ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER);
+ if (ret) {
+ dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret);
+ goto err_clk;
+ }
+
+ ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER);
+ if (ret) {
+ dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
+ goto err_clk;
+ }
+
+err_clk:
+ clk_disable_unprepare(sai->clk);
+
+ return ret;
+}
+
+static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 val_cr4, val_cr5, val_mr, reg_cr4, reg_cr5, reg_mr;
+ unsigned int channels = params_channels(params);
+ u32 word_width = snd_pcm_format_width(params_format(params));
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ reg_cr4 = FSL_SAI_TCR4;
+ reg_cr5 = FSL_SAI_TCR5;
+ reg_mr = FSL_SAI_TMR;
+ } else {
+ reg_cr4 = FSL_SAI_RCR4;
+ reg_cr5 = FSL_SAI_RCR5;
+ reg_mr = FSL_SAI_RMR;
+ }
+
+ val_cr4 = sai_readl(sai, sai->base + reg_cr4);
+ val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK;
+ val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK;
+
+ val_cr5 = sai_readl(sai, sai->base + reg_cr5);
+ val_cr5 &= ~FSL_SAI_CR5_WNW_MASK;
+ val_cr5 &= ~FSL_SAI_CR5_W0W_MASK;
+ val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+
+ val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
+ val_cr5 |= FSL_SAI_CR5_WNW(word_width);
+ val_cr5 |= FSL_SAI_CR5_W0W(word_width);
+
+ val_cr5 &= ~FSL_SAI_CR5_FBT_MASK;
+ if (sai->big_endian_data)
+ val_cr5 |= FSL_SAI_CR5_FBT(0);
+ else
+ val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
+
+ val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
+ val_mr = ~0UL - ((1 << channels) - 1);
+
+ sai_writel(sai, val_cr4, sai->base + reg_cr4);
+ sai_writel(sai, val_cr5, sai->base + reg_cr5);
+ sai_writel(sai, val_mr, sai->base + reg_mr);
+
+ return 0;
+}
+
+static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3;
+
+ val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2);
+ val_cr2 &= ~FSL_SAI_CR2_SYNC;
+ sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2);
+
+ val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2);
+ val_cr2 |= FSL_SAI_CR2_SYNC;
+ sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2);
+
+ tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR);
+ rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tcsr |= FSL_SAI_CSR_FRDE;
+ rcsr &= ~FSL_SAI_CSR_FRDE;
+ reg_cr3 = FSL_SAI_TCR3;
+ } else {
+ rcsr |= FSL_SAI_CSR_FRDE;
+ tcsr &= ~FSL_SAI_CSR_FRDE;
+ reg_cr3 = FSL_SAI_RCR3;
+ }
+
+ val_cr3 = sai_readl(sai, sai->base + reg_cr3);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ tcsr |= FSL_SAI_CSR_TERE;
+ rcsr |= FSL_SAI_CSR_TERE;
+ val_cr3 |= FSL_SAI_CR3_TRCE;
+
+ sai_writel(sai, val_cr3, sai->base + reg_cr3);
+ sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!(cpu_dai->playback_active || cpu_dai->capture_active)) {
+ tcsr &= ~FSL_SAI_CSR_TERE;
+ rcsr &= ~FSL_SAI_CSR_TERE;
+ }
+
+ val_cr3 &= ~FSL_SAI_CR3_TRCE;
+
+ sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR);
+ sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, val_cr3, sai->base + reg_cr3);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fsl_sai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ return clk_prepare_enable(sai->clk);
+}
+
+static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ clk_disable_unprepare(sai->clk);
+}
+
+static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
+ .set_sysclk = fsl_sai_set_dai_sysclk,
+ .set_fmt = fsl_sai_set_dai_fmt,
+ .hw_params = fsl_sai_hw_params,
+ .trigger = fsl_sai_trigger,
+ .startup = fsl_sai_startup,
+ .shutdown = fsl_sai_shutdown,
+};
+
+static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
+ int ret;
+
+ ret = clk_prepare_enable(sai->clk);
+ if (ret)
+ return ret;
+
+ sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR);
+ sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR);
+ sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1);
+ sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1);
+
+ clk_disable_unprepare(sai->clk);
+
+ snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
+ &sai->dma_params_rx);
+
+ snd_soc_dai_set_drvdata(cpu_dai, sai);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_sai_dai = {
+ .probe = fsl_sai_dai_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = FSL_SAI_FORMATS,
+ },
+ .ops = &fsl_sai_pcm_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_component = {
+ .name = "fsl-sai",
+};
+
+static int fsl_sai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_sai *sai;
+ struct resource *res;
+ int ret;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sai->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(sai->base))
+ return PTR_ERR(sai->base);
+
+ sai->clk = devm_clk_get(&pdev->dev, "sai");
+ if (IS_ERR(sai->clk)) {
+ dev_err(&pdev->dev, "Cannot get SAI's clock\n");
+ return PTR_ERR(sai->clk);
+ }
+
+ sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
+ sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
+ sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+ sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+
+ sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
+ sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+
+ platform_set_drvdata(pdev, sai);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
+ &fsl_sai_dai, 1);
+ if (ret)
+ return ret;
+
+ return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+ SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
+}
+
+static const struct of_device_id fsl_sai_ids[] = {
+ { .compatible = "fsl,vf610-sai", },
+ { /* sentinel */ }
+};
+
+static struct platform_driver fsl_sai_driver = {
+ .probe = fsl_sai_probe,
+ .driver = {
+ .name = "fsl-sai",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_sai_ids,
+ },
+};
+module_platform_driver(fsl_sai_driver);
+
+MODULE_DESCRIPTION("Freescale Soc SAI Interface");
+MODULE_AUTHOR("Xiubo Li, <Li.Xiubo@freescale.com>");
+MODULE_ALIAS("platform:fsl-sai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
new file mode 100644
index 000000000000..41bb62e69361
--- /dev/null
+++ b/sound/soc/fsl/fsl_sai.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __FSL_SAI_H
+#define __FSL_SAI_H
+
+#include <sound/dmaengine_pcm.h>
+
+#define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+/* SAI Transmit/Recieve Control Register */
+#define FSL_SAI_TCSR 0x00
+#define FSL_SAI_RCSR 0x80
+#define FSL_SAI_CSR_TERE BIT(31)
+#define FSL_SAI_CSR_FWF BIT(17)
+#define FSL_SAI_CSR_FRIE BIT(8)
+#define FSL_SAI_CSR_FRDE BIT(0)
+
+/* SAI Transmit Data/FIFO/MASK Register */
+#define FSL_SAI_TDR 0x20
+#define FSL_SAI_TFR 0x40
+#define FSL_SAI_TMR 0x60
+
+/* SAI Recieve Data/FIFO/MASK Register */
+#define FSL_SAI_RDR 0xa0
+#define FSL_SAI_RFR 0xc0
+#define FSL_SAI_RMR 0xe0
+
+/* SAI Transmit and Recieve Configuration 1 Register */
+#define FSL_SAI_TCR1 0x04
+#define FSL_SAI_RCR1 0x84
+
+/* SAI Transmit and Recieve Configuration 2 Register */
+#define FSL_SAI_TCR2 0x08
+#define FSL_SAI_RCR2 0x88
+#define FSL_SAI_CR2_SYNC BIT(30)
+#define FSL_SAI_CR2_MSEL_MASK (0xff << 26)
+#define FSL_SAI_CR2_MSEL_BUS 0
+#define FSL_SAI_CR2_MSEL_MCLK1 BIT(26)
+#define FSL_SAI_CR2_MSEL_MCLK2 BIT(27)
+#define FSL_SAI_CR2_MSEL_MCLK3 (BIT(26) | BIT(27))
+#define FSL_SAI_CR2_BCP BIT(25)
+#define FSL_SAI_CR2_BCD_MSTR BIT(24)
+
+/* SAI Transmit and Recieve Configuration 3 Register */
+#define FSL_SAI_TCR3 0x0c
+#define FSL_SAI_RCR3 0x8c
+#define FSL_SAI_CR3_TRCE BIT(16)
+#define FSL_SAI_CR3_WDFL(x) (x)
+#define FSL_SAI_CR3_WDFL_MASK 0x1f
+
+/* SAI Transmit and Recieve Configuration 4 Register */
+#define FSL_SAI_TCR4 0x10
+#define FSL_SAI_RCR4 0x90
+#define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
+#define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
+#define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
+#define FSL_SAI_CR4_SYWD_MASK (0x1f << 8)
+#define FSL_SAI_CR4_MF BIT(4)
+#define FSL_SAI_CR4_FSE BIT(3)
+#define FSL_SAI_CR4_FSP BIT(1)
+#define FSL_SAI_CR4_FSD_MSTR BIT(0)
+
+/* SAI Transmit and Recieve Configuration 5 Register */
+#define FSL_SAI_TCR5 0x14
+#define FSL_SAI_RCR5 0x94
+#define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24)
+#define FSL_SAI_CR5_WNW_MASK (0x1f << 24)
+#define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16)
+#define FSL_SAI_CR5_W0W_MASK (0x1f << 16)
+#define FSL_SAI_CR5_FBT(x) ((x) << 8)
+#define FSL_SAI_CR5_FBT_MASK (0x1f << 8)
+
+/* SAI type */
+#define FSL_SAI_DMA BIT(0)
+#define FSL_SAI_USE_AC97 BIT(1)
+#define FSL_SAI_NET BIT(2)
+#define FSL_SAI_TRA_SYN BIT(3)
+#define FSL_SAI_REC_SYN BIT(4)
+#define FSL_SAI_USE_I2S_SLAVE BIT(5)
+
+#define FSL_FMT_TRANSMITTER 0
+#define FSL_FMT_RECEIVER 1
+
+/* SAI clock sources */
+#define FSL_SAI_CLK_BUS 0
+#define FSL_SAI_CLK_MAST1 1
+#define FSL_SAI_CLK_MAST2 2
+#define FSL_SAI_CLK_MAST3 3
+
+/* SAI data transfer numbers per DMA request */
+#define FSL_SAI_MAXBURST_TX 6
+#define FSL_SAI_MAXBURST_RX 6
+
+struct fsl_sai {
+ struct clk *clk;
+
+ void __iomem *base;
+
+ bool big_endian_regs;
+ bool big_endian_data;
+
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+};
+
+#endif /* __FSL_SAI_H */
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 3920c3e849ce..4d075f1abe78 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -963,7 +963,7 @@ static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
@@ -982,7 +982,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config fsl_spdif_regmap_config = {
@@ -1107,11 +1107,6 @@ static int fsl_spdif_probe(struct platform_device *pdev)
/* Get the addresses and IRQ */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (IS_ERR(res)) {
- dev_err(&pdev->dev, "could not determine device resources\n");
- return PTR_ERR(res);
- }
-
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
@@ -1172,35 +1167,20 @@ static int fsl_spdif_probe(struct platform_device *pdev)
/* Register with ASoC */
dev_set_drvdata(&pdev->dev, spdif_priv);
- ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
- &spdif_priv->cpu_dai_drv, 1);
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
+ &spdif_priv->cpu_dai_drv, 1);
if (ret) {
dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
return ret;
}
ret = imx_pcm_dma_init(pdev);
- if (ret) {
+ if (ret)
dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
- goto error_component;
- }
-
- return ret;
-
-error_component:
- snd_soc_unregister_component(&pdev->dev);
return ret;
}
-static int fsl_spdif_remove(struct platform_device *pdev)
-{
- imx_pcm_dma_exit(pdev);
- snd_soc_unregister_component(&pdev->dev);
-
- return 0;
-}
-
static const struct of_device_id fsl_spdif_dt_ids[] = {
{ .compatible = "fsl,imx35-spdif", },
{}
@@ -1214,7 +1194,6 @@ static struct platform_driver fsl_spdif_driver = {
.of_match_table = fsl_spdif_dt_ids,
},
.probe = fsl_spdif_probe,
- .remove = fsl_spdif_remove,
};
module_platform_driver(fsl_spdif_driver);
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index c6b743978d5e..5428a1fda260 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -35,9 +35,11 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
@@ -79,8 +81,7 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
* ALSA that we support all rates and let the codec driver decide what rates
* are really supported.
*/
-#define FSLSSI_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
- SNDRV_PCM_RATE_CONTINUOUS)
+#define FSLSSI_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
/**
* FSLSSI_I2S_FORMATS: audio formats supported by the SSI
@@ -106,12 +107,33 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE)
#endif
-/* SIER bitflag of interrupts to enable */
-#define SIER_FLAGS (CCSR_SSI_SIER_TFRC_EN | CCSR_SSI_SIER_TDMAE | \
- CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TUE0_EN | \
- CCSR_SSI_SIER_TUE1_EN | CCSR_SSI_SIER_RFRC_EN | \
- CCSR_SSI_SIER_RDMAE | CCSR_SSI_SIER_RIE | \
- CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_ROE1_EN)
+#define FSLSSI_SIER_DBG_RX_FLAGS (CCSR_SSI_SIER_RFF0_EN | \
+ CCSR_SSI_SIER_RLS_EN | CCSR_SSI_SIER_RFS_EN | \
+ CCSR_SSI_SIER_ROE0_EN | CCSR_SSI_SIER_RFRC_EN)
+#define FSLSSI_SIER_DBG_TX_FLAGS (CCSR_SSI_SIER_TFE0_EN | \
+ CCSR_SSI_SIER_TLS_EN | CCSR_SSI_SIER_TFS_EN | \
+ CCSR_SSI_SIER_TUE0_EN | CCSR_SSI_SIER_TFRC_EN)
+#define FSLSSI_SISR_MASK (FSLSSI_SIER_DBG_RX_FLAGS | FSLSSI_SIER_DBG_TX_FLAGS)
+
+
+enum fsl_ssi_type {
+ FSL_SSI_MCP8610,
+ FSL_SSI_MX21,
+ FSL_SSI_MX35,
+ FSL_SSI_MX51,
+};
+
+struct fsl_ssi_reg_val {
+ u32 sier;
+ u32 srcr;
+ u32 stcr;
+ u32 scr;
+};
+
+struct fsl_ssi_rxtx_reg_val {
+ struct fsl_ssi_reg_val rx;
+ struct fsl_ssi_reg_val tx;
+};
/**
* fsl_ssi_private: per-SSI private data
@@ -119,8 +141,6 @@ static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
* @ssi: pointer to the SSI's registers
* @ssi_phys: physical address of the SSI registers
* @irq: IRQ of this SSI
- * @first_stream: pointer to the stream that was opened first
- * @second_stream: pointer to second stream
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
* @cpu_dai: the CPU DAI for this device
@@ -132,23 +152,30 @@ struct fsl_ssi_private {
struct ccsr_ssi __iomem *ssi;
dma_addr_t ssi_phys;
unsigned int irq;
- struct snd_pcm_substream *first_stream;
- struct snd_pcm_substream *second_stream;
unsigned int fifo_depth;
struct snd_soc_dai_driver cpu_dai_drv;
- struct device_attribute dev_attr;
struct platform_device *pdev;
+ enum fsl_ssi_type hw_type;
bool new_binding;
bool ssi_on_imx;
bool imx_ac97;
bool use_dma;
+ bool baudclk_locked;
+ bool irq_stats;
+ bool offline_config;
+ bool use_dual_fifo;
+ u8 i2s_mode;
+ spinlock_t baudclk_lock;
+ struct clk *baudclk;
struct clk *clk;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct imx_dma_data filter_data_tx;
struct imx_dma_data filter_data_rx;
struct imx_pcm_fiq_params fiq_params;
+ /* Register values for rx/tx configuration */
+ struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
struct {
unsigned int rfrc;
@@ -173,10 +200,21 @@ struct fsl_ssi_private {
unsigned int tfe1;
unsigned int tfe0;
} stats;
+ struct dentry *dbg_dir;
+ struct dentry *dbg_stats;
char name[1];
};
+static const struct of_device_id fsl_ssi_ids[] = {
+ { .compatible = "fsl,mpc8610-ssi", .data = (void *) FSL_SSI_MCP8610},
+ { .compatible = "fsl,imx51-ssi", .data = (void *) FSL_SSI_MX51},
+ { .compatible = "fsl,imx35-ssi", .data = (void *) FSL_SSI_MX35},
+ { .compatible = "fsl,imx21-ssi", .data = (void *) FSL_SSI_MX21},
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
+
/**
* fsl_ssi_isr: SSI interrupt handler
*
@@ -195,23 +233,40 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
irqreturn_t ret = IRQ_NONE;
__be32 sisr;
- __be32 sisr2 = 0;
+ __be32 sisr2;
+ __be32 sisr_write_mask = 0;
+
+ switch (ssi_private->hw_type) {
+ case FSL_SSI_MX21:
+ sisr_write_mask = 0;
+ break;
+
+ case FSL_SSI_MCP8610:
+ case FSL_SSI_MX35:
+ sisr_write_mask = CCSR_SSI_SISR_RFRC | CCSR_SSI_SISR_TFRC |
+ CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
+ CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1;
+ break;
+
+ case FSL_SSI_MX51:
+ sisr_write_mask = CCSR_SSI_SISR_ROE0 | CCSR_SSI_SISR_ROE1 |
+ CCSR_SSI_SISR_TUE0 | CCSR_SSI_SISR_TUE1;
+ break;
+ }
/* We got an interrupt, so read the status register to see what we
were interrupted for. We mask it with the Interrupt Enable register
so that we only check for events that we're interested in.
*/
- sisr = read_ssi(&ssi->sisr) & SIER_FLAGS;
+ sisr = read_ssi(&ssi->sisr) & FSLSSI_SISR_MASK;
if (sisr & CCSR_SSI_SISR_RFRC) {
ssi_private->stats.rfrc++;
- sisr2 |= CCSR_SSI_SISR_RFRC;
ret = IRQ_HANDLED;
}
if (sisr & CCSR_SSI_SISR_TFRC) {
ssi_private->stats.tfrc++;
- sisr2 |= CCSR_SSI_SISR_TFRC;
ret = IRQ_HANDLED;
}
@@ -252,25 +307,21 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
if (sisr & CCSR_SSI_SISR_ROE1) {
ssi_private->stats.roe1++;
- sisr2 |= CCSR_SSI_SISR_ROE1;
ret = IRQ_HANDLED;
}
if (sisr & CCSR_SSI_SISR_ROE0) {
ssi_private->stats.roe0++;
- sisr2 |= CCSR_SSI_SISR_ROE0;
ret = IRQ_HANDLED;
}
if (sisr & CCSR_SSI_SISR_TUE1) {
ssi_private->stats.tue1++;
- sisr2 |= CCSR_SSI_SISR_TUE1;
ret = IRQ_HANDLED;
}
if (sisr & CCSR_SSI_SISR_TUE0) {
ssi_private->stats.tue0++;
- sisr2 |= CCSR_SSI_SISR_TUE0;
ret = IRQ_HANDLED;
}
@@ -314,6 +365,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
ret = IRQ_HANDLED;
}
+ sisr2 = sisr & sisr_write_mask;
/* Clear the bits that we set */
if (sisr2)
write_ssi(sisr2, &ssi->sisr);
@@ -321,17 +373,287 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
return ret;
}
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+/* Show the statistics of a flag only if its interrupt is enabled. The
+ * compiler will optimze this code to a no-op if the interrupt is not
+ * enabled.
+ */
+#define SIER_SHOW(flag, name) \
+ do { \
+ if (FSLSSI_SISR_MASK & CCSR_SSI_SIER_##flag) \
+ seq_printf(s, #name "=%u\n", ssi_private->stats.name); \
+ } while (0)
+
+
+/**
+ * fsl_sysfs_ssi_show: display SSI statistics
+ *
+ * Display the statistics for the current SSI device. To avoid confusion,
+ * we only show those counts that are enabled.
+ */
+static int fsl_ssi_stats_show(struct seq_file *s, void *unused)
+{
+ struct fsl_ssi_private *ssi_private = s->private;
+
+ SIER_SHOW(RFRC_EN, rfrc);
+ SIER_SHOW(TFRC_EN, tfrc);
+ SIER_SHOW(CMDAU_EN, cmdau);
+ SIER_SHOW(CMDDU_EN, cmddu);
+ SIER_SHOW(RXT_EN, rxt);
+ SIER_SHOW(RDR1_EN, rdr1);
+ SIER_SHOW(RDR0_EN, rdr0);
+ SIER_SHOW(TDE1_EN, tde1);
+ SIER_SHOW(TDE0_EN, tde0);
+ SIER_SHOW(ROE1_EN, roe1);
+ SIER_SHOW(ROE0_EN, roe0);
+ SIER_SHOW(TUE1_EN, tue1);
+ SIER_SHOW(TUE0_EN, tue0);
+ SIER_SHOW(TFS_EN, tfs);
+ SIER_SHOW(RFS_EN, rfs);
+ SIER_SHOW(TLS_EN, tls);
+ SIER_SHOW(RLS_EN, rls);
+ SIER_SHOW(RFF1_EN, rff1);
+ SIER_SHOW(RFF0_EN, rff0);
+ SIER_SHOW(TFE1_EN, tfe1);
+ SIER_SHOW(TFE0_EN, tfe0);
+
+ return 0;
+}
+
+static int fsl_ssi_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, fsl_ssi_stats_show, inode->i_private);
+}
+
+static const struct file_operations fsl_ssi_stats_ops = {
+ .open = fsl_ssi_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
+ struct device *dev)
+{
+ ssi_private->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
+ if (!ssi_private->dbg_dir)
+ return -ENOMEM;
+
+ ssi_private->dbg_stats = debugfs_create_file("stats", S_IRUGO,
+ ssi_private->dbg_dir, ssi_private, &fsl_ssi_stats_ops);
+ if (!ssi_private->dbg_stats) {
+ debugfs_remove(ssi_private->dbg_dir);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
+{
+ debugfs_remove(ssi_private->dbg_stats);
+ debugfs_remove(ssi_private->dbg_dir);
+}
+
+#else
+
+static int fsl_ssi_debugfs_create(struct fsl_ssi_private *ssi_private,
+ struct device *dev)
+{
+ return 0;
+}
+
+static void fsl_ssi_debugfs_remove(struct fsl_ssi_private *ssi_private)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_DEBUG_FS) */
+
+/*
+ * Enable/Disable all rx/tx config flags at once.
+ */
+static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private,
+ bool enable)
+{
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ struct fsl_ssi_rxtx_reg_val *vals = &ssi_private->rxtx_reg_val;
+
+ if (enable) {
+ write_ssi_mask(&ssi->sier, 0, vals->rx.sier | vals->tx.sier);
+ write_ssi_mask(&ssi->srcr, 0, vals->rx.srcr | vals->tx.srcr);
+ write_ssi_mask(&ssi->stcr, 0, vals->rx.stcr | vals->tx.stcr);
+ } else {
+ write_ssi_mask(&ssi->srcr, vals->rx.srcr | vals->tx.srcr, 0);
+ write_ssi_mask(&ssi->stcr, vals->rx.stcr | vals->tx.stcr, 0);
+ write_ssi_mask(&ssi->sier, vals->rx.sier | vals->tx.sier, 0);
+ }
+}
+
+/*
+ * Enable/Disable a ssi configuration. You have to pass either
+ * ssi_private->rxtx_reg_val.rx or tx as vals parameter.
+ */
+static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable,
+ struct fsl_ssi_reg_val *vals)
+{
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ struct fsl_ssi_reg_val *avals;
+ u32 scr_val = read_ssi(&ssi->scr);
+ int nr_active_streams = !!(scr_val & CCSR_SSI_SCR_TE) +
+ !!(scr_val & CCSR_SSI_SCR_RE);
+
+ /* Find the other direction values rx or tx which we do not want to
+ * modify */
+ if (&ssi_private->rxtx_reg_val.rx == vals)
+ avals = &ssi_private->rxtx_reg_val.tx;
+ else
+ avals = &ssi_private->rxtx_reg_val.rx;
+
+ /* If vals should be disabled, start with disabling the unit */
+ if (!enable) {
+ u32 scr = vals->scr & (vals->scr ^ avals->scr);
+ write_ssi_mask(&ssi->scr, scr, 0);
+ }
+
+ /*
+ * We are running on a SoC which does not support online SSI
+ * reconfiguration, so we have to enable all necessary flags at once
+ * even if we do not use them later (capture and playback configuration)
+ */
+ if (ssi_private->offline_config) {
+ if ((enable && !nr_active_streams) ||
+ (!enable && nr_active_streams == 1))
+ fsl_ssi_rxtx_config(ssi_private, enable);
+
+ goto config_done;
+ }
+
+ /*
+ * Configure single direction units while the SSI unit is running
+ * (online configuration)
+ */
+ if (enable) {
+ write_ssi_mask(&ssi->sier, 0, vals->sier);
+ write_ssi_mask(&ssi->srcr, 0, vals->srcr);
+ write_ssi_mask(&ssi->stcr, 0, vals->stcr);
+ } else {
+ u32 sier;
+ u32 srcr;
+ u32 stcr;
+
+ /*
+ * Disabling the necessary flags for one of rx/tx while the
+ * other stream is active is a little bit more difficult. We
+ * have to disable only those flags that differ between both
+ * streams (rx XOR tx) and that are set in the stream that is
+ * disabled now. Otherwise we could alter flags of the other
+ * stream
+ */
+
+ /* These assignments are simply vals without bits set in avals*/
+ sier = vals->sier & (vals->sier ^ avals->sier);
+ srcr = vals->srcr & (vals->srcr ^ avals->srcr);
+ stcr = vals->stcr & (vals->stcr ^ avals->stcr);
+
+ write_ssi_mask(&ssi->srcr, srcr, 0);
+ write_ssi_mask(&ssi->stcr, stcr, 0);
+ write_ssi_mask(&ssi->sier, sier, 0);
+ }
+
+config_done:
+ /* Enabling of subunits is done after configuration */
+ if (enable)
+ write_ssi_mask(&ssi->scr, 0, vals->scr);
+}
+
+
+static void fsl_ssi_rx_config(struct fsl_ssi_private *ssi_private, bool enable)
+{
+ fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.rx);
+}
+
+static void fsl_ssi_tx_config(struct fsl_ssi_private *ssi_private, bool enable)
+{
+ fsl_ssi_config(ssi_private, enable, &ssi_private->rxtx_reg_val.tx);
+}
+
+/*
+ * Setup rx/tx register values used to enable/disable the streams. These will
+ * be used later in fsl_ssi_config to setup the streams without the need to
+ * check for all different SSI modes.
+ */
+static void fsl_ssi_setup_reg_vals(struct fsl_ssi_private *ssi_private)
+{
+ struct fsl_ssi_rxtx_reg_val *reg = &ssi_private->rxtx_reg_val;
+
+ reg->rx.sier = CCSR_SSI_SIER_RFF0_EN;
+ reg->rx.srcr = CCSR_SSI_SRCR_RFEN0;
+ reg->rx.scr = 0;
+ reg->tx.sier = CCSR_SSI_SIER_TFE0_EN;
+ reg->tx.stcr = CCSR_SSI_STCR_TFEN0;
+ reg->tx.scr = 0;
+
+ if (!ssi_private->imx_ac97) {
+ reg->rx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE;
+ reg->rx.sier |= CCSR_SSI_SIER_RFF0_EN;
+ reg->tx.scr = CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE;
+ reg->tx.sier |= CCSR_SSI_SIER_TFE0_EN;
+ }
+
+ if (ssi_private->use_dma) {
+ reg->rx.sier |= CCSR_SSI_SIER_RDMAE;
+ reg->tx.sier |= CCSR_SSI_SIER_TDMAE;
+ } else {
+ reg->rx.sier |= CCSR_SSI_SIER_RIE;
+ reg->tx.sier |= CCSR_SSI_SIER_TIE;
+ }
+
+ reg->rx.sier |= FSLSSI_SIER_DBG_RX_FLAGS;
+ reg->tx.sier |= FSLSSI_SIER_DBG_TX_FLAGS;
+}
+
+static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private)
+{
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+
+ /*
+ * Setup the clock control register
+ */
+ write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+ &ssi->stccr);
+ write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+ &ssi->srccr);
+
+ /*
+ * Enable AC97 mode and startup the SSI
+ */
+ write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
+ &ssi->sacnt);
+ write_ssi(0xff, &ssi->saccdis);
+ write_ssi(0x300, &ssi->saccen);
+
+ /*
+ * Enable SSI, Transmit and Receive. AC97 has to communicate with the
+ * codec before a stream is started.
+ */
+ write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
+ CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
+
+ write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
+}
+
static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
{
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- u8 i2s_mode;
u8 wm;
int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+ fsl_ssi_setup_reg_vals(ssi_private);
+
if (ssi_private->imx_ac97)
- i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
+ ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
else
- i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+ ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
/*
* Section 16.5 of the MPC8610 reference manual says that the SSI needs
@@ -348,16 +670,15 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
write_ssi_mask(&ssi->scr,
CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
CCSR_SSI_SCR_TFR_CLK_DIS |
- i2s_mode |
+ ssi_private->i2s_mode |
(synchronous ? CCSR_SSI_SCR_SYN : 0));
- write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
- CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
- CCSR_SSI_STCR_TSCKP, &ssi->stcr);
+ write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFSI |
+ CCSR_SSI_STCR_TEFS | CCSR_SSI_STCR_TSCKP, &ssi->stcr);
+
+ write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFSI |
+ CCSR_SSI_SRCR_REFS | CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
- write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
- CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
- CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
/*
* The DC and PM bits are only used if the SSI is the clock master.
*/
@@ -387,30 +708,24 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
* because it is also running without an active substream. Normally SSI
* is only enabled when there is a substream.
*/
- if (ssi_private->imx_ac97) {
- /*
- * Setup the clock control register
- */
- write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
- &ssi->stccr);
- write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
- &ssi->srccr);
-
- /*
- * Enable AC97 mode and startup the SSI
- */
- write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
- &ssi->sacnt);
- write_ssi(0xff, &ssi->saccdis);
- write_ssi(0x300, &ssi->saccen);
+ if (ssi_private->imx_ac97)
+ fsl_ssi_setup_ac97(ssi_private);
- /*
- * Enable SSI, Transmit and Receive
- */
- write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
- CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
+ /*
+ * Set a default slot number so that there is no need for those common
+ * cases like I2S mode to call the extra set_tdm_slot() any more.
+ */
+ if (!ssi_private->imx_ac97) {
+ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
+ CCSR_SSI_SxCCR_DC(2));
+ write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
+ CCSR_SSI_SxCCR_DC(2));
+ }
- write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
+ if (ssi_private->use_dual_fifo) {
+ write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
+ write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
+ write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
}
return 0;
@@ -431,62 +746,28 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
- int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+ unsigned long flags;
- /*
- * If this is the first stream opened, then request the IRQ
- * and initialize the SSI registers.
+ /* First, we only do fsl_ssi_setup() when SSI is going to be active.
+ * Second, fsl_ssi_setup was already called by ac97_init earlier if
+ * the driver is in ac97 mode.
*/
- if (!ssi_private->first_stream) {
- ssi_private->first_stream = substream;
-
- /*
- * fsl_ssi_setup was already called by ac97_init earlier if
- * the driver is in ac97 mode.
- */
- if (!ssi_private->imx_ac97)
- fsl_ssi_setup(ssi_private);
- } else {
- if (synchronous) {
- struct snd_pcm_runtime *first_runtime =
- ssi_private->first_stream->runtime;
- /*
- * This is the second stream open, and we're in
- * synchronous mode, so we need to impose sample
- * sample size constraints. This is because STCCR is
- * used for playback and capture in synchronous mode,
- * so there's no way to specify different word
- * lengths.
- *
- * Note that this can cause a race condition if the
- * second stream is opened before the first stream is
- * fully initialized. We provide some protection by
- * checking to make sure the first stream is
- * initialized, but it's not perfect. ALSA sometimes
- * re-initializes the driver with a different sample
- * rate or size. If the second stream is opened
- * before the first stream has received its final
- * parameters, then the second stream may be
- * constrained to the wrong sample rate or size.
- */
- if (!first_runtime->sample_bits) {
- dev_err(substream->pcm->card->dev,
- "set sample size in %s stream first\n",
- substream->stream ==
- SNDRV_PCM_STREAM_PLAYBACK
- ? "capture" : "playback");
- return -EAGAIN;
- }
-
- 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;
+ if (!dai->active && !ssi_private->imx_ac97) {
+ fsl_ssi_setup(ssi_private);
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ ssi_private->baudclk_locked = false;
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
}
+ /* When using dual fifo mode, it is safer to ensure an even period
+ * size. If appearing to an odd number while DMA always starts its
+ * task from fifo0, fifo1 would be neglected at the end of each
+ * period. But SSI would still access fifo1 with an invalid data.
+ */
+ if (ssi_private->use_dual_fifo)
+ snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+
return 0;
}
@@ -508,6 +789,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ unsigned int channels = params_channels(hw_params);
unsigned int sample_size =
snd_pcm_format_width(params_format(hw_params));
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
@@ -537,6 +819,248 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
else
write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+ if (!ssi_private->imx_ac97)
+ write_ssi_mask(&ssi->scr,
+ CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
+ channels == 1 ? 0 : ssi_private->i2s_mode);
+
+ return 0;
+}
+
+/**
+ * fsl_ssi_set_dai_fmt - configure Digital Audio Interface Format.
+ */
+static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ u32 strcr = 0, stcr, srcr, scr, mask;
+
+ scr = read_ssi(&ssi->scr) & ~(CCSR_SSI_SCR_SYN | CCSR_SSI_SCR_I2S_MODE_MASK);
+ scr |= CCSR_SSI_SCR_NET;
+
+ mask = CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR |
+ CCSR_SSI_STCR_TSCKP | CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TFSL |
+ CCSR_SSI_STCR_TEFS;
+ stcr = read_ssi(&ssi->stcr) & ~mask;
+ srcr = read_ssi(&ssi->srcr) & ~mask;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ scr |= ssi_private->i2s_mode;
+
+ /* Data on rising edge of bclk, frame low, 1clk before data */
+ strcr |= CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TSCKP |
+ CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* Data on rising edge of bclk, frame high */
+ strcr |= CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TSCKP;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* Data on rising edge of bclk, frame high, 1clk before data */
+ strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
+ CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TEFS;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /* Data on rising edge of bclk, frame high */
+ strcr |= CCSR_SSI_STCR_TFSL | CCSR_SSI_STCR_TSCKP |
+ CCSR_SSI_STCR_TXBIT0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to do for both normal cases */
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Invert bit clock */
+ strcr ^= CCSR_SSI_STCR_TSCKP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Invert frame clock */
+ strcr ^= CCSR_SSI_STCR_TFSI;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert both clocks */
+ strcr ^= CCSR_SSI_STCR_TSCKP;
+ strcr ^= CCSR_SSI_STCR_TFSI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ strcr |= CCSR_SSI_STCR_TFDIR | CCSR_SSI_STCR_TXDIR;
+ scr |= CCSR_SSI_SCR_SYS_CLK_EN;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ stcr |= strcr;
+ srcr |= strcr;
+
+ if (ssi_private->cpu_dai_drv.symmetric_rates) {
+ /* Need to clear RXDIR when using SYNC mode */
+ srcr &= ~CCSR_SSI_SRCR_RXDIR;
+ scr |= CCSR_SSI_SCR_SYN;
+ }
+
+ write_ssi(stcr, &ssi->stcr);
+ write_ssi(srcr, &ssi->srcr);
+ write_ssi(scr, &ssi->scr);
+
+ return 0;
+}
+
+/**
+ * fsl_ssi_set_dai_sysclk - configure Digital Audio Interface bit clock
+ *
+ * Note: This function can be only called when using SSI as DAI master
+ *
+ * Quick instruction for parameters:
+ * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
+ * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
+ */
+static int fsl_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ int synchronous = ssi_private->cpu_dai_drv.symmetric_rates, ret;
+ u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i;
+ unsigned long flags, clkrate, baudrate, tmprate;
+ u64 sub, savesub = 100000;
+
+ /* Don't apply it to any non-baudclk circumstance */
+ if (IS_ERR(ssi_private->baudclk))
+ return -EINVAL;
+
+ /* It should be already enough to divide clock by setting pm alone */
+ psr = 0;
+ div2 = 0;
+
+ factor = (div2 + 1) * (7 * psr + 1) * 2;
+
+ for (i = 0; i < 255; i++) {
+ /* The bclk rate must be smaller than 1/5 sysclk rate */
+ if (factor * (i + 1) < 5)
+ continue;
+
+ tmprate = freq * factor * (i + 2);
+ clkrate = clk_round_rate(ssi_private->baudclk, tmprate);
+
+ do_div(clkrate, factor);
+ afreq = (u32)clkrate / (i + 1);
+
+ if (freq == afreq)
+ sub = 0;
+ else if (freq / afreq == 1)
+ sub = freq - afreq;
+ else if (afreq / freq == 1)
+ sub = afreq - freq;
+ else
+ continue;
+
+ /* Calculate the fraction */
+ sub *= 100000;
+ do_div(sub, freq);
+
+ if (sub < savesub) {
+ baudrate = tmprate;
+ savesub = sub;
+ pm = i;
+ }
+
+ /* We are lucky */
+ if (savesub == 0)
+ break;
+ }
+
+ /* No proper pm found if it is still remaining the initial value */
+ if (pm == 999) {
+ dev_err(cpu_dai->dev, "failed to handle the required sysclk\n");
+ return -EINVAL;
+ }
+
+ stccr = CCSR_SSI_SxCCR_PM(pm + 1) | (div2 ? CCSR_SSI_SxCCR_DIV2 : 0) |
+ (psr ? CCSR_SSI_SxCCR_PSR : 0);
+ mask = CCSR_SSI_SxCCR_PM_MASK | CCSR_SSI_SxCCR_DIV2 | CCSR_SSI_SxCCR_PSR;
+
+ if (dir == SND_SOC_CLOCK_OUT || synchronous)
+ write_ssi_mask(&ssi->stccr, mask, stccr);
+ else
+ write_ssi_mask(&ssi->srccr, mask, stccr);
+
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ if (!ssi_private->baudclk_locked) {
+ ret = clk_set_rate(ssi_private->baudclk, baudrate);
+ if (ret) {
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+ dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
+ return -EINVAL;
+ }
+ ssi_private->baudclk_locked = true;
+ }
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+
+ return 0;
+}
+
+/**
+ * fsl_ssi_set_dai_tdm_slot - set TDM slot number
+ *
+ * Note: This function can be only called when using SSI as DAI master
+ */
+static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
+ struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+ u32 val;
+
+ /* The slot number should be >= 2 if using Network mode or I2S mode */
+ val = read_ssi(&ssi->scr) & (CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_NET);
+ if (val && slots < 2) {
+ dev_err(cpu_dai->dev, "slot number should be >= 2 in I2S or NET\n");
+ return -EINVAL;
+ }
+
+ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_DC_MASK,
+ CCSR_SSI_SxCCR_DC(slots));
+ write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_DC_MASK,
+ CCSR_SSI_SxCCR_DC(slots));
+
+ /* The register SxMSKs needs SSI to provide essential clock due to
+ * hardware design. So we here temporarily enable SSI to set them.
+ */
+ val = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
+ write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN);
+
+ write_ssi(tx_mask, &ssi->stmsk);
+ write_ssi(rx_mask, &ssi->srmsk);
+
+ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, val);
+
return 0;
}
@@ -555,77 +1079,46 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- unsigned int sier_bits;
-
- /*
- * Enable only the interrupts and DMA requests
- * that are needed for the channel. As the fiq
- * is polling for this bits, we have to ensure
- * that this are aligned with the preallocated
- * buffers
- */
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (ssi_private->use_dma)
- sier_bits = SIER_FLAGS;
- else
- sier_bits = CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TFE0_EN;
- } else {
- if (ssi_private->use_dma)
- sier_bits = SIER_FLAGS;
- else
- sier_bits = CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_RFF0_EN;
- }
+ unsigned long flags;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- write_ssi_mask(&ssi->scr, 0,
- CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
+ fsl_ssi_tx_config(ssi_private, true);
else
- write_ssi_mask(&ssi->scr, 0,
- CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
+ fsl_ssi_rx_config(ssi_private, true);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
+ fsl_ssi_tx_config(ssi_private, false);
else
- write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
+ fsl_ssi_rx_config(ssi_private, false);
if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
- (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
- write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
+ (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0) {
+ spin_lock_irqsave(&ssi_private->baudclk_lock, flags);
+ ssi_private->baudclk_locked = false;
+ spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
+ }
break;
default:
return -EINVAL;
}
- write_ssi(sier_bits, &ssi->sier);
+ if (ssi_private->imx_ac97) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
+ else
+ write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
+ }
return 0;
}
-/**
- * fsl_ssi_shutdown: shutdown the SSI
- *
- * Shutdown the SSI if there are no other substreams open.
- */
-static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-
- if (ssi_private->first_stream == substream)
- ssi_private->first_stream = ssi_private->second_stream;
-
- ssi_private->second_stream = NULL;
-}
-
static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
@@ -641,7 +1134,9 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.startup = fsl_ssi_startup,
.hw_params = fsl_ssi_hw_params,
- .shutdown = fsl_ssi_shutdown,
+ .set_fmt = fsl_ssi_set_dai_fmt,
+ .set_sysclk = fsl_ssi_set_dai_sysclk,
+ .set_tdm_slot = fsl_ssi_set_dai_tdm_slot,
.trigger = fsl_ssi_trigger,
};
@@ -649,14 +1144,13 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
static struct snd_soc_dai_driver fsl_ssi_dai_template = {
.probe = fsl_ssi_dai_probe,
.playback = {
- /* The SSI does not support monaural audio. */
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = FSLSSI_I2S_RATES,
.formats = FSLSSI_I2S_FORMATS,
},
.capture = {
- .channels_min = 2,
+ .channels_min = 1,
.channels_max = 2,
.rates = FSLSSI_I2S_RATES,
.formats = FSLSSI_I2S_FORMATS,
@@ -668,59 +1162,6 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
.name = "fsl-ssi",
};
-/**
- * fsl_ssi_ac97_trigger: start and stop the AC97 receive/transmit.
- *
- * This function is called by ALSA to start, stop, pause, and resume the
- * transfer of data.
- */
-static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(
- rtd->cpu_dai);
- struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_TIE |
- CCSR_SSI_SIER_TFE0_EN);
- else
- write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_RIE |
- CCSR_SSI_SIER_RFF0_EN);
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_TIE |
- CCSR_SSI_SIER_TFE0_EN, 0);
- else
- write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RIE |
- CCSR_SSI_SIER_RFF0_EN, 0);
- break;
-
- default:
- return -EINVAL;
- }
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
- else
- write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = {
- .startup = fsl_ssi_startup,
- .shutdown = fsl_ssi_shutdown,
- .trigger = fsl_ssi_ac97_trigger,
-};
-
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.ac97_control = 1,
.playback = {
@@ -737,7 +1178,7 @@ static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .ops = &fsl_ssi_ac97_dai_ops,
+ .ops = &fsl_ssi_dai_ops,
};
@@ -748,7 +1189,7 @@ static void fsl_ssi_ac97_init(void)
fsl_ssi_setup(fsl_ac97_data);
}
-void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
@@ -770,7 +1211,7 @@ void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
udelay(100);
}
-unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
+static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
@@ -795,56 +1236,6 @@ static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
.write = fsl_ssi_ac97_write,
};
-/* Show the statistics of a flag only if its interrupt is enabled. The
- * compiler will optimze this code to a no-op if the interrupt is not
- * enabled.
- */
-#define SIER_SHOW(flag, name) \
- do { \
- if (SIER_FLAGS & CCSR_SSI_SIER_##flag) \
- length += sprintf(buf + length, #name "=%u\n", \
- ssi_private->stats.name); \
- } while (0)
-
-
-/**
- * fsl_sysfs_ssi_show: display SSI statistics
- *
- * Display the statistics for the current SSI device. To avoid confusion,
- * we only show those counts that are enabled.
- */
-static ssize_t fsl_sysfs_ssi_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fsl_ssi_private *ssi_private =
- container_of(attr, struct fsl_ssi_private, dev_attr);
- ssize_t length = 0;
-
- SIER_SHOW(RFRC_EN, rfrc);
- SIER_SHOW(TFRC_EN, tfrc);
- SIER_SHOW(CMDAU_EN, cmdau);
- SIER_SHOW(CMDDU_EN, cmddu);
- SIER_SHOW(RXT_EN, rxt);
- SIER_SHOW(RDR1_EN, rdr1);
- SIER_SHOW(RDR0_EN, rdr0);
- SIER_SHOW(TDE1_EN, tde1);
- SIER_SHOW(TDE0_EN, tde0);
- SIER_SHOW(ROE1_EN, roe1);
- SIER_SHOW(ROE0_EN, roe0);
- SIER_SHOW(TUE1_EN, tue1);
- SIER_SHOW(TUE0_EN, tue0);
- SIER_SHOW(TFS_EN, tfs);
- SIER_SHOW(RFS_EN, rfs);
- SIER_SHOW(TLS_EN, tls);
- SIER_SHOW(RLS_EN, rls);
- SIER_SHOW(RFF1_EN, rff1);
- SIER_SHOW(RFF0_EN, rff0);
- SIER_SHOW(TFE1_EN, tfe1);
- SIER_SHOW(TFE0_EN, tfe0);
-
- return length;
-}
-
/**
* Make every character in a string lower-case
*/
@@ -866,6 +1257,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
int ret = 0;
struct device_attribute *dev_attr = NULL;
struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id;
+ enum fsl_ssi_type hw_type;
const char *p, *sprop;
const uint32_t *iprop;
struct resource res;
@@ -880,18 +1273,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
if (!of_device_is_available(np))
return -ENODEV;
- /* We only support the SSI in "I2S Slave" mode */
+ of_id = of_match_device(fsl_ssi_ids, &pdev->dev);
+ if (!of_id)
+ return -EINVAL;
+ hw_type = (enum fsl_ssi_type) of_id->data;
+
sprop = of_get_property(np, "fsl,mode", NULL);
if (!sprop) {
dev_err(&pdev->dev, "fsl,mode property is necessary\n");
return -EINVAL;
}
- if (!strcmp(sprop, "ac97-slave")) {
+ if (!strcmp(sprop, "ac97-slave"))
ac97 = true;
- } else if (strcmp(sprop, "i2s-slave")) {
- dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
- return -ENODEV;
- }
/* The DAI name is the last part of the full name of the node. */
p = strrchr(np->full_name, '/') + 1;
@@ -906,6 +1299,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ssi_private->use_dma = !of_property_read_bool(np,
"fsl,fiq-stream-filter");
+ ssi_private->hw_type = hw_type;
if (ac97) {
memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai,
@@ -936,14 +1330,17 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ssi_private->ssi_phys = res.start;
ssi_private->irq = irq_of_parse_and_map(np, 0);
- if (ssi_private->irq == NO_IRQ) {
+ if (!ssi_private->irq) {
dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
return -ENXIO;
}
/* Are the RX and the TX clocks locked? */
- if (!of_find_property(np, "fsl,ssi-asynchronous", NULL))
+ if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) {
ssi_private->cpu_dai_drv.symmetric_rates = 1;
+ ssi_private->cpu_dai_drv.symmetric_channels = 1;
+ ssi_private->cpu_dai_drv.symmetric_samplebits = 1;
+ }
/* Determine the FIFO depth. */
iprop = of_get_property(np, "fsl,fifo-depth", NULL);
@@ -953,8 +1350,38 @@ static int fsl_ssi_probe(struct platform_device *pdev)
/* Older 8610 DTs didn't have the fifo-depth property */
ssi_private->fifo_depth = 8;
- if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
- u32 dma_events[2];
+ ssi_private->baudclk_locked = false;
+ spin_lock_init(&ssi_private->baudclk_lock);
+
+ /*
+ * imx51 and later SoCs have a slightly different IP that allows the
+ * SSI configuration while the SSI unit is running.
+ *
+ * More important, it is necessary on those SoCs to configure the
+ * sperate TX/RX DMA bits just before starting the stream
+ * (fsl_ssi_trigger). The SDMA unit has to be configured before fsl_ssi
+ * sends any DMA requests to the SDMA unit, otherwise it is not defined
+ * how the SDMA unit handles the DMA request.
+ *
+ * SDMA units are present on devices starting at imx35 but the imx35
+ * reference manual states that the DMA bits should not be changed
+ * while the SSI unit is running (SSIEN). So we support the necessary
+ * online configuration of fsl-ssi starting at imx51.
+ */
+ switch (hw_type) {
+ case FSL_SSI_MCP8610:
+ case FSL_SSI_MX21:
+ case FSL_SSI_MX35:
+ ssi_private->offline_config = true;
+ break;
+ case FSL_SSI_MX51:
+ ssi_private->offline_config = false;
+ break;
+ }
+
+ if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX51 ||
+ hw_type == FSL_SSI_MX35) {
+ u32 dma_events[2], dmas[4];
ssi_private->ssi_on_imx = true;
ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
@@ -970,6 +1397,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
goto error_irqmap;
}
+ /* For those SLAVE implementations, we ingore non-baudclk cases
+ * and, instead, abandon MASTER mode that needs baud clock.
+ */
+ ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
+ if (IS_ERR(ssi_private->baudclk))
+ dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
+ PTR_ERR(ssi_private->baudclk));
+ else
+ clk_prepare_enable(ssi_private->baudclk);
+
/*
* We have burstsize be "fifo_depth - 2" to match the SSI
* watermark setting in fsl_ssi_startup().
@@ -1000,6 +1437,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
goto error_clk;
}
}
+ /* Should this be merge with the above? */
+ if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4)
+ && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
+ ssi_private->use_dual_fifo = true;
+ /* When using dual fifo mode, we need to keep watermark
+ * as even numbers due to dma script limitation.
+ */
+ ssi_private->dma_params_tx.maxburst &= ~0x1;
+ ssi_private->dma_params_rx.maxburst &= ~0x1;
+ }
shared = of_device_is_compatible(of_get_parent(np),
"fsl,spba-bus");
@@ -1008,32 +1455,25 @@ static int fsl_ssi_probe(struct platform_device *pdev)
dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
- } else if (ssi_private->use_dma) {
+ }
+
+ /*
+ * Enable interrupts only for MCP8610 and MX51. The other MXs have
+ * different writeable interrupt status registers.
+ */
+ if (ssi_private->use_dma) {
/* The 'name' should not have any slashes in it. */
ret = devm_request_irq(&pdev->dev, ssi_private->irq,
fsl_ssi_isr, 0, ssi_private->name,
ssi_private);
+ ssi_private->irq_stats = true;
if (ret < 0) {
dev_err(&pdev->dev, "could not claim irq %u\n",
ssi_private->irq);
- goto error_irqmap;
+ goto error_clk;
}
}
- /* Initialize the the device_attribute structure */
- dev_attr = &ssi_private->dev_attr;
- sysfs_attr_init(&dev_attr->attr);
- dev_attr->attr.name = "statistics";
- dev_attr->attr.mode = S_IRUGO;
- dev_attr->show = fsl_sysfs_ssi_show;
-
- ret = device_create_file(&pdev->dev, dev_attr);
- if (ret) {
- dev_err(&pdev->dev, "could not create sysfs %s file\n",
- ssi_private->dev_attr.attr.name);
- goto error_clk;
- }
-
/* Register with ASoC */
dev_set_drvdata(&pdev->dev, ssi_private);
@@ -1044,6 +1484,10 @@ static int fsl_ssi_probe(struct platform_device *pdev)
goto error_dev;
}
+ ret = fsl_ssi_debugfs_create(ssi_private, &pdev->dev);
+ if (ret)
+ goto error_dbgfs;
+
if (ssi_private->ssi_on_imx) {
if (!ssi_private->use_dma) {
@@ -1063,11 +1507,11 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
if (ret)
- goto error_dev;
+ goto error_pcm;
} else {
ret = imx_pcm_dma_init(pdev);
if (ret)
- goto error_dev;
+ goto error_pcm;
}
}
@@ -1109,19 +1553,28 @@ done:
return 0;
error_dai:
- if (ssi_private->ssi_on_imx)
- imx_pcm_dma_exit(pdev);
+ if (ssi_private->ssi_on_imx && !ssi_private->use_dma)
+ imx_pcm_fiq_exit(pdev);
+
+error_pcm:
+ fsl_ssi_debugfs_remove(ssi_private);
+
+error_dbgfs:
snd_soc_unregister_component(&pdev->dev);
error_dev:
device_remove_file(&pdev->dev, dev_attr);
error_clk:
- if (ssi_private->ssi_on_imx)
+ if (ssi_private->ssi_on_imx) {
+ if (!IS_ERR(ssi_private->baudclk))
+ clk_disable_unprepare(ssi_private->baudclk);
clk_disable_unprepare(ssi_private->clk);
+ }
error_irqmap:
- irq_dispose_mapping(ssi_private->irq);
+ if (ssi_private->irq_stats)
+ irq_dispose_mapping(ssi_private->irq);
return ret;
}
@@ -1130,27 +1583,22 @@ static int fsl_ssi_remove(struct platform_device *pdev)
{
struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
+ fsl_ssi_debugfs_remove(ssi_private);
+
if (!ssi_private->new_binding)
platform_device_unregister(ssi_private->pdev);
- if (ssi_private->ssi_on_imx)
- imx_pcm_dma_exit(pdev);
snd_soc_unregister_component(&pdev->dev);
- dev_set_drvdata(&pdev->dev, NULL);
- device_remove_file(&pdev->dev, &ssi_private->dev_attr);
- if (ssi_private->ssi_on_imx)
+ if (ssi_private->ssi_on_imx) {
+ if (!IS_ERR(ssi_private->baudclk))
+ clk_disable_unprepare(ssi_private->baudclk);
clk_disable_unprepare(ssi_private->clk);
- irq_dispose_mapping(ssi_private->irq);
+ }
+ if (ssi_private->irq_stats)
+ irq_dispose_mapping(ssi_private->irq);
return 0;
}
-static const struct of_device_id fsl_ssi_ids[] = {
- { .compatible = "fsl,mpc8610-ssi", },
- { .compatible = "fsl,imx21-ssi", },
- {}
-};
-MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
-
static struct platform_driver fsl_ssi_driver = {
.driver = {
.name = "fsl-ssi-dai",
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index e6b9a69e2a68..e6b63240a3d7 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -125,7 +125,9 @@ struct ccsr_ssi {
#define CCSR_SSI_SRCR_REFS 0x00000001
/* STCCR and SRCCR */
+#define CCSR_SSI_SxCCR_DIV2_SHIFT 18
#define CCSR_SSI_SxCCR_DIV2 0x00040000
+#define CCSR_SSI_SxCCR_PSR_SHIFT 17
#define CCSR_SSI_SxCCR_PSR 0x00020000
#define CCSR_SSI_SxCCR_WL_SHIFT 13
#define CCSR_SSI_SxCCR_WL_MASK 0x0001E000
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index d3bf71a0ec56..ac869931d7f1 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -66,13 +66,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
ssize_t ret;
- char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ char *buf;
int port = (int)file->private_data;
u32 pdcr, ptcr;
- if (!buf)
- return -ENOMEM;
-
if (audmux_clk) {
ret = clk_prepare_enable(audmux_clk);
if (ret)
@@ -85,6 +82,10 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
if (audmux_clk)
clk_disable_unprepare(audmux_clk);
+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n",
pdcr, ptcr);
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
index a3d60d4bea4c..a2fd7321b5a9 100644
--- a/sound/soc/fsl/imx-mc13783.c
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -112,7 +112,7 @@ static int imx_mc13783_probe(struct platform_device *pdev)
return ret;
}
- if (machine_is_mx31_3ds()) {
+ if (machine_is_mx31_3ds() || machine_is_mx31moboard()) {
imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
IMX_AUDMUX_V2_PTCR_SYN,
IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 4dc1296688e9..2585ae44e634 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -25,12 +25,10 @@
static bool filter(struct dma_chan *chan, void *param)
{
- struct snd_dmaengine_dai_dma_data *dma_data = param;
-
if (!imx_dma_is_general_purpose(chan))
return false;
- chan->private = dma_data->filter_data;
+ chan->private = param;
return true;
}
@@ -43,9 +41,6 @@ static const struct snd_pcm_hardware imx_pcm_hardware = {
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rate_min = 8000,
- .channels_min = 2,
- .channels_max = 2,
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = 65535, /* Limited by SDMA engine */
@@ -63,16 +58,11 @@ static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
int imx_pcm_dma_init(struct platform_device *pdev)
{
- return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
+ return devm_snd_dmaengine_pcm_register(&pdev->dev,
+ &imx_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
-void imx_pcm_dma_exit(struct platform_device *pdev)
-{
- snd_dmaengine_pcm_unregister(&pdev->dev);
-}
-EXPORT_SYMBOL_GPL(imx_pcm_dma_exit);
-
MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 34043c55f2a6..6553202dd48c 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -39,12 +39,11 @@ struct imx_pcm_runtime_data {
unsigned int period;
int periods;
unsigned long offset;
- unsigned long last_offset;
- unsigned long size;
struct hrtimer hrt;
int poll_time_ns;
struct snd_pcm_substream *substream;
- atomic_t running;
+ atomic_t playing;
+ atomic_t capturing;
};
static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
@@ -52,11 +51,9 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
struct imx_pcm_runtime_data *iprtd =
container_of(hrt, struct imx_pcm_runtime_data, hrt);
struct snd_pcm_substream *substream = iprtd->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
struct pt_regs regs;
- unsigned long delta;
- if (!atomic_read(&iprtd->running))
+ if (!atomic_read(&iprtd->playing) && !atomic_read(&iprtd->capturing))
return HRTIMER_NORESTART;
get_fiq_regs(&regs);
@@ -66,19 +63,7 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
else
iprtd->offset = regs.ARM_r9 & 0xffff;
- /* How much data have we transferred since the last period report? */
- if (iprtd->offset >= iprtd->last_offset)
- delta = iprtd->offset - iprtd->last_offset;
- else
- delta = runtime->buffer_size + iprtd->offset
- - iprtd->last_offset;
-
- /* If we've transferred at least a period then report it and
- * reset our poll time */
- if (delta >= iprtd->period) {
- snd_pcm_period_elapsed(substream);
- iprtd->last_offset = iprtd->offset;
- }
+ snd_pcm_period_elapsed(substream);
hrtimer_forward_now(hrt, ns_to_ktime(iprtd->poll_time_ns));
@@ -95,11 +80,9 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- iprtd->size = params_buffer_bytes(params);
iprtd->periods = params_periods(params);
- iprtd->period = params_period_bytes(params) ;
+ iprtd->period = params_period_bytes(params);
iprtd->offset = 0;
- iprtd->last_offset = 0;
iprtd->poll_time_ns = 1000000000 / params_rate(params) *
params_period_size(params);
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
@@ -124,7 +107,6 @@ static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
return 0;
}
-static int fiq_enable;
static int imx_pcm_fiq;
static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -136,23 +118,27 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- atomic_set(&iprtd->running, 1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ atomic_set(&iprtd->playing, 1);
+ else
+ atomic_set(&iprtd->capturing, 1);
hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns),
HRTIMER_MODE_REL);
- if (++fiq_enable == 1)
- enable_fiq(imx_pcm_fiq);
-
+ enable_fiq(imx_pcm_fiq);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- atomic_set(&iprtd->running, 0);
-
- if (--fiq_enable == 0)
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ atomic_set(&iprtd->playing, 0);
+ else
+ atomic_set(&iprtd->capturing, 0);
+ if (!atomic_read(&iprtd->playing) &&
+ !atomic_read(&iprtd->capturing))
disable_fiq(imx_pcm_fiq);
-
break;
+
default:
return -EINVAL;
}
@@ -176,9 +162,6 @@ static struct snd_pcm_hardware snd_imx_hardware = {
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rate_min = 8000,
- .channels_min = 2,
- .channels_max = 2,
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = 16 * 1024,
@@ -200,7 +183,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
iprtd->substream = substream;
- atomic_set(&iprtd->running, 0);
+ atomic_set(&iprtd->playing, 0);
+ atomic_set(&iprtd->capturing, 0);
hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
iprtd->hrt.function = snd_hrtimer_callback;
@@ -272,18 +256,16 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
return 0;
}
-static u64 imx_pcm_dmamask = DMA_BIT_MASK(32);
-
static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
+
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &imx_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = imx_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index 5d5b73303e11..c79cb27473be 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -40,16 +40,11 @@ struct imx_pcm_fiq_params {
#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)
int imx_pcm_dma_init(struct platform_device *pdev);
-void imx_pcm_dma_exit(struct platform_device *pdev);
#else
static inline int imx_pcm_dma_init(struct platform_device *pdev)
{
return -ENODEV;
}
-
-static inline void imx_pcm_dma_exit(struct platform_device *pdev)
-{
-}
#endif
#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_FIQ)
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 46c5b4fdfc52..1cb22dd034eb 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -33,8 +33,7 @@ struct imx_sgtl5000_data {
static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct imx_sgtl5000_data *data = container_of(rtd->card,
- struct imx_sgtl5000_data, card);
+ struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card);
struct device *dev = rtd->card->dev;
int ret;
@@ -62,7 +61,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
struct device_node *ssi_np, *codec_np;
struct platform_device *ssi_pdev;
struct i2c_client *codec_dev;
- struct imx_sgtl5000_data *data;
+ struct imx_sgtl5000_data *data = NULL;
int int_port, ext_port;
int ret;
@@ -128,7 +127,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
goto fail;
}
- data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+ data->codec_clk = clk_get(&codec_dev->dev, NULL);
if (IS_ERR(data->codec_clk)) {
ret = PTR_ERR(data->codec_clk);
goto fail;
@@ -159,19 +158,23 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
- ret = snd_soc_register_card(&data->card);
+ platform_set_drvdata(pdev, &data->card);
+ snd_soc_card_set_drvdata(&data->card, data);
+
+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
goto fail;
}
- platform_set_drvdata(pdev, data);
of_node_put(ssi_np);
of_node_put(codec_np);
return 0;
fail:
+ if (data && !IS_ERR(data->codec_clk))
+ clk_put(data->codec_clk);
if (ssi_np)
of_node_put(ssi_np);
if (codec_np)
@@ -182,9 +185,10 @@ fail:
static int imx_sgtl5000_remove(struct platform_device *pdev)
{
- struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card);
- snd_soc_unregister_card(&data->card);
+ clk_put(data->codec_clk);
return 0;
}
@@ -199,6 +203,7 @@ static struct platform_driver imx_sgtl5000_driver = {
.driver = {
.name = "imx-sgtl5000",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
.of_match_table = imx_sgtl5000_dt_ids,
},
.probe = imx_sgtl5000_probe,
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
index 816013b0ebba..e1dc40143600 100644
--- a/sound/soc/fsl/imx-spdif.c
+++ b/sound/soc/fsl/imx-spdif.c
@@ -14,17 +14,15 @@
#include <sound/soc.h>
struct imx_spdif_data {
- struct snd_soc_dai_link dai[2];
+ struct snd_soc_dai_link dai;
struct snd_soc_card card;
- struct platform_device *txdev;
- struct platform_device *rxdev;
};
static int imx_spdif_audio_probe(struct platform_device *pdev)
{
struct device_node *spdif_np, *np = pdev->dev.of_node;
struct imx_spdif_data *data;
- int ret = 0, num_links = 0;
+ int ret = 0;
spdif_np = of_parse_phandle(np, "spdif-controller", 0);
if (!spdif_np) {
@@ -35,74 +33,46 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
ret = -ENOMEM;
goto end;
}
- if (of_property_read_bool(np, "spdif-out")) {
- data->dai[num_links].name = "S/PDIF TX";
- data->dai[num_links].stream_name = "S/PDIF PCM Playback";
- data->dai[num_links].codec_dai_name = "dit-hifi";
- data->dai[num_links].codec_name = "spdif-dit";
- data->dai[num_links].cpu_of_node = spdif_np;
- data->dai[num_links].platform_of_node = spdif_np;
- num_links++;
-
- data->txdev = platform_device_register_simple("spdif-dit", -1, NULL, 0);
- if (IS_ERR(data->txdev)) {
- ret = PTR_ERR(data->txdev);
- dev_err(&pdev->dev, "register dit failed: %d\n", ret);
- goto end;
- }
- }
+ data->dai.name = "S/PDIF PCM";
+ data->dai.stream_name = "S/PDIF PCM";
+ data->dai.codec_dai_name = "snd-soc-dummy-dai";
+ data->dai.codec_name = "snd-soc-dummy";
+ data->dai.cpu_of_node = spdif_np;
+ data->dai.platform_of_node = spdif_np;
+ data->dai.playback_only = true;
+ data->dai.capture_only = true;
- if (of_property_read_bool(np, "spdif-in")) {
- data->dai[num_links].name = "S/PDIF RX";
- data->dai[num_links].stream_name = "S/PDIF PCM Capture";
- data->dai[num_links].codec_dai_name = "dir-hifi";
- data->dai[num_links].codec_name = "spdif-dir";
- data->dai[num_links].cpu_of_node = spdif_np;
- data->dai[num_links].platform_of_node = spdif_np;
- num_links++;
-
- data->rxdev = platform_device_register_simple("spdif-dir", -1, NULL, 0);
- if (IS_ERR(data->rxdev)) {
- ret = PTR_ERR(data->rxdev);
- dev_err(&pdev->dev, "register dir failed: %d\n", ret);
- goto error_dit;
- }
- }
+ if (of_property_read_bool(np, "spdif-out"))
+ data->dai.capture_only = false;
- if (!num_links) {
+ if (of_property_read_bool(np, "spdif-in"))
+ data->dai.playback_only = false;
+
+ if (data->dai.playback_only && data->dai.capture_only) {
dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
- goto error_dir;
+ goto end;
}
data->card.dev = &pdev->dev;
- data->card.num_links = num_links;
- data->card.dai_link = data->dai;
+ data->card.dai_link = &data->dai;
+ data->card.num_links = 1;
ret = snd_soc_of_parse_card_name(&data->card, "model");
if (ret)
- goto error_dir;
+ goto end;
- ret = snd_soc_register_card(&data->card);
+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret);
- goto error_dir;
+ goto end;
}
platform_set_drvdata(pdev, data);
- goto end;
-
-error_dir:
- if (data->rxdev)
- platform_device_unregister(data->rxdev);
-error_dit:
- if (data->txdev)
- platform_device_unregister(data->txdev);
end:
if (spdif_np)
of_node_put(spdif_np);
@@ -110,20 +80,6 @@ end:
return ret;
}
-static int imx_spdif_audio_remove(struct platform_device *pdev)
-{
- struct imx_spdif_data *data = platform_get_drvdata(pdev);
-
- if (data->rxdev)
- platform_device_unregister(data->rxdev);
- if (data->txdev)
- platform_device_unregister(data->txdev);
-
- snd_soc_unregister_card(&data->card);
-
- return 0;
-}
-
static const struct of_device_id imx_spdif_dt_ids[] = {
{ .compatible = "fsl,imx-audio-spdif", },
{ /* sentinel */ }
@@ -137,7 +93,6 @@ static struct platform_driver imx_spdif_driver = {
.of_match_table = imx_spdif_dt_ids,
},
.probe = imx_spdif_audio_probe,
- .remove = imx_spdif_audio_remove,
};
module_platform_driver(imx_spdif_driver);
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index f58bcd85c07f..df552fa1aa65 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -304,8 +304,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
scr |= SSI_SCR_RE;
sier |= sier_bits;
- if (++ssi->enabled == 1)
- scr |= SSI_SCR_SSIEN;
+ scr |= SSI_SCR_SSIEN;
break;
@@ -318,7 +317,7 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
scr &= ~SSI_SCR_RE;
sier &= ~sier_bits;
- if (--ssi->enabled == 0)
+ if (!(scr & (SSI_SCR_TE | SSI_SCR_RE)))
scr &= ~SSI_SCR_SSIEN;
break;
@@ -536,7 +535,9 @@ static int imx_ssi_probe(struct platform_device *pdev)
ret);
goto failed_clk;
}
- clk_prepare_enable(ssi->clk);
+ ret = clk_prepare_enable(ssi->clk);
+ if (ret)
+ goto failed_clk;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ssi->base = devm_ioremap_resource(&pdev->dev, res);
@@ -600,22 +601,19 @@ static int imx_ssi_probe(struct platform_device *pdev)
ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
- ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
- if (ret)
- goto failed_pcm_fiq;
+ ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
+ ssi->dma_init = imx_pcm_dma_init(pdev);
- ret = imx_pcm_dma_init(pdev);
- if (ret)
- goto failed_pcm_dma;
+ if (ssi->fiq_init && ssi->dma_init) {
+ ret = ssi->fiq_init;
+ goto failed_pcm;
+ }
return 0;
-failed_pcm_dma:
- imx_pcm_fiq_exit(pdev);
-failed_pcm_fiq:
+failed_pcm:
snd_soc_unregister_component(&pdev->dev);
failed_register:
- release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(ssi->clk);
failed_clk:
snd_soc_set_ac97_ops(NULL);
@@ -625,18 +623,16 @@ failed_clk:
static int imx_ssi_remove(struct platform_device *pdev)
{
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct imx_ssi *ssi = platform_get_drvdata(pdev);
- imx_pcm_dma_exit(pdev);
- imx_pcm_fiq_exit(pdev);
+ if (!ssi->fiq_init)
+ imx_pcm_fiq_exit(pdev);
snd_soc_unregister_component(&pdev->dev);
if (ssi->flags & IMX_SSI_USE_AC97)
ac97_ssi = NULL;
- release_mem_region(res->start, resource_size(res));
clk_disable_unprepare(ssi->clk);
snd_soc_set_ac97_ops(NULL);
diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
index fb1616ba8c59..be6562365b6a 100644
--- a/sound/soc/fsl/imx-ssi.h
+++ b/sound/soc/fsl/imx-ssi.h
@@ -211,7 +211,8 @@ struct imx_ssi {
struct imx_dma_data filter_data_rx;
struct imx_pcm_fiq_params fiq_params;
- int enabled;
+ int fiq_init;
+ int dma_init;
};
#endif /* _IMX_SSI_H */
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index 722afe69169e..3a3d17ce6ba4 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
{
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
struct imx_priv *priv = &card_priv;
- struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+ struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
struct device *dev = &priv->pdev->dev;
unsigned int pll_out;
int ret;
@@ -130,8 +130,6 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
break;
}
- dapm->bias_level = level;
-
return 0;
}
@@ -139,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card)
{
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
struct imx_priv *priv = &card_priv;
- struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+ struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
struct device *dev = &priv->pdev->dev;
int ret;
@@ -215,7 +213,7 @@ static int imx_wm8962_probe(struct platform_device *pdev)
goto fail;
}
codec_dev = of_find_i2c_device_by_node(codec_np);
- if (!codec_dev || !codec_dev->driver) {
+ if (!codec_dev || !codec_dev->dev.driver) {
dev_err(&pdev->dev, "failed to find codec platform device\n");
ret = -EINVAL;
goto fail;
@@ -266,21 +264,22 @@ static int imx_wm8962_probe(struct platform_device *pdev)
data->card.late_probe = imx_wm8962_late_probe;
data->card.set_bias_level = imx_wm8962_set_bias_level;
- ret = snd_soc_register_card(&data->card);
+ platform_set_drvdata(pdev, &data->card);
+ snd_soc_card_set_drvdata(&data->card, data);
+
+ ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
if (ret) {
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
goto clk_fail;
}
- platform_set_drvdata(pdev, data);
of_node_put(ssi_np);
of_node_put(codec_np);
return 0;
clk_fail:
- if (!IS_ERR(data->codec_clk))
- clk_disable_unprepare(data->codec_clk);
+ clk_disable_unprepare(data->codec_clk);
fail:
if (ssi_np)
of_node_put(ssi_np);
@@ -292,11 +291,11 @@ fail:
static int imx_wm8962_remove(struct platform_device *pdev)
{
- struct imx_wm8962_data *data = platform_get_drvdata(pdev);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
if (!IS_ERR(data->codec_clk))
clk_disable_unprepare(data->codec_clk);
- snd_soc_unregister_card(&data->card);
return 0;
}
@@ -311,6 +310,7 @@ static struct platform_driver imx_wm8962_driver = {
.driver = {
.name = "imx-wm8962",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
.of_match_table = imx_wm8962_dt_ids,
},
.probe = imx_wm8962_probe,
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 2a847ca494b5..f2b5d756b1f3 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -10,6 +10,8 @@
#include <linux/of_device.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <sound/soc.h>
@@ -198,10 +200,6 @@ static const struct snd_pcm_hardware psc_dma_hardware = {
SNDRV_PCM_INFO_BATCH,
.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
.period_bytes_max = 1024 * 1024,
.period_bytes_min = 32,
.periods_min = 2,
@@ -299,7 +297,6 @@ static struct snd_pcm_ops psc_dma_ops = {
.hw_params = psc_dma_hw_params,
};
-static u64 psc_dma_dmamask = DMA_BIT_MASK(32);
static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
@@ -307,15 +304,14 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_pcm *pcm = rtd->pcm;
struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
size_t size = psc_dma_hardware.buffer_bytes_max;
- int rc = 0;
+ int rc;
dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
card, dai, pcm);
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &psc_dma_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ rc = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 3ef7a0c92efa..24eafa2cfbf4 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -291,7 +291,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
rc = snd_soc_set_ac97_ops(&psc_ac97_ops);
if (rc != 0) {
- dev_err(&op->dev, "Failed to set AC'97 ops: %d\n", ret);
+ dev_err(&op->dev, "Failed to set AC'97 ops: %d\n", rc);
return rc;
}
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index f4efaadb80a2..5d07e8a74a21 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -26,8 +26,7 @@
* ALSA that we support all rates and let the codec driver decide what rates
* are really supported.
*/
-#define PSC_I2S_RATES (SNDRV_PCM_RATE_5512 | SNDRV_PCM_RATE_8000_192000 | \
- SNDRV_PCM_RATE_CONTINUOUS)
+#define PSC_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
/**
* PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 228c52e71440..fa756d05b2f7 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index ba59c23a137b..f75c3cf0e6de 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index f21551911533..9d89bb028621 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index eb4373840bb6..3665f612819d 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -69,7 +69,6 @@ static int pcm030_fabric_probe(struct platform_device *op)
return -ENOMEM;
card->dev = &op->dev;
- platform_set_drvdata(op, pdata);
pdata->card = card;
@@ -98,6 +97,8 @@ static int pcm030_fabric_probe(struct platform_device *op)
if (ret)
dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
+ platform_set_drvdata(op, pdata);
+
return ret;
}
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 8c49147db84c..2a1b1b5b5221 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -8,14 +8,13 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-
-#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
#include <sound/simple_card.h>
-#define asoc_simple_get_card_info(p) \
- container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
-
static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
struct asoc_simple_dai *set,
unsigned int daifmt)
@@ -24,9 +23,14 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
daifmt |= set->fmt;
- if (!ret && daifmt)
+ if (daifmt)
ret = snd_soc_dai_set_fmt(dai, daifmt);
+ if (ret == -ENOTSUPP) {
+ dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n");
+ ret = 0;
+ }
+
if (!ret && set->sysclk)
ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
@@ -35,7 +39,8 @@ static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct asoc_simple_card_info *info = asoc_simple_get_card_info(rtd);
+ struct asoc_simple_card_info *info =
+ snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *codec = rtd->codec_dai;
struct snd_soc_dai *cpu = rtd->cpu_dai;
unsigned int daifmt = info->daifmt;
@@ -52,22 +57,182 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int
+asoc_simple_card_sub_parse_of(struct device_node *np,
+ struct asoc_simple_dai *dai,
+ struct device_node **node)
+{
+ struct clk *clk;
+ int ret;
+
+ /*
+ * get node via "sound-dai = <&phandle port>"
+ * it will be used as xxx_of_node on soc_bind_dai_link()
+ */
+ *node = of_parse_phandle(np, "sound-dai", 0);
+ if (!*node)
+ return -ENODEV;
+
+ /* get dai->name */
+ ret = snd_soc_of_get_dai_name(np, &dai->name);
+ if (ret < 0)
+ goto parse_error;
+
+ /*
+ * bitclock-inversion, frame-inversion
+ * bitclock-master, frame-master
+ * and specific "format" if it has
+ */
+ dai->fmt = snd_soc_of_parse_daifmt(np, NULL);
+
+ /*
+ * dai->sysclk come from
+ * "clocks = <&xxx>" (if system has common clock)
+ * or "system-clock-frequency = <xxx>"
+ * or device's module clock.
+ */
+ if (of_property_read_bool(np, "clocks")) {
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ goto parse_error;
+ }
+
+ dai->sysclk = clk_get_rate(clk);
+ } else if (of_property_read_bool(np, "system-clock-frequency")) {
+ of_property_read_u32(np,
+ "system-clock-frequency",
+ &dai->sysclk);
+ } else {
+ clk = of_clk_get(*node, 0);
+ if (!IS_ERR(clk))
+ dai->sysclk = clk_get_rate(clk);
+ }
+
+ ret = 0;
+
+parse_error:
+ of_node_put(*node);
+
+ return ret;
+}
+
+static int asoc_simple_card_parse_of(struct device_node *node,
+ struct asoc_simple_card_info *info,
+ struct device *dev,
+ struct device_node **of_cpu,
+ struct device_node **of_codec,
+ struct device_node **of_platform)
+{
+ struct device_node *np;
+ char *name;
+ int ret;
+
+ /* get CPU/CODEC common format via simple-audio-card,format */
+ info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
+ (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
+
+ /* DAPM routes */
+ if (of_property_read_bool(node, "simple-audio-card,routing")) {
+ ret = snd_soc_of_parse_audio_routing(&info->snd_card,
+ "simple-audio-card,routing");
+ if (ret)
+ return ret;
+ }
+
+ /* CPU sub-node */
+ ret = -EINVAL;
+ np = of_get_child_by_name(node, "simple-audio-card,cpu");
+ if (np)
+ ret = asoc_simple_card_sub_parse_of(np,
+ &info->cpu_dai,
+ of_cpu);
+ if (ret < 0)
+ return ret;
+
+ /* CODEC sub-node */
+ ret = -EINVAL;
+ np = of_get_child_by_name(node, "simple-audio-card,codec");
+ if (np)
+ ret = asoc_simple_card_sub_parse_of(np,
+ &info->codec_dai,
+ of_codec);
+ if (ret < 0)
+ return ret;
+
+ if (!info->cpu_dai.name || !info->codec_dai.name)
+ return -EINVAL;
+
+ /* card name is created from CPU/CODEC dai name */
+ name = devm_kzalloc(dev,
+ strlen(info->cpu_dai.name) +
+ strlen(info->codec_dai.name) + 2,
+ GFP_KERNEL);
+ sprintf(name, "%s-%s", info->cpu_dai.name, info->codec_dai.name);
+ info->name = info->card = name;
+
+ /* simple-card assumes platform == cpu */
+ *of_platform = *of_cpu;
+
+ dev_dbg(dev, "card-name : %s\n", info->card);
+ dev_dbg(dev, "platform : %04x\n", info->daifmt);
+ dev_dbg(dev, "cpu : %s / %04x / %d\n",
+ info->cpu_dai.name,
+ info->cpu_dai.fmt,
+ info->cpu_dai.sysclk);
+ dev_dbg(dev, "codec : %s / %04x / %d\n",
+ info->codec_dai.name,
+ info->codec_dai.fmt,
+ info->codec_dai.sysclk);
+
+ return 0;
+}
+
static int asoc_simple_card_probe(struct platform_device *pdev)
{
- struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+ struct asoc_simple_card_info *cinfo;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *of_cpu, *of_codec, *of_platform;
struct device *dev = &pdev->dev;
+ int ret;
- if (!cinfo) {
- dev_err(dev, "no info for asoc-simple-card\n");
- return -EINVAL;
+ cinfo = NULL;
+ of_cpu = NULL;
+ of_codec = NULL;
+ of_platform = NULL;
+
+ cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL);
+ if (!cinfo)
+ return -ENOMEM;
+
+ if (np && of_device_is_available(np)) {
+ cinfo->snd_card.dev = dev;
+
+ ret = asoc_simple_card_parse_of(np, cinfo, dev,
+ &of_cpu,
+ &of_codec,
+ &of_platform);
+ if (ret < 0) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "parse error %d\n", ret);
+ return ret;
+ }
+ } else {
+ if (!dev->platform_data) {
+ dev_err(dev, "no info for asoc-simple-card\n");
+ return -EINVAL;
+ }
+
+ memcpy(cinfo, dev->platform_data, sizeof(*cinfo));
+ cinfo->snd_card.dev = dev;
}
if (!cinfo->name ||
!cinfo->card ||
- !cinfo->codec ||
- !cinfo->platform ||
- !cinfo->cpu_dai.name ||
- !cinfo->codec_dai.name) {
+ !cinfo->codec_dai.name ||
+ !(cinfo->codec || of_codec) ||
+ !(cinfo->platform || of_platform) ||
+ !(cinfo->cpu_dai.name || of_cpu)) {
dev_err(dev, "insufficient asoc_simple_card_info settings\n");
return -EINVAL;
}
@@ -81,6 +246,9 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
cinfo->snd_link.platform_name = cinfo->platform;
cinfo->snd_link.codec_name = cinfo->codec;
cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name;
+ cinfo->snd_link.cpu_of_node = of_cpu;
+ cinfo->snd_link.codec_of_node = of_codec;
+ cinfo->snd_link.platform_of_node = of_platform;
cinfo->snd_link.init = asoc_simple_card_dai_init;
/*
@@ -90,25 +258,25 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
cinfo->snd_card.owner = THIS_MODULE;
cinfo->snd_card.dai_link = &cinfo->snd_link;
cinfo->snd_card.num_links = 1;
- cinfo->snd_card.dev = &pdev->dev;
- return snd_soc_register_card(&cinfo->snd_card);
-}
+ snd_soc_card_set_drvdata(&cinfo->snd_card, cinfo);
-static int asoc_simple_card_remove(struct platform_device *pdev)
-{
- struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
-
- return snd_soc_unregister_card(&cinfo->snd_card);
+ return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card);
}
+static const struct of_device_id asoc_simple_of_match[] = {
+ { .compatible = "simple-audio-card", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
+
static struct platform_driver asoc_simple_card = {
.driver = {
.name = "asoc-simple-card",
.owner = THIS_MODULE,
+ .of_match_table = asoc_simple_of_match,
},
.probe = asoc_simple_card_probe,
- .remove = asoc_simple_card_remove,
};
module_platform_driver(asoc_simple_card);
diff --git a/sound/soc/mid-x86/Kconfig b/sound/soc/intel/Kconfig
index 61c10bf503d2..61c10bf503d2 100644
--- a/sound/soc/mid-x86/Kconfig
+++ b/sound/soc/intel/Kconfig
diff --git a/sound/soc/mid-x86/Makefile b/sound/soc/intel/Makefile
index 639883339465..639883339465 100644
--- a/sound/soc/mid-x86/Makefile
+++ b/sound/soc/intel/Makefile
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/intel/mfld_machine.c
index ee363845759e..d3d4c32434f7 100644
--- a/sound/soc/mid-x86/mfld_machine.c
+++ b/sound/soc/intel/mfld_machine.c
@@ -400,7 +400,7 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
}
/* register the soc card */
snd_soc_card_mfld.dev = &pdev->dev;
- ret_val = snd_soc_register_card(&snd_soc_card_mfld);
+ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_mfld);
if (ret_val) {
pr_debug("snd_soc_register_card failed %d\n", ret_val);
return ret_val;
@@ -410,20 +410,12 @@ static int snd_mfld_mc_probe(struct platform_device *pdev)
return 0;
}
-static int snd_mfld_mc_remove(struct platform_device *pdev)
-{
- pr_debug("snd_mfld_mc_remove called\n");
- snd_soc_unregister_card(&snd_soc_card_mfld);
- return 0;
-}
-
static struct platform_driver snd_mfld_mc_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "msic_audio",
},
.probe = snd_mfld_mc_probe,
- .remove = snd_mfld_mc_remove,
};
module_platform_driver(snd_mfld_mc_driver);
diff --git a/sound/soc/mid-x86/sst_dsp.h b/sound/soc/intel/sst_dsp.h
index 0fce1de284ff..0fce1de284ff 100644
--- a/sound/soc/mid-x86/sst_dsp.h
+++ b/sound/soc/intel/sst_dsp.h
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/intel/sst_platform.c
index 392fc0b8f5b8..f465a8180863 100644
--- a/sound/soc/mid-x86/sst_platform.c
+++ b/sound/soc/intel/sst_platform.c
@@ -40,7 +40,8 @@ static DEFINE_MUTEX(sst_lock);
int sst_register_dsp(struct sst_device *dev)
{
- BUG_ON(!dev);
+ if (WARN_ON(!dev))
+ return -EINVAL;
if (!try_module_get(dev->dev->driver->owner))
return -ENODEV;
mutex_lock(&sst_lock);
@@ -59,7 +60,8 @@ EXPORT_SYMBOL_GPL(sst_register_dsp);
int sst_unregister_dsp(struct sst_device *dev)
{
- BUG_ON(!dev);
+ if (WARN_ON(!dev))
+ return -EINVAL;
if (dev != sst)
return -EINVAL;
@@ -87,16 +89,6 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_SYNC_START),
- .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 |
- SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 |
- SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32),
- .rates = (SNDRV_PCM_RATE_8000|
- SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000),
- .rate_min = SST_MIN_RATE,
- .rate_max = SST_MAX_RATE,
- .channels_min = SST_MIN_CHANNEL,
- .channels_max = SST_MAX_CHANNEL,
.buffer_bytes_max = SST_MAX_BUFFER,
.period_bytes_min = SST_MIN_PERIOD_BYTES,
.period_bytes_max = SST_MAX_PERIOD_BYTES,
diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/intel/sst_platform.h
index cacc9066ec52..bee64fb7d2ef 100644
--- a/sound/soc/mid-x86/sst_platform.h
+++ b/sound/soc/intel/sst_platform.h
@@ -33,10 +33,6 @@
#define SST_STEREO 2
#define SST_MAX_CAP 5
-#define SST_MIN_RATE 8000
-#define SST_MAX_RATE 48000
-#define SST_MIN_CHANNEL 1
-#define SST_MAX_CHANNEL 5
#define SST_MAX_BUFFER (800*1024)
#define SST_MIN_BUFFER (800*1024)
#define SST_MIN_PERIOD_BYTES 32
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
index 5351cba66c9e..29f76af5d963 100644
--- a/sound/soc/jz4740/Kconfig
+++ b/sound/soc/jz4740/Kconfig
@@ -1,6 +1,7 @@
config SND_JZ4740_SOC
tristate "SoC Audio for Ingenic JZ4740 SoC"
depends on MACH_JZ4740 && SND_SOC
+ select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
the JZ4740 I2S interface. You will also need to select the audio
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index 4c849a49c72a..8f220009e0f6 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -29,9 +29,11 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+#include <asm/mach-jz4740/dma.h>
#include "jz4740-i2s.h"
-#include "jz4740-pcm.h"
#define JZ_REG_AIC_CONF 0x00
#define JZ_REG_AIC_CTRL 0x04
@@ -89,8 +91,8 @@ struct jz4740_i2s {
struct clk *clk_aic;
struct clk *clk_i2s;
- struct jz4740_pcm_config pcm_config_playback;
- struct jz4740_pcm_config pcm_config_capture;
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
};
static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
@@ -233,8 +235,6 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- enum jz4740_dma_width dma_width;
- struct jz4740_pcm_config *pcm_config;
unsigned int sample_size;
uint32_t ctrl;
@@ -243,11 +243,9 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
sample_size = 0;
- dma_width = JZ4740_DMA_WIDTH_8BIT;
break;
case SNDRV_PCM_FORMAT_S16:
sample_size = 1;
- dma_width = JZ4740_DMA_WIDTH_16BIT;
break;
default:
return -EINVAL;
@@ -260,22 +258,13 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
else
ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
-
- pcm_config = &i2s->pcm_config_playback;
- pcm_config->dma_config.dst_width = dma_width;
-
} else {
ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
-
- pcm_config = &i2s->pcm_config_capture;
- pcm_config->dma_config.src_width = dma_width;
}
jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
- snd_soc_dai_set_dma_data(dai, substream, pcm_config);
-
return 0;
}
@@ -342,25 +331,19 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai)
static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
{
- struct jz4740_dma_config *dma_config;
+ struct snd_dmaengine_dai_dma_data *dma_data;
/* Playback */
- dma_config = &i2s->pcm_config_playback.dma_config;
- dma_config->src_width = JZ4740_DMA_WIDTH_32BIT;
- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
- dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
- dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
- dma_config->mode = JZ4740_DMA_MODE_SINGLE;
- i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+ dma_data = &i2s->playback_dma_data;
+ dma_data->maxburst = 16;
+ dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT;
+ dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
/* Capture */
- dma_config = &i2s->pcm_config_capture.dma_config;
- dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT;
- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
- dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
- dma_config->flags = JZ4740_DMA_DST_AUTOINC;
- dma_config->mode = JZ4740_DMA_MODE_SINGLE;
- i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
+ dma_data = &i2s->capture_dma_data;
+ dma_data->maxburst = 16;
+ dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE;
+ dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
}
static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
@@ -371,6 +354,8 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
clk_prepare_enable(i2s->clk_aic);
jz4740_i2c_init_pcm_config(i2s);
+ snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
+ &i2s->capture_dma_data);
conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
(8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
@@ -432,91 +417,41 @@ static const struct snd_soc_component_driver jz4740_i2s_component = {
static int jz4740_i2s_dev_probe(struct platform_device *pdev)
{
struct jz4740_i2s *i2s;
+ struct resource *mem;
int ret;
- i2s = kzalloc(sizeof(*i2s), GFP_KERNEL);
-
+ i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s)
return -ENOMEM;
- i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!i2s->mem) {
- ret = -ENOENT;
- goto err_free;
- }
-
- i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem),
- pdev->name);
- if (!i2s->mem) {
- ret = -EBUSY;
- goto err_free;
- }
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2s->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(i2s->base))
+ return PTR_ERR(i2s->base);
- i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem));
- if (!i2s->base) {
- ret = -EBUSY;
- goto err_release_mem_region;
- }
+ i2s->phys_base = mem->start;
- i2s->phys_base = i2s->mem->start;
+ i2s->clk_aic = devm_clk_get(&pdev->dev, "aic");
+ if (IS_ERR(i2s->clk_aic))
+ return PTR_ERR(i2s->clk_aic);
- i2s->clk_aic = clk_get(&pdev->dev, "aic");
- if (IS_ERR(i2s->clk_aic)) {
- ret = PTR_ERR(i2s->clk_aic);
- goto err_iounmap;
- }
-
- i2s->clk_i2s = clk_get(&pdev->dev, "i2s");
- if (IS_ERR(i2s->clk_i2s)) {
- ret = PTR_ERR(i2s->clk_i2s);
- goto err_clk_put_aic;
- }
+ i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s");
+ if (IS_ERR(i2s->clk_i2s))
+ return PTR_ERR(i2s->clk_i2s);
platform_set_drvdata(pdev, i2s);
- ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component,
- &jz4740_i2s_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register DAI\n");
- goto err_clk_put_i2s;
- }
-
- return 0;
-
-err_clk_put_i2s:
- clk_put(i2s->clk_i2s);
-err_clk_put_aic:
- clk_put(i2s->clk_aic);
-err_iounmap:
- iounmap(i2s->base);
-err_release_mem_region:
- release_mem_region(i2s->mem->start, resource_size(i2s->mem));
-err_free:
- kfree(i2s);
-
- return ret;
-}
+ ret = devm_snd_soc_register_component(&pdev->dev,
+ &jz4740_i2s_component, &jz4740_i2s_dai, 1);
+ if (ret)
+ return ret;
-static int jz4740_i2s_dev_remove(struct platform_device *pdev)
-{
- struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
-
- snd_soc_unregister_component(&pdev->dev);
-
- clk_put(i2s->clk_i2s);
- clk_put(i2s->clk_aic);
-
- iounmap(i2s->base);
- release_mem_region(i2s->mem->start, resource_size(i2s->mem));
-
- kfree(i2s);
-
- return 0;
+ return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
}
static struct platform_driver jz4740_i2s_driver = {
.probe = jz4740_i2s_dev_probe,
- .remove = jz4740_i2s_dev_remove,
.driver = {
.name = "jz4740-i2s",
.owner = THIS_MODULE,
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
deleted file mode 100644
index 710059292318..000000000000
--- a/sound/soc/jz4740/jz4740-pcm.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/dma-mapping.h>
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/mach-jz4740/dma.h>
-#include "jz4740-pcm.h"
-
-struct jz4740_runtime_data {
- unsigned long dma_period;
- dma_addr_t dma_start;
- dma_addr_t dma_pos;
- dma_addr_t dma_end;
-
- struct jz4740_dma_chan *dma;
-
- dma_addr_t fifo_addr;
-};
-
-/* identify hardware playback capabilities */
-static const struct snd_pcm_hardware jz4740_pcm_hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
-
- .rates = SNDRV_PCM_RATE_8000_48000,
- .channels_min = 1,
- .channels_max = 2,
- .period_bytes_min = 16,
- .period_bytes_max = 2 * PAGE_SIZE,
- .periods_min = 2,
- .periods_max = 128,
- .buffer_bytes_max = 128 * 2 * PAGE_SIZE,
- .fifo_size = 32,
-};
-
-static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd,
- struct snd_pcm_substream *substream)
-{
- unsigned long count;
-
- if (prtd->dma_pos == prtd->dma_end)
- prtd->dma_pos = prtd->dma_start;
-
- if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
- count = prtd->dma_end - prtd->dma_pos;
- else
- count = prtd->dma_period;
-
- jz4740_dma_disable(prtd->dma);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
- jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr);
- } else {
- jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr);
- jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
- }
-
- jz4740_dma_set_transfer_count(prtd->dma, count);
-
- prtd->dma_pos += count;
-
- jz4740_dma_enable(prtd->dma);
-}
-
-static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
- void *dev_id)
-{
- struct snd_pcm_substream *substream = dev_id;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct jz4740_runtime_data *prtd = runtime->private_data;
-
- snd_pcm_period_elapsed(substream);
-
- jz4740_pcm_start_transfer(prtd, substream);
-}
-
-static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct jz4740_runtime_data *prtd = runtime->private_data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct jz4740_pcm_config *config;
-
- config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- if (!config)
- return 0;
-
- if (!prtd->dma) {
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
- prtd->dma = jz4740_dma_request(substream, "PCM Capture");
- else
- prtd->dma = jz4740_dma_request(substream, "PCM Playback");
- }
-
- if (!prtd->dma)
- return -EBUSY;
-
- jz4740_dma_configure(prtd->dma, &config->dma_config);
- prtd->fifo_addr = config->fifo_addr;
-
- jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
-
- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
- runtime->dma_bytes = params_buffer_bytes(params);
-
- prtd->dma_period = params_period_bytes(params);
- prtd->dma_start = runtime->dma_addr;
- prtd->dma_pos = prtd->dma_start;
- prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
-
- return 0;
-}
-
-static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- struct jz4740_runtime_data *prtd = substream->runtime->private_data;
-
- snd_pcm_set_runtime_buffer(substream, NULL);
- if (prtd->dma) {
- jz4740_dma_free(prtd->dma);
- prtd->dma = NULL;
- }
-
- return 0;
-}
-
-static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
-{
- struct jz4740_runtime_data *prtd = substream->runtime->private_data;
-
- if (!prtd->dma)
- return -EBUSY;
-
- prtd->dma_pos = prtd->dma_start;
-
- return 0;
-}
-
-static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct jz4740_runtime_data *prtd = runtime->private_data;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- jz4740_pcm_start_transfer(prtd, substream);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- jz4740_dma_disable(prtd->dma);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct jz4740_runtime_data *prtd = runtime->private_data;
- unsigned long byte_offset;
- snd_pcm_uframes_t offset;
- struct jz4740_dma_chan *dma = prtd->dma;
-
- /* prtd->dma_pos points to the end of the current transfer. So by
- * subtracting prdt->dma_start we get the offset to the end of the
- * current period in bytes. By subtracting the residue of the transfer
- * we get the current offset in bytes. */
- byte_offset = prtd->dma_pos - prtd->dma_start;
- byte_offset -= jz4740_dma_get_residue(dma);
-
- offset = bytes_to_frames(runtime, byte_offset);
- if (offset >= runtime->buffer_size)
- offset = 0;
-
- return offset;
-}
-
-static int jz4740_pcm_open(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct jz4740_runtime_data *prtd;
-
- prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
- if (prtd == NULL)
- return -ENOMEM;
-
- snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
-
- runtime->private_data = prtd;
-
- return 0;
-}
-
-static int jz4740_pcm_close(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct jz4740_runtime_data *prtd = runtime->private_data;
-
- kfree(prtd);
-
- return 0;
-}
-
-static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
-{
- return remap_pfn_range(vma, vma->vm_start,
- substream->dma_buffer.addr >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
-}
-
-static struct snd_pcm_ops jz4740_pcm_ops = {
- .open = jz4740_pcm_open,
- .close = jz4740_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = jz4740_pcm_hw_params,
- .hw_free = jz4740_pcm_hw_free,
- .prepare = jz4740_pcm_prepare,
- .trigger = jz4740_pcm_trigger,
- .pointer = jz4740_pcm_pointer,
- .mmap = jz4740_pcm_mmap,
-};
-
-static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
-{
- struct snd_pcm_substream *substream = pcm->streams[stream].substream;
- struct snd_dma_buffer *buf = &substream->dma_buffer;
- size_t size = jz4740_pcm_hardware.buffer_bytes_max;
-
- buf->dev.type = SNDRV_DMA_TYPE_DEV;
- buf->dev.dev = pcm->card->dev;
- buf->private_data = NULL;
-
- buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
- &buf->addr, GFP_KERNEL);
- if (!buf->area)
- return -ENOMEM;
-
- buf->bytes = size;
-
- return 0;
-}
-
-static void jz4740_pcm_free(struct snd_pcm *pcm)
-{
- struct snd_pcm_substream *substream;
- struct snd_dma_buffer *buf;
- int stream;
-
- for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) {
- substream = pcm->streams[stream].substream;
- if (!substream)
- continue;
-
- buf = &substream->dma_buffer;
- if (!buf->area)
- continue;
-
- dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area,
- buf->addr);
- buf->area = NULL;
- }
-}
-
-static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
-
-static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_card *card = rtd->card->snd_card;
- struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
-
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &jz4740_pcm_dmamask;
-
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
-
- if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
- ret = jz4740_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret)
- goto err;
- }
-
- if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
- ret = jz4740_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
- if (ret)
- goto err;
- }
-
-err:
- return ret;
-}
-
-static struct snd_soc_platform_driver jz4740_soc_platform = {
- .ops = &jz4740_pcm_ops,
- .pcm_new = jz4740_pcm_new,
- .pcm_free = jz4740_pcm_free,
-};
-
-static int jz4740_pcm_probe(struct platform_device *pdev)
-{
- return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
-}
-
-static int jz4740_pcm_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver jz4740_pcm_driver = {
- .probe = jz4740_pcm_probe,
- .remove = jz4740_pcm_remove,
- .driver = {
- .name = "jz4740-pcm-audio",
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(jz4740_pcm_driver);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
deleted file mode 100644
index 1220cbb4382c..000000000000
--- a/sound/soc/jz4740/jz4740-pcm.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * 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 _JZ4740_PCM_H
-#define _JZ4740_PCM_H
-
-#include <linux/dma-mapping.h>
-#include <asm/mach-jz4740/dma.h>
-
-
-struct jz4740_pcm_config {
- struct jz4740_dma_config dma_config;
- phys_addr_t fifo_addr;
-};
-
-#endif
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index 55fd6b5df55f..82b5f37cd2c7 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -73,7 +73,7 @@ static struct snd_soc_dai_link qi_lb60_dai = {
.name = "jz4740",
.stream_name = "jz4740",
.cpu_dai_name = "jz4740-i2s",
- .platform_name = "jz4740-pcm-audio",
+ .platform_name = "jz4740-i2s",
.codec_dai_name = "jz4740-hifi",
.codec_name = "jz4740-codec",
.init = qi_lb60_codec_init,
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index b238434f92b0..aac22fccdcdc 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -21,18 +21,6 @@
#include <sound/soc.h>
#include "kirkwood.h"
-#define KIRKWOOD_RATES \
- (SNDRV_PCM_RATE_8000_192000 | \
- SNDRV_PCM_RATE_CONTINUOUS | \
- SNDRV_PCM_RATE_KNOT)
-
-#define KIRKWOOD_FORMATS \
- (SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE | \
- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \
- SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE)
-
static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
{
struct snd_soc_pcm_runtime *soc_runtime = subs->private_data;
@@ -45,12 +33,6 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_PAUSE),
- .formats = KIRKWOOD_FORMATS,
- .rates = KIRKWOOD_RATES,
- .rate_min = 8000,
- .rate_max = 384000,
- .channels_min = 1,
- .channels_max = 8,
.buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES,
.period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES,
.period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES,
@@ -59,8 +41,6 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
.fifo_size = 0,
};
-static u64 kirkwood_dma_dmamask = DMA_BIT_MASK(32);
-
static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
{
struct kirkwood_dma_data *priv = dev_id;
@@ -161,7 +141,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
* Enable Error interrupts. We're only ack'ing them but
* it's useful for diagnostics
*/
- writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+ writel((unsigned int)-1, priv->io + KIRKWOOD_ERR_MASK);
}
dram = mv_mbus_dram_info();
@@ -292,10 +272,9 @@ static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd)
struct snd_pcm *pcm = rtd->pcm;
int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &kirkwood_dma_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = kirkwood_dma_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 0f3d73d4ef48..3920a5e8125f 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -33,6 +33,10 @@
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
+#define KIRKWOOD_SPDIF_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
@@ -103,7 +107,7 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
{
uint32_t clks_ctrl;
- if (rate == 44100 || rate == 48000 || rate == 96000) {
+ if (IS_ERR(priv->extclk)) {
/* use internal dco for the supported rates
* defined in kirkwood_i2s_dai */
dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
@@ -160,9 +164,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S16_LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
- KIRKWOOD_PLAYCTL_I2S_EN;
+ KIRKWOOD_PLAYCTL_I2S_EN |
+ KIRKWOOD_PLAYCTL_SPDIF_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
- KIRKWOOD_RECCTL_I2S_EN;
+ KIRKWOOD_RECCTL_I2S_EN |
+ KIRKWOOD_RECCTL_SPDIF_EN;
break;
/*
* doesn't work... S20_3LE != kirkwood 20bit format ?
@@ -178,9 +184,11 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S24_LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
- KIRKWOOD_PLAYCTL_I2S_EN;
+ KIRKWOOD_PLAYCTL_I2S_EN |
+ KIRKWOOD_PLAYCTL_SPDIF_EN;
ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
- KIRKWOOD_RECCTL_I2S_EN;
+ KIRKWOOD_RECCTL_I2S_EN |
+ KIRKWOOD_RECCTL_SPDIF_EN;
break;
case SNDRV_PCM_FORMAT_S32_LE:
i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
@@ -244,6 +252,11 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START:
/* configure */
ctl = priv->ctl_play;
+ if (dai->id == 0)
+ ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */
+ else
+ ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */
+
value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
writel(value, priv->io + KIRKWOOD_PLAYCTL);
@@ -258,7 +271,8 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_STOP:
/* stop audio, disable interrupts */
- ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
+ ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
+ KIRKWOOD_PLAYCTL_SPDIF_MUTE;
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
value = readl(priv->io + KIRKWOOD_INT_MASK);
@@ -272,13 +286,15 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
+ ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
+ KIRKWOOD_PLAYCTL_SPDIF_MUTE;
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
+ ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
+ KIRKWOOD_PLAYCTL_SPDIF_MUTE);
writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;
@@ -301,7 +317,13 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START:
/* configure */
ctl = priv->ctl_rec;
- value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
+ if (dai->id == 0)
+ ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */
+ else
+ ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */
+
+ value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN |
+ KIRKWOOD_RECCTL_SPDIF_EN);
writel(value, priv->io + KIRKWOOD_RECCTL);
/* enable interrupts */
@@ -361,9 +383,8 @@ static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
+static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
{
- struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
unsigned long value;
unsigned int reg_data;
@@ -404,9 +425,10 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
.set_fmt = kirkwood_i2s_set_fmt,
};
-
-static struct snd_soc_dai_driver kirkwood_i2s_dai = {
- .probe = kirkwood_i2s_probe,
+static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
+ {
+ .name = "i2s",
+ .id = 0,
.playback = {
.channels_min = 1,
.channels_max = 2,
@@ -422,27 +444,71 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
.formats = KIRKWOOD_I2S_FORMATS,
},
.ops = &kirkwood_i2s_dai_ops,
+ },
+ {
+ .name = "spdif",
+ .id = 1,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000,
+ .formats = KIRKWOOD_SPDIF_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000,
+ .formats = KIRKWOOD_SPDIF_FORMATS,
+ },
+ .ops = &kirkwood_i2s_dai_ops,
+ },
};
-static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
- .probe = kirkwood_i2s_probe,
+static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
+ {
+ .name = "i2s",
+ .id = 0,
.playback = {
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000 |
- SNDRV_PCM_RATE_CONTINUOUS |
- SNDRV_PCM_RATE_KNOT,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 192000,
.formats = KIRKWOOD_I2S_FORMATS,
},
.capture = {
.channels_min = 1,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000 |
- SNDRV_PCM_RATE_CONTINUOUS |
- SNDRV_PCM_RATE_KNOT,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 192000,
.formats = KIRKWOOD_I2S_FORMATS,
},
.ops = &kirkwood_i2s_dai_ops,
+ },
+ {
+ .name = "spdif",
+ .id = 1,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .formats = KIRKWOOD_SPDIF_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .formats = KIRKWOOD_SPDIF_FORMATS,
+ },
+ .ops = &kirkwood_i2s_dai_ops,
+ },
};
static const struct snd_soc_component_driver kirkwood_i2s_component = {
@@ -452,7 +518,7 @@ static const struct snd_soc_component_driver kirkwood_i2s_component = {
static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
{
struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
- struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
+ struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
struct kirkwood_dma_data *priv;
struct resource *mem;
struct device_node *np = pdev->dev.of_node;
@@ -496,14 +562,17 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
return err;
priv->extclk = devm_clk_get(&pdev->dev, "extclk");
- if (!IS_ERR(priv->extclk)) {
+ if (IS_ERR(priv->extclk)) {
+ if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ } else {
if (priv->extclk == priv->clk) {
devm_clk_put(&pdev->dev, priv->extclk);
priv->extclk = ERR_PTR(-EINVAL);
} else {
dev_info(&pdev->dev, "found external clock\n");
clk_prepare_enable(priv->extclk);
- soc_dai = &kirkwood_i2s_dai_extclk;
+ soc_dai = kirkwood_i2s_dai_extclk;
}
}
@@ -521,7 +590,7 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
}
err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
- soc_dai, 1);
+ soc_dai, 2);
if (err) {
dev_err(&pdev->dev, "snd_soc_register_component failed\n");
goto err_component;
@@ -532,6 +601,9 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
goto err_platform;
}
+
+ kirkwood_i2s_init(priv);
+
return 0;
err_platform:
snd_soc_unregister_component(&pdev->dev);
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
index 025be0e97164..65f2a5b9ec3b 100644
--- a/sound/soc/kirkwood/kirkwood-openrd.c
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -52,7 +52,7 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
{
.name = "CS42L51",
.stream_name = "CS42L51 HiFi",
- .cpu_dai_name = "mvebu-audio",
+ .cpu_dai_name = "i2s",
.platform_name = "mvebu-audio",
.codec_dai_name = "cs42l51-hifi",
.codec_name = "cs42l51-codec.0-004a",
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c
index 27545b0c4856..d213832b0c72 100644
--- a/sound/soc/kirkwood/kirkwood-t5325.c
+++ b/sound/soc/kirkwood/kirkwood-t5325.c
@@ -68,7 +68,7 @@ static struct snd_soc_dai_link t5325_dai[] = {
{
.name = "ALC5621",
.stream_name = "ALC5621 HiFi",
- .cpu_dai_name = "mvebu-audio",
+ .cpu_dai_name = "i2s",
.platform_name = "mvebu-audio",
.codec_dai_name = "alc5621-hifi",
.codec_name = "alc562x-codec.0-001a",
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index f8e1ccc1c58c..bf23afbba1d7 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -123,8 +123,8 @@
/* need to find where they come from */
#define KIRKWOOD_SND_MIN_PERIODS 8
#define KIRKWOOD_SND_MAX_PERIODS 16
-#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000
-#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
+#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x800
+#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000
#define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \
* KIRKWOOD_SND_MAX_PERIODS)
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index b16abbbf7764..a371b4f91c53 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -36,11 +36,6 @@ static const struct snd_pcm_hardware snd_mxs_hardware = {
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_HALF_DUPLEX,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S20_3LE |
- SNDRV_PCM_FMTBIT_S24_LE,
- .channels_min = 2,
- .channels_max = 2,
.period_bytes_min = 32,
.period_bytes_max = 8192,
.periods_min = 1,
@@ -56,16 +51,9 @@ static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = {
int mxs_pcm_platform_register(struct device *dev)
{
- return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
- SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+ return devm_snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX);
}
EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
-void mxs_pcm_platform_unregister(struct device *dev)
-{
- snd_dmaengine_pcm_unregister(dev);
-}
-EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister);
-
MODULE_LICENSE("GPL");
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
index bc685b67cac7..035ea0436ca5 100644
--- a/sound/soc/mxs/mxs-pcm.h
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -20,6 +20,5 @@
#define _MXS_PCM_H
int mxs_pcm_platform_register(struct device *dev);
-void mxs_pcm_platform_unregister(struct device *dev);
#endif
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index b56b8a0e8deb..231d7e7b0711 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -50,9 +50,9 @@ static struct mxs_saif *mxs_saif[2];
* This also means that both SAIFs must operate at the same sample rate.
*
* We abstract this as each saif has a master, the master could be
- * himself or other saifs. In the generic saif driver, saif does not need
- * to know the different clkmux. Saif only needs to know who is his master
- * and operating his master to generate the proper clock rate for him.
+ * itself or other saifs. In the generic saif driver, saif does not need
+ * to know the different clkmux. Saif only needs to know who is its master
+ * and operating its master to generate the proper clock rate for it.
* The master id is provided in mach-specific layer according to different
* clkmux setting.
*/
@@ -76,7 +76,7 @@ static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
* Since SAIF may work on EXTMASTER mode, IOW, it's working BITCLK&LRCLK
* is provided by other SAIF, we provide a interface here to get its master
* from its master_id.
- * Note that the master could be himself.
+ * Note that the master could be itself.
*/
static inline struct mxs_saif *mxs_saif_get_master(struct mxs_saif * saif)
{
@@ -494,6 +494,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
struct mxs_saif *master_saif;
u32 delay;
+ int ret;
master_saif = mxs_saif_get_master(saif);
if (!master_saif)
@@ -503,23 +504,37 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (saif->state == MXS_SAIF_STATE_RUNNING)
+ return 0;
+
dev_dbg(cpu_dai->dev, "start\n");
- clk_enable(master_saif->clk);
- if (!master_saif->mclk_in_use)
- __raw_writel(BM_SAIF_CTRL_RUN,
- master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
+ ret = clk_enable(master_saif->clk);
+ if (ret) {
+ dev_err(saif->dev, "Failed to enable master clock\n");
+ return ret;
+ }
/*
- * If the saif's master is not himself, we also need to enable
+ * If the saif's master is not itself, we also need to enable
* itself clk for its internal basic logic to work.
*/
if (saif != master_saif) {
- clk_enable(saif->clk);
+ ret = clk_enable(saif->clk);
+ if (ret) {
+ dev_err(saif->dev, "Failed to enable master clock\n");
+ clk_disable(master_saif->clk);
+ return ret;
+ }
+
__raw_writel(BM_SAIF_CTRL_RUN,
saif->base + SAIF_CTRL + MXS_SET_ADDR);
}
+ if (!master_saif->mclk_in_use)
+ __raw_writel(BM_SAIF_CTRL_RUN,
+ master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/*
* write data to saif data register to trigger
@@ -543,6 +558,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
}
master_saif->ongoing = 1;
+ saif->state = MXS_SAIF_STATE_RUNNING;
dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
__raw_readl(saif->base + SAIF_CTRL),
@@ -555,6 +571,9 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (saif->state == MXS_SAIF_STATE_STOPPED)
+ return 0;
+
dev_dbg(cpu_dai->dev, "stop\n");
/* wait a while for the current sample to complete */
@@ -575,6 +594,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
}
master_saif->ongoing = 0;
+ saif->state = MXS_SAIF_STATE_STOPPED;
break;
default:
@@ -768,8 +788,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "failed to init clocks\n");
}
- ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
- &mxs_saif_dai, 1);
+ ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component,
+ &mxs_saif_dai, 1);
if (ret) {
dev_err(&pdev->dev, "register DAI failed\n");
return ret;
@@ -778,23 +798,10 @@ static int mxs_saif_probe(struct platform_device *pdev)
ret = mxs_pcm_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
- goto failed_pdev_alloc;
+ return ret;
}
return 0;
-
-failed_pdev_alloc:
- snd_soc_unregister_component(&pdev->dev);
-
- return ret;
-}
-
-static int mxs_saif_remove(struct platform_device *pdev)
-{
- mxs_pcm_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
-
- return 0;
}
static const struct of_device_id mxs_saif_dt_ids[] = {
@@ -805,7 +812,6 @@ MODULE_DEVICE_TABLE(of, mxs_saif_dt_ids);
static struct platform_driver mxs_saif_driver = {
.probe = mxs_saif_probe,
- .remove = mxs_saif_remove,
.driver = {
.name = "mxs-saif",
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
index 53eaa4bf0e27..fbaf7badfdfb 100644
--- a/sound/soc/mxs/mxs-saif.h
+++ b/sound/soc/mxs/mxs-saif.h
@@ -124,6 +124,11 @@ struct mxs_saif {
u32 fifo_underrun;
u32 fifo_overrun;
+
+ enum {
+ MXS_SAIF_STATE_STOPPED,
+ MXS_SAIF_STATE_RUNNING,
+ } state;
};
extern int mxs_saif_put_mclk(unsigned int saif_id);
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 4bb273786ff3..61822cc53bd3 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -122,14 +122,12 @@ static struct snd_soc_card mxs_sgtl5000 = {
.num_links = ARRAY_SIZE(mxs_sgtl5000_dai),
};
-static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
+static int mxs_sgtl5000_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &mxs_sgtl5000;
+ int ret, i;
struct device_node *np = pdev->dev.of_node;
struct device_node *saif_np[2], *codec_np;
- int i;
-
- if (!np)
- return 1; /* no device tree */
saif_np[0] = of_parse_phandle(np, "saif-controllers", 0);
saif_np[1] = of_parse_phandle(np, "saif-controllers", 1);
@@ -152,18 +150,6 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
of_node_put(saif_np[0]);
of_node_put(saif_np[1]);
- return 0;
-}
-
-static int mxs_sgtl5000_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &mxs_sgtl5000;
- int ret;
-
- ret = mxs_sgtl5000_probe_dt(pdev);
- if (ret < 0)
- return ret;
-
/*
* Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
* The Sgtl5000 sysclk is derived from saif0 mclk and it's range
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
index c894ff0f2580..f434ed79d1b6 100644
--- a/sound/soc/nuc900/nuc900-pcm.c
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -32,9 +32,6 @@ static const struct snd_pcm_hardware nuc900_pcm_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 1,
- .channels_max = 2,
.buffer_bytes_max = 4*1024,
.period_bytes_min = 1*1024,
.period_bytes_max = 4*1024,
@@ -314,16 +311,15 @@ static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &nuc900_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, 4 * 1024, (4 * 1024) - 1);
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index daa78a0095fa..22ad9c5654b5 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,6 +1,6 @@
config SND_OMAP_SOC
tristate "SoC Audio for the Texas Instruments OMAP chips"
- depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST)
+ depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST)
select SND_DMAENGINE_PCM
config SND_OMAP_SOC_DMIC
@@ -26,10 +26,11 @@ config SND_OMAP_SOC_N810
config SND_OMAP_SOC_RX51
tristate "SoC Audio support for Nokia RX-51"
- depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
+ depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC3X
select SND_SOC_TPA6130A2
+ depends on GPIOLIB
help
Say Y if you want to add support for SoC audio on Nokia RX-51
hardware. This is also known as Nokia N900 product.
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 83433fdea32a..86c75384c3c8 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -36,10 +36,10 @@ static void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
if (mcbsp->pdata->reg_size == 2) {
((u16 *)mcbsp->reg_cache)[reg] = (u16)val;
- __raw_writew((u16)val, addr);
+ writew_relaxed((u16)val, addr);
} else {
((u32 *)mcbsp->reg_cache)[reg] = val;
- __raw_writel(val, addr);
+ writel_relaxed(val, addr);
}
}
@@ -48,22 +48,22 @@ static int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache)
void __iomem *addr = mcbsp->io_base + reg * mcbsp->pdata->reg_step;
if (mcbsp->pdata->reg_size == 2) {
- return !from_cache ? __raw_readw(addr) :
+ return !from_cache ? readw_relaxed(addr) :
((u16 *)mcbsp->reg_cache)[reg];
} else {
- return !from_cache ? __raw_readl(addr) :
+ return !from_cache ? readl_relaxed(addr) :
((u32 *)mcbsp->reg_cache)[reg];
}
}
static void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val)
{
- __raw_writel(val, mcbsp->st_data->io_base_st + reg);
+ writel_relaxed(val, mcbsp->st_data->io_base_st + reg);
}
static int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg)
{
- return __raw_readl(mcbsp->st_data->io_base_st + reg);
+ return readl_relaxed(mcbsp->st_data->io_base_st + reg);
}
#define MCBSP_READ(mcbsp, reg) \
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index 5e8d640d314f..3fde9e402710 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -100,12 +100,12 @@ static int n810_startup(struct snd_pcm_substream *substream)
SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
n810_ext_control(&codec->dapm);
- return clk_enable(sys_clkout2);
+ return clk_prepare_enable(sys_clkout2);
}
static void n810_shutdown(struct snd_pcm_substream *substream)
{
- clk_disable(sys_clkout2);
+ clk_disable_unprepare(sys_clkout2);
}
static int n810_hw_params(struct snd_pcm_substream *substream,
@@ -344,8 +344,11 @@ static int __init n810_soc_init(void)
clk_set_parent(sys_clkout2_src, func96m_clk);
clk_set_rate(sys_clkout2, 12000000);
- BUG_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
- (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0));
+ if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
+ (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) {
+ err = -EINVAL;
+ goto err4;
+ }
gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 12e566be3793..1bd531d718f9 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -61,12 +61,12 @@ struct omap_dmic {
static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
{
- __raw_writel(val, dmic->io_base + reg);
+ writel_relaxed(val, dmic->io_base + reg);
}
static inline int omap_dmic_read(struct omap_dmic *dmic, u16 reg)
{
- return __raw_readl(dmic->io_base + reg);
+ return readl_relaxed(dmic->io_base + reg);
}
static inline void omap_dmic_start(struct omap_dmic *dmic)
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 90d2a7cd2563..2f5b1536477e 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -74,12 +74,12 @@ struct omap_mcpdm {
static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
{
- __raw_writel(val, mcpdm->io_base + reg);
+ writel_relaxed(val, mcpdm->io_base + reg);
}
static inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg)
{
- return __raw_readl(mcpdm->io_base + reg);
+ return readl_relaxed(mcpdm->io_base + reg);
}
#ifdef DEBUG
@@ -490,14 +490,9 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
mcpdm->dev = &pdev->dev;
- return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
- &omap_mcpdm_dai, 1);
-}
-
-static int asoc_mcpdm_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
- return 0;
+ return devm_snd_soc_register_component(&pdev->dev,
+ &omap_mcpdm_component,
+ &omap_mcpdm_dai, 1);
}
static const struct of_device_id omap_mcpdm_of_match[] = {
@@ -514,7 +509,6 @@ static struct platform_driver asoc_mcpdm_driver = {
},
.probe = asoc_mcpdm_probe,
- .remove = asoc_mcpdm_remove,
};
module_platform_driver(asoc_mcpdm_driver);
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index a11405de86e8..07b8b7bc9d20 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -45,8 +45,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = 32,
.period_bytes_max = 64 * 1024,
.periods_min = 2,
@@ -156,8 +154,6 @@ static struct snd_pcm_ops omap_pcm_ops = {
.mmap = omap_pcm_mmap,
};
-static u64 omap_pcm_dmamask = DMA_BIT_MASK(64);
-
static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
int stream)
{
@@ -202,12 +198,11 @@ static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &omap_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(64);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(64));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = omap_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index 2a9324f794d8..6a8d6b5f160d 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -338,9 +338,9 @@ static int omap_twl4030_probe(struct platform_device *pdev)
}
snd_soc_card_set_drvdata(card, priv);
- ret = snd_soc_register_card(card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
ret);
return ret;
}
@@ -357,7 +357,6 @@ static int omap_twl4030_remove(struct platform_device *pdev)
snd_soc_jack_free_gpios(&priv->hs_jack,
ARRAY_SIZE(hs_jack_gpios),
hs_jack_gpios);
- snd_soc_unregister_card(card);
return 0;
}
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 4db74a083db1..6473052b6899 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -11,7 +11,7 @@ config SND_PXA2XX_SOC
config SND_MMP_SOC
bool "Soc Audio for Marvell MMP chips"
depends on ARCH_MMP
- select SND_DMAENGINE_PCM
+ select SND_SOC_GENERIC_DMAENGINE_PCM
select SND_ARM
help
Say Y if you want to add support for codecs attached to
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c
index 5b7d969f89a9..08acdc236bf8 100644
--- a/sound/soc/pxa/brownstone.c
+++ b/sound/soc/pxa/brownstone.c
@@ -163,6 +163,7 @@ static struct platform_driver mmp_driver = {
.driver = {
.name = "brownstone-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = brownstone_probe,
.remove = brownstone_remove,
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index f4cce1e80112..1853d41034bf 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -329,6 +329,7 @@ static struct platform_driver corgi_driver = {
.driver = {
.name = "corgi-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = corgi_probe,
.remove = corgi_remove,
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index 70d799b13f0d..44b5c09d296b 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -178,6 +178,7 @@ static struct platform_driver e740_driver = {
.driver = {
.name = "e740-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = e740_probe,
.remove = e740_remove,
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c
index f94d2ab51351..c34e447eb991 100644
--- a/sound/soc/pxa/e750_wm9705.c
+++ b/sound/soc/pxa/e750_wm9705.c
@@ -160,6 +160,7 @@ static struct platform_driver e750_driver = {
.driver = {
.name = "e750-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = e750_probe,
.remove = e750_remove,
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c
index 8768a640dd71..3137f800b43f 100644
--- a/sound/soc/pxa/e800_wm9712.c
+++ b/sound/soc/pxa/e800_wm9712.c
@@ -150,6 +150,7 @@ static struct platform_driver e800_driver = {
.driver = {
.name = "e800-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = e800_probe,
.remove = e800_remove,
diff --git a/sound/soc/pxa/imote2.c b/sound/soc/pxa/imote2.c
index eef1f7b7b38e..fd2f4eda1fd3 100644
--- a/sound/soc/pxa/imote2.c
+++ b/sound/soc/pxa/imote2.c
@@ -91,6 +91,7 @@ static struct platform_driver imote2_driver = {
.driver = {
.name = "imote2-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = imote2_probe,
.remove = imote2_remove,
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index bbea7780eac6..160c5245448f 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -215,6 +215,7 @@ static struct platform_driver mioa701_wm9713_driver = {
.driver = {
.name = "mioa701-wm9713",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
};
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 8235e231d89c..5e8d81330173 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -36,14 +36,9 @@ struct mmp_dma_data {
SNDRV_PCM_INFO_PAUSE | \
SNDRV_PCM_INFO_RESUME)
-#define MMP_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE)
-
static struct snd_pcm_hardware mmp_pcm_hardware[] = {
{
.info = MMP_PCM_INFO,
- .formats = MMP_PCM_FORMATS,
.period_bytes_min = 1024,
.period_bytes_max = 2048,
.periods_min = 2,
@@ -53,7 +48,6 @@ static struct snd_pcm_hardware mmp_pcm_hardware[] = {
},
{
.info = MMP_PCM_INFO,
- .formats = MMP_PCM_FORMATS,
.period_bytes_min = 1024,
.period_bytes_max = 2048,
.periods_min = 2,
@@ -67,27 +61,15 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_dmaengine_dai_dma_data *dma_params;
struct dma_slave_config slave_config;
int ret;
- dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- if (!dma_params)
- return 0;
-
- ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
+ ret =
+ snd_dmaengine_pcm_prepare_slave_config(substream, params,
+ &slave_config);
if (ret)
return ret;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- slave_config.dst_addr = dma_params->addr;
- slave_config.dst_maxburst = 4;
- } else {
- slave_config.src_addr = dma_params->addr;
- slave_config.src_maxburst = 4;
- }
-
ret = dmaengine_slave_config(chan, &slave_config);
if (ret)
return ret;
@@ -201,10 +183,9 @@ static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
if (!gpool)
return -ENOMEM;
- buf->area = (unsigned char *)gen_pool_alloc(gpool, size);
+ buf->area = gen_pool_dma_alloc(gpool, size, &buf->addr);
if (!buf->area)
return -ENOMEM;
- buf->addr = gen_pool_virt_to_phys(gpool, (unsigned long)buf->area);
buf->bytes = size;
return 0;
}
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c
index 41752a5fe3b0..5bf5f1f7cac5 100644
--- a/sound/soc/pxa/mmp-sspa.c
+++ b/sound/soc/pxa/mmp-sspa.c
@@ -455,8 +455,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
priv->dai_fmt = (unsigned int) -1;
platform_set_drvdata(pdev, priv);
- return snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
- &mmp_sspa_dai, 1);
+ return devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
+ &mmp_sspa_dai, 1);
}
static int asoc_mmp_sspa_remove(struct platform_device *pdev)
@@ -466,7 +466,6 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev)
clk_disable(priv->audio_clk);
clk_put(priv->audio_clk);
clk_put(priv->sysclk);
- snd_soc_unregister_component(&pdev->dev);
return 0;
}
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c
index e1ffcdd9a649..3284c4b901cb 100644
--- a/sound/soc/pxa/palm27x.c
+++ b/sound/soc/pxa/palm27x.c
@@ -181,6 +181,7 @@ static struct platform_driver palm27x_wm9712_driver = {
.driver = {
.name = "palm27x-asoc",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
};
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index fafe46355c31..c93e138d8dc3 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -303,6 +303,7 @@ static struct platform_driver poodle_driver = {
.driver = {
.name = "poodle-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = poodle_probe,
.remove = poodle_remove,
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index f1059d999de6..ae956e3f4b9d 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -89,33 +89,6 @@ static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
.filter_data = &pxa2xx_ac97_pcm_aux_mic_mono_req,
};
-#ifdef CONFIG_PM
-static int pxa2xx_ac97_suspend(struct snd_soc_dai *dai)
-{
- return pxa2xx_ac97_hw_suspend();
-}
-
-static int pxa2xx_ac97_resume(struct snd_soc_dai *dai)
-{
- return pxa2xx_ac97_hw_resume();
-}
-
-#else
-#define pxa2xx_ac97_suspend NULL
-#define pxa2xx_ac97_resume NULL
-#endif
-
-static int pxa2xx_ac97_probe(struct snd_soc_dai *dai)
-{
- return pxa2xx_ac97_hw_probe(to_platform_device(dai->dev));
-}
-
-static int pxa2xx_ac97_remove(struct snd_soc_dai *dai)
-{
- pxa2xx_ac97_hw_remove(to_platform_device(dai->dev));
- return 0;
-}
-
static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
@@ -185,10 +158,6 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
{
.name = "pxa2xx-ac97",
.ac97_control = 1,
- .probe = pxa2xx_ac97_probe,
- .remove = pxa2xx_ac97_remove,
- .suspend = pxa2xx_ac97_suspend,
- .resume = pxa2xx_ac97_resume,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
@@ -246,6 +215,12 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
return -ENXIO;
}
+ ret = pxa2xx_ac97_hw_probe(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "PXA2xx AC97 hw probe error (%d)\n", ret);
+ return ret;
+ }
+
ret = snd_soc_set_ac97_ops(&pxa2xx_ac97_ops);
if (ret != 0)
return ret;
@@ -262,15 +237,34 @@ static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
{
snd_soc_unregister_component(&pdev->dev);
snd_soc_set_ac97_ops(NULL);
+ pxa2xx_ac97_hw_remove(pdev);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int pxa2xx_ac97_dev_suspend(struct device *dev)
+{
+ return pxa2xx_ac97_hw_suspend();
+}
+
+static int pxa2xx_ac97_dev_resume(struct device *dev)
+{
+ return pxa2xx_ac97_hw_resume();
+}
+
+static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,
+ pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume);
+#endif
+
static struct platform_driver pxa2xx_ac97_driver = {
.probe = pxa2xx_ac97_dev_probe,
.remove = pxa2xx_ac97_dev_remove,
.driver = {
.name = "pxa2xx-ac97",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &pxa2xx_ac97_pm_ops,
+#endif
},
};
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index d5340a088858..c0d648d3339f 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -165,7 +165,8 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
{
struct snd_dmaengine_dai_dma_data *dma_data;
- BUG_ON(IS_ERR(clk_i2s));
+ if (WARN_ON(IS_ERR(clk_i2s)))
+ return -EINVAL;
clk_prepare_enable(clk_i2s);
clk_ena = 1;
pxa_i2s_wait();
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 806da27b8b67..d58b09f4f7a4 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -87,18 +87,15 @@ static struct snd_pcm_ops pxa2xx_pcm_ops = {
.mmap = pxa2xx_pcm_mmap,
};
-static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32);
-
static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &pxa2xx_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
index a3fe19123f07..1d9c2ed223bc 100644
--- a/sound/soc/pxa/tosa.c
+++ b/sound/soc/pxa/tosa.c
@@ -275,6 +275,7 @@ static struct platform_driver tosa_driver = {
.driver = {
.name = "tosa-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = tosa_probe,
.remove = tosa_remove,
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c
index 13c9ee0cb83b..0b535b570622 100644
--- a/sound/soc/pxa/ttc-dkb.c
+++ b/sound/soc/pxa/ttc-dkb.c
@@ -160,6 +160,7 @@ static struct platform_driver ttc_dkb_driver = {
.driver = {
.name = "ttc-dkb-audio",
.owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
},
.probe = ttc_dkb_probe,
.remove = ttc_dkb_remove,
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index 73bb99f0109a..7eba7979b9af 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -405,8 +405,7 @@ static int s6000_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
-#define S6000_I2S_RATES (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
- SNDRV_PCM_RATE_8000_192000)
+#define S6000_I2S_RATES SNDRV_PCM_RATE_CONTINUOUS
#define S6000_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops s6000_i2s_dai_ops = {
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c
index d0740a762963..fb8461e1b1f6 100644
--- a/sound/soc/s6000/s6000-pcm.c
+++ b/sound/soc/s6000/s6000-pcm.c
@@ -33,13 +33,6 @@ static struct snd_pcm_hardware s6000_pcm_hardware = {
.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_JOINT_DUPLEX),
- .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
- .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_5512 | \
- SNDRV_PCM_RATE_8000_192000),
- .rate_min = 0,
- .rate_max = 1562500,
- .channels_min = 2,
- .channels_max = 8,
.buffer_bytes_max = 0x7ffffff0,
.period_bytes_min = 16,
.period_bytes_max = 0xfffff0,
@@ -90,7 +83,8 @@ static void s6000_pcm_enqueue_dma(struct snd_pcm_substream *substream)
return;
}
- BUG_ON(period_size & 15);
+ if (WARN_ON(period_size & 15))
+ return;
s6dmac_put_fifo(DMA_MASK_DMAC(channel), DMA_INDEX_CHNL(channel),
src, dst, period_size);
@@ -444,8 +438,6 @@ static void s6000_pcm_free(struct snd_pcm *pcm)
snd_pcm_lib_preallocate_free_for_all(pcm);
}
-static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32);
-
static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime)
{
struct snd_card *card = runtime->card->snd_card;
@@ -456,10 +448,9 @@ static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime)
params = snd_soc_dai_get_dma_data(runtime->cpu_dai,
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream);
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &s6000_pcm_dmamask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ res = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (res)
+ return res;
if (params->dma_in) {
s6dmac_disable_chan(DMA_MASK_DMAC(params->dma_in),
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 2eea1840315d..350757400391 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,16 +1,25 @@
config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung"
depends on PLAT_SAMSUNG
- select S3C64XX_DMA if ARCH_S3C64XX
select S3C2410_DMA if ARCH_S3C24XX
+ select S3C64XX_PL080 if ARCH_S3C64XX
+ select SND_S3C_DMA if !ARCH_S3C24XX
+ select SND_S3C_DMA_LEGACY if ARCH_S3C24XX
+ select SND_SOC_GENERIC_DMAENGINE_PCM if !ARCH_S3C24XX
help
Say Y or M if you want to add support for codecs attached to
the Samsung SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below.
+config SND_S3C_DMA
+ tristate
+
+config SND_S3C_DMA_LEGACY
+ tristate
+
config SND_S3C24XX_I2S
tristate
- select S3C2410_DMA
+ select S3C24XX_DMA
config SND_S3C_I2SV2_SOC
tristate
@@ -50,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
select SND_SOC_WM8750
select SND_S3C2412_SOC_I2S
help
- Sat Y if you want to add support for SoC audio on the Jive.
+ Say Y if you want to add support for SoC audio on the Jive.
config SND_SOC_SAMSUNG_SMDK_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK"
@@ -136,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
config SND_SOC_SAMSUNG_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
- depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210)
+ depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
select SND_SOC_WM9713
select SND_SAMSUNG_AC97
help
- Sat Y if you want to add support for SoC audio on the SMDK.
+ Say Y if you want to add support for SoC audio on the SMDK.
config SND_SOC_SMARTQ
tristate "SoC I2S Audio support for SmartQ board"
@@ -201,7 +210,7 @@ config SND_SOC_TOBERMORY
config SND_SOC_BELLS
tristate "Audio support for Wolfson Bells"
- depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+ depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
select SND_SAMSUNG_I2S
select SND_SOC_WM5102
select SND_SOC_WM5110
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 709f6059ad67..86715d8efee6 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -1,5 +1,6 @@
# S3c24XX Platform Support
-snd-soc-s3c24xx-objs := dma.o
+snd-soc-s3c-dma-objs := dmaengine.o
+snd-soc-s3c-dma-legacy-objs := dma.o
snd-soc-idma-objs := idma.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
@@ -9,7 +10,8 @@ snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o
snd-soc-i2s-objs := i2s.o
-obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o
+obj-$(CONFIG_SND_S3C_DMA) += snd-soc-s3c-dma.o
+obj-$(CONFIG_SND_S3C_DMA_LEGACY) += snd-soc-s3c-dma-legacy.o
obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o
obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index 2acf987844e8..4a88e36c82ec 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -74,7 +74,7 @@ static void s3c_ac97_activate(struct snd_ac97 *ac97)
if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
return; /* Return if already active */
- INIT_COMPLETION(s3c_ac97.done);
+ reinit_completion(&s3c_ac97.done);
ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
@@ -103,7 +103,7 @@ static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
s3c_ac97_activate(ac97);
- INIT_COMPLETION(s3c_ac97.done);
+ reinit_completion(&s3c_ac97.done);
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
@@ -140,7 +140,7 @@ static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
s3c_ac97_activate(ac97);
- INIT_COMPLETION(s3c_ac97.done);
+ reinit_completion(&s3c_ac97.done);
ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
@@ -221,24 +221,6 @@ static struct snd_ac97_bus_ops s3c_ac97_ops = {
.reset = s3c_ac97_cold_reset,
};
-static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct s3c_dma_params *dma_data;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = &s3c_ac97_pcm_out;
- else
- dma_data = &s3c_ac97_pcm_in;
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
-
- return 0;
-}
-
static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
@@ -279,21 +261,6 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- return -ENODEV;
- else
- snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
-
- return 0;
-}
-
static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
@@ -329,15 +296,27 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops s3c_ac97_dai_ops = {
- .hw_params = s3c_ac97_hw_params,
.trigger = s3c_ac97_trigger,
};
static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
- .hw_params = s3c_ac97_hw_mic_params,
.trigger = s3c_ac97_mic_trigger,
};
+static int s3c_ac97_dai_probe(struct snd_soc_dai *dai)
+{
+ samsung_asoc_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in);
+
+ return 0;
+}
+
+static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
+{
+ samsung_asoc_init_dma_data(dai, NULL, &s3c_ac97_mic_in);
+
+ return 0;
+}
+
static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "samsung-ac97",
@@ -354,6 +333,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .probe = s3c_ac97_dai_probe,
.ops = &s3c_ac97_dai_ops,
},
[S3C_AC97_DAI_MIC] = {
@@ -365,6 +345,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
.channels_max = 1,
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .probe = s3c_ac97_mic_dai_probe,
.ops = &s3c_ac97_mic_dai_ops,
},
};
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 29e246803626..84f5d8b76679 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -356,6 +356,7 @@ static struct snd_soc_dapm_widget bells_widgets[] = {
static struct snd_soc_dapm_route bells_routes[] = {
{ "Sub CLK_SYS", NULL, "OPCLK" },
+ { "CLKIN", NULL, "OPCLK" },
{ "DMIC", NULL, "MICBIAS2" },
{ "IN2L", NULL, "DMIC" },
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c
index 9338d11e9216..dc09b71b7d9f 100644
--- a/sound/soc/samsung/dma.c
+++ b/sound/soc/samsung/dma.c
@@ -35,12 +35,6 @@ static const struct snd_pcm_hardware dma_hardware = {
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_U16_LE |
- SNDRV_PCM_FMTBIT_U8 |
- SNDRV_PCM_FMTBIT_S8,
- .channels_min = 2,
- .channels_max = 2,
.buffer_bytes_max = 128*1024,
.period_bytes_min = PAGE_SIZE,
.period_bytes_max = PAGE_SIZE*2,
@@ -406,20 +400,17 @@ static void dma_free_dma_buffers(struct snd_pcm *pcm)
}
}
-static u64 dma_mask = DMA_BIT_MASK(32);
-
static int dma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
pr_debug("Entered %s\n", __func__);
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &dma_mask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = preallocate_dma_buffer(pcm,
@@ -444,6 +435,14 @@ static struct snd_soc_platform_driver samsung_asoc_platform = {
.pcm_free = dma_free_dma_buffers,
};
+void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
+ struct s3c_dma_params *playback,
+ struct s3c_dma_params *capture)
+{
+ snd_soc_dai_init_dma_data(dai, playback, capture);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
+
int samsung_asoc_dma_platform_register(struct device *dev)
{
return snd_soc_register_platform(dev, &samsung_asoc_platform);
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h
index 0e86315a3eaf..225e5378014e 100644
--- a/sound/soc/samsung/dma.h
+++ b/sound/soc/samsung/dma.h
@@ -12,6 +12,8 @@
#ifndef _S3C_AUDIO_H
#define _S3C_AUDIO_H
+#include <sound/dmaengine_pcm.h>
+
struct s3c_dma_params {
struct s3c2410_dma_client *client; /* stream identifier */
int channel; /* Channel ID */
@@ -20,8 +22,12 @@ struct s3c_dma_params {
unsigned ch;
struct samsung_dma_ops *ops;
char *ch_name;
+ struct snd_dmaengine_dai_dma_data dma_data;
};
+void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
+ struct s3c_dma_params *playback,
+ struct s3c_dma_params *capture);
int samsung_asoc_dma_platform_register(struct device *dev);
void samsung_asoc_dma_platform_unregister(struct device *dev);
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c
new file mode 100644
index 000000000000..750ce5808d9f
--- /dev/null
+++ b/sound/soc/samsung/dmaengine.c
@@ -0,0 +1,83 @@
+/*
+ * dmaengine.c - Samsung dmaengine wrapper
+ *
+ * Author: Mark Brown <broonie@linaro.org>
+ * Copyright 2013 Linaro
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/amba/pl08x.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "dma.h"
+
+#ifdef CONFIG_ARCH_S3C64XX
+#define filter_fn pl08x_filter_id
+#else
+#define filter_fn NULL
+#endif
+
+static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = {
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+ .compat_filter_fn = filter_fn,
+};
+
+void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
+ struct s3c_dma_params *playback,
+ struct s3c_dma_params *capture)
+{
+ struct snd_dmaengine_dai_dma_data *playback_data = NULL;
+ struct snd_dmaengine_dai_dma_data *capture_data = NULL;
+
+ if (playback) {
+ playback_data = &playback->dma_data;
+ playback_data->filter_data = (void *)playback->channel;
+ playback_data->chan_name = playback->ch_name;
+ playback_data->addr = playback->dma_addr;
+ playback_data->addr_width = playback->dma_size;
+ }
+ if (capture) {
+ capture_data = &capture->dma_data;
+ capture_data->filter_data = (void *)capture->channel;
+ capture_data->chan_name = capture->ch_name;
+ capture_data->addr = capture->dma_addr;
+ capture_data->addr_width = capture->dma_size;
+ }
+
+ snd_soc_dai_init_dma_data(dai, playback_data, capture_data);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
+
+int samsung_asoc_dma_platform_register(struct device *dev)
+{
+ return snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config,
+ SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME |
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
+
+void samsung_asoc_dma_platform_unregister(struct device *dev)
+{
+ return snd_dmaengine_pcm_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
+
+MODULE_AUTHOR("Mark Brown <broonie@linaro.org>");
+MODULE_DESCRIPTION("Samsung dmaengine ASoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index fa91376e323d..fbced589d077 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -23,6 +23,7 @@
#include "regs-iis.h"
#include <asm/mach-types.h>
+#include <mach/gpio-samsung.h>
#include "s3c24xx-i2s.h"
static unsigned int rates[] = {
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index b302f3b7a587..0a9b44c940ce 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -22,8 +22,6 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include <mach/dma.h>
-
#include <linux/platform_data/asoc-s3c.h>
#include "dma.h"
@@ -702,12 +700,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
}
writel(mod, i2s->addr + I2SMOD);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- snd_soc_dai_set_dma_data(dai, substream,
- (void *)&i2s->dma_playback);
- else
- snd_soc_dai_set_dma_data(dai, substream,
- (void *)&i2s->dma_capture);
+ samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
i2s->frmclk = params_rate(params);
@@ -953,8 +946,11 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
- if (other && other->clk) /* If this is probe on secondary */
+ if (other && other->clk) { /* If this is probe on secondary */
+ samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
+ NULL);
goto probe_exit;
+ }
i2s->addr = ioremap(i2s->base, 0x100);
if (i2s->addr == NULL) {
@@ -970,6 +966,8 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
}
clk_prepare_enable(i2s->clk);
+ samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
+
if (other) {
other->addr = i2s->addr;
other->clk = i2s->clk;
@@ -1060,7 +1058,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
i2s->i2s_dai_drv.ops = &samsung_i2s_dai_ops;
i2s->i2s_dai_drv.suspend = i2s_suspend;
i2s->i2s_dai_drv.resume = i2s_resume;
- i2s->i2s_dai_drv.playback.channels_min = 2;
+ i2s->i2s_dai_drv.playback.channels_min = 1;
i2s->i2s_dai_drv.playback.channels_max = 2;
i2s->i2s_dai_drv.playback.rates = SAMSUNG_I2S_RATES;
i2s->i2s_dai_drv.playback.formats = SAMSUNG_I2S_FMTS;
@@ -1073,7 +1071,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
dev_set_drvdata(&i2s->pdev->dev, i2s);
} else { /* Create a new platform_device for Secondary */
i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1);
- if (IS_ERR(i2s->pdev))
+ if (!i2s->pdev)
return NULL;
i2s->pdev->dev.parent = &pdev->dev;
@@ -1143,9 +1141,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to get drvdata\n");
return -EFAULT;
}
- snd_soc_register_component(&sec_dai->pdev->dev,
- &samsung_i2s_component,
- &sec_dai->i2s_dai_drv, 1);
+ devm_snd_soc_register_component(&sec_dai->pdev->dev,
+ &samsung_i2s_component,
+ &sec_dai->i2s_dai_drv, 1);
samsung_asoc_dma_platform_register(&pdev->dev);
return 0;
}
@@ -1258,8 +1256,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
goto err;
}
- snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component,
- &pri_dai->i2s_dai_drv, 1);
+ devm_snd_soc_register_component(&pri_dai->pdev->dev,
+ &samsung_i2s_component,
+ &pri_dai->i2s_dai_drv, 1);
pm_runtime_enable(&pdev->dev);
@@ -1267,7 +1266,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
return 0;
err:
- release_mem_region(regs_base, resource_size(res));
+ if (res)
+ release_mem_region(regs_base, resource_size(res));
return ret;
}
@@ -1294,7 +1294,6 @@ static int samsung_i2s_remove(struct platform_device *pdev)
i2s->sec_dai = NULL;
samsung_asoc_dma_platform_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
return 0;
}
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c
index ce1e1e16f250..3d5cf1530b6f 100644
--- a/sound/soc/samsung/idma.c
+++ b/sound/soc/samsung/idma.c
@@ -35,14 +35,6 @@ static const struct snd_pcm_hardware idma_hardware = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_U16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_U24_LE |
- SNDRV_PCM_FMTBIT_U8 |
- SNDRV_PCM_FMTBIT_S8,
- .channels_min = 2,
- .channels_max = 2,
.buffer_bytes_max = MAX_IDMA_BUFFER,
.period_bytes_min = 128,
.period_bytes_max = MAX_IDMA_PERIOD,
@@ -383,18 +375,15 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream)
return 0;
}
-static u64 idma_mask = DMA_BIT_MASK(32);
-
static int idma_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
- int ret = 0;
+ int ret;
- if (!card->dev->dma_mask)
- card->dev->dma_mask = &idma_mask;
- if (!card->dev->coherent_dma_mask)
- card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = preallocate_idma_buffer(pcm,
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 807db417d234..98a04c11202d 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -20,6 +20,7 @@
#include <sound/soc.h>
+#include <mach/gpio-samsung.h>
#include <asm/mach-types.h>
#include "regs-iis.h"
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c
index e54256fc4b2c..6a5e4bf6ac96 100644
--- a/sound/soc/samsung/pcm.c
+++ b/sound/soc/samsung/pcm.c
@@ -275,7 +275,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(rtd->cpu_dai);
- struct s3c_dma_params *dma_data;
void __iomem *regs = pcm->regs;
struct clk *clk;
int sclk_div, sync_div;
@@ -284,13 +283,6 @@ static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
dev_dbg(pcm->dev, "Entered %s\n", __func__);
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dma_data = pcm->dma_playback;
- else
- dma_data = pcm->dma_capture;
-
- snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_data);
-
/* Strictly check for sample size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -461,10 +453,20 @@ static const struct snd_soc_dai_ops s3c_pcm_dai_ops = {
.set_fmt = s3c_pcm_set_fmt,
};
+static int s3c_pcm_dai_probe(struct snd_soc_dai *dai)
+{
+ struct s3c_pcm_info *pcm = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, pcm->dma_playback, pcm->dma_capture);
+
+ return 0;
+}
+
#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
#define S3C_PCM_DAI_DECLARE \
.symmetric_rates = 1, \
+ .probe = s3c_pcm_dai_probe, \
.ops = &s3c_pcm_dai_ops, \
.playback = { \
.channels_min = 2, \
diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h
index c3878f7acb83..a71be45bbffc 100644
--- a/sound/soc/samsung/regs-ac97.h
+++ b/sound/soc/samsung/regs-ac97.h
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-ac97.h
- *
+/*
* Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
*
@@ -10,8 +9,8 @@
* S3C2440 AC97 Controller
*/
-#ifndef __ASM_ARCH_REGS_AC97_H
-#define __ASM_ARCH_REGS_AC97_H __FILE__
+#ifndef __SAMSUNG_REGS_AC97_H__
+#define __SAMSUNG_REGS_AC97_H__
#define S3C_AC97_GLBCTRL (0x00)
@@ -64,4 +63,4 @@
#define S3C_AC97_PCM_DATA (0x18)
#define S3C_AC97_MIC_DATA (0x1C)
-#endif /* __ASM_ARCH_REGS_AC97_H */
+#endif /* __SAMSUNG_REGS_AC97_H__ */
diff --git a/sound/soc/samsung/regs-iis.h b/sound/soc/samsung/regs-iis.h
index a18d35e7a735..dc6cbbe9c4f0 100644
--- a/sound/soc/samsung/regs-iis.h
+++ b/sound/soc/samsung/regs-iis.h
@@ -1,5 +1,4 @@
-/* arch/arm/plat-samsung/include/plat/regs-iis.h
- *
+/*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
*
@@ -10,8 +9,8 @@
* S3C2410 IIS register definition
*/
-#ifndef __ASM_ARCH_REGS_IIS_H
-#define __ASM_ARCH_REGS_IIS_H
+#ifndef __SAMSUNG_REGS_IIS_H__
+#define __SAMSUNG_REGS_IIS_H__
#define S3C2410_IISCON (0x00)
@@ -67,4 +66,4 @@
#define S3C2410_IISFIFO (0x10)
-#endif /* __ASM_ARCH_REGS_IIS_H */
+#endif /* __SAMSUNG_REGS_IIS_H__ */
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 704460a37005..06ebdc061770 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -24,6 +24,7 @@
#include <sound/soc.h>
#include <sound/jack.h>
+#include <mach/gpio-samsung.h>
#include "regs-iis.h"
#include <asm/mach-types.h>
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c
index e5e81b111001..79e7efb9283c 100644
--- a/sound/soc/samsung/s3c-i2s-v2.c
+++ b/sound/soc/samsung/s3c-i2s-v2.c
@@ -31,11 +31,7 @@
#undef S3C_IIS_V2_SUPPORTED
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
- || defined(CONFIG_CPU_S5PV210)
-#define S3C_IIS_V2_SUPPORTED
-#endif
-
-#ifdef CONFIG_PLAT_S3C64XX
+ || defined(CONFIG_ARCH_S3C64XX) || defined(CONFIG_CPU_S5PV210)
#define S3C_IIS_V2_SUPPORTED
#endif
@@ -733,7 +729,7 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
struct snd_soc_component_driver *cmp_drv,
struct snd_soc_dai_driver *dai_drv)
{
- struct snd_soc_dai_ops *ops = drv->ops;
+ struct snd_soc_dai_ops *ops = dai_drv->ops;
ops->trigger = s3c2412_i2s_trigger;
if (!ops->hw_params)
@@ -746,8 +742,8 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
if (!ops->delay)
ops->delay = s3c2412_i2s_delay;
- drv->suspend = s3c2412_i2s_suspend;
- drv->resume = s3c2412_i2s_resume;
+ dai_drv->suspend = s3c2412_i2s_suspend;
+ dai_drv->resume = s3c2412_i2s_resume;
return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
}
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c
index ea885cb9f76c..d0794458963a 100644
--- a/sound/soc/samsung/s3c2412-i2s.c
+++ b/sound/soc/samsung/s3c2412-i2s.c
@@ -26,6 +26,8 @@
#include <sound/pcm_params.h>
#include <mach/dma.h>
+#include <mach/gpio-samsung.h>
+#include <plat/gpio-cfg.h>
#include "dma.h"
#include "regs-i2s-v2.h"
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c
index 9c8ebd872fac..f31e916dd8c4 100644
--- a/sound/soc/samsung/s3c24xx-i2s.c
+++ b/sound/soc/samsung/s3c24xx-i2s.c
@@ -24,6 +24,8 @@
#include <sound/pcm_params.h>
#include <mach/dma.h>
+#include <mach/gpio-samsung.h>
+#include <plat/gpio-cfg.h>
#include "regs-iis.h"
#include "dma.h"
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c
index 58ae3237ef69..c3b2adafb7b5 100644
--- a/sound/soc/samsung/smartq_wm8987.c
+++ b/sound/soc/samsung/smartq_wm8987.c
@@ -19,6 +19,7 @@
#include <sound/soc.h>
#include <sound/jack.h>
+#include <mach/gpio-samsung.h>
#include <asm/mach-types.h>
#include "i2s.h"
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index 5fd7a05a9b9e..d38ae98e2f32 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -9,6 +9,7 @@
#include "../codecs/wm8994.h"
#include <sound/pcm_params.h>
+#include <sound/soc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -151,13 +152,11 @@ static struct snd_soc_card smdk = {
.num_links = ARRAY_SIZE(smdk_dai),
};
-#ifdef CONFIG_OF
static const struct of_device_id samsung_wm8994_of_match[] = {
{ .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
{},
};
MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
-#endif /* CONFIG_OF */
static int smdk_audio_probe(struct platform_device *pdev)
{
@@ -187,13 +186,13 @@ static int smdk_audio_probe(struct platform_device *pdev)
smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node;
}
- id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
+ id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev);
if (id)
*board = *((struct smdk_wm8994_data *)id->data);
platform_set_drvdata(pdev, board);
- ret = snd_soc_register_card(card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
@@ -201,23 +200,14 @@ static int smdk_audio_probe(struct platform_device *pdev)
return ret;
}
-static int smdk_audio_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- snd_soc_unregister_card(card);
-
- return 0;
-}
-
static struct platform_driver smdk_audio_driver = {
.driver = {
.name = "smdk-audio-wm8894",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(samsung_wm8994_of_match),
+ .pm = &snd_soc_pm_ops,
},
.probe = smdk_audio_probe,
- .remove = smdk_audio_remove,
};
module_platform_driver(smdk_audio_driver);
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 56d8ff6a402d..ff60e11ecb56 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU
config SND_SOC_RCAR
tristate "R-Car series SRU/SCU/SSIU/SSI support"
select SND_SIMPLE_CARD
- select RCAR_CLK_ADG
+ select REGMAP
help
This option enables R-Car SUR/SCU/SSIU/SSI sound support
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 1a8b03e4b41b..c85f8eb66c97 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -89,29 +89,12 @@ struct camelot_pcm {
#define DMABRG_PREALLOC_BUFFER 32 * 1024
#define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024
-/* support everything the SSI supports */
-#define DMABRG_RATES \
- SNDRV_PCM_RATE_8000_192000
-
-#define DMABRG_FMTS \
- (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
- SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
- SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
- SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
-
static struct snd_pcm_hardware camelot_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_BATCH),
- .formats = DMABRG_FMTS,
- .rates = DMABRG_RATES,
- .rate_min = 8000,
- .rate_max = 192000,
- .channels_min = 2,
- .channels_max = 8, /* max of the SSI */
.buffer_bytes_max = DMABRG_PERIOD_MAX,
.period_bytes_min = DMABRG_PERIOD_MIN,
.period_bytes_max = DMABRG_PERIOD_MAX / 2,
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index b33ca7cd085b..1967f44e7cd4 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -232,9 +232,9 @@ struct fsi_stream {
* these are for DMAEngine
*/
struct dma_chan *chan;
- struct sh_dmae_slave slave; /* see fsi_handler_init() */
struct work_struct work;
dma_addr_t dma;
+ int dma_id;
int loop_cnt;
int additional_pos;
};
@@ -1410,15 +1410,6 @@ static void fsi_dma_do_work(struct work_struct *work)
}
}
-static bool fsi_dma_filter(struct dma_chan *chan, void *param)
-{
- struct sh_dmae_slave *slave = param;
-
- chan->private = slave;
-
- return true;
-}
-
static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
{
schedule_work(&io->work);
@@ -1446,15 +1437,34 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev)
{
dma_cap_mask_t mask;
+ int is_play = fsi_stream_is_play(fsi, io);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
+ io->chan = dma_request_slave_channel_compat(mask,
+ shdma_chan_filter, (void *)io->dma_id,
+ dev, is_play ? "tx" : "rx");
+ if (io->chan) {
+ struct dma_slave_config cfg;
+ int ret;
+
+ cfg.slave_id = io->dma_id;
+ cfg.dst_addr = 0; /* use default addr */
+ cfg.src_addr = 0; /* use default addr */
+ cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+
+ ret = dmaengine_slave_config(io->chan, &cfg);
+ if (ret < 0) {
+ dma_release_channel(io->chan);
+ io->chan = NULL;
+ }
+ }
+
if (!io->chan) {
/* switch to PIO handler */
- if (fsi_stream_is_play(fsi, io))
+ if (is_play)
fsi->playback.handler = &fsi_pio_push_handler;
else
fsi->capture.handler = &fsi_pio_pop_handler;
@@ -1777,12 +1787,6 @@ static struct snd_pcm_hardware fsi_pcm_hardware = {
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE,
- .formats = FSI_FMTS,
- .rates = FSI_RATES,
- .rate_min = 8000,
- .rate_max = 192000,
- .channels_min = 2,
- .channels_max = 2,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8192,
@@ -1960,7 +1964,7 @@ static void fsi_handler_init(struct fsi_priv *fsi,
fsi->capture.priv = fsi;
if (info->tx_id) {
- fsi->playback.slave.shdma_slave.slave_id = info->tx_id;
+ fsi->playback.dma_id = info->tx_id;
fsi->playback.handler = &fsi_dma_push_handler;
}
}
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index d80deb7ccf13..a53235c4d1b0 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -8,7 +8,6 @@
* for more details.
*/
#include <linux/sh_clk.h>
-#include <mach/clock.h>
#include "rsnd.h"
#define CLKA 0
@@ -20,8 +19,9 @@
struct rsnd_adg {
struct clk *clk[CLKMAX];
- int rate_of_441khz_div_6;
- int rate_of_48khz_div_6;
+ int rbga_rate_for_441khz_div_6; /* RBGA */
+ int rbgb_rate_for_48khz_div_6; /* RBGB */
+ u32 ckr;
};
#define for_each_rsnd_clk(pos, adg, i) \
@@ -30,41 +30,114 @@ struct rsnd_adg {
i++, (pos) = adg->clk[i])
#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
-static enum rsnd_reg rsnd_adg_ssi_reg_get(int id)
+static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ unsigned int src_rate,
+ unsigned int dst_rate)
{
- enum rsnd_reg reg;
+ struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int idx, sel, div, shift;
+ u32 mask, val;
+ int id = rsnd_mod_id(mod);
+ unsigned int sel_rate [] = {
+ clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */
+ clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */
+ clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */
+ 0, /* 011: MLBCLK (not used) */
+ adg->rbga_rate_for_441khz_div_6,/* 100: RBGA */
+ adg->rbgb_rate_for_48khz_div_6, /* 101: RBGB */
+ };
+
+ /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */
+ for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
+ for (div = 128, idx = 0;
+ div <= 2048;
+ div *= 2, idx++) {
+ if (src_rate == sel_rate[sel] / div) {
+ val = (idx << 4) | sel;
+ goto find_rate;
+ }
+ }
+ }
+ dev_err(dev, "can't find convert src clk\n");
+ return -EINVAL;
+
+find_rate:
+ shift = (id % 4) * 8;
+ mask = 0xFF << shift;
+ val = val << shift;
+
+ dev_dbg(dev, "adg convert src clk = %02x\n", val);
+
+ switch (id / 4) {
+ case 0:
+ rsnd_mod_bset(mod, AUDIO_CLK_SEL3, mask, val);
+ break;
+ case 1:
+ rsnd_mod_bset(mod, AUDIO_CLK_SEL4, mask, val);
+ break;
+ case 2:
+ rsnd_mod_bset(mod, AUDIO_CLK_SEL5, mask, val);
+ break;
+ }
+
+ /*
+ * Gen1 doesn't need dst_rate settings,
+ * since it uses SSI WS pin.
+ * see also rsnd_src_set_route_if_gen1()
+ */
+
+ return 0;
+}
+
+int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ unsigned int src_rate,
+ unsigned int dst_rate)
+{
+ if (rsnd_is_gen1(priv))
+ return rsnd_adg_set_convert_clk_gen1(priv, mod,
+ src_rate, dst_rate);
+
+ return -EINVAL;
+}
+
+static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val)
+{
+ int id = rsnd_mod_id(mod);
+ int shift = (id % 4) * 8;
+ u32 mask = 0xFF << shift;
+
+ val = val << shift;
/*
* SSI 8 is not connected to ADG.
* it works with SSI 7
*/
if (id == 8)
- return RSND_REG_MAX;
-
- if (0 <= id && id <= 3)
- reg = RSND_REG_AUDIO_CLK_SEL0;
- else if (4 <= id && id <= 7)
- reg = RSND_REG_AUDIO_CLK_SEL1;
- else
- reg = RSND_REG_AUDIO_CLK_SEL2;
-
- return reg;
+ return;
+
+ switch (id / 4) {
+ case 0:
+ rsnd_mod_bset(mod, AUDIO_CLK_SEL0, mask, val);
+ break;
+ case 1:
+ rsnd_mod_bset(mod, AUDIO_CLK_SEL1, mask, val);
+ break;
+ case 2:
+ rsnd_mod_bset(mod, AUDIO_CLK_SEL2, mask, val);
+ break;
+ }
}
int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- enum rsnd_reg reg;
- int id;
-
/*
* "mod" = "ssi" here.
* we can get "ssi id" from mod
*/
- id = rsnd_mod_id(mod);
- reg = rsnd_adg_ssi_reg_get(id);
-
- rsnd_write(priv, mod, reg, 0);
+ rsnd_adg_set_ssi_clk(mod, 0);
return 0;
}
@@ -75,8 +148,7 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
struct device *dev = rsnd_priv_to_dev(priv);
struct clk *clk;
- enum rsnd_reg reg;
- int id, shift, i;
+ int i;
u32 data;
int sel_table[] = {
[CLKA] = 0x1,
@@ -102,12 +174,12 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
/*
* find 1/6 clock from BRGA/BRGB
*/
- if (rate == adg->rate_of_441khz_div_6) {
+ if (rate == adg->rbga_rate_for_441khz_div_6) {
data = 0x10;
goto found_clock;
}
- if (rate == adg->rate_of_48khz_div_6) {
+ if (rate == adg->rbgb_rate_for_48khz_div_6) {
data = 0x20;
goto found_clock;
}
@@ -116,23 +188,19 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
found_clock:
+ /* see rsnd_adg_ssi_clk_init() */
+ rsnd_mod_bset(mod, SSICKR, 0x00FF0000, adg->ckr);
+ rsnd_mod_write(mod, BRRA, 0x00000002); /* 1/6 */
+ rsnd_mod_write(mod, BRRB, 0x00000002); /* 1/6 */
+
/*
* This "mod" = "ssi" here.
* we can get "ssi id" from mod
*/
- id = rsnd_mod_id(mod);
- reg = rsnd_adg_ssi_reg_get(id);
-
- dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate);
-
- /*
- * Enable SSIx clock
- */
- shift = (id % 4) * 8;
+ rsnd_adg_set_ssi_clk(mod, data);
- rsnd_bset(priv, mod, reg,
- 0xFF << shift,
- data << shift);
+ dev_dbg(dev, "ADG: ssi%d selects clk%d = %d",
+ rsnd_mod_id(mod), i, rate);
return 0;
}
@@ -161,8 +229,8 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
* rsnd_adg_ssi_clk_try_start()
*/
ckr = 0;
- adg->rate_of_441khz_div_6 = 0;
- adg->rate_of_48khz_div_6 = 0;
+ adg->rbga_rate_for_441khz_div_6 = 0;
+ adg->rbgb_rate_for_48khz_div_6 = 0;
for_each_rsnd_clk(clk, adg, i) {
rate = clk_get_rate(clk);
@@ -170,21 +238,19 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
continue;
/* RBGA */
- if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) {
- adg->rate_of_441khz_div_6 = rate / 6;
+ if (!adg->rbga_rate_for_441khz_div_6 && (0 == rate % 44100)) {
+ adg->rbga_rate_for_441khz_div_6 = rate / 6;
ckr |= brg_table[i] << 20;
}
/* RBGB */
- if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) {
- adg->rate_of_48khz_div_6 = rate / 6;
+ if (!adg->rbgb_rate_for_48khz_div_6 && (0 == rate % 48000)) {
+ adg->rbgb_rate_for_48khz_div_6 = rate / 6;
ckr |= brg_table[i] << 16;
}
}
- rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr);
- rsnd_priv_write(priv, BRRA, 0x00000002); /* 1/6 */
- rsnd_priv_write(priv, BRRB, 0x00000002); /* 1/6 */
+ adg->ckr = ckr;
}
int rsnd_adg_probe(struct platform_device *pdev,
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index a35706028514..743de5e3b1e1 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -94,6 +94,7 @@
*
*/
#include <linux/pm_runtime.h>
+#include <linux/shdma-base.h>
#include "rsnd.h"
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
@@ -103,54 +104,9 @@
* rsnd_platform functions
*/
#define rsnd_platform_call(priv, dai, func, param...) \
- (!(priv->info->func) ? -ENODEV : \
+ (!(priv->info->func) ? 0 : \
priv->info->func(param))
-
-/*
- * basic function
- */
-u32 rsnd_read(struct rsnd_priv *priv,
- struct rsnd_mod *mod, enum rsnd_reg reg)
-{
- void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
-
- BUG_ON(!base);
-
- return ioread32(base);
-}
-
-void rsnd_write(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 data)
-{
- void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- BUG_ON(!base);
-
- dev_dbg(dev, "w %p : %08x\n", base, data);
-
- iowrite32(data, base);
-}
-
-void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
- enum rsnd_reg reg, u32 mask, u32 data)
-{
- void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
- struct device *dev = rsnd_priv_to_dev(priv);
- u32 val;
-
- BUG_ON(!base);
-
- val = ioread32(base);
- val &= ~mask;
- val |= data & mask;
- iowrite32(val, base);
-
- dev_dbg(dev, "s %p : %08x\n", base, val);
-}
-
/*
* rsnd_mod functions
*/
@@ -244,9 +200,8 @@ static void rsnd_dma_do_work(struct work_struct *work)
return;
}
+ dma_async_issue_pending(dma->chan);
}
-
- dma_async_issue_pending(dma->chan);
}
int rsnd_dma_available(struct rsnd_dma *dma)
@@ -254,13 +209,6 @@ int rsnd_dma_available(struct rsnd_dma *dma)
return !!dma->chan;
}
-static bool rsnd_dma_filter(struct dma_chan *chan, void *param)
-{
- chan->private = param;
-
- return true;
-}
-
int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
int is_play, int id,
int (*inquiry)(struct rsnd_dma *dma,
@@ -268,7 +216,9 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
int (*complete)(struct rsnd_dma *dma))
{
struct device *dev = rsnd_priv_to_dev(priv);
+ struct dma_slave_config cfg;
dma_cap_mask_t mask;
+ int ret;
if (dma->chan) {
dev_err(dev, "it already has dma channel\n");
@@ -278,15 +228,23 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- dma->slave.shdma_slave.slave_id = id;
-
- dma->chan = dma_request_channel(mask, rsnd_dma_filter,
- &dma->slave.shdma_slave);
+ dma->chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+ (void *)id, dev,
+ is_play ? "tx" : "rx");
if (!dma->chan) {
dev_err(dev, "can't get dma channel\n");
return -EIO;
}
+ cfg.slave_id = id;
+ cfg.dst_addr = 0; /* use default addr when playback */
+ cfg.src_addr = 0; /* use default addr when capture */
+ cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+
+ ret = dmaengine_slave_config(dma->chan, &cfg);
+ if (ret < 0)
+ goto rsnd_dma_init_err;
+
dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
dma->priv = priv;
dma->inquiry = inquiry;
@@ -294,6 +252,11 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
INIT_WORK(&dma->work, rsnd_dma_do_work);
return 0;
+
+rsnd_dma_init_err:
+ rsnd_dma_quit(priv, dma);
+
+ return ret;
}
void rsnd_dma_quit(struct rsnd_priv *priv,
@@ -324,15 +287,13 @@ int rsnd_dai_connect(struct rsnd_dai *rdai,
struct rsnd_mod *mod,
struct rsnd_dai_stream *io)
{
- struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- if (!mod) {
- dev_err(dev, "NULL mod\n");
+ if (!mod)
return -EIO;
- }
if (!list_empty(&mod->list)) {
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
dev_err(dev, "%s%d is not empty\n",
rsnd_mod_name(mod),
rsnd_mod_id(mod));
@@ -363,6 +324,9 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
{
+ if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+ return NULL;
+
return priv->rdai + id;
}
@@ -664,12 +628,6 @@ static struct snd_pcm_hardware rsnd_pcm_hardware = {
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE,
- .formats = RSND_FMTS,
- .rates = RSND_RATES,
- .rate_min = 8000,
- .rate_max = 192000,
- .channels_min = 2,
- .channels_max = 2,
.buffer_bytes_max = 64 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 8192,
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index babb203b43b7..add088bd4b2a 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -10,41 +10,154 @@
*/
#include "rsnd.h"
-struct rsnd_gen_ops {
- int (*path_init)(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
- int (*path_exit)(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io);
-};
-
-struct rsnd_gen_reg_map {
- int index; /* -1 : not supported */
- u32 offset_id; /* offset of ssi0, ssi1, ssi2... */
- u32 offset_adr; /* offset of SSICR, SSISR, ... */
-};
-
struct rsnd_gen {
void __iomem *base[RSND_BASE_MAX];
- struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
struct rsnd_gen_ops *ops;
+
+ struct regmap *regmap;
+ struct regmap_field *regs[RSND_REG_MAX];
};
#define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen)
-/*
- * Gen2
- * will be filled in the future
- */
+#define RSND_REG_SET(gen, id, reg_id, offset, _id_offset, _id_size) \
+ [id] = { \
+ .reg = (unsigned int)gen->base[reg_id] + offset, \
+ .lsb = 0, \
+ .msb = 31, \
+ .id_size = _id_size, \
+ .id_offset = _id_offset, \
+ }
/*
- * Gen1
+ * basic function
*/
-static int rsnd_gen1_path_init(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+static int rsnd_regmap_write32(void *context, const void *_data, size_t count)
+{
+ struct rsnd_priv *priv = context;
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 *data = (u32 *)_data;
+ u32 val = data[1];
+ void __iomem *reg = (void *)data[0];
+
+ iowrite32(val, reg);
+
+ dev_dbg(dev, "w %p : %08x\n", reg, val);
+
+ return 0;
+}
+
+static int rsnd_regmap_read32(void *context,
+ const void *_data, size_t reg_size,
+ void *_val, size_t val_size)
+{
+ struct rsnd_priv *priv = context;
+ struct device *dev = rsnd_priv_to_dev(priv);
+ u32 *data = (u32 *)_data;
+ u32 *val = (u32 *)_val;
+ void __iomem *reg = (void *)data[0];
+
+ *val = ioread32(reg);
+
+ dev_dbg(dev, "r %p : %08x\n", reg, *val);
+
+ return 0;
+}
+
+static struct regmap_bus rsnd_regmap_bus = {
+ .write = rsnd_regmap_write32,
+ .read = rsnd_regmap_read32,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+static int rsnd_is_accessible_reg(struct rsnd_priv *priv,
+ struct rsnd_gen *gen, enum rsnd_reg reg)
+{
+ if (!gen->regs[reg]) {
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_err(dev, "unsupported register access %x\n", reg);
+ return 0;
+ }
+
+ return 1;
+}
+
+u32 rsnd_read(struct rsnd_priv *priv,
+ struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+ u32 val;
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return 0;
+
+ regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
+
+ return val;
+}
+
+void rsnd_write(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 data)
+{
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return;
+
+ regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
+}
+
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
+ enum rsnd_reg reg, u32 mask, u32 data)
+{
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+ if (!rsnd_is_accessible_reg(priv, gen, reg))
+ return;
+
+ regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
+ mask, data);
+}
+
+static int rsnd_gen_regmap_init(struct rsnd_priv *priv,
+ struct rsnd_gen *gen,
+ struct reg_field *regf)
+{
+ int i;
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct regmap_config regc;
+
+ memset(&regc, 0, sizeof(regc));
+ regc.reg_bits = 32;
+ regc.val_bits = 32;
+
+ gen->regmap = devm_regmap_init(dev, &rsnd_regmap_bus, priv, &regc);
+ if (IS_ERR(gen->regmap)) {
+ dev_err(dev, "regmap error %ld\n", PTR_ERR(gen->regmap));
+ return PTR_ERR(gen->regmap);
+ }
+
+ for (i = 0; i < RSND_REG_MAX; i++) {
+ gen->regs[i] = NULL;
+ if (!regf[i].reg)
+ continue;
+
+ gen->regs[i] = devm_regmap_field_alloc(dev, gen->regmap, regf[i]);
+ if (IS_ERR(gen->regs[i]))
+ return PTR_ERR(gen->regs[i]);
+
+ }
+
+ return 0;
+}
+
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
struct rsnd_mod *mod;
int ret;
@@ -82,9 +195,9 @@ static int rsnd_gen1_path_init(struct rsnd_priv *priv,
return ret;
}
-static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
{
struct rsnd_mod *mod, *n;
int ret = 0;
@@ -98,44 +211,139 @@ static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
return ret;
}
-static struct rsnd_gen_ops rsnd_gen1_ops = {
- .path_init = rsnd_gen1_path_init,
- .path_exit = rsnd_gen1_path_exit,
-};
+/*
+ * Gen2
+ */
+
+/* single address mapping */
+#define RSND_GEN2_S_REG(gen, reg, id, offset) \
+ RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, 0, 10)
-#define RSND_GEN1_REG_MAP(g, s, i, oi, oa) \
- do { \
- (g)->reg_map[RSND_REG_##i].index = RSND_GEN1_##s; \
- (g)->reg_map[RSND_REG_##i].offset_id = oi; \
- (g)->reg_map[RSND_REG_##i].offset_adr = oa; \
- } while (0)
+/* multi address mapping */
+#define RSND_GEN2_M_REG(gen, reg, id, offset, _id_offset) \
+ RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN2_##reg, offset, _id_offset, 10)
-static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
+static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
{
- RSND_GEN1_REG_MAP(gen, SRU, SRC_ROUTE_SEL, 0x0, 0x00);
- RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL0, 0x0, 0x08);
- RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL1, 0x0, 0x0c);
- RSND_GEN1_REG_MAP(gen, SRU, SRC_TMG_SEL2, 0x0, 0x10);
- RSND_GEN1_REG_MAP(gen, SRU, SRC_CTRL, 0x0, 0xc0);
- RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE0, 0x0, 0xD0);
- RSND_GEN1_REG_MAP(gen, SRU, SSI_MODE1, 0x0, 0xD4);
- RSND_GEN1_REG_MAP(gen, SRU, BUSIF_MODE, 0x4, 0x20);
- RSND_GEN1_REG_MAP(gen, SRU, BUSIF_ADINR, 0x40, 0x214);
-
- RSND_GEN1_REG_MAP(gen, ADG, BRRA, 0x0, 0x00);
- RSND_GEN1_REG_MAP(gen, ADG, BRRB, 0x0, 0x04);
- RSND_GEN1_REG_MAP(gen, ADG, SSICKR, 0x0, 0x08);
- RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL0, 0x0, 0x0c);
- RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL1, 0x0, 0x10);
- RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL3, 0x0, 0x18);
- RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL4, 0x0, 0x1c);
- RSND_GEN1_REG_MAP(gen, ADG, AUDIO_CLK_SEL5, 0x0, 0x20);
-
- RSND_GEN1_REG_MAP(gen, SSI, SSICR, 0x40, 0x00);
- RSND_GEN1_REG_MAP(gen, SSI, SSISR, 0x40, 0x04);
- RSND_GEN1_REG_MAP(gen, SSI, SSITDR, 0x40, 0x08);
- RSND_GEN1_REG_MAP(gen, SSI, SSIRDR, 0x40, 0x0c);
- RSND_GEN1_REG_MAP(gen, SSI, SSIWSR, 0x40, 0x20);
+ struct reg_field regf[RSND_REG_MAX] = {
+ RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800),
+ RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804),
+ /* FIXME: it needs SSI_MODE2/3 in the future */
+ RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80),
+
+ RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00),
+ RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04),
+ RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08),
+ RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c),
+ RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10),
+ RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14),
+
+ RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40),
+ RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40),
+ RSND_GEN2_M_REG(gen, SSI, SSITDR, 0x08, 0x40),
+ RSND_GEN2_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40),
+ RSND_GEN2_M_REG(gen, SSI, SSIWSR, 0x20, 0x40),
+ };
+
+ return rsnd_gen_regmap_init(priv, gen, regf);
+}
+
+static int rsnd_gen2_probe(struct platform_device *pdev,
+ struct rcar_snd_info *info,
+ struct rsnd_priv *priv)
+{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+ struct resource *scu_res;
+ struct resource *adg_res;
+ struct resource *ssiu_res;
+ struct resource *ssi_res;
+ int ret;
+
+ /*
+ * map address
+ */
+ scu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SCU);
+ adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_ADG);
+ ssiu_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSIU);
+ ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN2_SSI);
+
+ gen->base[RSND_GEN2_SCU] = devm_ioremap_resource(dev, scu_res);
+ gen->base[RSND_GEN2_ADG] = devm_ioremap_resource(dev, adg_res);
+ gen->base[RSND_GEN2_SSIU] = devm_ioremap_resource(dev, ssiu_res);
+ gen->base[RSND_GEN2_SSI] = devm_ioremap_resource(dev, ssi_res);
+ if (IS_ERR(gen->base[RSND_GEN2_SCU]) ||
+ IS_ERR(gen->base[RSND_GEN2_ADG]) ||
+ IS_ERR(gen->base[RSND_GEN2_SSIU]) ||
+ IS_ERR(gen->base[RSND_GEN2_SSI]))
+ return -ENODEV;
+
+ ret = rsnd_gen2_regmap_init(priv, gen);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "Gen2 device probed\n");
+ dev_dbg(dev, "SRU : %08x => %p\n", scu_res->start,
+ gen->base[RSND_GEN2_SCU]);
+ dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start,
+ gen->base[RSND_GEN2_ADG]);
+ dev_dbg(dev, "SSIU : %08x => %p\n", ssiu_res->start,
+ gen->base[RSND_GEN2_SSIU]);
+ dev_dbg(dev, "SSI : %08x => %p\n", ssi_res->start,
+ gen->base[RSND_GEN2_SSI]);
+
+ return 0;
+}
+
+/*
+ * Gen1
+ */
+
+/* single address mapping */
+#define RSND_GEN1_S_REG(gen, reg, id, offset) \
+ RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, 0, 9)
+
+/* multi address mapping */
+#define RSND_GEN1_M_REG(gen, reg, id, offset, _id_offset) \
+ RSND_REG_SET(gen, RSND_REG_##id, RSND_GEN1_##reg, offset, _id_offset, 9)
+
+static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen)
+{
+ struct reg_field regf[RSND_REG_MAX] = {
+ RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_SEL, 0x00),
+ RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL0, 0x08),
+ RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL1, 0x0c),
+ RSND_GEN1_S_REG(gen, SRU, SRC_TMG_SEL2, 0x10),
+ RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0),
+ RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0),
+ RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4),
+ RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4),
+ RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8),
+ RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40),
+ RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40),
+ RSND_GEN1_M_REG(gen, SRU, SRC_ADINR, 0x214, 0x40),
+ RSND_GEN1_M_REG(gen, SRU, SRC_IFSCR, 0x21c, 0x40),
+ RSND_GEN1_M_REG(gen, SRU, SRC_IFSVR, 0x220, 0x40),
+ RSND_GEN1_M_REG(gen, SRU, SRC_SRCCR, 0x224, 0x40),
+ RSND_GEN1_M_REG(gen, SRU, SRC_MNFSR, 0x228, 0x40),
+
+ RSND_GEN1_S_REG(gen, ADG, BRRA, 0x00),
+ RSND_GEN1_S_REG(gen, ADG, BRRB, 0x04),
+ RSND_GEN1_S_REG(gen, ADG, SSICKR, 0x08),
+ RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c),
+ RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10),
+ RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL3, 0x18),
+ RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL4, 0x1c),
+ RSND_GEN1_S_REG(gen, ADG, AUDIO_CLK_SEL5, 0x20),
+
+ RSND_GEN1_M_REG(gen, SSI, SSICR, 0x00, 0x40),
+ RSND_GEN1_M_REG(gen, SSI, SSISR, 0x04, 0x40),
+ RSND_GEN1_M_REG(gen, SSI, SSITDR, 0x08, 0x40),
+ RSND_GEN1_M_REG(gen, SSI, SSIRDR, 0x0c, 0x40),
+ RSND_GEN1_M_REG(gen, SSI, SSIWSR, 0x20, 0x40),
+ };
+
+ return rsnd_gen_regmap_init(priv, gen, regf);
}
static int rsnd_gen1_probe(struct platform_device *pdev,
@@ -147,6 +355,7 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
struct resource *sru_res;
struct resource *adg_res;
struct resource *ssi_res;
+ int ret;
/*
* map address
@@ -163,8 +372,9 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
IS_ERR(gen->base[RSND_GEN1_SSI]))
return -ENODEV;
- gen->ops = &rsnd_gen1_ops;
- rsnd_gen1_reg_map_init(gen);
+ ret = rsnd_gen1_regmap_init(priv, gen);
+ if (ret < 0)
+ return ret;
dev_dbg(dev, "Gen1 device probed\n");
dev_dbg(dev, "SRU : %08x => %p\n", sru_res->start,
@@ -178,72 +388,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
}
-static void rsnd_gen1_remove(struct platform_device *pdev,
- struct rsnd_priv *priv)
-{
-}
-
/*
* Gen
*/
-int rsnd_gen_path_init(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
- return gen->ops->path_init(priv, rdai, io);
-}
-
-int rsnd_gen_path_exit(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
-
- return gen->ops->path_exit(priv, rdai, io);
-}
-
-void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- enum rsnd_reg reg)
-{
- struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
- struct device *dev = rsnd_priv_to_dev(priv);
- int index;
- u32 offset_id, offset_adr;
-
- if (reg >= RSND_REG_MAX) {
- dev_err(dev, "rsnd_reg reg error\n");
- return NULL;
- }
-
- index = gen->reg_map[reg].index;
- offset_id = gen->reg_map[reg].offset_id;
- offset_adr = gen->reg_map[reg].offset_adr;
-
- if (index < 0) {
- dev_err(dev, "unsupported reg access %d\n", reg);
- return NULL;
- }
-
- if (offset_id && mod)
- offset_id *= rsnd_mod_id(mod);
-
- /*
- * index/offset were set on gen1/gen2
- */
-
- return gen->base[index] + offset_id + offset_adr;
-}
-
int rsnd_gen_probe(struct platform_device *pdev,
struct rcar_snd_info *info,
struct rsnd_priv *priv)
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_gen *gen;
- int i;
+ int ret;
gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
if (!gen) {
@@ -253,28 +407,19 @@ int rsnd_gen_probe(struct platform_device *pdev,
priv->gen = gen;
- /*
- * see
- * rsnd_reg_get()
- * rsnd_gen_probe()
- */
- for (i = 0; i < RSND_REG_MAX; i++)
- gen->reg_map[i].index = -1;
-
- /*
- * init each module
- */
+ ret = -ENODEV;
if (rsnd_is_gen1(priv))
- return rsnd_gen1_probe(pdev, info, priv);
+ ret = rsnd_gen1_probe(pdev, info, priv);
+ else if (rsnd_is_gen2(priv))
+ ret = rsnd_gen2_probe(pdev, info, priv);
- dev_err(dev, "unknown generation R-Car sound device\n");
+ if (ret < 0)
+ dev_err(dev, "unknown generation R-Car sound device\n");
- return -ENODEV;
+ return ret;
}
void rsnd_gen_remove(struct platform_device *pdev,
struct rsnd_priv *priv)
{
- if (rsnd_is_gen1(priv))
- rsnd_gen1_remove(pdev, priv);
}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 9cc6986a8cfb..4ca66cd899c8 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -31,16 +31,24 @@
* see gen1/gen2 for detail
*/
enum rsnd_reg {
- /* SRU/SCU */
- RSND_REG_SRC_ROUTE_SEL,
- RSND_REG_SRC_TMG_SEL0,
- RSND_REG_SRC_TMG_SEL1,
- RSND_REG_SRC_TMG_SEL2,
- RSND_REG_SRC_CTRL,
+ /* SRU/SCU/SSIU */
+ RSND_REG_SRC_ROUTE_SEL, /* for Gen1 */
+ RSND_REG_SRC_TMG_SEL0, /* for Gen1 */
+ RSND_REG_SRC_TMG_SEL1, /* for Gen1 */
+ RSND_REG_SRC_TMG_SEL2, /* for Gen1 */
+ RSND_REG_SRC_ROUTE_CTRL, /* for Gen1 */
RSND_REG_SSI_MODE0,
RSND_REG_SSI_MODE1,
RSND_REG_BUSIF_MODE,
- RSND_REG_BUSIF_ADINR,
+ RSND_REG_INT_ENABLE, /* for Gen2 */
+ RSND_REG_SRC_ROUTE_MODE0,
+ RSND_REG_SRC_SWRSR,
+ RSND_REG_SRC_SRCIR,
+ RSND_REG_SRC_ADINR,
+ RSND_REG_SRC_IFSCR,
+ RSND_REG_SRC_IFSVR,
+ RSND_REG_SRC_SRCCR,
+ RSND_REG_SRC_MNFSR,
/* ADG */
RSND_REG_BRRA,
@@ -49,9 +57,9 @@ enum rsnd_reg {
RSND_REG_AUDIO_CLK_SEL0,
RSND_REG_AUDIO_CLK_SEL1,
RSND_REG_AUDIO_CLK_SEL2,
- RSND_REG_AUDIO_CLK_SEL3,
- RSND_REG_AUDIO_CLK_SEL4,
- RSND_REG_AUDIO_CLK_SEL5,
+ RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */
+ RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */
+ RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */
/* SSI */
RSND_REG_SSICR,
@@ -78,10 +86,6 @@ struct rsnd_dai_stream;
#define rsnd_mod_bset(m, r, s, d) \
rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
-#define rsnd_priv_read(p, r) rsnd_read(p, NULL, RSND_REG_##r)
-#define rsnd_priv_write(p, r, d) rsnd_write(p, NULL, RSND_REG_##r, d)
-#define rsnd_priv_bset(p, r, s, d) rsnd_bset(p, NULL, RSND_REG_##r, s, d)
-
u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
enum rsnd_reg reg, u32 data);
@@ -178,11 +182,11 @@ struct rsnd_dai {
struct rsnd_dai_stream playback;
struct rsnd_dai_stream capture;
- int clk_master:1;
- int bit_clk_inv:1;
- int frm_clk_inv:1;
- int sys_delay:1;
- int data_alignment:1;
+ unsigned int clk_master:1;
+ unsigned int bit_clk_inv:1;
+ unsigned int frm_clk_inv:1;
+ unsigned int sys_delay:1;
+ unsigned int data_alignment:1;
};
#define rsnd_dai_nr(priv) ((priv)->dai_nr)
@@ -220,8 +224,8 @@ int rsnd_gen_path_exit(struct rsnd_priv *priv,
void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
struct rsnd_mod *mod,
enum rsnd_reg reg);
-#define rsnd_is_gen1(s) ((s)->info->flags & RSND_GEN1)
-#define rsnd_is_gen2(s) ((s)->info->flags & RSND_GEN2)
+#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1)
+#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2)
/*
* R-Car ADG
@@ -233,6 +237,10 @@ int rsnd_adg_probe(struct platform_device *pdev,
struct rsnd_priv *priv);
void rsnd_adg_remove(struct platform_device *pdev,
struct rsnd_priv *priv);
+int rsnd_adg_set_convert_clk(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ unsigned int src_rate,
+ unsigned int dst_rate);
/*
* R-Car sound priv
@@ -285,6 +293,11 @@ int rsnd_scu_probe(struct platform_device *pdev,
void rsnd_scu_remove(struct platform_device *pdev,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
+bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod);
+unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
+ struct rsnd_mod *ssi_mod,
+ struct snd_pcm_runtime *runtime);
+
#define rsnd_scu_nr(priv) ((priv)->scu_nr)
/*
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
index 2df2e9150b89..9bb08bb1d455 100644
--- a/sound/soc/sh/rcar/scu.c
+++ b/sound/soc/sh/rcar/scu.c
@@ -13,9 +13,13 @@
struct rsnd_scu {
struct rsnd_scu_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
+ struct clk *clk;
};
#define rsnd_scu_mode_flags(p) ((p)->info->flags)
+#define rsnd_scu_convert_rate(p) ((p)->info->convert_rate)
+
+#define RSND_SCU_NAME_SIZE 16
/*
* ADINR
@@ -26,6 +30,15 @@ struct rsnd_scu {
#define OTBL_18 (6 << 16)
#define OTBL_16 (8 << 16)
+/*
+ * image of SRC (Sampling Rate Converter)
+ *
+ * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+
+ * 48kHz <-> | SRC | <------> | SSI | <-----> | codec |
+ * 44.1kHz <-> +-----+ +-----+ +-------+
+ * ...
+ *
+ */
#define rsnd_mod_to_scu(_mod) \
container_of((_mod), struct rsnd_scu, mod)
@@ -36,7 +49,8 @@ struct rsnd_scu {
((pos) = (struct rsnd_scu *)(priv)->scu + i); \
i++)
-static int rsnd_scu_set_route(struct rsnd_priv *priv,
+/* Gen1 only */
+static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@@ -55,7 +69,7 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
{ 0x3, 28, }, /* 7 */
{ 0x3, 30, }, /* 8 */
};
-
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
u32 mask;
u32 val;
int shift;
@@ -68,7 +82,7 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
return 0;
id = rsnd_mod_id(mod);
- if (id < 0 || id > ARRAY_SIZE(routes))
+ if (id < 0 || id >= ARRAY_SIZE(routes))
return -EIO;
/*
@@ -85,9 +99,18 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
*/
shift = (id % 4) * 8;
mask = 0x1F << shift;
- if (8 == id) /* SRU8 is very special */
+
+ /*
+ * ADG is used as source clock if SRC was used,
+ * then, SSI WS is used as destination clock.
+ * SSI WS is used as source clock if SRC is not used
+ * (when playback, source/destination become reverse when capture)
+ */
+ if (rsnd_scu_convert_rate(scu)) /* use ADG */
+ val = 0;
+ else if (8 == id) /* use SSI WS, but SRU8 is special */
val = id << shift;
- else
+ else /* use SSI WS */
val = (id + 1) << shift;
switch (id / 4) {
@@ -105,30 +128,45 @@ static int rsnd_scu_set_route(struct rsnd_priv *priv,
return 0;
}
-static int rsnd_scu_set_mode(struct rsnd_priv *priv,
- struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
+unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv,
+ struct rsnd_mod *ssi_mod,
+ struct snd_pcm_runtime *runtime)
{
- int id = rsnd_mod_id(mod);
- u32 val;
+ struct rsnd_scu *scu;
+ unsigned int rate;
- if (rsnd_is_gen1(priv)) {
- val = (1 << id);
- rsnd_mod_bset(mod, SRC_CTRL, val, val);
- }
+ /* this function is assuming SSI id = SCU id here */
+ scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod)));
- return 0;
+ /*
+ * return convert rate if SRC is used,
+ * otherwise, return runtime->rate as usual
+ */
+ rate = rsnd_scu_convert_rate(scu);
+ if (!rate)
+ rate = runtime->rate;
+
+ return rate;
}
-static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
+static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv,
struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ u32 convert_rate = rsnd_scu_convert_rate(scu);
u32 adinr = runtime->channels;
+ /* set/clear soft reset */
+ rsnd_mod_write(mod, SRC_SWRSR, 0);
+ rsnd_mod_write(mod, SRC_SWRSR, 1);
+
+ /* Initialize the operation of the SRC internal circuits */
+ rsnd_mod_write(mod, SRC_SRCIR, 1);
+
+ /* Set channel number and output bit length */
switch (runtime->sample_bits) {
case 16:
adinr |= OTBL_16;
@@ -139,13 +177,93 @@ static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
default:
return -EIO;
}
+ rsnd_mod_write(mod, SRC_ADINR, adinr);
+
+ if (convert_rate) {
+ u32 fsrate = 0x0400000 / convert_rate * runtime->rate;
+ int ret;
+
+ /* Enable the initial value of IFS */
+ rsnd_mod_write(mod, SRC_IFSCR, 1);
+
+ /* Set initial value of IFS */
+ rsnd_mod_write(mod, SRC_IFSVR, fsrate);
+
+ /* Select SRC mode (fixed value) */
+ rsnd_mod_write(mod, SRC_SRCCR, 0x00010110);
+
+ /* Set the restriction value of the FS ratio (98%) */
+ rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98);
+
+ if (rsnd_is_gen1(priv)) {
+ /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
+ }
+
+ /* set convert clock */
+ ret = rsnd_adg_set_convert_clk(priv, mod,
+ runtime->rate,
+ convert_rate);
+ if (ret < 0)
+ return ret;
+ }
+ /* Cancel the initialization and operate the SRC function */
+ rsnd_mod_write(mod, SRC_SRCIR, 0);
+
+ /* use DMA transfer */
rsnd_mod_write(mod, BUSIF_MODE, 1);
- rsnd_mod_write(mod, BUSIF_ADINR, adinr);
return 0;
}
+static int rsnd_scu_transfer_start(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ int id = rsnd_mod_id(mod);
+ u32 val;
+
+ if (rsnd_is_gen1(priv)) {
+ val = (1 << id);
+ rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val);
+ }
+
+ if (rsnd_scu_convert_rate(scu))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+
+ return 0;
+}
+
+static int rsnd_scu_transfer_stop(struct rsnd_priv *priv,
+ struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ int id = rsnd_mod_id(mod);
+ u32 mask;
+
+ if (rsnd_is_gen1(priv)) {
+ mask = (1 << id);
+ rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0);
+ }
+
+ if (rsnd_scu_convert_rate(scu))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
+
+ return 0;
+}
+
+bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod)
+{
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+ u32 flags = rsnd_scu_mode_flags(scu);
+
+ return !!(flags & RSND_SCU_USE_HPBIF);
+}
+
static int rsnd_scu_start(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@@ -153,13 +271,12 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- u32 flags = rsnd_scu_mode_flags(scu);
int ret;
/*
* SCU will be used if it has RSND_SCU_USE_HPBIF flags
*/
- if (!(flags & RSND_SCU_USE_HPBIF)) {
+ if (!rsnd_scu_hpbif_is_enable(mod)) {
/* it use PIO transter */
dev_dbg(dev, "%s%d is not used\n",
rsnd_mod_name(mod), rsnd_mod_id(mod));
@@ -167,16 +284,19 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
return 0;
}
+ clk_enable(scu->clk);
+
/* it use DMA transter */
- ret = rsnd_scu_set_route(priv, mod, rdai, io);
+
+ ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io);
if (ret < 0)
return ret;
- ret = rsnd_scu_set_mode(priv, mod, rdai, io);
+ ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io);
if (ret < 0)
return ret;
- ret = rsnd_scu_set_hpbif(priv, mod, rdai, io);
+ ret = rsnd_scu_transfer_start(priv, mod, rdai, io);
if (ret < 0)
return ret;
@@ -185,14 +305,33 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
return 0;
}
+static int rsnd_scu_stop(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct rsnd_dai_stream *io)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+
+ if (!rsnd_scu_hpbif_is_enable(mod))
+ return 0;
+
+ rsnd_scu_transfer_stop(priv, mod, rdai, io);
+
+ clk_disable(scu->clk);
+
+ return 0;
+}
+
static struct rsnd_mod_ops rsnd_scu_ops = {
.name = "scu",
.start = rsnd_scu_start,
+ .stop = rsnd_scu_stop,
};
struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
{
- BUG_ON(id < 0 || id >= rsnd_scu_nr(priv));
+ if (WARN_ON(id < 0 || id >= rsnd_scu_nr(priv)))
+ id = 0;
return &((struct rsnd_scu *)(priv->scu) + id)->mod;
}
@@ -203,6 +342,8 @@ int rsnd_scu_probe(struct platform_device *pdev,
{
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_scu *scu;
+ struct clk *clk;
+ char name[RSND_SCU_NAME_SIZE];
int i, nr;
/*
@@ -219,9 +360,16 @@ int rsnd_scu_probe(struct platform_device *pdev,
priv->scu = scu;
for_each_rsnd_scu(scu, priv, i) {
+ snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i);
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
rsnd_mod_init(priv, &scu->mod,
&rsnd_scu_ops, i);
scu->info = &info->scu_info[i];
+ scu->clk = clk;
dev_dbg(dev, "SCU%d probed\n", i);
}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index fae26d3f79d2..4b8cf7ca9d19 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -101,29 +101,30 @@ struct rsnd_ssiu {
#define rsnd_ssi_to_ssiu(ssi)\
(((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
-static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
- struct rsnd_ssiu *ssiu)
+static void rsnd_ssi_mode_set(struct rsnd_priv *priv,
+ struct rsnd_dai *rdai,
+ struct rsnd_ssi *ssi)
{
struct device *dev = rsnd_priv_to_dev(priv);
- struct rsnd_ssi *ssi;
+ struct rsnd_mod *scu;
+ struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
+ int id = rsnd_mod_id(&ssi->mod);
u32 flags;
u32 val;
- int i;
+
+ scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod));
/*
* SSI_MODE0
*/
- ssiu->ssi_mode0 = 0;
- for_each_rsnd_ssi(ssi, priv, i) {
- flags = rsnd_ssi_mode_flags(ssi);
-
- /* see also BUSIF_MODE */
- if (!(flags & RSND_SSI_DEPENDENT)) {
- ssiu->ssi_mode0 |= (1 << i);
- dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i);
- } else {
- dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i);
- }
+
+ /* see also BUSIF_MODE */
+ if (rsnd_scu_hpbif_is_enable(scu)) {
+ ssiu->ssi_mode0 &= ~(1 << id);
+ dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id);
+ } else {
+ ssiu->ssi_mode0 |= (1 << id);
+ dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id);
}
/*
@@ -132,7 +133,7 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
#define ssi_parent_set(p, sync, adg, ext) \
do { \
ssi->parent = ssiu->ssi + p; \
- if (flags & RSND_SSI_CLK_FROM_ADG) \
+ if (rsnd_rdai_is_clk_master(rdai)) \
val = adg; \
else \
val = ext; \
@@ -140,15 +141,11 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
val |= sync; \
} while (0)
- ssiu->ssi_mode1 = 0;
- for_each_rsnd_ssi(ssi, priv, i) {
- flags = rsnd_ssi_mode_flags(ssi);
-
- if (!(flags & RSND_SSI_CLK_PIN_SHARE))
- continue;
+ flags = rsnd_ssi_mode_flags(ssi);
+ if (flags & RSND_SSI_CLK_PIN_SHARE) {
val = 0;
- switch (i) {
+ switch (id) {
case 1:
ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
break;
@@ -165,11 +162,6 @@ static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
ssiu->ssi_mode1 |= val;
}
-}
-
-static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi)
-{
- struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
@@ -195,9 +187,10 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
}
static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
- unsigned int rate)
+ struct rsnd_dai_stream *io)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
int i, j, ret;
int adg_clk_div_table[] = {
@@ -207,6 +200,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
1, 2, 4, 8, 16, 6, 12,
};
unsigned int main_rate;
+ unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime);
/*
* Find best clock, and try to start ADG
@@ -217,7 +211,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
/*
* this driver is assuming that
* system word is 64fs (= 2 x 32bit)
- * see rsnd_ssi_start()
+ * see rsnd_ssi_init()
*/
main_rate = rate / adg_clk_div_table[i]
* 32 * 2 * ssi_clk_mul_table[j];
@@ -259,14 +253,10 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
clk_enable(ssi->clk);
if (rsnd_rdai_is_clk_master(rdai)) {
- struct snd_pcm_runtime *runtime;
-
- runtime = rsnd_io_to_runtime(io);
-
if (rsnd_ssi_clk_from_parent(ssi))
rsnd_ssi_hw_start(ssi->parent, rdai, io);
else
- rsnd_ssi_master_clk_start(ssi, runtime->rate);
+ rsnd_ssi_master_clk_start(ssi, io);
}
}
@@ -379,7 +369,7 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
ssi->cr_own = cr;
ssi->err = -1; /* ignore 1st error */
- rsnd_ssi_mode_set(ssi);
+ rsnd_ssi_mode_set(priv, rdai, ssi);
dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
@@ -465,6 +455,10 @@ static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
/* enable PIO IRQ */
ssi->cr_etc = UIEN | OIEN | DIEN;
+ /* enable PIO interrupt if gen2 */
+ if (rsnd_is_gen2(priv))
+ rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000);
+
rsnd_ssi_hw_start(ssi, rdai, io);
dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
@@ -619,7 +613,8 @@ struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
{
- BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv));
+ if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
+ id = 0;
return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
}
@@ -657,7 +652,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
- clk = clk_get(dev, name);
+ clk = devm_clk_get(dev, name);
if (IS_ERR(clk))
return PTR_ERR(clk);
@@ -706,8 +701,6 @@ int rsnd_ssi_probe(struct platform_device *pdev,
rsnd_mod_init(priv, &ssi->mod, ops, i);
}
- rsnd_ssi_mode_init(priv, ssiu);
-
dev_dbg(dev, "ssi probed\n");
return 0;
@@ -720,7 +713,6 @@ void rsnd_ssi_remove(struct platform_device *pdev,
int i;
for_each_rsnd_ssi(ssi, priv, i) {
- clk_put(ssi->clk);
if (rsnd_ssi_dma_available(ssi))
rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
}
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index 9dc24ffa892a..d55babee14f8 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -543,7 +543,8 @@ static void siu_dai_shutdown(struct snd_pcm_substream *substream,
/* Stop the siu if the other stream is not using it */
if (!port_info->play_cap) {
/* during stmread or stmwrite ? */
- BUG_ON(port_info->playback.rw_flg || port_info->capture.rw_flg);
+ if (WARN_ON(port_info->playback.rw_flg || port_info->capture.rw_flg))
+ return;
siu_dai_spbstop(port_info);
siu_dai_stop(port_info);
}
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index e72f55428f0b..375dc6dfba4e 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -11,12 +11,9 @@
* option) any later version.
*/
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
#include <sound/soc.h>
-#include <linux/bitmap.h>
-#include <linux/rbtree.h>
#include <linux/export.h>
+#include <linux/slab.h>
#include <trace/events/asoc.h>
@@ -39,7 +36,8 @@ static bool snd_soc_set_cache_val(void *base, unsigned int idx,
break;
}
default:
- BUG();
+ WARN(1, "Invalid word_size %d\n", word_size);
+ break;
}
return false;
}
@@ -60,132 +58,49 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
return cache[idx];
}
default:
- BUG();
+ WARN(1, "Invalid word_size %d\n", word_size);
+ break;
}
/* unreachable */
return -1;
}
-static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
+int snd_soc_cache_init(struct snd_soc_codec *codec)
{
- int i;
- int ret;
- const struct snd_soc_codec_driver *codec_drv;
- unsigned int val;
+ const struct snd_soc_codec_driver *codec_drv = codec->driver;
+ size_t reg_size;
- codec_drv = codec->driver;
- for (i = 0; i < codec_drv->reg_cache_size; ++i) {
- ret = snd_soc_cache_read(codec, i, &val);
- if (ret)
- return ret;
- if (codec->reg_def_copy)
- if (snd_soc_get_cache_val(codec->reg_def_copy,
- i, codec_drv->reg_word_size) == val)
- continue;
-
- WARN_ON(!snd_soc_codec_writable_register(codec, i));
+ reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
- ret = snd_soc_write(codec, i, val);
- if (ret)
- return ret;
- dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n",
- i, val);
- }
- return 0;
-}
-
-static int snd_soc_flat_cache_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
-{
- snd_soc_set_cache_val(codec->reg_cache, reg, value,
- codec->driver->reg_word_size);
- return 0;
-}
-
-static int snd_soc_flat_cache_read(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int *value)
-{
- *value = snd_soc_get_cache_val(codec->reg_cache, reg,
- codec->driver->reg_word_size);
- return 0;
-}
+ mutex_init(&codec->cache_rw_mutex);
-static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec)
-{
- if (!codec->reg_cache)
- return 0;
- kfree(codec->reg_cache);
- codec->reg_cache = NULL;
- return 0;
-}
+ dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n",
+ codec->name);
-static int snd_soc_flat_cache_init(struct snd_soc_codec *codec)
-{
- if (codec->reg_def_copy)
- codec->reg_cache = kmemdup(codec->reg_def_copy,
- codec->reg_size, GFP_KERNEL);
+ if (codec_drv->reg_cache_default)
+ codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
+ reg_size, GFP_KERNEL);
else
- codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL);
+ codec->reg_cache = kzalloc(reg_size, GFP_KERNEL);
if (!codec->reg_cache)
return -ENOMEM;
return 0;
}
-/* an array of all supported compression types */
-static const struct snd_soc_cache_ops cache_types[] = {
- /* Flat *must* be the first entry for fallback */
- {
- .id = SND_SOC_FLAT_COMPRESSION,
- .name = "flat",
- .init = snd_soc_flat_cache_init,
- .exit = snd_soc_flat_cache_exit,
- .read = snd_soc_flat_cache_read,
- .write = snd_soc_flat_cache_write,
- .sync = snd_soc_flat_cache_sync
- },
-};
-
-int snd_soc_cache_init(struct snd_soc_codec *codec)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cache_types); ++i)
- if (cache_types[i].id == codec->compress_type)
- break;
-
- /* Fall back to flat compression */
- if (i == ARRAY_SIZE(cache_types)) {
- dev_warn(codec->dev, "ASoC: Could not match compress type: %d\n",
- codec->compress_type);
- i = 0;
- }
-
- mutex_init(&codec->cache_rw_mutex);
- codec->cache_ops = &cache_types[i];
-
- if (codec->cache_ops->init) {
- if (codec->cache_ops->name)
- dev_dbg(codec->dev, "ASoC: Initializing %s cache for %s codec\n",
- codec->cache_ops->name, codec->name);
- return codec->cache_ops->init(codec);
- }
- return -ENOSYS;
-}
-
/*
* NOTE: keep in mind that this function might be called
* multiple times.
*/
int snd_soc_cache_exit(struct snd_soc_codec *codec)
{
- if (codec->cache_ops && codec->cache_ops->exit) {
- if (codec->cache_ops->name)
- dev_dbg(codec->dev, "ASoC: Destroying %s cache for %s codec\n",
- codec->cache_ops->name, codec->name);
- return codec->cache_ops->exit(codec);
- }
- return -ENOSYS;
+ dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n",
+ codec->name);
+ if (!codec->reg_cache)
+ return 0;
+ kfree(codec->reg_cache);
+ codec->reg_cache = NULL;
+ return 0;
}
/**
@@ -198,18 +113,15 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
int snd_soc_cache_read(struct snd_soc_codec *codec,
unsigned int reg, unsigned int *value)
{
- int ret;
+ if (!value)
+ return -EINVAL;
mutex_lock(&codec->cache_rw_mutex);
-
- if (value && codec->cache_ops && codec->cache_ops->read) {
- ret = codec->cache_ops->read(codec, reg, value);
- mutex_unlock(&codec->cache_rw_mutex);
- return ret;
- }
-
+ *value = snd_soc_get_cache_val(codec->reg_cache, reg,
+ codec->driver->reg_word_size);
mutex_unlock(&codec->cache_rw_mutex);
- return -ENOSYS;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_cache_read);
@@ -223,20 +135,42 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_read);
int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
+ mutex_lock(&codec->cache_rw_mutex);
+ snd_soc_set_cache_val(codec->reg_cache, reg, value,
+ codec->driver->reg_word_size);
+ mutex_unlock(&codec->cache_rw_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_cache_write);
+
+static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
+{
+ int i;
int ret;
+ const struct snd_soc_codec_driver *codec_drv;
+ unsigned int val;
- mutex_lock(&codec->cache_rw_mutex);
+ codec_drv = codec->driver;
+ for (i = 0; i < codec_drv->reg_cache_size; ++i) {
+ ret = snd_soc_cache_read(codec, i, &val);
+ if (ret)
+ return ret;
+ if (codec_drv->reg_cache_default)
+ if (snd_soc_get_cache_val(codec_drv->reg_cache_default,
+ i, codec_drv->reg_word_size) == val)
+ continue;
- if (codec->cache_ops && codec->cache_ops->write) {
- ret = codec->cache_ops->write(codec, reg, value);
- mutex_unlock(&codec->cache_rw_mutex);
- return ret;
- }
+ WARN_ON(!snd_soc_codec_writable_register(codec, i));
- mutex_unlock(&codec->cache_rw_mutex);
- return -ENOSYS;
+ ret = snd_soc_write(codec, i, val);
+ if (ret)
+ return ret;
+ dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n",
+ i, val);
+ }
+ return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_cache_write);
/**
* snd_soc_cache_sync: Sync the register cache with the hardware.
@@ -249,92 +183,19 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write);
*/
int snd_soc_cache_sync(struct snd_soc_codec *codec)
{
+ const char *name = "flat";
int ret;
- const char *name;
- if (!codec->cache_sync) {
+ if (!codec->cache_sync)
return 0;
- }
-
- if (!codec->cache_ops || !codec->cache_ops->sync)
- return -ENOSYS;
- if (codec->cache_ops->name)
- name = codec->cache_ops->name;
- else
- name = "unknown";
-
- if (codec->cache_ops->name)
- dev_dbg(codec->dev, "ASoC: Syncing %s cache for %s codec\n",
- codec->cache_ops->name, codec->name);
+ dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n",
+ codec->name);
trace_snd_soc_cache_sync(codec, name, "start");
- ret = codec->cache_ops->sync(codec);
+ ret = snd_soc_flat_cache_sync(codec);
if (!ret)
codec->cache_sync = 0;
trace_snd_soc_cache_sync(codec, name, "end");
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
-
-static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- const struct snd_soc_codec_driver *codec_drv;
- unsigned int min, max, index;
-
- codec_drv = codec->driver;
- min = 0;
- max = codec_drv->reg_access_size - 1;
- do {
- index = (min + max) / 2;
- if (codec_drv->reg_access_default[index].reg == reg)
- return index;
- if (codec_drv->reg_access_default[index].reg < reg)
- min = index + 1;
- else
- max = index;
- } while (min <= max);
- return -1;
-}
-
-int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- int index;
-
- if (reg >= codec->driver->reg_cache_size)
- return 1;
- index = snd_soc_get_reg_access_index(codec, reg);
- if (index < 0)
- return 0;
- return codec->driver->reg_access_default[index].vol;
-}
-EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register);
-
-int snd_soc_default_readable_register(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- int index;
-
- if (reg >= codec->driver->reg_cache_size)
- return 1;
- index = snd_soc_get_reg_access_index(codec, reg);
- if (index < 0)
- return 0;
- return codec->driver->reg_access_default[index].read;
-}
-EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
-
-int snd_soc_default_writable_register(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- int index;
-
- if (reg >= codec->driver->reg_cache_size)
- return 1;
- index = snd_soc_get_reg_access_index(codec, reg);
- if (index < 0)
- return 0;
- return codec->driver->reg_access_default[index].write;
-}
-EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 53c9ecdd119f..5e9690c85d8f 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -24,6 +24,7 @@
#include <sound/compress_driver.h>
#include <sound/soc.h>
#include <sound/initval.h>
+#include <sound/soc-dpcm.h>
static int soc_compr_open(struct snd_compr_stream *cstream)
{
@@ -75,6 +76,98 @@ out:
return ret;
}
+static int soc_compr_open_fe(struct snd_compr_stream *cstream)
+{
+ struct snd_soc_pcm_runtime *fe = cstream->private_data;
+ struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
+ struct snd_soc_platform *platform = fe->platform;
+ struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *codec_dai = fe->codec_dai;
+ struct snd_soc_dpcm *dpcm;
+ struct snd_soc_dapm_widget_list *list;
+ int stream;
+ int ret = 0;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ else
+ stream = SNDRV_PCM_STREAM_CAPTURE;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+ if (platform->driver->compr_ops && platform->driver->compr_ops->open) {
+ ret = platform->driver->compr_ops->open(cstream);
+ if (ret < 0) {
+ pr_err("compress asoc: can't open platform %s\n", platform->name);
+ goto out;
+ }
+ }
+
+ if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
+ ret = fe->dai_link->compr_ops->startup(cstream);
+ if (ret < 0) {
+ pr_err("compress asoc: %s startup failed\n", fe->dai_link->name);
+ goto machine_err;
+ }
+ }
+
+ fe->dpcm[stream].runtime = fe_substream->runtime;
+
+ if (dpcm_path_get(fe, stream, &list) <= 0) {
+ dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
+ fe->dai_link->name, stream ? "capture" : "playback");
+ }
+
+ /* calculate valid and active FE <-> BE dpcms */
+ dpcm_process_paths(fe, stream, &list, 1);
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_startup(fe, stream);
+ if (ret < 0) {
+ /* clean up all links */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+ dpcm_be_disconnect(fe, stream);
+ fe->dpcm[stream].runtime = NULL;
+ goto fe_err;
+ }
+
+ dpcm_clear_pending_state(fe, stream);
+ dpcm_path_put(&list);
+
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ cpu_dai->playback_active++;
+ codec_dai->playback_active++;
+ } else {
+ cpu_dai->capture_active++;
+ codec_dai->capture_active++;
+ }
+
+ cpu_dai->active++;
+ codec_dai->active++;
+ fe->codec->active++;
+
+ mutex_unlock(&fe->card->mutex);
+
+ return 0;
+
+fe_err:
+ if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
+ fe->dai_link->compr_ops->shutdown(cstream);
+machine_err:
+ if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+ platform->driver->compr_ops->free(cstream);
+out:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+}
+
/*
* Power down the audio subsystem pmdown_time msecs after close is called.
* This is to ensure there are no pops or clicks in between any music tracks
@@ -164,6 +257,65 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
return 0;
}
+static int soc_compr_free_fe(struct snd_compr_stream *cstream)
+{
+ struct snd_soc_pcm_runtime *fe = cstream->private_data;
+ struct snd_soc_platform *platform = fe->platform;
+ struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dai *codec_dai = fe->codec_dai;
+ struct snd_soc_dpcm *dpcm;
+ int stream, ret;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK) {
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ cpu_dai->playback_active--;
+ codec_dai->playback_active--;
+ } else {
+ stream = SNDRV_PCM_STREAM_CAPTURE;
+ cpu_dai->capture_active--;
+ codec_dai->capture_active--;
+ }
+
+ cpu_dai->active--;
+ codec_dai->active--;
+ fe->codec->active--;
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_hw_free(fe, stream);
+ if (ret < 0)
+ dev_err(fe->dev, "compressed hw_free failed %d\n", ret);
+
+ ret = dpcm_be_dai_shutdown(fe, stream);
+
+ /* mark FE's links ready to prune */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
+ else
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
+
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+ dpcm_be_disconnect(fe, stream);
+
+ fe->dpcm[stream].runtime = NULL;
+
+ if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
+ fe->dai_link->compr_ops->shutdown(cstream);
+
+ if (platform->driver->compr_ops && platform->driver->compr_ops->free)
+ platform->driver->compr_ops->free(cstream);
+
+ mutex_unlock(&fe->card->mutex);
+ return 0;
+}
+
static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd)
{
@@ -194,6 +346,59 @@ out:
return ret;
}
+static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd)
+{
+ struct snd_soc_pcm_runtime *fe = cstream->private_data;
+ struct snd_soc_platform *platform = fe->platform;
+ int ret = 0, stream;
+
+ if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN ||
+ cmd == SND_COMPR_TRIGGER_DRAIN) {
+
+ if (platform->driver->compr_ops &&
+ platform->driver->compr_ops->trigger)
+ return platform->driver->compr_ops->trigger(cstream, cmd);
+ }
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ else
+ stream = SNDRV_PCM_STREAM_CAPTURE;
+
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+ if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) {
+ ret = platform->driver->compr_ops->trigger(cstream, cmd);
+ if (ret < 0)
+ goto out;
+ }
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_trigger(fe, stream, cmd);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
+ break;
+ }
+
+out:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+}
+
static int soc_compr_set_params(struct snd_compr_stream *cstream,
struct snd_compr_params *params)
{
@@ -241,6 +446,64 @@ err:
return ret;
}
+static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
+ struct snd_compr_params *params)
+{
+ struct snd_soc_pcm_runtime *fe = cstream->private_data;
+ struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream;
+ struct snd_soc_platform *platform = fe->platform;
+ int ret = 0, stream;
+
+ if (cstream->direction == SND_COMPRESS_PLAYBACK)
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ else
+ stream = SNDRV_PCM_STREAM_CAPTURE;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+ if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
+ ret = platform->driver->compr_ops->set_params(cstream, params);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->set_params) {
+ ret = fe->dai_link->compr_ops->set_params(cstream);
+ if (ret < 0)
+ goto out;
+ }
+
+ /*
+ * Create an empty hw_params for the BE as the machine driver must
+ * fix this up to match DSP decoder and ASRC configuration.
+ * I.e. machine driver fixup for compressed BE is mandatory.
+ */
+ memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
+ sizeof(struct snd_pcm_hw_params));
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_hw_params(fe, stream);
+ if (ret < 0)
+ goto out;
+
+ ret = dpcm_be_dai_prepare(fe, stream);
+ if (ret < 0)
+ goto out;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
+ else
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
+
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+
+out:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+}
+
static int soc_compr_get_params(struct snd_compr_stream *cstream,
struct snd_codec *params)
{
@@ -360,6 +623,7 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
return ret;
}
+
/* ASoC Compress operations */
static struct snd_compr_ops soc_compr_ops = {
.open = soc_compr_open,
@@ -375,6 +639,21 @@ static struct snd_compr_ops soc_compr_ops = {
.get_codec_caps = soc_compr_get_codec_caps
};
+/* ASoC Dynamic Compress operations */
+static struct snd_compr_ops soc_compr_dyn_ops = {
+ .open = soc_compr_open_fe,
+ .free = soc_compr_free_fe,
+ .set_params = soc_compr_set_params_fe,
+ .get_params = soc_compr_get_params,
+ .set_metadata = soc_compr_set_metadata,
+ .get_metadata = soc_compr_get_metadata,
+ .trigger = soc_compr_trigger_fe,
+ .pointer = soc_compr_pointer,
+ .ack = soc_compr_ack,
+ .get_caps = soc_compr_get_caps,
+ .get_codec_caps = soc_compr_get_codec_caps
+};
+
/* create a new compress */
int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
{
@@ -383,6 +662,7 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_compr *compr;
+ struct snd_pcm *be_pcm;
char new_name[64];
int ret = 0, direction = 0;
@@ -410,7 +690,26 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
ret = -ENOMEM;
goto compr_err;
}
- memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
+
+ if (rtd->dai_link->dynamic) {
+ snprintf(new_name, sizeof(new_name), "(%s)",
+ rtd->dai_link->stream_name);
+
+ ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+ 1, 0, &be_pcm);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
+ rtd->dai_link->name);
+ goto compr_err;
+ }
+
+ rtd->pcm = be_pcm;
+ rtd->fe_compr = 1;
+ be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
+ be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
+ memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
+ } else
+ memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
/* Add copy callback for not memory mapped DSPs */
if (platform->driver->compr_ops && platform->driver->compr_ops->copy)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4d0561312f3b..fe1df50805a3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -662,6 +662,8 @@ int snd_soc_suspend(struct device *dev)
codec->cache_sync = 1;
if (codec->using_regmap)
regcache_mark_dirty(codec->control_data);
+ /* deactivate pins to sleep state */
+ pinctrl_pm_select_sleep_state(codec->dev);
break;
default:
dev_dbg(codec->dev,
@@ -679,6 +681,9 @@ int snd_soc_suspend(struct device *dev)
if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
cpu_dai->driver->suspend(cpu_dai);
+
+ /* deactivate pins to sleep state */
+ pinctrl_pm_select_sleep_state(cpu_dai->dev);
}
if (card->suspend_post)
@@ -807,6 +812,16 @@ int snd_soc_resume(struct device *dev)
if (list_empty(&card->codec_dev_list))
return 0;
+ /* activate pins from sleep state */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
+ if (cpu_dai->active)
+ pinctrl_pm_select_default_state(cpu_dai->dev);
+ if (codec_dai->active)
+ pinctrl_pm_select_default_state(codec_dai->dev);
+ }
+
/* AC97 devices might have other drivers hanging off them so
* need to resume immediately. Other drivers don't have that
* problem and may take a substantial amount of time to resume
@@ -1380,7 +1395,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
return -ENODEV;
list_add(&cpu_dai->dapm.list, &card->dapm_list);
- snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
}
if (cpu_dai->driver->probe) {
@@ -1590,17 +1604,13 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num)
soc_remove_codec(codec);
}
-static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
- enum snd_soc_compress_type compress_type)
+static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
{
int ret;
if (codec->cache_init)
return 0;
- /* override the compress_type if necessary */
- if (compress_type && codec->compress_type != compress_type)
- codec->compress_type = compress_type;
ret = snd_soc_cache_init(codec);
if (ret < 0) {
dev_err(codec->dev,
@@ -1615,8 +1625,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
- struct snd_soc_codec_conf *codec_conf;
- enum snd_soc_compress_type compress_type;
struct snd_soc_dai_link *dai_link;
int ret, i, order, dai_fmt;
@@ -1640,19 +1648,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
list_for_each_entry(codec, &codec_list, list) {
if (codec->cache_init)
continue;
- /* by default we don't override the compress_type */
- compress_type = 0;
- /* check to see if we need to override the compress_type */
- for (i = 0; i < card->num_configs; ++i) {
- codec_conf = &card->codec_conf[i];
- if (!strcmp(codec->name, codec_conf->dev_name)) {
- compress_type = codec_conf->compress_type;
- if (compress_type && compress_type
- != codec->compress_type)
- break;
- }
- }
- ret = snd_soc_init_codec_cache(codec, compress_type);
+ ret = snd_soc_init_codec_cache(codec);
if (ret < 0)
goto base_error;
}
@@ -1732,6 +1728,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
}
snd_soc_dapm_link_dai_widgets(card);
+ snd_soc_dapm_connect_dai_link_widgets(card);
if (card->controls)
snd_soc_add_card_controls(card, card->controls, card->num_controls);
@@ -1948,6 +1945,14 @@ int snd_soc_poweroff(struct device *dev)
snd_soc_dapm_shutdown(card);
+ /* deactivate pins to sleep state */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
+ pinctrl_pm_select_sleep_state(cpu_dai->dev);
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_poweroff);
@@ -2298,13 +2303,6 @@ unsigned int snd_soc_write(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_soc_write);
-unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
- unsigned int reg, const void *data, size_t len)
-{
- return codec->bulk_write_raw(codec, reg, data, len);
-}
-EXPORT_SYMBOL_GPL(snd_soc_bulk_write_raw);
-
/**
* snd_soc_update_bits - update codec register bits
* @codec: audio codec
@@ -2577,8 +2575,9 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
if (uinfo->value.enumerated.item > e->max - 1)
uinfo->value.enumerated.item = e->max - 1;
- strcpy(uinfo->value.enumerated.name,
- e->texts[uinfo->value.enumerated.item]);
+ strlcpy(uinfo->value.enumerated.name,
+ e->texts[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name));
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
@@ -3214,11 +3213,11 @@ int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
break;
case 2:
((u16 *)(&ucontrol->value.bytes.data))[0]
- &= ~params->mask;
+ &= cpu_to_be16(~params->mask);
break;
case 4:
((u32 *)(&ucontrol->value.bytes.data))[0]
- &= ~params->mask;
+ &= cpu_to_be32(~params->mask);
break;
default:
return -EINVAL;
@@ -3486,7 +3485,7 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
return dai->codec->driver->set_sysclk(dai->codec, clk_id, 0,
freq, dir);
else
- return -EINVAL;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
@@ -3507,7 +3506,7 @@ int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
return codec->driver->set_sysclk(codec, clk_id, source,
freq, dir);
else
- return -EINVAL;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk);
@@ -3577,6 +3576,22 @@ int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll);
/**
+ * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
+ * @dai: DAI
+ * @ratio Ratio of BCLK to Sample rate.
+ *
+ * Configures the DAI for a preset BCLK to sample rate ratio.
+ */
+int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ if (dai->driver && dai->driver->ops->set_bclk_ratio)
+ return dai->driver->ops->set_bclk_ratio(dai, ratio);
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
+
+/**
* snd_soc_dai_set_fmt - configure DAI hardware audio format.
* @dai: DAI
* @fmt: SND_SOC_DAIFMT_ format value.
@@ -3776,6 +3791,16 @@ int snd_soc_register_card(struct snd_soc_card *card)
if (ret != 0)
soc_cleanup_card_debugfs(card);
+ /* deactivate pins to sleep state */
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
+ struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
+ if (!codec_dai->active)
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
+ if (!cpu_dai->active)
+ pinctrl_pm_select_sleep_state(cpu_dai->dev);
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_card);
@@ -4021,6 +4046,113 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count)
}
/**
+ * snd_soc_register_component - Register a component with the ASoC core
+ *
+ */
+static int
+__snd_soc_register_component(struct device *dev,
+ struct snd_soc_component *cmpnt,
+ const struct snd_soc_component_driver *cmpnt_drv,
+ struct snd_soc_dai_driver *dai_drv,
+ int num_dai, bool allow_single_dai)
+{
+ int ret;
+
+ dev_dbg(dev, "component register %s\n", dev_name(dev));
+
+ if (!cmpnt) {
+ dev_err(dev, "ASoC: Failed to connecting component\n");
+ return -ENOMEM;
+ }
+
+ cmpnt->name = fmt_single_name(dev, &cmpnt->id);
+ if (!cmpnt->name) {
+ dev_err(dev, "ASoC: Failed to simplifying name\n");
+ return -ENOMEM;
+ }
+
+ cmpnt->dev = dev;
+ cmpnt->driver = cmpnt_drv;
+ cmpnt->dai_drv = dai_drv;
+ cmpnt->num_dai = num_dai;
+
+ /*
+ * snd_soc_register_dai() uses fmt_single_name(), and
+ * snd_soc_register_dais() uses fmt_multiple_name()
+ * for dai->name which is used for name based matching
+ *
+ * this function is used from cpu/codec.
+ * allow_single_dai flag can ignore "codec" driver reworking
+ * since it had been used snd_soc_register_dais(),
+ */
+ if ((1 == num_dai) && allow_single_dai)
+ ret = snd_soc_register_dai(dev, dai_drv);
+ else
+ ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ if (ret < 0) {
+ dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+ goto error_component_name;
+ }
+
+ mutex_lock(&client_mutex);
+ list_add(&cmpnt->list, &component_list);
+ mutex_unlock(&client_mutex);
+
+ dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
+
+ return ret;
+
+error_component_name:
+ kfree(cmpnt->name);
+
+ return ret;
+}
+
+int snd_soc_register_component(struct device *dev,
+ const struct snd_soc_component_driver *cmpnt_drv,
+ struct snd_soc_dai_driver *dai_drv,
+ int num_dai)
+{
+ struct snd_soc_component *cmpnt;
+
+ cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
+ if (!cmpnt) {
+ dev_err(dev, "ASoC: Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ return __snd_soc_register_component(dev, cmpnt, cmpnt_drv,
+ dai_drv, num_dai, true);
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_component);
+
+/**
+ * snd_soc_unregister_component - Unregister a component from the ASoC core
+ *
+ */
+void snd_soc_unregister_component(struct device *dev)
+{
+ struct snd_soc_component *cmpnt;
+
+ list_for_each_entry(cmpnt, &component_list, list) {
+ if (dev == cmpnt->dev)
+ goto found;
+ }
+ return;
+
+found:
+ snd_soc_unregister_dais(dev, cmpnt->num_dai);
+
+ mutex_lock(&client_mutex);
+ list_del(&cmpnt->list);
+ mutex_unlock(&client_mutex);
+
+ dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
+ kfree(cmpnt->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
+
+/**
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
* @platform: The platform to add
@@ -4166,7 +4298,6 @@ int snd_soc_register_codec(struct device *dev,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
- size_t reg_size;
struct snd_soc_codec *codec;
int ret, i;
@@ -4183,11 +4314,6 @@ int snd_soc_register_codec(struct device *dev,
goto fail_codec;
}
- if (codec_drv->compress_type)
- codec->compress_type = codec_drv->compress_type;
- else
- codec->compress_type = SND_SOC_FLAT_COMPRESSION;
-
codec->write = codec_drv->write;
codec->read = codec_drv->read;
codec->volatile_register = codec_drv->volatile_register;
@@ -4204,35 +4330,6 @@ int snd_soc_register_codec(struct device *dev,
codec->num_dai = num_dai;
mutex_init(&codec->mutex);
- /* allocate CODEC register cache */
- if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
- reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
- codec->reg_size = reg_size;
- /* it is necessary to make a copy of the default register cache
- * because in the case of using a compression type that requires
- * the default register cache to be marked as the
- * kernel might have freed the array by the time we initialize
- * the cache.
- */
- if (codec_drv->reg_cache_default) {
- codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
- reg_size, GFP_KERNEL);
- if (!codec->reg_def_copy) {
- ret = -ENOMEM;
- goto fail_codec_name;
- }
- }
- }
-
- if (codec_drv->reg_access_size && codec_drv->reg_access_default) {
- if (!codec->volatile_register)
- codec->volatile_register = snd_soc_default_volatile_register;
- if (!codec->readable_register)
- codec->readable_register = snd_soc_default_readable_register;
- if (!codec->writable_register)
- codec->writable_register = snd_soc_default_writable_register;
- }
-
for (i = 0; i < num_dai; i++) {
fixup_codec_formats(&dai_drv[i].playback);
fixup_codec_formats(&dai_drv[i].capture);
@@ -4242,10 +4339,12 @@ int snd_soc_register_codec(struct device *dev,
list_add(&codec->list, &codec_list);
mutex_unlock(&client_mutex);
- /* register any DAIs */
- ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+ /* register component */
+ ret = __snd_soc_register_component(dev, &codec->component,
+ &codec_drv->component_driver,
+ dai_drv, num_dai, false);
if (ret < 0) {
- dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+ dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret);
goto fail_codec_name;
}
@@ -4280,7 +4379,7 @@ void snd_soc_unregister_codec(struct device *dev)
return;
found:
- snd_soc_unregister_dais(dev, codec->num_dai);
+ snd_soc_unregister_component(dev);
mutex_lock(&client_mutex);
list_del(&codec->list);
@@ -4289,98 +4388,11 @@ found:
dev_dbg(codec->dev, "ASoC: Unregistered codec '%s'\n", codec->name);
snd_soc_cache_exit(codec);
- kfree(codec->reg_def_copy);
kfree(codec->name);
kfree(codec);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
-
-/**
- * snd_soc_register_component - Register a component with the ASoC core
- *
- */
-int snd_soc_register_component(struct device *dev,
- const struct snd_soc_component_driver *cmpnt_drv,
- struct snd_soc_dai_driver *dai_drv,
- int num_dai)
-{
- struct snd_soc_component *cmpnt;
- int ret;
-
- dev_dbg(dev, "component register %s\n", dev_name(dev));
-
- cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
- if (!cmpnt) {
- dev_err(dev, "ASoC: Failed to allocate memory\n");
- return -ENOMEM;
- }
-
- cmpnt->name = fmt_single_name(dev, &cmpnt->id);
- if (!cmpnt->name) {
- dev_err(dev, "ASoC: Failed to simplifying name\n");
- return -ENOMEM;
- }
-
- cmpnt->dev = dev;
- cmpnt->driver = cmpnt_drv;
- cmpnt->num_dai = num_dai;
-
- /*
- * snd_soc_register_dai() uses fmt_single_name(), and
- * snd_soc_register_dais() uses fmt_multiple_name()
- * for dai->name which is used for name based matching
- */
- if (1 == num_dai)
- ret = snd_soc_register_dai(dev, dai_drv);
- else
- ret = snd_soc_register_dais(dev, dai_drv, num_dai);
- if (ret < 0) {
- dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
- goto error_component_name;
- }
-
- mutex_lock(&client_mutex);
- list_add(&cmpnt->list, &component_list);
- mutex_unlock(&client_mutex);
-
- dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
-
- return ret;
-
-error_component_name:
- kfree(cmpnt->name);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_register_component);
-
-/**
- * snd_soc_unregister_component - Unregister a component from the ASoC core
- *
- */
-void snd_soc_unregister_component(struct device *dev)
-{
- struct snd_soc_component *cmpnt;
-
- list_for_each_entry(cmpnt, &component_list, list) {
- if (dev == cmpnt->dev)
- goto found;
- }
- return;
-
-found:
- snd_soc_unregister_dais(dev, cmpnt->num_dai);
-
- mutex_lock(&client_mutex);
- list_del(&cmpnt->list);
- mutex_unlock(&client_mutex);
-
- dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
- kfree(cmpnt->name);
-}
-EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
-
/* Retrieve a card's name from device tree */
int snd_soc_of_parse_card_name(struct snd_soc_card *card,
const char *propname)
@@ -4568,6 +4580,64 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
+int snd_soc_of_get_dai_name(struct device_node *of_node,
+ const char **dai_name)
+{
+ struct snd_soc_component *pos;
+ struct of_phandle_args args;
+ int ret;
+
+ ret = of_parse_phandle_with_args(of_node, "sound-dai",
+ "#sound-dai-cells", 0, &args);
+ if (ret)
+ return ret;
+
+ ret = -EPROBE_DEFER;
+
+ mutex_lock(&client_mutex);
+ list_for_each_entry(pos, &component_list, list) {
+ if (pos->dev->of_node != args.np)
+ continue;
+
+ if (pos->driver->of_xlate_dai_name) {
+ ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name);
+ } else {
+ int id = -1;
+
+ switch (args.args_count) {
+ case 0:
+ id = 0; /* same as dai_drv[0] */
+ break;
+ case 1:
+ id = args.args[0];
+ break;
+ default:
+ /* not supported */
+ break;
+ }
+
+ if (id < 0 || id >= pos->num_dai) {
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = 0;
+
+ *dai_name = pos->dai_drv[id].name;
+ if (!*dai_name)
+ *dai_name = pos->name;
+ }
+
+ break;
+ }
+ mutex_unlock(&client_mutex);
+
+ of_node_put(args.np);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
+
static int __init snd_soc_init(void)
{
#ifdef CONFIG_DEBUG_FS
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c17c14c394df..dc8ff13187f7 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -59,31 +59,31 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0,
- [snd_soc_dapm_supply] = 1,
[snd_soc_dapm_regulator_supply] = 1,
[snd_soc_dapm_clock_supply] = 1,
- [snd_soc_dapm_micbias] = 2,
+ [snd_soc_dapm_supply] = 2,
+ [snd_soc_dapm_micbias] = 3,
[snd_soc_dapm_dai_link] = 2,
- [snd_soc_dapm_dai_in] = 3,
- [snd_soc_dapm_dai_out] = 3,
- [snd_soc_dapm_aif_in] = 3,
- [snd_soc_dapm_aif_out] = 3,
- [snd_soc_dapm_mic] = 4,
- [snd_soc_dapm_mux] = 5,
- [snd_soc_dapm_virt_mux] = 5,
- [snd_soc_dapm_value_mux] = 5,
- [snd_soc_dapm_dac] = 6,
- [snd_soc_dapm_switch] = 7,
- [snd_soc_dapm_mixer] = 7,
- [snd_soc_dapm_mixer_named_ctl] = 7,
- [snd_soc_dapm_pga] = 8,
- [snd_soc_dapm_adc] = 9,
- [snd_soc_dapm_out_drv] = 10,
- [snd_soc_dapm_hp] = 10,
- [snd_soc_dapm_spk] = 10,
- [snd_soc_dapm_line] = 10,
- [snd_soc_dapm_kcontrol] = 11,
- [snd_soc_dapm_post] = 12,
+ [snd_soc_dapm_dai_in] = 4,
+ [snd_soc_dapm_dai_out] = 4,
+ [snd_soc_dapm_aif_in] = 4,
+ [snd_soc_dapm_aif_out] = 4,
+ [snd_soc_dapm_mic] = 5,
+ [snd_soc_dapm_mux] = 6,
+ [snd_soc_dapm_virt_mux] = 6,
+ [snd_soc_dapm_value_mux] = 6,
+ [snd_soc_dapm_dac] = 7,
+ [snd_soc_dapm_switch] = 8,
+ [snd_soc_dapm_mixer] = 8,
+ [snd_soc_dapm_mixer_named_ctl] = 8,
+ [snd_soc_dapm_pga] = 9,
+ [snd_soc_dapm_adc] = 10,
+ [snd_soc_dapm_out_drv] = 11,
+ [snd_soc_dapm_hp] = 11,
+ [snd_soc_dapm_spk] = 11,
+ [snd_soc_dapm_line] = 11,
+ [snd_soc_dapm_kcontrol] = 12,
+ [snd_soc_dapm_post] = 13,
};
static int dapm_down_seq[] = {
@@ -109,10 +109,10 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_dai_in] = 10,
[snd_soc_dapm_dai_out] = 10,
[snd_soc_dapm_dai_link] = 11,
- [snd_soc_dapm_clock_supply] = 12,
- [snd_soc_dapm_regulator_supply] = 12,
[snd_soc_dapm_supply] = 12,
- [snd_soc_dapm_post] = 13,
+ [snd_soc_dapm_clock_supply] = 13,
+ [snd_soc_dapm_regulator_supply] = 13,
+ [snd_soc_dapm_post] = 14,
};
static void pop_wait(u32 pop_time)
@@ -371,12 +371,16 @@ static void dapm_reset(struct snd_soc_card *card)
}
}
-static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
+static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
+ unsigned int *value)
{
- if (w->codec)
- return snd_soc_read(w->codec, reg);
- else if (w->platform)
- return snd_soc_platform_read(w->platform, reg);
+ if (w->codec) {
+ *value = snd_soc_read(w->codec, reg);
+ return 0;
+ } else if (w->platform) {
+ *value = snd_soc_platform_read(w->platform, reg);
+ return 0;
+ }
dev_err(w->dapm->dev, "ASoC: no valid widget read method\n");
return -1;
@@ -409,6 +413,12 @@ static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
mutex_unlock(&w->platform->mutex);
}
+static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
+{
+ if (dapm->codec && dapm->codec->using_regmap)
+ regmap_async_complete(dapm->codec->control_data);
+}
+
static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
unsigned short reg, unsigned int mask, unsigned int value)
{
@@ -417,19 +427,19 @@ static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
int ret;
if (w->codec && w->codec->using_regmap) {
- ret = regmap_update_bits_check(w->codec->control_data,
- reg, mask, value, &change);
+ ret = regmap_update_bits_check_async(w->codec->control_data,
+ reg, mask, value,
+ &change);
if (ret != 0)
return ret;
} else {
soc_widget_lock(w);
- ret = soc_widget_read(w, reg);
+ ret = soc_widget_read(w, reg, &old);
if (ret < 0) {
soc_widget_unlock(w);
return ret;
}
- old = ret;
new = (old & ~mask) | (value & mask);
change = old != new;
if (change) {
@@ -499,18 +509,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
int val;
struct soc_mixer_control *mc = (struct soc_mixer_control *)
w->kcontrol_news[i].private_value;
- unsigned int reg = mc->reg;
+ 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;
- val = soc_widget_read(w, reg);
- val = (val >> shift) & mask;
- if (invert)
- val = max - val;
+ if (reg != SND_SOC_NOPM) {
+ soc_widget_read(w, reg, &val);
+ val = (val >> shift) & mask;
+ if (invert)
+ val = max - val;
+ p->connect = !!val;
+ } else {
+ p->connect = 0;
+ }
- p->connect = !!val;
}
break;
case snd_soc_dapm_mux: {
@@ -518,7 +532,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
w->kcontrol_news[i].private_value;
int val, item;
- val = soc_widget_read(w, e->reg);
+ soc_widget_read(w, e->reg, &val);
item = (val >> e->shift_l) & e->mask;
if (item < e->max && !strcmp(p->name, e->texts[item]))
@@ -547,7 +561,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
w->kcontrol_news[i].private_value;
int val, item;
- val = soc_widget_read(w, e->reg);
+ soc_widget_read(w, e->reg, &val);
val = (val >> e->shift_l) & e->mask;
for (item = 0; item < e->max; item++) {
if (val == e->values[item])
@@ -1197,6 +1211,8 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
{
int ret;
+ soc_dapm_async_complete(w->dapm);
+
if (SND_SOC_DAPM_EVENT_ON(event)) {
if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, false);
@@ -1230,6 +1246,8 @@ int dapm_clock_event(struct snd_soc_dapm_widget *w,
if (!w->clk)
return -EIO;
+ soc_dapm_async_complete(w->dapm);
+
#ifdef CONFIG_HAVE_CLK
if (SND_SOC_DAPM_EVENT_ON(event)) {
return clk_prepare_enable(w->clk);
@@ -1412,7 +1430,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card,
power = 0;
break;
default:
- BUG();
+ WARN(1, "Unknown event %d\n", event);
return;
}
@@ -1422,6 +1440,7 @@ static void dapm_seq_check_event(struct snd_soc_card *card,
if (w->event && (w->event_flags & event)) {
pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
w->name, ev_name);
+ soc_dapm_async_complete(w->dapm);
trace_snd_soc_dapm_widget_event_start(w, event);
ret = w->event(w, NULL, event);
trace_snd_soc_dapm_widget_event_done(w, event);
@@ -1444,7 +1463,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_card *card,
power_list)->reg;
list_for_each_entry(w, pending, power_list) {
- BUG_ON(reg != w->reg);
+ WARN_ON(reg != w->reg);
w->power = w->new_power;
mask |= w->mask << w->shift;
@@ -1494,6 +1513,7 @@ static void dapm_seq_run(struct snd_soc_card *card,
struct list_head *list, int event, bool power_up)
{
struct snd_soc_dapm_widget *w, *n;
+ struct snd_soc_dapm_context *d;
LIST_HEAD(pending);
int cur_sort = -1;
int cur_subseq = -1;
@@ -1524,6 +1544,9 @@ static void dapm_seq_run(struct snd_soc_card *card,
cur_subseq);
}
+ if (cur_dapm && w->dapm != cur_dapm)
+ soc_dapm_async_complete(cur_dapm);
+
INIT_LIST_HEAD(&pending);
cur_sort = -1;
cur_subseq = INT_MIN;
@@ -1582,6 +1605,10 @@ static void dapm_seq_run(struct snd_soc_card *card,
cur_dapm->seq_notifier(cur_dapm,
i, cur_subseq);
}
+
+ list_for_each_entry(d, &card->dapm_list, list) {
+ soc_dapm_async_complete(d);
+ }
}
static void dapm_widget_update(struct snd_soc_card *card)
@@ -1840,6 +1867,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
*/
switch (w->id) {
case snd_soc_dapm_siggen:
+ case snd_soc_dapm_vmid:
break;
case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply:
@@ -1949,7 +1977,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
w->active ? "active" : "inactive");
list_for_each_entry(p, &w->sources, list_sink) {
- if (p->connected && !p->connected(w, p->sink))
+ if (p->connected && !p->connected(w, p->source))
continue;
if (p->connect)
@@ -2001,7 +2029,7 @@ static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
level = "Off\n";
break;
default:
- BUG();
+ WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
level = "Unknown\n";
break;
}
@@ -2448,7 +2476,8 @@ err:
}
static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
- const struct snd_soc_dapm_route *route)
+ const struct snd_soc_dapm_route *route,
+ unsigned int is_prefixed)
{
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
@@ -2458,7 +2487,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
char prefixed_source[80];
int ret;
- if (dapm->codec && dapm->codec->name_prefix) {
+ if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
@@ -2586,7 +2615,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
- r = snd_soc_dapm_add_route(dapm, route);
+ r = snd_soc_dapm_add_route(dapm, route, false);
if (r < 0) {
dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
route->source,
@@ -2757,7 +2786,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
/* Read the initial power state from the device */
if (w->reg >= 0) {
- val = soc_widget_read(w, w->reg) >> w->shift;
+ soc_widget_read(w, w->reg, &val);
+ val = val >> w->shift;
val &= w->mask;
if (val == w->on_val)
w->power = 1;
@@ -2791,7 +2821,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
+ int reg = mc->reg;
unsigned int shift = mc->shift;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
@@ -2804,7 +2834,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
kcontrol->id.name);
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- if (dapm_kcontrol_is_powered(kcontrol))
+ if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM)
val = (snd_soc_read(codec, reg) >> shift) & mask;
else
val = dapm_kcontrol_get_value(kcontrol);
@@ -2835,7 +2865,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
+ int reg = mc->reg;
unsigned int shift = mc->shift;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
@@ -2843,6 +2873,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val;
int connect, change;
struct snd_soc_dapm_update update;
+ int ret = 0;
if (snd_soc_volsw_is_stereo(mc))
dev_warn(codec->dapm.dev,
@@ -2857,26 +2888,35 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- dapm_kcontrol_set_value(kcontrol, val);
+ change = dapm_kcontrol_set_value(kcontrol, val);
+
+ if (reg != SND_SOC_NOPM) {
+ mask = mask << shift;
+ val = val << shift;
- mask = mask << shift;
- val = val << shift;
+ change = snd_soc_test_bits(codec, reg, mask, val);
+ }
- change = snd_soc_test_bits(codec, reg, mask, val);
if (change) {
- update.kcontrol = kcontrol;
- update.reg = reg;
- update.mask = mask;
- update.val = val;
+ if (reg != SND_SOC_NOPM) {
+ update.kcontrol = kcontrol;
+ update.reg = reg;
+ update.mask = mask;
+ update.val = val;
- card->update = &update;
+ card->update = &update;
+ }
- soc_dapm_mixer_update_power(card, kcontrol, connect);
+ ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
card->update = NULL;
}
mutex_unlock(&card->dapm_mutex);
+
+ if (ret > 0)
+ soc_dpcm_runtime_update(card);
+
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2925,6 +2965,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
unsigned int val, mux, change;
unsigned int mask;
struct snd_soc_dapm_update update;
+ int ret = 0;
if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL;
@@ -2948,12 +2989,16 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
card->update = &update;
- soc_dapm_mux_update_power(card, kcontrol, mux, e);
+ ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
card->update = NULL;
}
mutex_unlock(&card->dapm_mutex);
+
+ if (ret > 0)
+ soc_dpcm_runtime_update(card);
+
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2989,6 +3034,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value;
int change;
+ int ret = 0;
if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL;
@@ -2998,9 +3044,13 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
value = ucontrol->value.enumerated.item[0];
change = dapm_kcontrol_set_value(kcontrol, value);
if (change)
- soc_dapm_mux_update_power(card, kcontrol, value, e);
+ ret = soc_dapm_mux_update_power(card, kcontrol, value, e);
mutex_unlock(&card->dapm_mutex);
+
+ if (ret > 0)
+ soc_dpcm_runtime_update(card);
+
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -3067,6 +3117,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
unsigned int val, mux, change;
unsigned int mask;
struct snd_soc_dapm_update update;
+ int ret = 0;
if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL;
@@ -3090,12 +3141,16 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
card->update = &update;
- soc_dapm_mux_update_power(card, kcontrol, mux, e);
+ ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
card->update = NULL;
}
mutex_unlock(&card->dapm_mutex);
+
+ if (ret > 0)
+ soc_dpcm_runtime_update(card);
+
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -3329,8 +3384,9 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
u64 fmt;
int ret;
- BUG_ON(!config);
- BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks));
+ if (WARN_ON(!config) ||
+ WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
+ return -EINVAL;
/* We only support a single source and sink, pick the first */
source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
@@ -3338,9 +3394,10 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
list_source);
- BUG_ON(!source_p || !sink_p);
- BUG_ON(!sink_p->source || !source_p->sink);
- BUG_ON(!source_p->source || !sink_p->sink);
+ if (WARN_ON(!source_p || !sink_p) ||
+ WARN_ON(!sink_p->source || !source_p->sink) ||
+ WARN_ON(!source_p->source || !sink_p->sink))
+ return -EINVAL;
source = source_p->source->priv;
sink = sink_p->sink->priv;
@@ -3416,7 +3473,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
break;
default:
- BUG();
+ WARN(1, "Unknown event %d\n", event);
return -EINVAL;
}
@@ -3495,6 +3552,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
if (!w) {
dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
dai->driver->playback.stream_name);
+ return -ENOMEM;
}
w->priv = dai;
@@ -3513,6 +3571,7 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
if (!w) {
dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
dai->driver->capture.stream_name);
+ return -ENOMEM;
}
w->priv = dai;
@@ -3580,6 +3639,55 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
return 0;
}
+void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd = card->rtd;
+ struct snd_soc_dai *cpu_dai, *codec_dai;
+ struct snd_soc_dapm_route r;
+ int i;
+
+ memset(&r, 0, sizeof(r));
+
+ /* for each BE DAI link... */
+ for (i = 0; i < card->num_rtd; i++) {
+ rtd = &card->rtd[i];
+ cpu_dai = rtd->cpu_dai;
+ codec_dai = rtd->codec_dai;
+
+ /* dynamic FE links have no fixed DAI mapping */
+ if (rtd->dai_link->dynamic)
+ continue;
+
+ /* there is no point in connecting BE DAI links with dummies */
+ if (snd_soc_dai_is_dummy(codec_dai) ||
+ snd_soc_dai_is_dummy(cpu_dai))
+ continue;
+
+ /* connect BE DAI playback if widgets are valid */
+ if (codec_dai->playback_widget && cpu_dai->playback_widget) {
+ r.source = cpu_dai->playback_widget->name;
+ r.sink = codec_dai->playback_widget->name;
+ dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
+ cpu_dai->codec->name, r.source,
+ codec_dai->platform->name, r.sink);
+
+ snd_soc_dapm_add_route(&card->dapm, &r, true);
+ }
+
+ /* connect BE DAI capture if widgets are valid */
+ if (codec_dai->capture_widget && cpu_dai->capture_widget) {
+ r.source = codec_dai->capture_widget->name;
+ r.sink = cpu_dai->capture_widget->name;
+ dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
+ codec_dai->codec->name, r.source,
+ cpu_dai->platform->name, r.sink);
+
+ snd_soc_dapm_add_route(&card->dapm, &r, true);
+ }
+
+ }
+}
+
static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
int event)
{
diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c
new file mode 100644
index 000000000000..7ac745df1412
--- /dev/null
+++ b/sound/soc/soc-devres.c
@@ -0,0 +1,127 @@
+/*
+ * soc-devres.c -- ALSA SoC Audio Layer devres functions
+ *
+ * Copyright (C) 2013 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+static void devm_component_release(struct device *dev, void *res)
+{
+ snd_soc_unregister_component(*(struct device **)res);
+}
+
+/**
+ * devm_snd_soc_register_component - resource managed component registration
+ * @dev: Device used to manage component
+ * @cmpnt_drv: Component driver
+ * @dai_drv: DAI driver
+ * @num_dai: Number of DAIs to register
+ *
+ * Register a component with automatic unregistration when the device is
+ * unregistered.
+ */
+int devm_snd_soc_register_component(struct device *dev,
+ const struct snd_soc_component_driver *cmpnt_drv,
+ struct snd_soc_dai_driver *dai_drv, int num_dai)
+{
+ struct device **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
+ if (ret == 0) {
+ *ptr = dev;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
+
+static void devm_card_release(struct device *dev, void *res)
+{
+ snd_soc_unregister_card(*(struct snd_soc_card **)res);
+}
+
+/**
+ * devm_snd_soc_register_card - resource managed card registration
+ * @dev: Device used to manage card
+ * @card: Card to register
+ *
+ * Register a card with automatic unregistration when the device is
+ * unregistered.
+ */
+int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card)
+{
+ struct snd_soc_card **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_card_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = snd_soc_register_card(card);
+ if (ret == 0) {
+ *ptr = card;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_snd_soc_register_card);
+
+#ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM
+
+static void devm_dmaengine_pcm_release(struct device *dev, void *res)
+{
+ snd_dmaengine_pcm_unregister(*(struct device **)res);
+}
+
+/**
+ * devm_snd_dmaengine_pcm_register - resource managed dmaengine PCM registration
+ * @dev: The parent device for the PCM device
+ * @config: Platform specific PCM configuration
+ * @flags: Platform specific quirks
+ *
+ * Register a dmaengine based PCM device with automatic unregistration when the
+ * device is unregistered.
+ */
+int devm_snd_dmaengine_pcm_register(struct device *dev,
+ const struct snd_dmaengine_pcm_config *config, unsigned int flags)
+{
+ struct device **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = snd_dmaengine_pcm_register(dev, config, flags);
+ if (ret == 0) {
+ *ptr = dev;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_snd_dmaengine_pcm_register);
+
+#endif
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index e29ec3cd84b1..5bace124ef43 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -25,7 +25,7 @@
#include <sound/dmaengine_pcm.h>
struct dmaengine_pcm {
- struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1];
+ struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
const struct snd_dmaengine_pcm_config *config;
struct snd_soc_platform platform;
unsigned int flags;
@@ -36,6 +36,15 @@ static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
return container_of(p, struct dmaengine_pcm, platform);
}
+static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
+ struct snd_pcm_substream *substream)
+{
+ if (!pcm->chan[substream->stream])
+ return NULL;
+
+ return pcm->chan[substream->stream]->device->dev;
+}
+
/**
* snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback
* @substream: PCM substream
@@ -75,12 +84,21 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+ int (*prepare_slave_config)(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct dma_slave_config *slave_config);
struct dma_slave_config slave_config;
int ret;
- if (pcm->config->prepare_slave_config) {
- ret = pcm->config->prepare_slave_config(substream, params,
- &slave_config);
+ memset(&slave_config, 0, sizeof(slave_config));
+
+ if (!pcm->config)
+ prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config;
+ else
+ prepare_slave_config = pcm->config->prepare_slave_config;
+
+ if (prepare_slave_config) {
+ ret = prepare_slave_config(substream, params, &slave_config);
if (ret)
return ret;
@@ -92,28 +110,59 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
-static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
+static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct device *dma_dev = dmaengine_dma_dev(pcm, substream);
struct dma_chan *chan = pcm->chan[substream->stream];
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ struct dma_slave_caps dma_caps;
+ struct snd_pcm_hardware hw;
int ret;
- ret = snd_soc_set_runtime_hwparams(substream,
+ if (pcm->config && pcm->config->pcm_hardware)
+ return snd_soc_set_runtime_hwparams(substream,
pcm->config->pcm_hardware);
- if (ret)
- return ret;
- return snd_dmaengine_pcm_open(substream, chan);
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ memset(&hw, 0, sizeof(hw));
+ hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED;
+ hw.periods_min = 2;
+ hw.periods_max = UINT_MAX;
+ hw.period_bytes_min = 256;
+ hw.period_bytes_max = dma_get_max_seg_size(dma_dev);
+ hw.buffer_bytes_max = SIZE_MAX;
+ hw.fifo_size = dma_data->fifo_size;
+
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
+ hw.info |= SNDRV_PCM_INFO_BATCH;
+
+ ret = dma_get_slave_caps(chan, &dma_caps);
+ if (ret == 0) {
+ if (dma_caps.cmd_pause)
+ hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME;
+ if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT)
+ hw.info |= SNDRV_PCM_INFO_BATCH;
+ }
+
+ return snd_soc_set_runtime_hwparams(substream, &hw);
}
-static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
- struct snd_pcm_substream *substream)
+static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
{
- if (!pcm->chan[substream->stream])
- return NULL;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct dma_chan *chan = pcm->chan[substream->stream];
+ int ret;
- return pcm->chan[substream->stream]->device->dev;
+ ret = dmaengine_pcm_set_runtime_hwparams(substream);
+ if (ret)
+ return ret;
+
+ return snd_dmaengine_pcm_open(substream, chan);
}
static void dmaengine_pcm_free(struct snd_pcm *pcm)
@@ -126,30 +175,71 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
struct snd_pcm_substream *substream)
{
struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_dmaengine_dai_dma_data *dma_data;
+ dma_filter_fn fn = NULL;
+
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) && pcm->chan[0])
return pcm->chan[0];
- if (pcm->config->compat_request_channel)
+ if (pcm->config && pcm->config->compat_request_channel)
return pcm->config->compat_request_channel(rtd, substream);
- return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn,
- snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
+ if (pcm->config)
+ fn = pcm->config->compat_filter_fn;
+
+ return snd_dmaengine_pcm_request_channel(fn, dma_data->filter_data);
+}
+
+static bool dmaengine_pcm_can_report_residue(struct dma_chan *chan)
+{
+ struct dma_slave_caps dma_caps;
+ int ret;
+
+ ret = dma_get_slave_caps(chan, &dma_caps);
+ if (ret != 0)
+ return true;
+
+ if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR)
+ return false;
+
+ return true;
}
static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
const struct snd_dmaengine_pcm_config *config = pcm->config;
+ struct device *dev = rtd->platform->dev;
+ struct snd_dmaengine_dai_dma_data *dma_data;
struct snd_pcm_substream *substream;
+ size_t prealloc_buffer_size;
+ size_t max_buffer_size;
unsigned int i;
int ret;
+ if (config && config->prealloc_buffer_size) {
+ prealloc_buffer_size = config->prealloc_buffer_size;
+ max_buffer_size = config->pcm_hardware->buffer_bytes_max;
+ } else {
+ prealloc_buffer_size = 512 * 1024;
+ max_buffer_size = SIZE_MAX;
+ }
+
+
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
substream = rtd->pcm->streams[i].substream;
if (!substream)
continue;
+ dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+ if (!pcm->chan[i] &&
+ (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME))
+ pcm->chan[i] = dma_request_slave_channel(dev,
+ dma_data->chan_name);
+
if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) {
pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,
substream);
@@ -163,12 +253,22 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
ret = snd_pcm_lib_preallocate_pages(substream,
- SNDRV_DMA_TYPE_DEV,
+ SNDRV_DMA_TYPE_DEV_IRAM,
dmaengine_dma_dev(pcm, substream),
- config->prealloc_buffer_size,
- config->pcm_hardware->buffer_bytes_max);
+ prealloc_buffer_size,
+ max_buffer_size);
if (ret)
goto err_free;
+
+ /*
+ * This will only return false if we know for sure that at least
+ * one channel does not support residue reporting. If the DMA
+ * driver does not implement the slave_caps API we rely having
+ * the NO_RESIDUE flag set manually in case residue reporting is
+ * not supported.
+ */
+ if (!dmaengine_pcm_can_report_residue(pcm->chan[i]))
+ pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE;
}
return 0;
@@ -178,6 +278,18 @@ err_free:
return ret;
}
+static snd_pcm_uframes_t dmaengine_pcm_pointer(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
+ return snd_dmaengine_pcm_pointer_no_residue(substream);
+ else
+ return snd_dmaengine_pcm_pointer(substream);
+}
+
static const struct snd_pcm_ops dmaengine_pcm_ops = {
.open = dmaengine_pcm_open,
.close = snd_dmaengine_pcm_close,
@@ -185,7 +297,7 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = {
.hw_params = dmaengine_pcm_hw_params,
.hw_free = snd_pcm_lib_free_pages,
.trigger = snd_dmaengine_pcm_trigger,
- .pointer = snd_dmaengine_pcm_pointer,
+ .pointer = dmaengine_pcm_pointer,
};
static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
@@ -195,44 +307,72 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
.probe_order = SND_SOC_COMP_ORDER_LATE,
};
-static const struct snd_pcm_ops dmaengine_no_residue_pcm_ops = {
- .open = dmaengine_pcm_open,
- .close = snd_dmaengine_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = dmaengine_pcm_hw_params,
- .hw_free = snd_pcm_lib_free_pages,
- .trigger = snd_dmaengine_pcm_trigger,
- .pointer = snd_dmaengine_pcm_pointer_no_residue,
-};
-
-static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = {
- .ops = &dmaengine_no_residue_pcm_ops,
- .pcm_new = dmaengine_pcm_new,
- .pcm_free = dmaengine_pcm_free,
- .probe_order = SND_SOC_COMP_ORDER_LATE,
-};
-
static const char * const dmaengine_pcm_dma_channel_names[] = {
[SNDRV_PCM_STREAM_PLAYBACK] = "tx",
[SNDRV_PCM_STREAM_CAPTURE] = "rx",
};
-static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
- struct device *dev)
+static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
+ struct device *dev, const struct snd_dmaengine_pcm_config *config)
{
unsigned int i;
+ const char *name;
+ struct dma_chan *chan;
+
+ if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT |
+ SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) ||
+ !dev->of_node)
+ return 0;
+
+ if (config && config->dma_dev) {
+ /*
+ * If this warning is seen, it probably means that your Linux
+ * device structure does not match your HW device structure.
+ * It would be best to refactor the Linux device structure to
+ * correctly match the HW structure.
+ */
+ dev_warn(dev, "DMA channels sourced from device %s",
+ dev_name(config->dma_dev));
+ dev = config->dma_dev;
+ }
- if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node)
- return;
+ for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE;
+ i++) {
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
+ name = "rx-tx";
+ else
+ name = dmaengine_pcm_dma_channel_names[i];
+ if (config && config->chan_names[i])
+ name = config->chan_names[i];
+ chan = dma_request_slave_channel_reason(dev, name);
+ if (IS_ERR(chan)) {
+ if (PTR_ERR(chan) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ pcm->chan[i] = NULL;
+ } else {
+ pcm->chan[i] = chan;
+ }
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
+ break;
+ }
- if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) {
- pcm->chan[0] = dma_request_slave_channel(dev, "rx-tx");
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
pcm->chan[1] = pcm->chan[0];
- } else {
- for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
- pcm->chan[i] = dma_request_slave_channel(dev,
- dmaengine_pcm_dma_channel_names[i]);
- }
+
+ return 0;
+}
+
+static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm)
+{
+ unsigned int i;
+
+ for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE;
+ i++) {
+ if (!pcm->chan[i])
+ continue;
+ dma_release_channel(pcm->chan[i]);
+ if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
+ break;
}
}
@@ -246,6 +386,7 @@ int snd_dmaengine_pcm_register(struct device *dev,
const struct snd_dmaengine_pcm_config *config, unsigned int flags)
{
struct dmaengine_pcm *pcm;
+ int ret;
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (!pcm)
@@ -254,14 +395,21 @@ int snd_dmaengine_pcm_register(struct device *dev,
pcm->config = config;
pcm->flags = flags;
- dmaengine_pcm_request_chan_of(pcm, dev);
+ ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
+ if (ret)
+ goto err_free_dma;
- if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
- return snd_soc_add_platform(dev, &pcm->platform,
- &dmaengine_no_residue_pcm_platform);
- else
- return snd_soc_add_platform(dev, &pcm->platform,
- &dmaengine_pcm_platform);
+ ret = snd_soc_add_platform(dev, &pcm->platform,
+ &dmaengine_pcm_platform);
+ if (ret)
+ goto err_free_dma;
+
+ return 0;
+
+err_free_dma:
+ dmaengine_pcm_release_chan(pcm);
+ kfree(pcm);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
@@ -276,7 +424,6 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
{
struct snd_soc_platform *platform;
struct dmaengine_pcm *pcm;
- unsigned int i;
platform = snd_soc_lookup_platform(dev);
if (!platform)
@@ -284,15 +431,8 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
pcm = soc_platform_to_pcm(platform);
- for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
- if (pcm->chan[i]) {
- dma_release_channel(pcm->chan[i]);
- if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
- break;
- }
- }
-
snd_soc_remove_platform(platform);
+ dmaengine_pcm_release_chan(pcm);
kfree(pcm);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 122c0c18b9dd..aa886cca3ecf 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -65,31 +65,6 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg)
return val;
}
-/* Primitive bulk write support for soc-cache. The data pointed to by
- * `data' needs to already be in the form the hardware expects. Any
- * data written through this function will not go through the cache as
- * it only handles writing to volatile or out of bounds registers.
- *
- * This is currently only supported for devices using the regmap API
- * wrappers.
- */
-static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec,
- unsigned int reg,
- const void *data, size_t len)
-{
- /* To ensure that we don't get out of sync with the cache, check
- * whether the base register is volatile or if we've directly asked
- * to bypass the cache. Out of bounds registers are considered
- * volatile.
- */
- if (!codec->cache_bypass
- && !snd_soc_codec_volatile_register(codec, reg)
- && reg < codec->driver->reg_cache_size)
- return -EINVAL;
-
- return regmap_raw_write(codec->control_data, reg, data, len);
-}
-
/**
* snd_soc_codec_set_cache_io: Set up standard I/O functions.
*
@@ -119,20 +94,19 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
memset(&config, 0, sizeof(config));
codec->write = hw_write;
codec->read = hw_read;
- codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
config.reg_bits = addr_bits;
config.val_bits = data_bits;
switch (control) {
-#if defined(CONFIG_REGMAP_I2C) || defined(CONFIG_REGMAP_I2C_MODULE)
+#if IS_ENABLED(CONFIG_REGMAP_I2C)
case SND_SOC_I2C:
codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev),
&config);
break;
#endif
-#if defined(CONFIG_REGMAP_SPI) || defined(CONFIG_REGMAP_SPI_MODULE)
+#if IS_ENABLED(CONFIG_REGMAP_SPI)
case SND_SOC_SPI:
codec->control_data = regmap_init_spi(to_spi_device(codec->dev),
&config);
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 71358e3b54d9..23d43dac91da 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -65,6 +65,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
struct snd_soc_codec *codec;
struct snd_soc_dapm_context *dapm;
struct snd_soc_jack_pin *pin;
+ unsigned int sync = 0;
int enable;
trace_snd_soc_jack_report(jack, mask, status);
@@ -92,12 +93,16 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
snd_soc_dapm_enable_pin(dapm, pin->pin);
else
snd_soc_dapm_disable_pin(dapm, pin->pin);
+
+ /* we need to sync for this case only */
+ sync = 1;
}
/* Report before the DAPM sync to help users updating micbias status */
blocking_notifier_call_chain(&jack->notifier, jack->status, jack);
- snd_soc_dapm_sync(dapm);
+ if (sync)
+ snd_soc_dapm_sync(dapm);
snd_jack_report(jack->jack, jack->status);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 330c9a6b5cb5..47e1ce771e65 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -57,7 +58,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
/* DPCM stream event, send event to FE and all active BEs. */
-static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
+int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
int event)
{
struct snd_soc_dpcm *dpcm;
@@ -83,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret;
- if (!soc_dai->driver->symmetric_rates &&
- !rtd->dai_link->symmetric_rates)
- return 0;
+ if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
+ rtd->dai_link->symmetric_rates)) {
+ dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
+ soc_dai->rate);
- /* This can happen if multiple streams are starting simultaneously -
- * the second can need to get its constraints before the first has
- * picked a rate. Complain and allow the application to carry on.
- */
- if (!soc_dai->rate) {
- dev_warn(soc_dai->dev,
- "ASoC: Not enforcing symmetric_rates due to race\n");
- return 0;
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ soc_dai->rate, soc_dai->rate);
+ if (ret < 0) {
+ dev_err(soc_dai->dev,
+ "ASoC: Unable to apply rate constraint: %d\n",
+ ret);
+ return ret;
+ }
}
- dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate);
+ if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
+ rtd->dai_link->symmetric_channels)) {
+ dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
+ soc_dai->channels);
- ret = snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- soc_dai->rate, soc_dai->rate);
- if (ret < 0) {
- dev_err(soc_dai->dev,
- "ASoC: Unable to apply rate symmetry constraint: %d\n",
- ret);
- return ret;
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ soc_dai->channels,
+ soc_dai->channels);
+ if (ret < 0) {
+ dev_err(soc_dai->dev,
+ "ASoC: Unable to apply channel symmetry constraint: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
+ rtd->dai_link->symmetric_samplebits)) {
+ dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
+ soc_dai->sample_bits);
+
+ ret = snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ soc_dai->sample_bits,
+ soc_dai->sample_bits);
+ if (ret < 0) {
+ dev_err(soc_dai->dev,
+ "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
+ ret);
+ return ret;
+ }
}
return 0;
}
+static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int rate, channels, sample_bits, symmetry;
+
+ rate = params_rate(params);
+ channels = params_channels(params);
+ sample_bits = snd_pcm_format_physical_width(params_format(params));
+
+ /* reject unmatched parameters when applying symmetry */
+ symmetry = cpu_dai->driver->symmetric_rates ||
+ codec_dai->driver->symmetric_rates ||
+ rtd->dai_link->symmetric_rates;
+ if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
+ dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
+ cpu_dai->rate, rate);
+ return -EINVAL;
+ }
+
+ symmetry = cpu_dai->driver->symmetric_channels ||
+ codec_dai->driver->symmetric_channels ||
+ rtd->dai_link->symmetric_channels;
+ if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
+ dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
+ cpu_dai->channels, channels);
+ return -EINVAL;
+ }
+
+ symmetry = cpu_dai->driver->symmetric_samplebits ||
+ codec_dai->driver->symmetric_samplebits ||
+ rtd->dai_link->symmetric_samplebits;
+ if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
+ dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
+ cpu_dai->sample_bits, sample_bits);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
+ struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver;
+ struct snd_soc_dai_link *link = rtd->dai_link;
+
+ return cpu_driver->symmetric_rates || codec_driver->symmetric_rates ||
+ link->symmetric_rates || cpu_driver->symmetric_channels ||
+ codec_driver->symmetric_channels || link->symmetric_channels ||
+ cpu_driver->symmetric_samplebits ||
+ codec_driver->symmetric_samplebits ||
+ link->symmetric_samplebits;
+}
+
/*
* List of sample sizes that might go over the bus for parameter
* application. There ought to be a wildcard sample size for things
@@ -147,24 +230,32 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
}
}
-static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw,
+static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
struct snd_soc_pcm_stream *codec_stream,
struct snd_soc_pcm_stream *cpu_stream)
{
- hw->rate_min = max(codec_stream->rate_min, cpu_stream->rate_min);
- hw->rate_max = max(codec_stream->rate_max, cpu_stream->rate_max);
+ struct snd_pcm_hardware *hw = &runtime->hw;
+
hw->channels_min = max(codec_stream->channels_min,
cpu_stream->channels_min);
hw->channels_max = min(codec_stream->channels_max,
cpu_stream->channels_max);
- hw->formats = codec_stream->formats & cpu_stream->formats;
- hw->rates = codec_stream->rates & cpu_stream->rates;
- if (codec_stream->rates
- & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- hw->rates |= cpu_stream->rates;
- if (cpu_stream->rates
- & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
- hw->rates |= codec_stream->rates;
+ if (hw->formats)
+ hw->formats &= codec_stream->formats & cpu_stream->formats;
+ else
+ hw->formats = codec_stream->formats & cpu_stream->formats;
+ hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates,
+ cpu_stream->rates);
+
+ hw->rate_min = 0;
+ hw->rate_max = UINT_MAX;
+
+ snd_pcm_limit_hw_rates(runtime);
+
+ hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
+ hw->rate_min = max(hw->rate_min, codec_stream->rate_min);
+ hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
+ hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max);
}
/*
@@ -183,6 +274,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
int ret = 0;
+ pinctrl_pm_select_default_state(cpu_dai->dev);
+ pinctrl_pm_select_default_state(codec_dai->dev);
pm_runtime_get_sync(cpu_dai->dev);
pm_runtime_get_sync(codec_dai->dev);
pm_runtime_get_sync(platform->dev);
@@ -190,7 +283,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
/* startup the audio subsystem */
- if (cpu_dai->driver->ops->startup) {
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {
ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "ASoC: can't open interface"
@@ -208,7 +301,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
- if (codec_dai->driver->ops->startup) {
+ if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {
ret = codec_dai->driver->ops->startup(substream, codec_dai);
if (ret < 0) {
dev_err(codec_dai->dev, "ASoC: can't open codec"
@@ -232,15 +325,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
/* Check that the codec and cpu DAIs are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->playback,
+ soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback,
&cpu_dai_drv->playback);
} else {
- soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->capture,
+ soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture,
&cpu_dai_drv->capture);
}
+ if (soc_pcm_has_symmetry(substream))
+ runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
+
ret = -EINVAL;
- snd_pcm_limit_hw_rates(runtime);
if (!runtime->hw.rates) {
printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
codec_dai->name, cpu_dai->name);
@@ -317,6 +412,10 @@ out:
pm_runtime_put(platform->dev);
pm_runtime_put(codec_dai->dev);
pm_runtime_put(cpu_dai->dev);
+ if (!codec_dai->active)
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
+ if (!cpu_dai->active)
+ pinctrl_pm_select_sleep_state(cpu_dai->dev);
return ret;
}
@@ -383,11 +482,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (!codec_dai->active)
codec_dai->rate = 0;
- /* Muting the DAC suppresses artifacts caused during digital
- * shutdown, for example from stopping clocks.
- */
- snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
-
if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai);
@@ -426,6 +520,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
pm_runtime_put(platform->dev);
pm_runtime_put(codec_dai->dev);
pm_runtime_put(cpu_dai->dev);
+ if (!codec_dai->active)
+ pinctrl_pm_select_sleep_state(codec_dai->dev);
+ if (!cpu_dai->active)
+ pinctrl_pm_select_sleep_state(cpu_dai->dev);
return 0;
}
@@ -463,7 +561,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- if (codec_dai->driver->ops->prepare) {
+ if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) {
ret = codec_dai->driver->ops->prepare(substream, codec_dai);
if (ret < 0) {
dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n",
@@ -472,7 +570,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
}
}
- if (cpu_dai->driver->ops->prepare) {
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n",
@@ -514,6 +612,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+ ret = soc_pcm_params_symmetry(substream, params);
+ if (ret)
+ goto out;
+
if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
ret = rtd->dai_link->ops->hw_params(substream, params);
if (ret < 0) {
@@ -523,7 +625,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- if (codec_dai->driver->ops->hw_params) {
+ if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) {
ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
if (ret < 0) {
dev_err(codec_dai->dev, "ASoC: can't set %s hw params:"
@@ -532,7 +634,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- if (cpu_dai->driver->ops->hw_params) {
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) {
ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
if (ret < 0) {
dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n",
@@ -550,20 +652,27 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
}
}
- /* store the rate for each DAIs */
+ /* store the parameters for each DAIs */
cpu_dai->rate = params_rate(params);
+ cpu_dai->channels = params_channels(params);
+ cpu_dai->sample_bits =
+ snd_pcm_format_physical_width(params_format(params));
+
codec_dai->rate = params_rate(params);
+ codec_dai->channels = params_channels(params);
+ codec_dai->sample_bits =
+ snd_pcm_format_physical_width(params_format(params));
out:
mutex_unlock(&rtd->pcm_mutex);
return ret;
platform_err:
- if (cpu_dai->driver->ops->hw_free)
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
interface_err:
- if (codec_dai->driver->ops->hw_free)
+ if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
codec_err:
@@ -583,12 +692,26 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
- struct snd_soc_codec *codec = rtd->codec;
+ bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
+ /* clear the corresponding DAIs parameters when going to be inactive */
+ if (cpu_dai->active == 1) {
+ cpu_dai->rate = 0;
+ cpu_dai->channels = 0;
+ cpu_dai->sample_bits = 0;
+ }
+
+ if (codec_dai->active == 1) {
+ codec_dai->rate = 0;
+ codec_dai->channels = 0;
+ codec_dai->sample_bits = 0;
+ }
+
/* apply codec digital mute */
- if (!codec->active)
+ if ((playback && codec_dai->playback_active == 1) ||
+ (!playback && codec_dai->capture_active == 1))
snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
/* free any machine hw params */
@@ -600,10 +723,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
platform->driver->ops->hw_free(substream);
/* now free hw params for the DAIs */
- if (codec_dai->driver->ops->hw_free)
+ if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free)
codec_dai->driver->ops->hw_free(substream, codec_dai);
- if (cpu_dai->driver->ops->hw_free)
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
mutex_unlock(&rtd->pcm_mutex);
@@ -618,7 +741,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->driver->ops->trigger) {
+ if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) {
ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
if (ret < 0)
return ret;
@@ -630,7 +753,7 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
- if (cpu_dai->driver->ops->trigger) {
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->trigger) {
ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
@@ -647,7 +770,8 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret;
- if (codec_dai->driver->ops->bespoke_trigger) {
+ if (codec_dai->driver->ops &&
+ codec_dai->driver->ops->bespoke_trigger) {
ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
if (ret < 0)
return ret;
@@ -659,7 +783,7 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
return ret;
}
- if (cpu_dai->driver->ops->bespoke_trigger) {
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->bespoke_trigger) {
ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
if (ret < 0)
return ret;
@@ -684,10 +808,10 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
if (platform->driver->ops && platform->driver->ops->pointer)
offset = platform->driver->ops->pointer(substream);
- if (cpu_dai->driver->ops->delay)
+ if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay)
delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
- if (codec_dai->driver->ops->delay)
+ if (codec_dai->driver->ops && codec_dai->driver->ops->delay)
delay += codec_dai->driver->ops->delay(substream, codec_dai);
if (platform->driver->delay)
@@ -721,7 +845,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
- dev_dbg(fe->dev, " connected new DPCM %s path %s %s %s\n",
+ dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n",
stream ? "capture" : "playback", fe->dai_link->name,
stream ? "<-" : "->", be->dai_link->name);
@@ -749,7 +873,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
if (dpcm->fe == fe)
continue;
- dev_dbg(fe->dev, " reparent %s path %s %s %s\n",
+ dev_dbg(fe->dev, "reparent %s path %s %s %s\n",
stream ? "capture" : "playback",
dpcm->fe->dai_link->name,
stream ? "<-" : "->", dpcm->be->dai_link->name);
@@ -761,7 +885,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
}
/* disconnect a BE and FE */
-static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
+void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm, *d;
@@ -773,7 +897,7 @@ static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
continue;
- dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n",
+ dev_dbg(fe->dev, "freed DSP %s path %s %s %s\n",
stream ? "capture" : "playback", fe->dai_link->name,
stream ? "<-" : "->", dpcm->be->dai_link->name);
@@ -857,7 +981,7 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list,
return 0;
}
-static int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
+int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list_)
{
struct snd_soc_dai *cpu_dai = fe->cpu_dai;
@@ -879,11 +1003,6 @@ static int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
return paths;
}
-static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
-{
- kfree(*list);
-}
-
static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
struct snd_soc_dapm_widget_list **list_)
{
@@ -953,7 +1072,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
continue;
/* don't connect if FE is not running */
- if (!fe->dpcm[stream].runtime)
+ if (!fe->dpcm[stream].runtime && !fe->fe_compr)
continue;
/* newly connected FE and BE */
@@ -978,7 +1097,7 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
* Find the corresponding BE DAIs that source or sink audio to this
* FE substream.
*/
-static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
+int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
int stream, struct snd_soc_dapm_widget_list **list, int new)
{
if (new)
@@ -987,7 +1106,7 @@ static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
return dpcm_prune_paths(fe, stream, list);
}
-static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
+void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
@@ -1025,7 +1144,7 @@ static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
}
}
-static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
+int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
int err, count = 0;
@@ -1037,6 +1156,12 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
struct snd_pcm_substream *be_substream =
snd_soc_dpcm_get_substream(be, stream);
+ if (!be_substream) {
+ dev_err(be->dev, "ASoC: no backend %s stream\n",
+ stream ? "capture" : "playback");
+ continue;
+ }
+
/* is this op for this BE ? */
if (!snd_soc_dpcm_be_can_update(fe, be, stream))
continue;
@@ -1054,7 +1179,8 @@ static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
continue;
- dev_dbg(be->dev, "ASoC: open BE %s\n", be->dai_link->name);
+ dev_dbg(be->dev, "ASoC: open %s BE %s\n",
+ stream ? "capture" : "playback", be->dai_link->name);
be_substream->runtime = be->dpcm[stream].runtime;
err = soc_pcm_open(be_substream);
@@ -1105,6 +1231,20 @@ unwind:
return err;
}
+static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
+ struct snd_soc_pcm_stream *stream)
+{
+ runtime->hw.rate_min = stream->rate_min;
+ runtime->hw.rate_max = stream->rate_max;
+ runtime->hw.channels_min = stream->channels_min;
+ runtime->hw.channels_max = stream->channels_max;
+ if (runtime->hw.formats)
+ runtime->hw.formats &= stream->formats;
+ else
+ runtime->hw.formats = stream->formats;
+ runtime->hw.rates = stream->rates;
+}
+
static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1112,21 +1252,10 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
- runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
- runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
- runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
- runtime->hw.formats &= cpu_dai_drv->playback.formats;
- runtime->hw.rates = cpu_dai_drv->playback.rates;
- } else {
- runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
- runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
- runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
- runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
- runtime->hw.formats &= cpu_dai_drv->capture.formats;
- runtime->hw.rates = cpu_dai_drv->capture.rates;
- }
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
+ else
+ dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
}
static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
@@ -1167,7 +1296,7 @@ be_err:
return ret;
}
-static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
@@ -1228,7 +1357,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
return 0;
}
-static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
+int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
@@ -1293,7 +1422,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
return 0;
}
-static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
+int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
int ret;
@@ -1423,7 +1552,7 @@ static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
return ret;
}
-static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
+int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
int cmd)
{
struct snd_soc_dpcm *dpcm;
@@ -1591,7 +1720,7 @@ out:
return ret;
}
-static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
+int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
int ret = 0;
@@ -1673,7 +1802,7 @@ static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_platform *platform = rtd->platform;
- if (platform->driver->ops->ioctl)
+ if (platform->driver->ops && platform->driver->ops->ioctl)
return platform->driver->ops->ioctl(substream, cmd, arg);
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
@@ -1934,8 +2063,8 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name);
- if (drv->ops->digital_mute && dai->playback_active)
- drv->ops->digital_mute(dai, mute);
+ if (drv->ops && drv->ops->digital_mute && dai->playback_active)
+ drv->ops->digital_mute(dai, mute);
}
return 0;
@@ -2007,10 +2136,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
int ret = 0, playback = 0, capture = 0;
if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
- if (cpu_dai->driver->playback.channels_min)
- playback = 1;
- if (cpu_dai->driver->capture.channels_min)
- capture = 1;
+ playback = rtd->dai_link->dpcm_playback;
+ capture = rtd->dai_link->dpcm_capture;
} else {
if (codec_dai->driver->playback.channels_min &&
cpu_dai->driver->playback.channels_min)
@@ -2116,7 +2243,7 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
pcm->private_free = platform->driver->pcm_free;
out:
- dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name,
+ dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name);
return ret;
}
@@ -2224,7 +2351,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_platform *platform)
{
- if (platform->driver->ops->trigger)
+ if (platform->driver->ops && platform->driver->ops->trigger)
return platform->driver->ops->trigger(substream, cmd);
return 0;
}
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 29b211e9c060..7f22ca35a413 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -59,10 +59,6 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params)
EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk);
static const struct snd_pcm_hardware dummy_dma_hardware = {
- .formats = 0xffffffff,
- .channels_min = 1,
- .channels_max = UINT_MAX,
-
/* Random values to keep userspace happy when checking constraints */
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER,
@@ -75,7 +71,11 @@ static const struct snd_pcm_hardware dummy_dma_hardware = {
static int dummy_dma_open(struct snd_pcm_substream *substream)
{
- snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ /* BE's dont need dummy params */
+ if (!rtd->dai_link->no_pcm)
+ snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware);
return 0;
}
@@ -119,6 +119,13 @@ static struct snd_soc_dai_driver dummy_dai = {
},
};
+int snd_soc_dai_is_dummy(struct snd_soc_dai *dai)
+{
+ if (dai->driver == &dummy_dai)
+ return 1;
+ return 0;
+}
+
static int snd_soc_dummy_probe(struct platform_device *pdev)
{
int ret;
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index 63acfeb4b69d..4ab442a63d7e 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -18,12 +18,14 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/spear_dma.h>
#include <sound/spear_spdif.h>
#include "spdif_in_regs.h"
+#include "spear_pcm.h"
struct spdif_in_params {
u32 format;
@@ -37,6 +39,8 @@ struct spdif_in_dev {
struct device *dev;
void (*reset_perip)(void);
int irq;
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_pcm_config config;
};
static void spdif_in_configure(struct spdif_in_dev *host)
@@ -53,7 +57,8 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai)
{
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
- dai->capture_dma_data = &host->dma_params;
+ host->dma_params_rx.filter_data = &host->dma_params;
+ dai->capture_dma_data = &host->dma_params_rx;
return 0;
}
@@ -244,7 +249,6 @@ static int spdif_in_probe(struct platform_device *pdev)
host->dma_params.addr = res_fifo->start;
host->dma_params.max_burst = 16;
host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_params.filter = pdata->filter;
host->reset_perip = pdata->reset_perip;
host->dev = &pdev->dev;
@@ -257,20 +261,17 @@ static int spdif_in_probe(struct platform_device *pdev)
return ret;
}
- return snd_soc_register_component(&pdev->dev, &spdif_in_component,
- &spdif_in_dai, 1);
-}
-
-static int spdif_in_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
+ ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component,
+ &spdif_in_dai, 1);
+ if (ret)
+ return ret;
- return 0;
+ return devm_spear_pcm_platform_register(&pdev->dev, &host->config,
+ pdata->filter);
}
static struct platform_driver spdif_in_driver = {
.probe = spdif_in_probe,
- .remove = spdif_in_remove,
.driver = {
.name = "spdif-in",
.owner = THIS_MODULE,
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index 2fdf68c98d22..fe99f461aff0 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -18,10 +18,12 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <sound/dmaengine_pcm.h>
#include <sound/soc.h>
#include <sound/spear_dma.h>
#include <sound/spear_spdif.h>
#include "spdif_out_regs.h"
+#include "spear_pcm.h"
struct spdif_out_params {
u32 rate;
@@ -35,6 +37,8 @@ struct spdif_out_dev {
struct spdif_out_params saved_params;
u32 running;
void __iomem *io_base;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+ struct snd_dmaengine_pcm_config config;
};
static void spdif_out_configure(struct spdif_out_dev *host)
@@ -244,7 +248,8 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai)
{
struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
- dai->playback_dma_data = &host->dma_params;
+ host->dma_params_tx.filter_data = &host->dma_params;
+ dai->playback_dma_data = &host->dma_params_tx;
return snd_soc_add_dai_controls(dai, spdif_out_controls,
ARRAY_SIZE(spdif_out_controls));
@@ -303,20 +308,16 @@ static int spdif_out_probe(struct platform_device *pdev)
host->dma_params.addr = res->start + SPDIF_OUT_FIFO_DATA;
host->dma_params.max_burst = 16;
host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_params.filter = pdata->filter;
dev_set_drvdata(&pdev->dev, host);
- ret = snd_soc_register_component(&pdev->dev, &spdif_out_component,
- &spdif_out_dai, 1);
- return ret;
-}
-
-static int spdif_out_remove(struct platform_device *pdev)
-{
- snd_soc_unregister_component(&pdev->dev);
+ ret = devm_snd_soc_register_component(&pdev->dev, &spdif_out_component,
+ &spdif_out_dai, 1);
+ if (ret)
+ return ret;
- return 0;
+ return devm_spear_pcm_platform_register(&pdev->dev, &host->config,
+ pdata->filter);
}
#ifdef CONFIG_PM
@@ -357,7 +358,6 @@ static SIMPLE_DEV_PM_OPS(spdif_out_dev_pm_ops, spdif_out_suspend, \
static struct platform_driver spdif_out_driver = {
.probe = spdif_out_probe,
- .remove = spdif_out_remove,
.driver = {
.name = "spdif-out",
.owner = THIS_MODULE,
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index 4707f2b862c3..0e5a8f35d0ad 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -18,6 +18,7 @@
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/spear_dma.h>
+#include "spear_pcm.h"
static const struct snd_pcm_hardware spear_pcm_hardware = {
.info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -31,49 +32,24 @@ static const struct snd_pcm_hardware spear_pcm_hardware = {
.fifo_size = 0, /* fifo size in bytes */
};
-static struct dma_chan *spear_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_substream *substream)
-{
- struct spear_dma_data *dma_data;
-
- dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- return snd_dmaengine_pcm_request_channel(dma_data->filter, dma_data);
-}
-
static const struct snd_dmaengine_pcm_config spear_dmaengine_pcm_config = {
.pcm_hardware = &spear_pcm_hardware,
- .compat_request_channel = spear_pcm_request_chan,
.prealloc_buffer_size = 16 * 1024,
};
-static int spear_soc_platform_probe(struct platform_device *pdev)
+int devm_spear_pcm_platform_register(struct device *dev,
+ struct snd_dmaengine_pcm_config *config,
+ bool (*filter)(struct dma_chan *chan, void *slave))
{
- return snd_dmaengine_pcm_register(&pdev->dev,
- &spear_dmaengine_pcm_config,
+ *config = spear_dmaengine_pcm_config;
+ config->compat_filter_fn = filter;
+
+ return snd_dmaengine_pcm_register(dev, config,
SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
-
-static int spear_soc_platform_remove(struct platform_device *pdev)
-{
- snd_dmaengine_pcm_unregister(&pdev->dev);
- return 0;
-}
-
-static struct platform_driver spear_pcm_driver = {
- .driver = {
- .name = "spear-pcm-audio",
- .owner = THIS_MODULE,
- },
-
- .probe = spear_soc_platform_probe,
- .remove = spear_soc_platform_remove,
-};
-
-module_platform_driver(spear_pcm_driver);
+EXPORT_SYMBOL_GPL(devm_spear_pcm_platform_register);
MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
MODULE_DESCRIPTION("SPEAr PCM DMA module");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:spear-pcm-audio");
diff --git a/sound/soc/spear/spear_pcm.h b/sound/soc/spear/spear_pcm.h
new file mode 100644
index 000000000000..9b0ca62d6f02
--- /dev/null
+++ b/sound/soc/spear/spear_pcm.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SPEAR_PCM_H__
+#define __SPEAR_PCM_H__
+
+int devm_spear_pcm_platform_register(struct device *dev,
+ struct snd_dmaengine_pcm_config *config,
+ bool (*filter)(struct dma_chan *chan, void *slave));
+
+#endif
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index 8fc653ca3ab4..9f9c1856f822 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,6 +1,8 @@
config SND_SOC_TEGRA
tristate "SoC Audio for the Tegra System-on-Chip"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
+ depends on COMMON_CLK
+ depends on RESET_CONTROLLER
select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
help
@@ -116,3 +118,13 @@ config SND_SOC_TEGRA_ALC5632
help
Say Y or M here if you want to add support for SoC audio on the
Toshiba AC100 netbook.
+
+config SND_SOC_TEGRA_MAX98090
+ tristate "SoC Audio support for Tegra boards using a MAX98090 codec"
+ depends on SND_SOC_TEGRA && I2C && GPIOLIB
+ select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+ select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+ select SND_SOC_MAX98090
+ help
+ Say Y or M here if you want to add support for SoC audio on Tegra
+ boards using the MAX98090 codec, such as Venice2.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 21d2550a08a4..5ae588cd96c4 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -24,6 +24,7 @@ snd-soc-tegra-wm8903-objs := tegra_wm8903.o
snd-soc-tegra-wm9712-objs := tegra_wm9712.o
snd-soc-tegra-trimslice-objs := trimslice.o
snd-soc-tegra-alc5632-objs := tegra_alc5632.o
+snd-soc-tegra-max98090-objs := tegra_max98090.o
obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
@@ -31,3 +32,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
+obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index ae27bcd586d2..cf5e1cfe818d 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -313,7 +313,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
{
struct tegra20_ac97 *ac97;
struct resource *mem;
- u32 of_dma[2];
void __iomem *regs;
int ret = 0;
@@ -348,14 +347,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
goto err_clk_put;
}
- if (of_property_read_u32_array(pdev->dev.of_node,
- "nvidia,dma-request-selector",
- of_dma, 2) < 0) {
- dev_err(&pdev->dev, "No DMA resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node,
"nvidia,codec-reset-gpio", 0);
if (gpio_is_valid(ac97->reset_gpio)) {
@@ -380,12 +371,10 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->capture_dma_data.maxburst = 4;
- ac97->capture_dma_data.slave_id = of_dma[1];
ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->playback_dma_data.maxburst = 4;
- ac97->playback_dma_data.slave_id = of_dma[1];
ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
if (ret)
@@ -404,7 +393,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
if (ret) {
dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
- goto err_asoc_utils_fini;
+ goto err_clk_disable_unprepare;
}
ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
@@ -412,7 +401,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
- goto err_asoc_utils_fini;
+ goto err_clk_disable_unprepare;
}
ret = tegra_pcm_platform_register(&pdev->dev);
@@ -428,6 +417,8 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
+err_clk_disable_unprepare:
+ clk_disable_unprepare(ac97->clk_ac97);
err_asoc_utils_fini:
tegra_asoc_utils_fini(&ac97->util_data);
err_clk_put:
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 52af7f6fb37f..42c1f6bfaf2e 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -74,7 +74,7 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- unsigned int mask, val;
+ unsigned int mask = 0, val = 0;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -83,10 +83,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL;
}
- mask = TEGRA20_I2S_CTRL_MASTER_ENABLE;
+ mask |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- val = TEGRA20_I2S_CTRL_MASTER_ENABLE;
+ val |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
break;
case SND_SOC_DAIFMT_CBM_CFM:
break;
@@ -297,7 +297,7 @@ static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -310,7 +310,7 @@ static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
@@ -321,7 +321,7 @@ static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config tegra20_i2s_regmap_config = {
@@ -339,9 +339,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = {
static int tegra20_i2s_platform_probe(struct platform_device *pdev)
{
struct tegra20_i2s *i2s;
- struct resource *mem, *memregion, *dmareq;
- u32 of_dma[2];
- u32 dma_ch;
+ struct resource *mem, *memregion;
void __iomem *regs;
int ret;
@@ -370,20 +368,6 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
goto err_clk_put;
}
- dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmareq) {
- if (of_property_read_u32_array(pdev->dev.of_node,
- "nvidia,dma-request-selector",
- of_dma, 2) < 0) {
- dev_err(&pdev->dev, "No DMA resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
- dma_ch = of_dma[1];
- } else {
- dma_ch = dmareq->start;
- }
-
memregion = devm_request_mem_region(&pdev->dev, mem->start,
resource_size(mem), DRV_NAME);
if (!memregion) {
@@ -410,12 +394,10 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->capture_dma_data.maxburst = 4;
- i2s->capture_dma_data.slave_id = dma_ch;
i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->playback_dma_data.maxburst = 4;
- i2s->playback_dma_data.slave_id = dma_ch;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 551b3c93ce93..8c7c1028e579 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -67,15 +67,15 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
{
struct device *dev = dai->dev;
struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
- unsigned int mask, val;
+ unsigned int mask = 0, val = 0;
int ret, spdifclock;
- mask = TEGRA20_SPDIF_CTRL_PACK |
- TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+ mask |= TEGRA20_SPDIF_CTRL_PACK |
+ TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- val = TEGRA20_SPDIF_CTRL_PACK |
- TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+ val |= TEGRA20_SPDIF_CTRL_PACK |
+ TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
break;
default:
return -EINVAL;
@@ -213,7 +213,7 @@ static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg)
@@ -234,7 +234,7 @@ static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg)
@@ -247,7 +247,7 @@ static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config tegra20_spdif_regmap_config = {
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index d554d46d08b5..d6f4c9940e0c 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -24,8 +24,8 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/slab.h>
-#include <linux/clk/tegra.h>
#include <sound/soc.h>
#include "tegra30_ahub.h"
@@ -95,11 +95,12 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
}
int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel)
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg)
{
int channel;
u32 reg, val;
+ struct tegra30_ahub_cif_conf cif_conf;
channel = find_first_zero_bit(ahub->rx_usage,
TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
@@ -109,9 +110,11 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
__set_bit(channel, ahub->rx_usage);
*rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
+ snprintf(dmachan, dmachan_len, "rx%d", channel);
*fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
(channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
- *reqsel = ahub->dma_sel + channel;
+
+ pm_runtime_get_sync(ahub->dev);
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
@@ -123,15 +126,23 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
tegra30_apbif_write(reg, val);
+ cif_conf.threshold = 0;
+ cif_conf.audio_channels = 2;
+ cif_conf.client_channels = 2;
+ cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.expand = 0;
+ cif_conf.stereo_conv = 0;
+ cif_conf.replicate = 0;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
+ cif_conf.truncate = 0;
+ cif_conf.mono_conv = 0;
+
reg = TEGRA30_AHUB_CIF_RX_CTRL +
(channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
- val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
- TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
- tegra30_apbif_write(reg, val);
+ ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
+
+ pm_runtime_put(ahub->dev);
return 0;
}
@@ -142,12 +153,16 @@ int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
@@ -157,12 +172,16 @@ int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
@@ -178,11 +197,12 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel)
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg)
{
int channel;
u32 reg, val;
+ struct tegra30_ahub_cif_conf cif_conf;
channel = find_first_zero_bit(ahub->tx_usage,
TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
@@ -192,9 +212,11 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
__set_bit(channel, ahub->tx_usage);
*txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
+ snprintf(dmachan, dmachan_len, "tx%d", channel);
*fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
(channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
- *reqsel = ahub->dma_sel + channel;
+
+ pm_runtime_get_sync(ahub->dev);
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
@@ -206,15 +228,23 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
tegra30_apbif_write(reg, val);
+ cif_conf.threshold = 0;
+ cif_conf.audio_channels = 2;
+ cif_conf.client_channels = 2;
+ cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.expand = 0;
+ cif_conf.stereo_conv = 0;
+ cif_conf.replicate = 0;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
+ cif_conf.truncate = 0;
+ cif_conf.mono_conv = 0;
+
reg = TEGRA30_AHUB_CIF_TX_CTRL +
(channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
- val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
- TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
- tegra30_apbif_write(reg, val);
+ ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf);
+
+ pm_runtime_put(ahub->dev);
return 0;
}
@@ -225,12 +255,16 @@ int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
@@ -240,12 +274,16 @@ int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
int reg, val;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_CHANNEL_CTRL +
(channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
val = tegra30_apbif_read(reg);
val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
tegra30_apbif_write(reg, val);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
@@ -266,10 +304,14 @@ int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_AUDIO_RX +
(channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
tegra30_audio_write(reg, 1 << txcif);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
@@ -279,35 +321,51 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
int reg;
+ pm_runtime_get_sync(ahub->dev);
+
reg = TEGRA30_AHUB_AUDIO_RX +
(channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
tegra30_audio_write(reg, 0);
+ pm_runtime_put(ahub->dev);
+
return 0;
}
EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
-#define CLK_LIST_MASK_TEGRA30 BIT(0)
-#define CLK_LIST_MASK_TEGRA114 BIT(1)
+#define MOD_LIST_MASK_TEGRA30 BIT(0)
+#define MOD_LIST_MASK_TEGRA114 BIT(1)
+#define MOD_LIST_MASK_TEGRA124 BIT(2)
-#define CLK_LIST_MASK_TEGRA30_OR_LATER \
- (CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114)
+#define MOD_LIST_MASK_TEGRA30_OR_LATER \
+ (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \
+ MOD_LIST_MASK_TEGRA124)
+#define MOD_LIST_MASK_TEGRA114_OR_LATER \
+ (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124)
static const struct {
- const char *clk_name;
- u32 clk_list_mask;
-} configlink_clocks[] = {
- { "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER },
- { "amx", CLK_LIST_MASK_TEGRA114 },
- { "adx", CLK_LIST_MASK_TEGRA114 },
+ const char *rst_name;
+ u32 mod_list_mask;
+} configlink_mods[] = {
+ { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER },
+ { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER },
+ { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER },
+ { "amx1", MOD_LIST_MASK_TEGRA124 },
+ { "adx1", MOD_LIST_MASK_TEGRA124 },
+ { "afc0", MOD_LIST_MASK_TEGRA124 },
+ { "afc1", MOD_LIST_MASK_TEGRA124 },
+ { "afc2", MOD_LIST_MASK_TEGRA124 },
+ { "afc3", MOD_LIST_MASK_TEGRA124 },
+ { "afc4", MOD_LIST_MASK_TEGRA124 },
+ { "afc5", MOD_LIST_MASK_TEGRA124 },
};
#define LAST_REG(name) \
@@ -346,7 +404,7 @@ static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
return true;
default:
break;
- };
+ }
if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
@@ -381,7 +439,7 @@ static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
return true;
default:
break;
- };
+ }
if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
@@ -436,14 +494,22 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
};
static struct tegra30_ahub_soc_data soc_data_tegra30 = {
- .clk_list_mask = CLK_LIST_MASK_TEGRA30,
+ .mod_list_mask = MOD_LIST_MASK_TEGRA30,
+ .set_audio_cif = tegra30_ahub_set_cif,
};
static struct tegra30_ahub_soc_data soc_data_tegra114 = {
- .clk_list_mask = CLK_LIST_MASK_TEGRA114,
+ .mod_list_mask = MOD_LIST_MASK_TEGRA114,
+ .set_audio_cif = tegra30_ahub_set_cif,
+};
+
+static struct tegra30_ahub_soc_data soc_data_tegra124 = {
+ .mod_list_mask = MOD_LIST_MASK_TEGRA124,
+ .set_audio_cif = tegra124_ahub_set_cif,
};
static const struct of_device_id tegra30_ahub_of_match[] = {
+ { .compatible = "nvidia,tegra124-ahub", .data = &soc_data_tegra124 },
{ .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-ahub", .data = &soc_data_tegra30 },
{},
@@ -453,10 +519,9 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct tegra30_ahub_soc_data *soc_data;
- struct clk *clk;
+ struct reset_control *rst;
int i;
struct resource *res0, *res1, *region;
- u32 of_dma[2];
void __iomem *regs_apbif, *regs_ahub;
int ret = 0;
@@ -473,19 +538,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
* operate correctly, all devices on this bus must be out of reset.
* Ensure that here.
*/
- for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
- if (!(configlink_clocks[i].clk_list_mask &
- soc_data->clk_list_mask))
+ for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) {
+ if (!(configlink_mods[i].mod_list_mask &
+ soc_data->mod_list_mask))
continue;
- clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "Can't get clock %s\n",
- configlink_clocks[i].clk_name);
- ret = PTR_ERR(clk);
+
+ rst = reset_control_get(&pdev->dev,
+ configlink_mods[i].rst_name);
+ if (IS_ERR(rst)) {
+ dev_err(&pdev->dev, "Can't get reset %s\n",
+ configlink_mods[i].rst_name);
+ ret = PTR_ERR(rst);
goto err;
}
- tegra_periph_reset_deassert(clk);
- clk_put(clk);
+
+ ret = reset_control_deassert(rst);
+ reset_control_put(rst);
+ if (ret)
+ goto err;
}
ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
@@ -497,6 +567,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
}
dev_set_drvdata(&pdev->dev, ahub);
+ ahub->soc_data = soc_data;
ahub->dev = &pdev->dev;
ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
@@ -513,16 +584,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
goto err_clk_put_d_audio;
}
- if (of_property_read_u32_array(pdev->dev.of_node,
- "nvidia,dma-request-selector",
- of_dma, 2) < 0) {
- dev_err(&pdev->dev,
- "Missing property nvidia,dma-request-selector\n");
- ret = -ENODEV;
- goto err_clk_put_d_audio;
- }
- ahub->dma_sel = of_dma[1];
-
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res0) {
dev_err(&pdev->dev, "No apbif memory resource\n");
@@ -669,6 +730,70 @@ static struct platform_driver tegra30_ahub_driver = {
};
module_platform_driver(tegra30_ahub_driver);
+void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf)
+{
+ unsigned int value;
+
+ value = (conf->threshold <<
+ TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ ((conf->audio_channels - 1) <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ ((conf->client_channels - 1) <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ (conf->audio_bits <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ (conf->client_bits <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
+ (conf->expand <<
+ TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
+ (conf->stereo_conv <<
+ TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
+ (conf->replicate <<
+ TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
+ (conf->direction <<
+ TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
+ (conf->truncate <<
+ TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
+ (conf->mono_conv <<
+ TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
+
+ regmap_write(regmap, reg, value);
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_set_cif);
+
+void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf)
+{
+ unsigned int value;
+
+ value = (conf->threshold <<
+ TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ ((conf->audio_channels - 1) <<
+ TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ ((conf->client_channels - 1) <<
+ TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ (conf->audio_bits <<
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT) |
+ (conf->client_bits <<
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT) |
+ (conf->expand <<
+ TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT) |
+ (conf->stereo_conv <<
+ TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT) |
+ (conf->replicate <<
+ TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT) |
+ (conf->direction <<
+ TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT) |
+ (conf->truncate <<
+ TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT) |
+ (conf->mono_conv <<
+ TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT);
+
+ regmap_write(regmap, reg, value);
+}
+EXPORT_SYMBOL_GPL(tegra124_ahub_set_cif);
+
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("Tegra30 AHUB driver");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 09766cdc45ca..fd7ba75ed814 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -25,16 +25,30 @@
#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0xf
#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT)
+#define TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 24
+#define TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0x3f
+#define TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA124_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT)
+
/* Channel count minus 1 */
#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 24
#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 7
#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT)
/* Channel count minus 1 */
+#define TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 20
+#define TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 0xf
+#define TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA124_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT)
+
+/* Channel count minus 1 */
#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16
#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 7
#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT)
+/* Channel count minus 1 */
+#define TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16
+#define TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 0xf
+#define TEGRA124_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT)
+
#define TEGRA30_AUDIOCIF_BITS_4 0
#define TEGRA30_AUDIOCIF_BITS_8 1
#define TEGRA30_AUDIOCIF_BITS_12 2
@@ -86,7 +100,7 @@
#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1 (TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG (TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
-#define TEGRA30_AUDIOCIF_CTRL_REPLICATE 3
+#define TEGRA30_AUDIOCIF_CTRL_REPLICATE_SHIFT 3
#define TEGRA30_AUDIOCIF_DIRECTION_TX 0
#define TEGRA30_AUDIOCIF_DIRECTION_RX 1
@@ -451,15 +465,15 @@ enum tegra30_ahub_rxcif {
};
extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel);
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg);
extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
- dma_addr_t *fiforeg,
- unsigned int *reqsel);
+ char *dmachan, int dmachan_len,
+ dma_addr_t *fiforeg);
extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
@@ -468,8 +482,30 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
+struct tegra30_ahub_cif_conf {
+ unsigned int threshold;
+ unsigned int audio_channels;
+ unsigned int client_channels;
+ unsigned int audio_bits;
+ unsigned int client_bits;
+ unsigned int expand;
+ unsigned int stereo_conv;
+ unsigned int replicate;
+ unsigned int direction;
+ unsigned int truncate;
+ unsigned int mono_conv;
+};
+
+void tegra30_ahub_set_cif(struct regmap *regmap, unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf);
+void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf);
+
struct tegra30_ahub_soc_data {
- u32 clk_list_mask;
+ u32 mod_list_mask;
+ void (*set_audio_cif)(struct regmap *regmap,
+ unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf);
/*
* FIXME: There are many more differences in HW, such as:
* - More APBIF channels.
@@ -488,7 +524,6 @@ struct tegra30_ahub {
struct device *dev;
struct clk *clk_d_audio;
struct clk *clk_apbif;
- int dma_sel;
resource_size_t apbif_addr;
struct regmap *regmap_apbif;
struct regmap *regmap_ahub;
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 47565fd04505..49ad9366add8 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -30,6 +30,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -72,52 +73,11 @@ static int tegra30_i2s_runtime_resume(struct device *dev)
return 0;
}
-static int tegra30_i2s_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- int ret;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
- &i2s->playback_dma_data.addr,
- &i2s->playback_dma_data.slave_id);
- i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- i2s->playback_dma_data.maxburst = 4;
- tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
- i2s->playback_fifo_cif);
- } else {
- ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
- &i2s->capture_dma_data.addr,
- &i2s->capture_dma_data.slave_id);
- i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- i2s->capture_dma_data.maxburst = 4;
- tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
- i2s->capture_i2s_cif);
- }
-
- return ret;
-}
-
-static void tegra30_i2s_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
- tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
- } else {
- tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
- tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
- }
-}
-
static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
unsigned int fmt)
{
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- unsigned int mask, val;
+ unsigned int mask = 0, val = 0;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
@@ -126,10 +86,10 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
return -EINVAL;
}
- mask = TEGRA30_I2S_CTRL_MASTER_ENABLE;
+ mask |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
- val = TEGRA30_I2S_CTRL_MASTER_ENABLE;
+ val |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
break;
case SND_SOC_DAIFMT_CBM_CFM:
break;
@@ -179,6 +139,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
unsigned int mask, val, reg;
int ret, sample_size, srate, i2sclock, bitcnt;
+ struct tegra30_ahub_cif_conf cif_conf;
if (params_channels(params) != 2)
return -EINVAL;
@@ -217,21 +178,26 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val);
- val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
- (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
- TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
- TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16;
+ cif_conf.threshold = 0;
+ cif_conf.audio_channels = 2;
+ cif_conf.client_channels = 2;
+ cif_conf.audio_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.client_bits = TEGRA30_AUDIOCIF_BITS_16;
+ cif_conf.expand = 0;
+ cif_conf.stereo_conv = 0;
+ cif_conf.replicate = 0;
+ cif_conf.truncate = 0;
+ cif_conf.mono_conv = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_RX;
reg = TEGRA30_I2S_CIF_RX_CTRL;
} else {
- val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+ cif_conf.direction = TEGRA30_AUDIOCIF_DIRECTION_TX;
reg = TEGRA30_I2S_CIF_TX_CTRL;
}
- regmap_write(i2s->regmap, reg, val);
+ i2s->soc_data->set_audio_cif(i2s->regmap, reg, &cif_conf);
val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
(1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
@@ -310,8 +276,6 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai)
}
static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
- .startup = tegra30_i2s_startup,
- .shutdown = tegra30_i2s_shutdown,
.set_fmt = tegra30_i2s_set_fmt,
.hw_params = tegra30_i2s_hw_params,
.trigger = tegra30_i2s_trigger,
@@ -369,7 +333,7 @@ static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static bool tegra30_i2s_volatile_reg(struct device *dev, unsigned int reg)
@@ -382,7 +346,7 @@ static bool tegra30_i2s_volatile_reg(struct device *dev, unsigned int reg)
return true;
default:
return false;
- };
+ }
}
static const struct regmap_config tegra30_i2s_regmap_config = {
@@ -396,9 +360,24 @@ static const struct regmap_config tegra30_i2s_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+static const struct tegra30_i2s_soc_data tegra30_i2s_config = {
+ .set_audio_cif = tegra30_ahub_set_cif,
+};
+
+static const struct tegra30_i2s_soc_data tegra124_i2s_config = {
+ .set_audio_cif = tegra124_ahub_set_cif,
+};
+
+static const struct of_device_id tegra30_i2s_of_match[] = {
+ { .compatible = "nvidia,tegra124-i2s", .data = &tegra124_i2s_config },
+ { .compatible = "nvidia,tegra30-i2s", .data = &tegra30_i2s_config },
+ {},
+};
+
static int tegra30_i2s_platform_probe(struct platform_device *pdev)
{
struct tegra30_i2s *i2s;
+ const struct of_device_id *match;
u32 cif_ids[2];
struct resource *mem, *memregion;
void __iomem *regs;
@@ -412,6 +391,14 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
}
dev_set_drvdata(&pdev->dev, i2s);
+ match = of_match_device(tegra30_i2s_of_match, &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ i2s->soc_data = (struct tegra30_i2s_soc_data *)match->data;
+
i2s->dai = tegra30_i2s_dai_template;
i2s->dai.name = dev_name(&pdev->dev);
@@ -469,15 +456,51 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
goto err_pm_disable;
}
+ i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->playback_dma_data.maxburst = 4;
+ ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
+ i2s->playback_dma_chan,
+ sizeof(i2s->playback_dma_chan),
+ &i2s->playback_dma_data.addr);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not alloc TX FIFO: %d\n", ret);
+ goto err_suspend;
+ }
+ ret = tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
+ i2s->playback_fifo_cif);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not route TX FIFO: %d\n", ret);
+ goto err_free_tx_fifo;
+ }
+
+ i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ i2s->capture_dma_data.maxburst = 4;
+ ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
+ i2s->capture_dma_chan,
+ sizeof(i2s->capture_dma_chan),
+ &i2s->capture_dma_data.addr);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not alloc RX FIFO: %d\n", ret);
+ goto err_unroute_tx_fifo;
+ }
+ ret = tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
+ i2s->capture_i2s_cif);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not route TX FIFO: %d\n", ret);
+ goto err_free_rx_fifo;
+ }
+
ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component,
&i2s->dai, 1);
if (ret) {
dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
ret = -ENOMEM;
- goto err_suspend;
+ goto err_unroute_rx_fifo;
}
- ret = tegra_pcm_platform_register(&pdev->dev);
+ ret = tegra_pcm_platform_register_with_chan_names(&pdev->dev,
+ &i2s->dma_config, i2s->playback_dma_chan,
+ i2s->capture_dma_chan);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
goto err_unregister_component;
@@ -487,6 +510,14 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
+err_unroute_rx_fifo:
+ tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+err_free_rx_fifo:
+ tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+err_unroute_tx_fifo:
+ tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+err_free_tx_fifo:
+ tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
tegra30_i2s_runtime_suspend(&pdev->dev);
@@ -509,6 +540,12 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
tegra_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_component(&pdev->dev);
+ tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+ tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+
+ tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+ tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
+
clk_put(i2s->clk_i2s);
return 0;
@@ -539,11 +576,6 @@ static int tegra30_i2s_resume(struct device *dev)
}
#endif
-static const struct of_device_id tegra30_i2s_of_match[] = {
- { .compatible = "nvidia,tegra30-i2s", },
- {},
-};
-
static const struct dev_pm_ops tegra30_i2s_pm_ops = {
SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
tegra30_i2s_runtime_resume, NULL)
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index bea23afe3b9f..774fc6ad2026 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -225,17 +225,27 @@
#define TEGRA30_I2S_LCOEF_COEF_MASK_US 0xffff
#define TEGRA30_I2S_LCOEF_COEF_MASK (TEGRA30_I2S_LCOEF_COEF_MASK_US << TEGRA30_I2S_LCOEF_COEF_SHIFT)
+struct tegra30_i2s_soc_data {
+ void (*set_audio_cif)(struct regmap *regmap,
+ unsigned int reg,
+ struct tegra30_ahub_cif_conf *conf);
+};
+
struct tegra30_i2s {
+ const struct tegra30_i2s_soc_data *soc_data;
struct snd_soc_dai_driver dai;
int cif_id;
struct clk *clk_i2s;
enum tegra30_ahub_txcif capture_i2s_cif;
enum tegra30_ahub_rxcif capture_fifo_cif;
+ char capture_dma_chan[8];
struct snd_dmaengine_dai_dma_data capture_dma_data;
enum tegra30_ahub_rxcif playback_i2s_cif;
enum tegra30_ahub_txcif playback_fifo_cif;
+ char playback_dma_chan[8];
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
+ struct snd_dmaengine_pcm_config dma_config;
};
#endif
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index d173880f290d..1be311c51a18 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -182,6 +182,8 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
else if (of_machine_is_compatible("nvidia,tegra114"))
data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
+ else if (of_machine_is_compatible("nvidia,tegra124"))
+ data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA124;
else {
dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
return -EINVAL;
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 19fdcafed32f..9577121ce971 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -30,6 +30,7 @@ enum tegra_asoc_utils_soc {
TEGRA_ASOC_UTILS_SOC_TEGRA20,
TEGRA_ASOC_UTILS_SOC_TEGRA30,
TEGRA_ASOC_UTILS_SOC_TEGRA114,
+ TEGRA_ASOC_UTILS_SOC_TEGRA124,
};
struct tegra_asoc_utils_data {
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
new file mode 100644
index 000000000000..0283cfb7c031
--- /dev/null
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -0,0 +1,275 @@
+/*
+ * Tegra machine ASoC driver for boards using a MAX90809 CODEC.
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-max98090"
+
+struct tegra_max98090 {
+ struct tegra_asoc_utils_data util_data;
+ int gpio_hp_det;
+};
+
+static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk;
+ int err;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 8000:
+ case 16000:
+ case 24000:
+ case 32000:
+ case 48000:
+ case 64000:
+ case 96000:
+ mclk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ default:
+ mclk = 12000000;
+ break;
+ }
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai clock not set\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops tegra_max98090_ops = {
+ .hw_params = tegra_max98090_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_max98090_hp_jack;
+
+static struct snd_soc_jack_pin tegra_max98090_hp_jack_pins[] = {
+ {
+ .pin = "Headphones",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = {
+ .name = "Headphone detection",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+ .invert = 1,
+};
+
+static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_SPK("Speakers", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_max98090_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speakers"),
+};
+
+static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct tegra_max98090 *machine = snd_soc_card_get_drvdata(codec->card);
+
+ if (gpio_is_valid(machine->gpio_hp_det)) {
+ snd_soc_jack_new(codec, "Headphones", SND_JACK_HEADPHONE,
+ &tegra_max98090_hp_jack);
+ snd_soc_jack_add_pins(&tegra_max98090_hp_jack,
+ ARRAY_SIZE(tegra_max98090_hp_jack_pins),
+ tegra_max98090_hp_jack_pins);
+
+ tegra_max98090_hp_jack_gpio.gpio = machine->gpio_hp_det;
+ snd_soc_jack_add_gpios(&tegra_max98090_hp_jack,
+ 1,
+ &tegra_max98090_hp_jack_gpio);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_link tegra_max98090_dai = {
+ .name = "max98090",
+ .stream_name = "max98090 PCM",
+ .codec_dai_name = "HiFi",
+ .init = tegra_max98090_asoc_init,
+ .ops = &tegra_max98090_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_max98090 = {
+ .name = "tegra-max98090",
+ .owner = THIS_MODULE,
+ .dai_link = &tegra_max98090_dai,
+ .num_links = 1,
+ .controls = tegra_max98090_controls,
+ .num_controls = ARRAY_SIZE(tegra_max98090_controls),
+ .dapm_widgets = tegra_max98090_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra_max98090_dapm_widgets),
+ .fully_routed = true,
+};
+
+static int tegra_max98090_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &snd_soc_tegra_max98090;
+ struct tegra_max98090 *machine;
+ int ret;
+
+ machine = devm_kzalloc(&pdev->dev,
+ sizeof(struct tegra_max98090), GFP_KERNEL);
+ if (!machine) {
+ dev_err(&pdev->dev, "Can't allocate tegra_max98090\n");
+ return -ENOMEM;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, machine);
+
+ machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+ if (machine->gpio_hp_det == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+ goto err;
+
+ tegra_max98090_dai.codec_of_node = of_parse_phandle(np,
+ "nvidia,audio-codec", 0);
+ if (!tegra_max98090_dai.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tegra_max98090_dai.cpu_of_node = of_parse_phandle(np,
+ "nvidia,i2s-controller", 0);
+ if (!tegra_max98090_dai.cpu_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tegra_max98090_dai.platform_of_node = tegra_max98090_dai.cpu_of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+ goto err;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_fini_utils;
+ }
+
+ return 0;
+
+err_fini_utils:
+ tegra_asoc_utils_fini(&machine->util_data);
+err:
+ return ret;
+}
+
+static int tegra_max98090_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct tegra_max98090 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_jack_free_gpios(&tegra_max98090_hp_jack, 1,
+ &tegra_max98090_hp_jack_gpio);
+
+ snd_soc_unregister_card(card);
+
+ tegra_asoc_utils_fini(&machine->util_data);
+
+ return 0;
+}
+
+static const struct of_device_id tegra_max98090_of_match[] = {
+ { .compatible = "nvidia,tegra-audio-max98090", },
+ {},
+};
+
+static struct platform_driver tegra_max98090_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = tegra_max98090_of_match,
+ },
+ .probe = tegra_max98090_probe,
+ .remove = tegra_max98090_remove,
+};
+module_platform_driver(tegra_max98090_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_max98090_of_match);
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index f056f632557c..93caed500565 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -42,9 +42,6 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 2,
- .channels_max = 2,
.period_bytes_min = 1024,
.period_bytes_max = PAGE_SIZE,
.periods_min = 2,
@@ -56,18 +53,28 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = {
.pcm_hardware = &tegra_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
- .compat_filter_fn = NULL,
.prealloc_buffer_size = PAGE_SIZE * 8,
};
int tegra_pcm_platform_register(struct device *dev)
{
- return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config,
- SND_DMAENGINE_PCM_FLAG_NO_DT |
- SND_DMAENGINE_PCM_FLAG_COMPAT);
+ return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config, 0);
}
EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
+int tegra_pcm_platform_register_with_chan_names(struct device *dev,
+ struct snd_dmaengine_pcm_config *config,
+ char *txdmachan, char *rxdmachan)
+{
+ *config = tegra_dmaengine_pcm_config;
+ config->dma_dev = dev->parent;
+ config->chan_names[0] = txdmachan;
+ config->chan_names[1] = rxdmachan;
+
+ return snd_dmaengine_pcm_register(dev, config, 0);
+}
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_register_with_chan_names);
+
void tegra_pcm_platform_unregister(struct device *dev)
{
return snd_dmaengine_pcm_unregister(dev);
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index 68ad901714a9..7883dec748a3 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -31,7 +31,12 @@
#ifndef __TEGRA_PCM_H__
#define __TEGRA_PCM_H__
+struct snd_dmaengine_pcm_config;
+
int tegra_pcm_platform_register(struct device *dev);
+int tegra_pcm_platform_register_with_chan_names(struct device *dev,
+ struct snd_dmaengine_pcm_config *config,
+ char *txdmachan, char *rxdmachan);
void tegra_pcm_platform_unregister(struct device *dev);
#endif
diff --git a/sound/soc/tegra/tegra_wm9712.c b/sound/soc/tegra/tegra_wm9712.c
index 5e119630b0e0..45b57892b6a5 100644
--- a/sound/soc/tegra/tegra_wm9712.c
+++ b/sound/soc/tegra/tegra_wm9712.c
@@ -55,7 +55,6 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link tegra_wm9712_dai = {
.name = "AC97 HiFi",
.stream_name = "AC97 HiFi",
- .cpu_dai_name = "tegra20-ac97",
.codec_dai_name = "wm9712-hifi",
.codec_name = "wm9712-codec",
.init = tegra_wm9712_init,
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index e0305a148568..9edd68db9f48 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drvdata->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(drvdata->base))
return PTR_ERR(drvdata->base);
- drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
platform_set_drvdata(pdev, drvdata);
drvdata->physbase = r->start;
if (sizeof(drvdata->physbase) > sizeof(r->start) &&
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index 45a6428cba8d..f0829de28708 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -40,11 +40,6 @@ static const struct snd_pcm_hardware txx9aclc_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_PAUSE,
-#ifdef __BIG_ENDIAN
- .formats = SNDRV_PCM_FMTBIT_S16_BE,
-#else
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
-#endif
.period_bytes_min = 1024,
.period_bytes_max = 8 * 1024,
.periods_min = 2,
@@ -115,8 +110,8 @@ static void txx9aclc_dma_complete(void *arg)
spin_lock_irqsave(&dmadata->dma_lock, flags);
if (dmadata->frag_count >= 0) {
dmadata->dmacount--;
- BUG_ON(dmadata->dmacount < 0);
- tasklet_schedule(&dmadata->tasklet);
+ if (!WARN_ON(dmadata->dmacount < 0))
+ tasklet_schedule(&dmadata->tasklet);
}
spin_unlock_irqrestore(&dmadata->dma_lock, flags);
}
@@ -181,7 +176,10 @@ static void txx9aclc_dma_tasklet(unsigned long data)
spin_unlock_irqrestore(&dmadata->dma_lock, flags);
return;
}
- BUG_ON(dmadata->dmacount >= NR_DMA_CHAIN);
+ if (WARN_ON(dmadata->dmacount >= NR_DMA_CHAIN)) {
+ spin_unlock_irqrestore(&dmadata->dma_lock, flags);
+ return;
+ }
while (dmadata->dmacount < NR_DMA_CHAIN) {
dmadata->dmacount++;
spin_unlock_irqrestore(&dmadata->dma_lock, flags);
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index 178d1bad6259..b3b66aa98dce 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -91,6 +91,8 @@ static int mop500_of_probe(struct platform_device *pdev,
for (i = 0; i < 2; i++) {
mop500_dai_links[i].cpu_of_node = msp_np[i];
mop500_dai_links[i].cpu_dai_name = NULL;
+ mop500_dai_links[i].platform_of_node = msp_np[i];
+ mop500_dai_links[i].platform_name = NULL;
mop500_dai_links[i].codec_of_node = codec_np;
mop500_dai_links[i].codec_name = NULL;
}
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
index c6fb5cce980e..5f4807b2c007 100644
--- a/sound/soc/ux500/ux500_msp_dai.c
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -17,12 +17,14 @@
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/asoc-ux500-msp.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
+#include <sound/dmaengine_pcm.h>
#include "ux500_msp_i2s.h"
#include "ux500_msp_dai.h"
@@ -654,16 +656,52 @@ static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ struct snd_dmaengine_dai_dma_data *playback_dma_data;
+ struct snd_dmaengine_dai_dma_data *capture_dma_data;
+
+ playback_dma_data = devm_kzalloc(dai->dev,
+ sizeof(*playback_dma_data),
+ GFP_KERNEL);
+ if (!playback_dma_data)
+ return -ENOMEM;
+
+ capture_dma_data = devm_kzalloc(dai->dev,
+ sizeof(*capture_dma_data),
+ GFP_KERNEL);
+ if (!capture_dma_data)
+ return -ENOMEM;
+
+ playback_dma_data->addr = drvdata->msp->playback_dma_data.tx_rx_addr;
+ capture_dma_data->addr = drvdata->msp->capture_dma_data.tx_rx_addr;
+
+ playback_dma_data->maxburst = 4;
+ capture_dma_data->maxburst = 4;
+
+ snd_soc_dai_init_dma_data(dai, playback_dma_data, capture_dma_data);
+
+ return 0;
+}
+
static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
{
struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ struct msp_i2s_platform_data *pdata = dai->dev->platform_data;
+ int ret;
- dai->playback_dma_data = &drvdata->msp->playback_dma_data;
- dai->capture_dma_data = &drvdata->msp->capture_dma_data;
+ if (!pdata) {
+ ret = ux500_msp_dai_of_probe(dai);
+ return ret;
+ }
drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
+ snd_soc_dai_init_dma_data(dai,
+ &drvdata->msp->playback_dma_data,
+ &drvdata->msp->capture_dma_data);
return 0;
}
@@ -680,87 +718,19 @@ static struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
}
};
-static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
- {
- .name = "ux500-msp-i2s.0",
- .probe = ux500_msp_dai_probe,
- .id = 0,
- .suspend = NULL,
- .resume = NULL,
- .playback = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .capture = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .ops = ux500_msp_dai_ops,
- },
- {
- .name = "ux500-msp-i2s.1",
- .probe = ux500_msp_dai_probe,
- .id = 1,
- .suspend = NULL,
- .resume = NULL,
- .playback = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .capture = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .ops = ux500_msp_dai_ops,
- },
- {
- .name = "ux500-msp-i2s.2",
- .id = 2,
- .probe = ux500_msp_dai_probe,
- .suspend = NULL,
- .resume = NULL,
- .playback = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .capture = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .ops = ux500_msp_dai_ops,
- },
- {
- .name = "ux500-msp-i2s.3",
- .probe = ux500_msp_dai_probe,
- .id = 3,
- .suspend = NULL,
- .resume = NULL,
- .playback = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .capture = {
- .channels_min = UX500_MSP_MIN_CHANNELS,
- .channels_max = UX500_MSP_MAX_CHANNELS,
- .rates = UX500_I2S_RATES,
- .formats = UX500_I2S_FORMATS,
- },
- .ops = ux500_msp_dai_ops,
- },
+static struct snd_soc_dai_driver ux500_msp_dai_drv = {
+ .probe = ux500_msp_dai_probe,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback.channels_min = UX500_MSP_MIN_CHANNELS,
+ .playback.channels_max = UX500_MSP_MAX_CHANNELS,
+ .playback.rates = UX500_I2S_RATES,
+ .playback.formats = UX500_I2S_FORMATS,
+ .capture.channels_min = UX500_MSP_MIN_CHANNELS,
+ .capture.channels_max = UX500_MSP_MAX_CHANNELS,
+ .capture.rates = UX500_I2S_RATES,
+ .capture.formats = UX500_I2S_FORMATS,
+ .ops = ux500_msp_dai_ops,
};
static const struct snd_soc_component_driver ux500_msp_component = {
@@ -771,10 +741,14 @@ static const struct snd_soc_component_driver ux500_msp_component = {
static int ux500_msp_drv_probe(struct platform_device *pdev)
{
struct ux500_msp_i2s_drvdata *drvdata;
+ struct msp_i2s_platform_data *pdata = pdev->dev.platform_data;
+ struct device_node *np = pdev->dev.of_node;
int ret = 0;
- dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__,
- pdev->name);
+ if (!pdata && !np) {
+ dev_err(&pdev->dev, "No platform data or Device Tree found\n");
+ return -ENODEV;
+ }
drvdata = devm_kzalloc(&pdev->dev,
sizeof(struct ux500_msp_i2s_drvdata),
@@ -826,7 +800,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, drvdata);
ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,
- &ux500_msp_dai_drv[drvdata->msp->id], 1);
+ &ux500_msp_dai_drv, 1);
if (ret < 0) {
dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
__func__, drvdata->msp->id);
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
index 1ca8b08ae993..959d7b4edf56 100644
--- a/sound/soc/ux500/ux500_msp_i2s.c
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -646,6 +646,34 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
}
+static int ux500_msp_i2s_of_init_msp(struct platform_device *pdev,
+ struct ux500_msp *msp,
+ struct msp_i2s_platform_data **platform_data)
+{
+ struct msp_i2s_platform_data *pdata;
+
+ *platform_data = devm_kzalloc(&pdev->dev,
+ sizeof(struct msp_i2s_platform_data),
+ GFP_KERNEL);
+ pdata = *platform_data;
+ if (!pdata)
+ return -ENOMEM;
+
+ msp->playback_dma_data.dma_cfg = devm_kzalloc(&pdev->dev,
+ sizeof(struct stedma40_chan_cfg),
+ GFP_KERNEL);
+ if (!msp->playback_dma_data.dma_cfg)
+ return -ENOMEM;
+
+ msp->capture_dma_data.dma_cfg = devm_kzalloc(&pdev->dev,
+ sizeof(struct stedma40_chan_cfg),
+ GFP_KERNEL);
+ if (!msp->capture_dma_data.dma_cfg)
+ return -ENOMEM;
+
+ return 0;
+}
+
int ux500_msp_i2s_init_msp(struct platform_device *pdev,
struct ux500_msp **msp_p,
struct msp_i2s_platform_data *platform_data)
@@ -653,30 +681,28 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
struct resource *res = NULL;
struct device_node *np = pdev->dev.of_node;
struct ux500_msp *msp;
+ int ret;
*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
msp = *msp_p;
if (!msp)
return -ENOMEM;
- if (np) {
- if (!platform_data) {
- platform_data = devm_kzalloc(&pdev->dev,
- sizeof(struct msp_i2s_platform_data), GFP_KERNEL);
- if (!platform_data)
- return -ENOMEM;
- }
- } else
- if (!platform_data)
+ if (!platform_data) {
+ if (np) {
+ ret = ux500_msp_i2s_of_init_msp(pdev, msp,
+ &platform_data);
+ if (ret)
+ return ret;
+ } else
return -EINVAL;
+ } else {
+ msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
+ msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
+ msp->id = platform_data->id;
+ }
- dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
- pdev->name, platform_data->id);
-
- msp->id = platform_data->id;
msp->dev = &pdev->dev;
- msp->playback_dma_data.dma_cfg = platform_data->msp_i2s_dma_tx;
- msp->capture_dma_data.dma_cfg = platform_data->msp_i2s_dma_rx;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
index 258d0bcee0bd..875de0f68b85 100644
--- a/sound/soc/ux500/ux500_msp_i2s.h
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -475,7 +475,7 @@ struct ux500_msp_dma_params {
};
struct ux500_msp {
- enum msp_i2s_id id;
+ int id;
void __iomem *registers;
struct device *dev;
struct ux500_msp_dma_params playback_dma_data;
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index ce554de5d9dc..51a66a87305a 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -28,12 +28,6 @@
#include "ux500_msp_i2s.h"
#include "ux500_pcm.h"
-#define UX500_PLATFORM_MIN_RATE 8000
-#define UX500_PLATFORM_MAX_RATE 48000
-
-#define UX500_PLATFORM_MIN_CHANNELS 1
-#define UX500_PLATFORM_MAX_CHANNELS 8
-
#define UX500_PLATFORM_PERIODS_BYTES_MIN 128
#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE)
#define UX500_PLATFORM_PERIODS_MIN 2
@@ -45,15 +39,6 @@ static const struct snd_pcm_hardware ux500_pcm_hw = {
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE,
- .formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_U16_LE |
- SNDRV_PCM_FMTBIT_S16_BE |
- SNDRV_PCM_FMTBIT_U16_BE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = UX500_PLATFORM_MIN_RATE,
- .rate_max = UX500_PLATFORM_MAX_RATE,
- .channels_min = UX500_PLATFORM_MIN_CHANNELS,
- .channels_max = UX500_PLATFORM_MAX_CHANNELS,
.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
.period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
.period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
@@ -65,14 +50,10 @@ static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_substream *substream)
{
struct snd_soc_dai *dai = rtd->cpu_dai;
- struct device *dev = dai->dev;
u16 per_data_width, mem_data_width;
struct stedma40_chan_cfg *dma_cfg;
struct ux500_msp_dma_params *dma_params;
- dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
- snd_pcm_stream_str(substream));
-
dma_params = snd_soc_dai_get_dma_data(dai, substream);
dma_cfg = dma_params->dma_cfg;
@@ -108,26 +89,36 @@ static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
struct dma_slave_config *slave_config)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct ux500_msp_dma_params *dma_params;
- struct stedma40_chan_cfg *dma_cfg;
+ struct msp_i2s_platform_data *pdata = rtd->cpu_dai->dev->platform_data;
+ struct snd_dmaengine_dai_dma_data *snd_dma_params;
+ struct ux500_msp_dma_params *ste_dma_params;
+ dma_addr_t dma_addr;
int ret;
- dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
- dma_cfg = dma_params->dma_cfg;
+ if (pdata) {
+ ste_dma_params =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ dma_addr = ste_dma_params->tx_rx_addr;
+ } else {
+ snd_dma_params =
+ snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+ dma_addr = snd_dma_params->addr;
+ }
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
if (ret)
return ret;
slave_config->dst_maxburst = 4;
- slave_config->dst_addr_width = dma_cfg->dst_info.data_width;
slave_config->src_maxburst = 4;
- slave_config->src_addr_width = dma_cfg->src_info.data_width;
+
+ slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- slave_config->dst_addr = dma_params->tx_rx_addr;
+ slave_config->dst_addr = dma_addr;
else
- slave_config->src_addr = dma_params->tx_rx_addr;
+ slave_config->src_addr = dma_addr;
return 0;
}
@@ -139,15 +130,25 @@ static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
.prepare_slave_config = ux500_pcm_prepare_slave_config,
};
+static const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = {
+ .compat_request_channel = ux500_pcm_request_chan,
+ .prepare_slave_config = ux500_pcm_prepare_slave_config,
+};
+
int ux500_pcm_register_platform(struct platform_device *pdev)
{
+ const struct snd_dmaengine_pcm_config *pcm_config;
+ struct device_node *np = pdev->dev.of_node;
int ret;
- ret = snd_dmaengine_pcm_register(&pdev->dev,
- &ux500_dmaengine_pcm_config,
- SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
- SND_DMAENGINE_PCM_FLAG_COMPAT |
- SND_DMAENGINE_PCM_FLAG_NO_DT);
+ if (np)
+ pcm_config = &ux500_dmaengine_of_pcm_config;
+ else
+ pcm_config = &ux500_dmaengine_pcm_config;
+
+ ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config,
+ SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
if (ret < 0) {
dev_err(&pdev->dev,
"%s: ERROR: Failed to register platform '%s' (%d)!\n",
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 45759f4cca75..11e953a1fa45 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -626,31 +626,20 @@ static int soundcore_open(struct inode *inode, struct file *file)
if (s)
new_fops = fops_get(s->unit_fops);
}
+ spin_unlock(&sound_loader_lock);
if (new_fops) {
/*
* We rely upon the fact that we can't be unloaded while the
- * subdriver is there, so if ->open() is successful we can
- * safely drop the reference counter and if it is not we can
- * revert to old ->f_op. Ugly, indeed, but that's the cost of
- * switching ->f_op in the first place.
+ * subdriver is there.
*/
int err = 0;
- const struct file_operations *old_fops = file->f_op;
- file->f_op = new_fops;
- spin_unlock(&sound_loader_lock);
+ replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode,file);
- if (err) {
- fops_put(file->f_op);
- file->f_op = fops_get(old_fops);
- }
-
- fops_put(old_fops);
return err;
}
- spin_unlock(&sound_loader_lock);
return -ENODEV;
}
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 54aaad2a10f5..dbb1b625eb2f 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -429,7 +429,8 @@ static void snd_cs4231_advance_dma(struct cs4231_dma_control *dma_cont,
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
unsigned int offset = period_size * (*periods_sent);
- BUG_ON(period_size >= (1 << 24));
+ if (WARN_ON(period_size >= (1 << 24)))
+ return;
if (dma_cont->request(dma_cont,
runtime->dma_addr + offset, period_size))
@@ -906,18 +907,24 @@ static int snd_cs4231_playback_prepare(struct snd_pcm_substream *substream)
struct snd_cs4231 *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&chip->lock, flags);
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
CS4231_PLAYBACK_PIO);
- BUG_ON(runtime->period_size > 0xffff + 1);
+ if (WARN_ON(runtime->period_size > 0xffff + 1)) {
+ ret = -EINVAL;
+ goto out;
+ }
chip->p_periods_sent = 0;
+
+out:
spin_unlock_irqrestore(&chip->lock, flags);
- return 0;
+ return ret;
}
static int snd_cs4231_capture_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
index 8e3d9a6c7a3b..25c38afaee49 100644
--- a/sound/spi/at73c213.c
+++ b/sound/spi/at73c213.c
@@ -174,7 +174,7 @@ static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
dac_rate_new = 8 * (ssc_rate / ssc_div);
status = clk_round_rate(chip->board->dac_clk, dac_rate_new);
- if (status < 0)
+ if (status <= 0)
return status;
/* Ignore difference smaller than 256 Hz. */
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c
index c39c77978468..66edc4a7917f 100644
--- a/sound/usb/6fire/chip.c
+++ b/sound/usb/6fire/chip.c
@@ -101,7 +101,7 @@ static int usb6fire_chip_probe(struct usb_interface *intf,
usb_set_intfdata(intf, chips[i]);
mutex_unlock(&register_mutex);
return 0;
- } else if (regidx < 0)
+ } else if (!devices[i] && regidx < 0)
regidx = i;
}
if (regidx < 0) {
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index de9408b83f75..e05a86b7c0da 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -14,6 +14,7 @@ config SND_USB_AUDIO
select SND_HWDEP
select SND_RAWMIDI
select SND_PCM
+ select BITREVERSE
help
Say Y here to include support for USB audio and USB MIDI
devices.
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c
index ae6b50f9ed56..f65fc0987cfb 100644
--- a/sound/usb/caiaq/control.c
+++ b/sound/usb/caiaq/control.c
@@ -28,6 +28,7 @@
#include "control.h"
#define CNT_INTVAL 0x10000
+#define MASCHINE_BANK_SIZE 32
static int control_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
@@ -105,6 +106,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1))
cmd = EP1_CMD_DIMM_LEDS;
+ if (cdev->chip.usb_id ==
+ USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER))
+ cmd = EP1_CMD_DIMM_LEDS;
+
if (pos & CNT_INTVAL) {
int i = pos & ~CNT_INTVAL;
@@ -121,6 +126,20 @@ static int control_put(struct snd_kcontrol *kcontrol,
usb_sndbulkpipe(cdev->chip.dev, 8),
cdev->ep8_out_buf, sizeof(cdev->ep8_out_buf),
&actual_len, 200);
+ } else if (cdev->chip.usb_id ==
+ USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) {
+
+ int bank = 0;
+ int offset = 0;
+
+ if (i >= MASCHINE_BANK_SIZE) {
+ bank = 0x1e;
+ offset = MASCHINE_BANK_SIZE;
+ }
+
+ snd_usb_caiaq_send_command_bank(cdev, cmd, bank,
+ cdev->control_state + offset,
+ MASCHINE_BANK_SIZE);
} else {
snd_usb_caiaq_send_command(cdev, cmd,
cdev->control_state, sizeof(cdev->control_state));
@@ -490,6 +509,74 @@ static struct caiaq_controller kontrols4_controller[] = {
{ "LED: FX2: Mode", 133 | CNT_INTVAL },
};
+static struct caiaq_controller maschine_controller[] = {
+ { "LED: Pad 1", 3 | CNT_INTVAL },
+ { "LED: Pad 2", 2 | CNT_INTVAL },
+ { "LED: Pad 3", 1 | CNT_INTVAL },
+ { "LED: Pad 4", 0 | CNT_INTVAL },
+ { "LED: Pad 5", 7 | CNT_INTVAL },
+ { "LED: Pad 6", 6 | CNT_INTVAL },
+ { "LED: Pad 7", 5 | CNT_INTVAL },
+ { "LED: Pad 8", 4 | CNT_INTVAL },
+ { "LED: Pad 9", 11 | CNT_INTVAL },
+ { "LED: Pad 10", 10 | CNT_INTVAL },
+ { "LED: Pad 11", 9 | CNT_INTVAL },
+ { "LED: Pad 12", 8 | CNT_INTVAL },
+ { "LED: Pad 13", 15 | CNT_INTVAL },
+ { "LED: Pad 14", 14 | CNT_INTVAL },
+ { "LED: Pad 15", 13 | CNT_INTVAL },
+ { "LED: Pad 16", 12 | CNT_INTVAL },
+
+ { "LED: Mute", 16 | CNT_INTVAL },
+ { "LED: Solo", 17 | CNT_INTVAL },
+ { "LED: Select", 18 | CNT_INTVAL },
+ { "LED: Duplicate", 19 | CNT_INTVAL },
+ { "LED: Navigate", 20 | CNT_INTVAL },
+ { "LED: Pad Mode", 21 | CNT_INTVAL },
+ { "LED: Pattern", 22 | CNT_INTVAL },
+ { "LED: Scene", 23 | CNT_INTVAL },
+
+ { "LED: Shift", 24 | CNT_INTVAL },
+ { "LED: Erase", 25 | CNT_INTVAL },
+ { "LED: Grid", 26 | CNT_INTVAL },
+ { "LED: Right Bottom", 27 | CNT_INTVAL },
+ { "LED: Rec", 28 | CNT_INTVAL },
+ { "LED: Play", 29 | CNT_INTVAL },
+ { "LED: Left Bottom", 32 | CNT_INTVAL },
+ { "LED: Restart", 33 | CNT_INTVAL },
+
+ { "LED: Group A", 41 | CNT_INTVAL },
+ { "LED: Group B", 40 | CNT_INTVAL },
+ { "LED: Group C", 37 | CNT_INTVAL },
+ { "LED: Group D", 36 | CNT_INTVAL },
+ { "LED: Group E", 39 | CNT_INTVAL },
+ { "LED: Group F", 38 | CNT_INTVAL },
+ { "LED: Group G", 35 | CNT_INTVAL },
+ { "LED: Group H", 34 | CNT_INTVAL },
+
+ { "LED: Auto Write", 42 | CNT_INTVAL },
+ { "LED: Snap", 43 | CNT_INTVAL },
+ { "LED: Right Top", 44 | CNT_INTVAL },
+ { "LED: Left Top", 45 | CNT_INTVAL },
+ { "LED: Sampling", 46 | CNT_INTVAL },
+ { "LED: Browse", 47 | CNT_INTVAL },
+ { "LED: Step", 48 | CNT_INTVAL },
+ { "LED: Control", 49 | CNT_INTVAL },
+
+ { "LED: Top Button 1", 57 | CNT_INTVAL },
+ { "LED: Top Button 2", 56 | CNT_INTVAL },
+ { "LED: Top Button 3", 55 | CNT_INTVAL },
+ { "LED: Top Button 4", 54 | CNT_INTVAL },
+ { "LED: Top Button 5", 53 | CNT_INTVAL },
+ { "LED: Top Button 6", 52 | CNT_INTVAL },
+ { "LED: Top Button 7", 51 | CNT_INTVAL },
+ { "LED: Top Button 8", 50 | CNT_INTVAL },
+
+ { "LED: Note Repeat", 58 | CNT_INTVAL },
+
+ { "Backlight Display", 59 | CNT_INTVAL }
+};
+
static int add_controls(struct caiaq_controller *c, int num,
struct snd_usb_caiaqdev *cdev)
{
@@ -553,6 +640,11 @@ int snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *cdev)
ret = add_controls(kontrols4_controller,
ARRAY_SIZE(kontrols4_controller), cdev);
break;
+
+ case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
+ ret = add_controls(maschine_controller,
+ ARRAY_SIZE(maschine_controller), cdev);
+ break;
}
return ret;
diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c
index 1a61dd12fe38..bc55f708a696 100644
--- a/sound/usb/caiaq/device.c
+++ b/sound/usb/caiaq/device.c
@@ -235,6 +235,31 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,
cdev->ep1_out_buf, len+1, &actual_len, 200);
}
+int snd_usb_caiaq_send_command_bank(struct snd_usb_caiaqdev *cdev,
+ unsigned char command,
+ unsigned char bank,
+ const unsigned char *buffer,
+ int len)
+{
+ int actual_len;
+ struct usb_device *usb_dev = cdev->chip.dev;
+
+ if (!usb_dev)
+ return -EIO;
+
+ if (len > EP1_BUFSIZE - 2)
+ len = EP1_BUFSIZE - 2;
+
+ if (buffer && len > 0)
+ memcpy(cdev->ep1_out_buf+2, buffer, len);
+
+ cdev->ep1_out_buf[0] = command;
+ cdev->ep1_out_buf[1] = bank;
+
+ return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1),
+ cdev->ep1_out_buf, len+2, &actual_len, 200);
+}
+
int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev,
int rate, int depth, int bpp)
{
diff --git a/sound/usb/caiaq/device.h b/sound/usb/caiaq/device.h
index ad102fac6942..ab0f7520a99b 100644
--- a/sound/usb/caiaq/device.h
+++ b/sound/usb/caiaq/device.h
@@ -128,5 +128,10 @@ int snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev,
unsigned char command,
const unsigned char *buffer,
int len);
+int snd_usb_caiaq_send_command_bank(struct snd_usb_caiaqdev *cdev,
+ unsigned char command,
+ unsigned char bank,
+ const unsigned char *buffer,
+ int len);
#endif /* CAIAQ_DEVICE_H */
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 64952e2d3ed1..d979050e6a6a 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -79,7 +79,6 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card *
/* Vendor/product IDs for this card */
static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
-static int nrpacks = 8; /* max. number of packets per urb */
static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
static bool ignore_ctl_error;
static bool autoclock = true;
@@ -94,8 +93,6 @@ module_param_array(vid, int, NULL, 0444);
MODULE_PARM_DESC(vid, "Vendor ID for the USB audio device.");
module_param_array(pid, int, NULL, 0444);
MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
-module_param(nrpacks, int, 0644);
-MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
module_param_array(device_setup, int, NULL, 0444);
MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
module_param(ignore_ctl_error, bool, 0444);
@@ -349,6 +346,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
+ case USB_SPEED_WIRELESS:
case USB_SPEED_SUPER:
break;
default:
@@ -374,7 +372,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->dev = dev;
chip->card = card;
chip->setup = device_setup[idx];
- chip->nrpacks = nrpacks;
chip->autoclock = autoclock;
chip->probing = 1;
@@ -754,19 +751,4 @@ static struct usb_driver usb_audio_driver = {
.supports_autosuspend = 1,
};
-static int __init snd_usb_audio_init(void)
-{
- if (nrpacks < 1 || nrpacks > MAX_PACKS) {
- printk(KERN_WARNING "invalid nrpacks value.\n");
- return -EINVAL;
- }
- return usb_register(&usb_audio_driver);
-}
-
-static void __exit snd_usb_audio_cleanup(void)
-{
- usb_deregister(&usb_audio_driver);
-}
-
-module_init(snd_usb_audio_init);
-module_exit(snd_usb_audio_cleanup);
+module_usb_driver(usb_audio_driver);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 5ecacaa90b53..9867ab866857 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -2,11 +2,11 @@
#define __USBAUDIO_CARD_H
#define MAX_NR_RATES 1024
-#define MAX_PACKS 20
+#define MAX_PACKS 6 /* per URB */
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
-#define MAX_URBS 8
+#define MAX_URBS 12
#define SYNC_URBS 4 /* always four urbs for sync */
-#define MAX_QUEUE 24 /* try not to exceed this queue length, in ms */
+#define MAX_QUEUE 18 /* try not to exceed this queue length, in ms */
struct audioformat {
struct list_head list;
@@ -87,6 +87,7 @@ struct snd_usb_endpoint {
unsigned int phase; /* phase accumulator */
unsigned int maxpacksize; /* max packet size in bytes */
unsigned int maxframesize; /* max packet size in frames */
+ unsigned int max_urb_frames; /* max URB size in frames */
unsigned int curpacksize; /* current packet size in bytes (for capture) */
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int syncmaxsize; /* sync endpoint packet size */
@@ -95,7 +96,7 @@ struct snd_usb_endpoint {
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
unsigned char silence_value;
unsigned int stride;
- int iface, alt_idx;
+ int iface, altsetting;
int skip_packets; /* quirks for devices to ignore the first n packets
in a stream */
@@ -116,6 +117,8 @@ struct snd_usb_substream {
unsigned int channels_max; /* max channels in the all audiofmts */
unsigned int cur_rate; /* current rate (for hw_params callback) */
unsigned int period_bytes; /* current period bytes (for hw_params callback) */
+ unsigned int period_frames; /* current frames per period */
+ unsigned int buffer_periods; /* current periods per buffer */
unsigned int altset_idx; /* USB data format: index of alternate setting */
unsigned int txfr_quirk:1; /* allow sub-frame alignment */
unsigned int fmt_type; /* USB audio format type (1-3) */
@@ -125,6 +128,7 @@ struct snd_usb_substream {
unsigned int hwptr_done; /* processed byte position in the buffer */
unsigned int transfer_done; /* processed frames since last period update */
+ unsigned int frame_limit; /* limits number of packets in URB */
/* data and sync endpoints for this stream */
unsigned int ep_num; /* the endpoint number */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 93e970f2b3c0..83aabea259d7 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -33,7 +33,6 @@
#include "pcm.h"
#include "quirks.h"
-#define EP_FLAG_ACTIVATED 0
#define EP_FLAG_RUNNING 1
#define EP_FLAG_STOPPING 2
@@ -426,9 +425,9 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
list_for_each_entry(ep, &chip->ep_list, list) {
if (ep->ep_num == ep_num &&
ep->iface == alts->desc.bInterfaceNumber &&
- ep->alt_idx == alts->desc.bAlternateSetting) {
+ ep->altsetting == alts->desc.bAlternateSetting) {
snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
- ep_num, ep->iface, ep->alt_idx, ep);
+ ep_num, ep->iface, ep->altsetting, ep);
goto __exit_unlock;
}
}
@@ -447,7 +446,7 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
ep->type = type;
ep->ep_num = ep_num;
ep->iface = alts->desc.bInterfaceNumber;
- ep->alt_idx = alts->desc.bAlternateSetting;
+ ep->altsetting = alts->desc.bAlternateSetting;
INIT_LIST_HEAD(&ep->ready_playback_urbs);
ep_num &= USB_ENDPOINT_NUMBER_MASK;
@@ -574,11 +573,14 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
snd_pcm_format_t pcm_format,
unsigned int channels,
unsigned int period_bytes,
+ unsigned int frames_per_period,
+ unsigned int periods_per_buffer,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep)
{
- unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
- int is_playback = usb_pipeout(ep->pipe);
+ unsigned int maxsize, minsize, packs_per_ms, max_packs_per_urb;
+ unsigned int max_packs_per_period, urbs_per_period, urb_packs;
+ unsigned int max_urbs, i;
int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels;
if (pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && fmt->dsd_dop) {
@@ -611,58 +613,81 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
else
ep->curpacksize = maxsize;
- if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+ if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) {
packs_per_ms = 8 >> ep->datainterval;
- else
- packs_per_ms = 1;
-
- if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
- urb_packs = max(ep->chip->nrpacks, 1);
- urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
+ max_packs_per_urb = MAX_PACKS_HS;
} else {
- urb_packs = 1;
+ packs_per_ms = 1;
+ max_packs_per_urb = MAX_PACKS;
}
+ if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
+ max_packs_per_urb = min(max_packs_per_urb,
+ 1U << sync_ep->syncinterval);
+ max_packs_per_urb = max(1u, max_packs_per_urb >> ep->datainterval);
- urb_packs *= packs_per_ms;
+ /*
+ * Capture endpoints need to use small URBs because there's no way
+ * to tell in advance where the next period will end, and we don't
+ * want the next URB to complete much after the period ends.
+ *
+ * Playback endpoints with implicit sync much use the same parameters
+ * as their corresponding capture endpoint.
+ */
+ if (usb_pipein(ep->pipe) ||
+ snd_usb_endpoint_implicit_feedback_sink(ep)) {
- if (sync_ep && !snd_usb_endpoint_implicit_feedback_sink(ep))
- urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
+ urb_packs = packs_per_ms;
+ /*
+ * Wireless devices can poll at a max rate of once per 4ms.
+ * For dataintervals less than 5, increase the packet count to
+ * allow the host controller to use bursting to fill in the
+ * gaps.
+ */
+ if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_WIRELESS) {
+ int interval = ep->datainterval;
+ while (interval < 5) {
+ urb_packs <<= 1;
+ ++interval;
+ }
+ }
+ /* make capture URBs <= 1 ms and smaller than a period */
+ urb_packs = min(max_packs_per_urb, urb_packs);
+ while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
+ urb_packs >>= 1;
+ ep->nurbs = MAX_URBS;
- /* decide how many packets to be used */
- if (is_playback && !snd_usb_endpoint_implicit_feedback_sink(ep)) {
- unsigned int minsize, maxpacks;
+ /*
+ * Playback endpoints without implicit sync are adjusted so that
+ * a period fits as evenly as possible in the smallest number of
+ * URBs. The total number of URBs is adjusted to the size of the
+ * ALSA buffer, subject to the MAX_URBS and MAX_QUEUE limits.
+ */
+ } else {
/* determine how small a packet can be */
- minsize = (ep->freqn >> (16 - ep->datainterval))
- * (frame_bits >> 3);
+ minsize = (ep->freqn >> (16 - ep->datainterval)) *
+ (frame_bits >> 3);
/* with sync from device, assume it can be 12% lower */
if (sync_ep)
minsize -= minsize >> 3;
minsize = max(minsize, 1u);
- total_packs = (period_bytes + minsize - 1) / minsize;
- /* we need at least two URBs for queueing */
- if (total_packs < 2) {
- total_packs = 2;
- } else {
- /* and we don't want too long a queue either */
- maxpacks = max(MAX_QUEUE * packs_per_ms, urb_packs * 2);
- total_packs = min(total_packs, maxpacks);
- }
- } else {
- while (urb_packs > 1 && urb_packs * maxsize >= period_bytes)
- urb_packs >>= 1;
- total_packs = MAX_URBS * urb_packs;
- }
- ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
- if (ep->nurbs > MAX_URBS) {
- /* too much... */
- ep->nurbs = MAX_URBS;
- total_packs = MAX_URBS * urb_packs;
- } else if (ep->nurbs < 2) {
- /* too little - we need at least two packets
- * to ensure contiguous playback/capture
- */
- ep->nurbs = 2;
+ /* how many packets will contain an entire ALSA period? */
+ max_packs_per_period = DIV_ROUND_UP(period_bytes, minsize);
+
+ /* how many URBs will contain a period? */
+ urbs_per_period = DIV_ROUND_UP(max_packs_per_period,
+ max_packs_per_urb);
+ /* how many packets are needed in each URB? */
+ urb_packs = DIV_ROUND_UP(max_packs_per_period, urbs_per_period);
+
+ /* limit the number of frames in a single URB */
+ ep->max_urb_frames = DIV_ROUND_UP(frames_per_period,
+ urbs_per_period);
+
+ /* try to use enough URBs to contain an entire ALSA buffer */
+ max_urbs = min((unsigned) MAX_URBS,
+ MAX_QUEUE * packs_per_ms / urb_packs);
+ ep->nurbs = min(max_urbs, urbs_per_period * periods_per_buffer);
}
/* allocate and initialize data urbs */
@@ -670,8 +695,7 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
struct snd_urb_ctx *u = &ep->urb[i];
u->index = i;
u->ep = ep;
- u->packets = (i + 1) * total_packs / ep->nurbs
- - i * total_packs / ep->nurbs;
+ u->packets = urb_packs;
u->buffer_size = maxsize * u->packets;
if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
@@ -703,8 +727,7 @@ out_of_memory:
/*
* configure a sync endpoint
*/
-static int sync_ep_set_params(struct snd_usb_endpoint *ep,
- struct audioformat *fmt)
+static int sync_ep_set_params(struct snd_usb_endpoint *ep)
{
int i;
@@ -748,6 +771,8 @@ out_of_memory:
* @pcm_format: the audio fomat.
* @channels: the number of audio channels.
* @period_bytes: the number of bytes in one alsa period.
+ * @period_frames: the number of frames in one alsa period.
+ * @buffer_periods: the number of periods in one alsa buffer.
* @rate: the frame rate.
* @fmt: the USB audio format information
* @sync_ep: the sync endpoint to use, if any
@@ -760,6 +785,8 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
snd_pcm_format_t pcm_format,
unsigned int channels,
unsigned int period_bytes,
+ unsigned int period_frames,
+ unsigned int buffer_periods,
unsigned int rate,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep)
@@ -793,10 +820,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
switch (ep->type) {
case SND_USB_ENDPOINT_TYPE_DATA:
err = data_ep_set_params(ep, pcm_format, channels,
- period_bytes, fmt, sync_ep);
+ period_bytes, period_frames,
+ buffer_periods, fmt, sync_ep);
break;
case SND_USB_ENDPOINT_TYPE_SYNC:
- err = sync_ep_set_params(ep, fmt);
+ err = sync_ep_set_params(ep);
break;
default:
err = -EINVAL;
@@ -931,28 +959,21 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
*
* @ep: the endpoint to deactivate
*
- * If the endpoint is not currently in use, this functions will select the
- * alternate interface setting 0 for the interface of this endpoint.
+ * If the endpoint is not currently in use, this functions will
+ * deactivate its associated URBs.
*
* In case of any active users, this functions does nothing.
- *
- * Returns an error if usb_set_interface() failed, 0 in all other
- * cases.
*/
-int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
+void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
{
if (!ep)
- return -EINVAL;
-
- deactivate_urbs(ep, true);
- wait_clear_urbs(ep);
+ return;
if (ep->use_count != 0)
- return 0;
-
- clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
+ return;
- return 0;
+ deactivate_urbs(ep, true);
+ wait_clear_urbs(ep);
}
/**
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 2287adf5ca59..1c7e8ee48abc 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -12,6 +12,8 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
snd_pcm_format_t pcm_format,
unsigned int channels,
unsigned int period_bytes,
+ unsigned int period_frames,
+ unsigned int buffer_periods,
unsigned int rate,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep);
@@ -20,7 +22,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep);
void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
-int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_free(struct list_head *head);
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 3525231c6b97..d244fd3703d8 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -189,8 +189,10 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
chip->usb_id == USB_ID(0x0ccd, 0x00b1)) &&
fp->altsetting == 5 && fp->maxpacksize == 392)
rate = 96000;
- /* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */
- if (rate == 16000 && chip->usb_id == USB_ID(0x041e, 0x4068))
+ /* Creative VF0420/VF0470 Live Cams report 16 kHz instead of 8kHz */
+ if (rate == 16000 &&
+ (chip->usb_id == USB_ID(0x041e, 0x4064) ||
+ chip->usb_id == USB_ID(0x041e, 0x4068)))
rate = 8000;
fp->rate_table[fp->nr_rates] = rate;
diff --git a/sound/usb/helper.c b/sound/usb/helper.c
index 620902463c6e..51ed1ac825fd 100644
--- a/sound/usb/helper.c
+++ b/sound/usb/helper.c
@@ -118,6 +118,7 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
{
switch (snd_usb_get_speed(chip->dev)) {
case USB_SPEED_HIGH:
+ case USB_SPEED_WIRELESS:
case USB_SPEED_SUPER:
if (get_endpoint(alts, 0)->bInterval >= 1 &&
get_endpoint(alts, 0)->bInterval <= 4)
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
index c21a3df9a0df..2c44139b4041 100644
--- a/sound/usb/hiface/pcm.c
+++ b/sound/usb/hiface/pcm.c
@@ -110,7 +110,7 @@ static const struct snd_pcm_hardware pcm_hw = {
#define HIFACE_RATE_96000 0x4a
#define HIFACE_RATE_176400 0x40
#define HIFACE_RATE_192000 0x48
-#define HIFACE_RATE_352000 0x58
+#define HIFACE_RATE_352800 0x58
#define HIFACE_RATE_384000 0x68
static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate)
@@ -141,8 +141,8 @@ static int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate)
case 192000:
rate_value = HIFACE_RATE_192000;
break;
- case 352000:
- rate_value = HIFACE_RATE_352000;
+ case 352800:
+ rate_value = HIFACE_RATE_352800;
break;
case 384000:
rate_value = HIFACE_RATE_384000;
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 95558ef4a7a0..44b0ba4feab3 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1151,14 +1151,14 @@ static void check_no_speaker_on_headset(struct snd_kcontrol *kctl,
const char *names_to_check[] = {
"Headset", "headset", "Headphone", "headphone", NULL};
const char **s;
- bool found = 0;
+ bool found = false;
if (strcmp("Speaker", kctl->id.name))
return;
for (s = names_to_check; *s; s++)
if (strstr(card->shortname, *s)) {
- found = 1;
+ found = true;
break;
}
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index cc2dd1f0decb..32af6b741ef5 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -322,6 +322,12 @@ static struct usbmix_name_map hercules_usb51_map[] = {
{ 0 } /* terminator */
};
+/* Plantronics Gamecom 780 has a broken volume control, better to disable it */
+static struct usbmix_name_map gamecom780_map[] = {
+ { 9, NULL }, /* FU, speaker out */
+ {}
+};
+
/*
* Control map entries
*/
@@ -358,6 +364,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x046d, 0x09a4),
.ignore_ctl_error = 1,
},
+ { /* Plantronics GameCom 780 */
+ .id = USB_ID(0x047f, 0xc010),
+ .map = gamecom780_map,
+ },
{
/* Hercules DJ Console (Windows Edition) */
.id = USB_ID(0x06f8, 0xb000),
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index d42a584cf829..f4b12c216f1c 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -433,6 +433,89 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
}
}
+/* EMU0204 */
+static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *texts[2] = {"1/2",
+ "3/4"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item > 1)
+ uinfo->value.enumerated.item = 1;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = kcontrol->private_value;
+ return 0;
+}
+
+static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ unsigned int value = ucontrol->value.enumerated.item[0];
+ int err, changed;
+ unsigned char buf[2];
+
+ if (value > 1)
+ return -EINVAL;
+
+ buf[0] = 0x01;
+ buf[1] = value ? 0x02 : 0x01;
+
+ changed = value != kcontrol->private_value;
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown) {
+ err = -ENODEV;
+ goto out;
+ }
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ 0x0400, 0x0e00, buf, 2);
+ out:
+ up_read(&mixer->chip->shutdown_rwsem);
+ if (err < 0)
+ return err;
+ kcontrol->private_value = value;
+ return changed;
+}
+
+
+static struct snd_kcontrol_new snd_emu0204_controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Jack Channels",
+ .info = snd_emu0204_ch_switch_info,
+ .get = snd_emu0204_ch_switch_get,
+ .put = snd_emu0204_ch_switch_put,
+ .private_value = 0,
+ },
+};
+
+static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer)
+{
+ int i, err;
+
+ for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) {
+ err = snd_ctl_add(mixer->chip->card,
+ snd_ctl_new1(&snd_emu0204_controls[i], mixer));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
/* ASUS Xonar U1 / U3 controls */
static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
@@ -1520,7 +1603,7 @@ static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
return err;
}
- return err;
+ return 0;
}
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
@@ -1545,6 +1628,13 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
snd_audigy2nx_proc_read);
break;
+ /* EMU0204 */
+ case USB_ID(0x041e, 0x3f19):
+ err = snd_emu0204_controls_create(mixer);
+ if (err < 0)
+ break;
+ break;
+
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C400 */
err = snd_c400_create_mixer(mixer);
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index b375d58871e7..ca3256d6fde3 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -241,16 +241,17 @@ static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
struct snd_usb_endpoint *ep = subs->sync_endpoint;
if (subs->data_endpoint->iface != subs->sync_endpoint->iface ||
- subs->data_endpoint->alt_idx != subs->sync_endpoint->alt_idx) {
+ subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) {
err = usb_set_interface(subs->dev,
subs->sync_endpoint->iface,
- subs->sync_endpoint->alt_idx);
+ subs->sync_endpoint->altsetting);
if (err < 0) {
+ clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
snd_printk(KERN_ERR
"%d:%d:%d: cannot set interface (%d)\n",
subs->dev->devnum,
subs->sync_endpoint->iface,
- subs->sync_endpoint->alt_idx, err);
+ subs->sync_endpoint->altsetting, err);
return -EIO;
}
}
@@ -282,22 +283,6 @@ static void stop_endpoints(struct snd_usb_substream *subs, bool wait)
}
}
-static int deactivate_endpoints(struct snd_usb_substream *subs)
-{
- int reta, retb;
-
- reta = snd_usb_endpoint_deactivate(subs->sync_endpoint);
- retb = snd_usb_endpoint_deactivate(subs->data_endpoint);
-
- if (reta < 0)
- return reta;
-
- if (retb < 0)
- return retb;
-
- return 0;
-}
-
static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
unsigned int altsetting,
struct usb_host_interface **alts,
@@ -595,6 +580,7 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
subs->pcm_format,
subs->channels,
subs->period_bytes,
+ 0, 0,
subs->cur_rate,
subs->cur_audiofmt,
NULL);
@@ -631,6 +617,7 @@ static int configure_sync_endpoint(struct snd_usb_substream *subs)
subs->pcm_format,
sync_fp->channels,
sync_period_bytes,
+ 0, 0,
subs->cur_rate,
sync_fp,
NULL);
@@ -653,6 +640,8 @@ static int configure_endpoint(struct snd_usb_substream *subs)
subs->pcm_format,
subs->channels,
subs->period_bytes,
+ subs->period_frames,
+ subs->buffer_periods,
subs->cur_rate,
subs->cur_audiofmt,
subs->sync_endpoint);
@@ -689,6 +678,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
subs->pcm_format = params_format(hw_params);
subs->period_bytes = params_period_bytes(hw_params);
+ subs->period_frames = params_period_size(hw_params);
+ subs->buffer_periods = params_periods(hw_params);
subs->channels = params_channels(hw_params);
subs->cur_rate = params_rate(hw_params);
@@ -730,7 +721,8 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
down_read(&subs->stream->chip->shutdown_rwsem);
if (!subs->stream->chip->shutdown) {
stop_endpoints(subs, true);
- deactivate_endpoints(subs);
+ snd_usb_endpoint_deactivate(subs->sync_endpoint);
+ snd_usb_endpoint_deactivate(subs->data_endpoint);
}
up_read(&subs->stream->chip->shutdown_rwsem);
return snd_pcm_lib_free_vmalloc_buffer(substream);
@@ -1363,6 +1355,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
frames = 0;
urb->number_of_packets = 0;
spin_lock_irqsave(&subs->lock, flags);
+ subs->frame_limit += ep->max_urb_frames;
for (i = 0; i < ctx->packets; i++) {
if (ctx->packet_size[i])
counts = ctx->packet_size[i];
@@ -1377,6 +1370,7 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
subs->transfer_done += counts;
if (subs->transfer_done >= runtime->period_size) {
subs->transfer_done -= runtime->period_size;
+ subs->frame_limit = 0;
period_elapsed = 1;
if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
if (subs->transfer_done > 0) {
@@ -1399,8 +1393,10 @@ static void prepare_playback_urb(struct snd_usb_substream *subs,
break;
}
}
- if (period_elapsed &&
- !snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+ /* finish at the period boundary or after enough frames */
+ if ((period_elapsed ||
+ subs->transfer_done >= subs->frame_limit) &&
+ !snd_usb_endpoint_implicit_feedback_sink(ep))
break;
}
bytes = frames * ep->stride;
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index f5f0595ef9c7..f652b10ce905 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -72,22 +72,21 @@
}
},
-/* Creative/Toshiba Multimedia Center SB-0500 */
+/* Creative/E-Mu devices */
{
- USB_DEVICE(0x041e, 0x3048),
+ USB_DEVICE(0x041e, 0x3010),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Toshiba",
- .product_name = "SB-0500",
+ .vendor_name = "Creative Labs",
+ .product_name = "Sound Blaster MP3+",
.ifnum = QUIRK_NO_INTERFACE
}
},
-
-/* Creative/E-Mu devices */
+/* Creative/Toshiba Multimedia Center SB-0500 */
{
- USB_DEVICE(0x041e, 0x3010),
+ USB_DEVICE(0x041e, 0x3048),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Creative Labs",
- .product_name = "Sound Blaster MP3+",
+ .vendor_name = "Toshiba",
+ .product_name = "SB-0500",
.ifnum = QUIRK_NO_INTERFACE
}
},
@@ -2521,6 +2520,46 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ USB_DEVICE(0x1235, 0x0010),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .vendor_name = "Focusrite",
+ .product_name = "Saffire 6 USB",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 0,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC,
+ .rates = SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+ .rate_max = 48000,
+ .nr_rates = 2,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000
+ }
+ }
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_MIDI_RAW_BYTES
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+{
USB_DEVICE(0x1235, 0x0018),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
.vendor_name = "Novation",
@@ -2569,6 +2608,57 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.type = QUIRK_MIDI_NOVATION
}
},
+{
+ /*
+ * Focusrite Scarlett 18i6
+ *
+ * Avoid mixer creation, which otherwise fails because some of
+ * the interface descriptor subtypes for interface 0 are
+ * unknown. That should be fixed or worked-around but this at
+ * least allows the device to be used successfully with a DAW
+ * and an external mixer. See comments below about other
+ * ignored interfaces.
+ */
+ USB_DEVICE(0x1235, 0x8004),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Focusrite",
+ .product_name = "Scarlett 18i6",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = & (const struct snd_usb_audio_quirk[]) {
+ {
+ /* InterfaceSubClass 1 (Control Device) */
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ /* InterfaceSubClass 1 (Control Device) */
+ .ifnum = 3,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 4,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ /* InterfaceSubClass 1 (Device Firmware Update) */
+ .ifnum = 5,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
/* Access Music devices */
{
@@ -2671,7 +2761,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2679,13 +2769,13 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
.vendor_name = "Hauppauge",
- .product_name = "HVR-850",
+ .product_name = "HVR-950Q",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_AUDIO_ALIGN_TRANSFER,
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2699,7 +2789,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2713,7 +2803,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2727,7 +2817,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2741,7 +2831,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f),
+ USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240),
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
@@ -2749,7 +2839,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
.vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
+ .product_name = "HVR-850",
.ifnum = QUIRK_ANY_INTERFACE,
.type = QUIRK_AUDIO_ALIGN_TRANSFER,
}
@@ -3054,58 +3144,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
{
/*
- * Focusrite Scarlett 18i6
- *
- * Avoid mixer creation, which otherwise fails because some of
- * the interface descriptor subtypes for interface 0 are
- * unknown. That should be fixed or worked-around but this at
- * least allows the device to be used successfully with a DAW
- * and an external mixer. See comments below about other
- * ignored interfaces.
- */
- USB_DEVICE(0x1235, 0x8004),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Focusrite",
- .product_name = "Scarlett 18i6",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_COMPOSITE,
- .data = & (const struct snd_usb_audio_quirk[]) {
- {
- /* InterfaceSubClass 1 (Control Device) */
- .ifnum = 0,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- /* InterfaceSubClass 1 (Control Device) */
- .ifnum = 3,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = 4,
- .type = QUIRK_MIDI_STANDARD_INTERFACE
- },
- {
- /* InterfaceSubClass 1 (Device Firmware Update) */
- .ifnum = 5,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = -1
- }
- }
- }
-},
-
-{
- /*
* Some USB MIDI devices don't have an audio control interface,
* so we have to grab MIDI streaming interfaces here.
*/
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 0df9ede99dfd..89730707614c 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -660,10 +660,23 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev)
return err;
}
+/* quirk for Plantronics GameCom 780 with CM6302 chip */
+static int snd_usb_gamecon780_boot_quirk(struct usb_device *dev)
+{
+ /* set the initial volume and don't change; other values are either
+ * too loud or silent due to firmware bug (bko#65251)
+ */
+ u8 buf[2] = { 0x74, 0xdc };
+ return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ UAC_FU_VOLUME << 8, 9 << 8, buf, 2);
+}
+
/*
* Novation Twitch DJ controller
+ * Focusrite Novation Saffire 6 USB audio card
*/
-static int snd_usb_twitch_boot_quirk(struct usb_device *dev)
+static int snd_usb_novation_boot_quirk(struct usb_device *dev)
{
/* preemptively set up the device because otherwise the
* raw MIDI endpoints are not active */
@@ -972,9 +985,9 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
/* Digidesign Mbox 2 */
return snd_usb_mbox2_boot_quirk(dev);
- case USB_ID(0x1235, 0x0018):
- /* Focusrite Novation Twitch */
- return snd_usb_twitch_boot_quirk(dev);
+ case USB_ID(0x1235, 0x0010): /* Focusrite Novation Saffire 6 USB */
+ case USB_ID(0x1235, 0x0018): /* Focusrite Novation Twitch */
+ return snd_usb_novation_boot_quirk(dev);
case USB_ID(0x133e, 0x0815):
/* Access Music VirusTI Desktop */
@@ -986,6 +999,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
return snd_usb_nativeinstruments_boot_quirk(dev);
case USB_ID(0x0763, 0x2012): /* M-Audio Fast Track Pro USB */
return snd_usb_fasttrackpro_boot_quirk(dev);
+ case USB_ID(0x047f, 0xc010): /* Plantronics Gamecom 780 */
+ return snd_usb_gamecon780_boot_quirk(dev);
}
return 0;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index c4339f97226b..2fb71be5e100 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -273,16 +273,14 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
SNDRV_CHMAP_TSL, /* top side left */
SNDRV_CHMAP_TSR, /* top side right */
SNDRV_CHMAP_BC, /* bottom center */
- SNDRV_CHMAP_BLC, /* bottom left center */
- SNDRV_CHMAP_BRC, /* bottom right center */
+ SNDRV_CHMAP_RLC, /* back left of center */
+ SNDRV_CHMAP_RRC, /* back right of center */
0 /* terminator */
};
struct snd_pcm_chmap_elem *chmap;
const unsigned int *maps;
int c;
- if (!bits)
- return NULL;
if (channels > ARRAY_SIZE(chmap->map))
return NULL;
@@ -293,9 +291,19 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits,
maps = protocol == UAC_VERSION_2 ? uac2_maps : uac1_maps;
chmap->channels = channels;
c = 0;
- for (; bits && *maps; maps++, bits >>= 1) {
- if (bits & 1)
- chmap->map[c++] = *maps;
+
+ if (bits) {
+ for (; bits && *maps; maps++, bits >>= 1)
+ if (bits & 1)
+ chmap->map[c++] = *maps;
+ } else {
+ /* If we're missing wChannelConfig, then guess something
+ to make sure the channel map is not skipped entirely */
+ if (channels == 1)
+ chmap->map[c++] = SNDRV_CHMAP_MONO;
+ else
+ for (; c < channels && *maps; maps++)
+ chmap->map[c++] = *maps;
}
for (; c < channels; c++)
@@ -579,6 +587,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
num_channels = as->bNrChannels;
format = le32_to_cpu(as->bmFormats);
+ chconfig = le32_to_cpu(as->bmChannelConfig);
/* lookup the terminal associated to this interface
* to extract the clock */
@@ -586,7 +595,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
as->bTerminalLink);
if (input_term) {
clock = input_term->bCSourceID;
- chconfig = le32_to_cpu(input_term->bmChannelConfig);
+ if (!chconfig && (num_channels == input_term->bNrChannels))
+ chconfig = le32_to_cpu(input_term->bmChannelConfig);
break;
}
@@ -652,7 +662,6 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
* (fp->maxpacksize & 0x7ff);
fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
fp->clock = clock;
- fp->chmap = convert_chmap(num_channels, chconfig, protocol);
/* some quirks for attributes here */
@@ -688,12 +697,16 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
/* ok, let's parse further... */
if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) {
kfree(fp->rate_table);
- kfree(fp->chmap);
kfree(fp);
fp = NULL;
continue;
}
+ /* Create chmap */
+ if (fp->channels != num_channels)
+ chconfig = 0;
+ fp->chmap = convert_chmap(fp->channels, chconfig, protocol);
+
snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index caabe9b3af49..5d2fe0530745 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -55,7 +55,6 @@ struct snd_usb_audio {
struct list_head mixer_list; /* list of mixer interfaces */
int setup; /* from the 'device_setup' module param */
- int nrpacks; /* from the 'nrpacks' module param */
bool autoclock; /* from the 'autoclock' module param */
struct usb_host_interface *ctrl_intf; /* the audio control interface */
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index d0323a693ba2..999550bbad40 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -262,7 +262,9 @@ static int usb_stream_hwdep_mmap(struct snd_hwdep *hw,
}
area->vm_ops = &usb_stream_hwdep_vm_ops;
- area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ area->vm_flags |= VM_DONTDUMP;
+ if (!read)
+ area->vm_flags |= VM_DONTEXPAND;
area->vm_private_data = us122l;
atomic_inc(&us122l->mmap_count);
out:
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 63fb5219f0f8..6234a51625b1 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -299,19 +299,6 @@ static void usX2Y_error_urb_status(struct usX2Ydev *usX2Y,
usX2Y_clients_stop(usX2Y);
}
-static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
- struct snd_usX2Y_substream *subs, struct urb *urb)
-{
- snd_printk(KERN_ERR
-"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
-"Most probably some urb of usb-frame %i is still missing.\n"
-"Cause could be too long delays in usb-hcd interrupt handling.\n",
- usb_get_current_frame_number(usX2Y->dev),
- subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
- usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame);
- usX2Y_clients_stop(usX2Y);
-}
-
static void i_usX2Y_urb_complete(struct urb *urb)
{
struct snd_usX2Y_substream *subs = urb->context;
@@ -328,12 +315,9 @@ static void i_usX2Y_urb_complete(struct urb *urb)
usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
- subs->completed_urb = urb;
- else {
- usX2Y_error_sequence(usX2Y, subs, urb);
- return;
- }
+
+ subs->completed_urb = urb;
+
{
struct snd_usX2Y_substream *capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE],
*playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index f2a1acdc4d83..814d0e887c62 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -244,13 +244,8 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (likely((urb->start_frame & 0xFFFF) == (usX2Y->wait_iso_frame & 0xFFFF)))
- subs->completed_urb = urb;
- else {
- usX2Y_error_sequence(usX2Y, subs, urb);
- return;
- }
+ subs->completed_urb = urb;
capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
OpenPOWER on IntegriCloud