aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/Makefile2
-rw-r--r--sound/core/control.c1
-rw-r--r--sound/core/hrtimer.c2
-rw-r--r--sound/core/hwdep.c1
-rw-r--r--sound/core/misc.c20
-rw-r--r--sound/core/oss/pcm_oss.c3
-rw-r--r--sound/core/pcm_lib.c1
-rw-r--r--sound/core/pcm_native.c16
-rw-r--r--sound/core/rawmidi.c8
-rw-r--r--sound/core/seq/oss/seq_oss_device.h2
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c1
-rw-r--r--sound/core/seq/seq_clientmgr.c1
-rw-r--r--sound/core/seq/seq_fifo.c12
-rw-r--r--sound/core/seq/seq_memory.c27
-rw-r--r--sound/core/seq/seq_memory.h1
-rw-r--r--sound/core/seq/seq_queue.c33
-rw-r--r--sound/core/seq/seq_virmidi.c4
-rw-r--r--sound/core/timer.c19
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c4
-rw-r--r--sound/drivers/mtpav.c4
-rw-r--r--sound/drivers/mts64.c4
-rw-r--r--sound/drivers/opl3/opl3_lib.c2
-rw-r--r--sound/drivers/pcsp/pcsp_lib.c2
-rw-r--r--sound/drivers/portman2x4.c4
-rw-r--r--sound/drivers/serial-u16550.c4
-rw-r--r--sound/drivers/vx/vx_pcm.c8
-rw-r--r--sound/firewire/Kconfig1
-rw-r--r--sound/firewire/bebob/bebob.c4
-rw-r--r--sound/firewire/bebob/bebob.h1
-rw-r--r--sound/firewire/bebob/bebob_hwdep.c17
-rw-r--r--sound/firewire/bebob/bebob_midi.c26
-rw-r--r--sound/firewire/bebob/bebob_pcm.c51
-rw-r--r--sound/firewire/dice/dice-interface.h1
-rw-r--r--sound/firewire/dice/dice-midi.c22
-rw-r--r--sound/firewire/dice/dice-stream.c12
-rw-r--r--sound/firewire/dice/dice.h1
-rw-r--r--sound/firewire/digi00x/digi00x-hwdep.c17
-rw-r--r--sound/firewire/digi00x/digi00x-midi.c52
-rw-r--r--sound/firewire/digi00x/digi00x-pcm.c52
-rw-r--r--sound/firewire/digi00x/digi00x.h1
-rw-r--r--sound/firewire/fireworks/fireworks.h1
-rw-r--r--sound/firewire/fireworks/fireworks_hwdep.c19
-rw-r--r--sound/firewire/fireworks/fireworks_midi.c26
-rw-r--r--sound/firewire/fireworks/fireworks_pcm.c52
-rw-r--r--sound/firewire/fireworks/fireworks_stream.c2
-rw-r--r--sound/firewire/lib.c6
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c26
-rw-r--r--sound/firewire/oxfw/oxfw-scs1x.c14
-rw-r--r--sound/firewire/oxfw/oxfw.c1
-rw-r--r--sound/firewire/oxfw/oxfw.h1
-rw-r--r--sound/firewire/tascam/tascam-hwdep.c17
-rw-r--r--sound/firewire/tascam/tascam-midi.c26
-rw-r--r--sound/firewire/tascam/tascam-pcm.c52
-rw-r--r--sound/firewire/tascam/tascam-stream.c2
-rw-r--r--sound/firewire/tascam/tascam.h1
-rw-r--r--sound/hda/ext/hdac_ext_stream.c15
-rw-r--r--sound/hda/hdac_controller.c2
-rw-r--r--sound/hda/hdac_i915.c18
-rw-r--r--sound/hda/hdac_stream.c6
-rw-r--r--sound/isa/gus/gus_pcm.c2
-rw-r--r--sound/isa/gus/gus_uart.c4
-rw-r--r--sound/isa/msnd/msnd.c1
-rw-r--r--sound/isa/msnd/msnd_midi.c2
-rw-r--r--sound/isa/sb/emu8000.c2
-rw-r--r--sound/isa/sb/emu8000_patch.c2
-rw-r--r--sound/isa/sb/emu8000_pcm.c2
-rw-r--r--sound/isa/sb/sb8_midi.c4
-rw-r--r--sound/isa/wavefront/wavefront_midi.c4
-rw-r--r--sound/isa/wavefront/wavefront_synth.c1
-rw-r--r--sound/mips/hal2.c4
-rw-r--r--sound/oss/ad1848.c7
-rw-r--r--sound/oss/dmabuf.c2
-rw-r--r--sound/oss/dmasound/dmasound_atari.c2
-rw-r--r--sound/oss/dmasound/dmasound_core.c3
-rw-r--r--sound/oss/dmasound/dmasound_paula.c2
-rw-r--r--sound/oss/dmasound/dmasound_q40.c2
-rw-r--r--sound/oss/midibuf.c2
-rw-r--r--sound/oss/msnd.c2
-rw-r--r--sound/oss/msnd_pinnacle.c2
-rw-r--r--sound/oss/os.h2
-rw-r--r--sound/oss/sound_config.h1
-rw-r--r--sound/oss/swarm_cs4297a.c4
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c2
-rw-r--r--sound/pci/als4000.c2
-rw-r--r--sound/pci/au88x0/au88x0_game.c2
-rw-r--r--sound/pci/azt3328.c2
-rw-r--r--sound/pci/ca0106/ca_midi.c4
-rw-r--r--sound/pci/cmipci.c2
-rw-r--r--sound/pci/cs4281.c6
-rw-r--r--sound/pci/cs46xx/cs46xx_dsp_task_types.h2
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c46
-rw-r--r--sound/pci/cs46xx/dsp_spos.c3
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pm.c4
-rw-r--r--sound/pci/ctxfi/cthw20k1.c19
-rw-r--r--sound/pci/ctxfi/cthw20k2.c19
-rw-r--r--sound/pci/echoaudio/layla24_dsp.c2
-rw-r--r--sound/pci/echoaudio/midi.c4
-rw-r--r--sound/pci/emu10k1/emu10k1.c11
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c2
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c228
-rw-r--r--sound/pci/emu10k1/emu10k1x.c4
-rw-r--r--sound/pci/emu10k1/emumpu401.c4
-rw-r--r--sound/pci/ens1370.c6
-rw-r--r--sound/pci/es1938.c2
-rw-r--r--sound/pci/es1968.c2
-rw-r--r--sound/pci/hda/hda_auto_parser.c4
-rw-r--r--sound/pci/hda/hda_codec.c76
-rw-r--r--sound/pci/hda/hda_codec.h3
-rw-r--r--sound/pci/hda/hda_controller.c4
-rw-r--r--sound/pci/hda/hda_controller.h1
-rw-r--r--sound/pci/hda/hda_intel.c38
-rw-r--r--sound/pci/hda/patch_ca0132.c6
-rw-r--r--sound/pci/hda/patch_conexant.c28
-rw-r--r--sound/pci/hda/patch_hdmi.c248
-rw-r--r--sound/pci/hda/patch_realtek.c121
-rw-r--r--sound/pci/hda/patch_sigmatel.c30
-rw-r--r--sound/pci/ice1712/ice1724.c4
-rw-r--r--sound/pci/ice1712/wm8766.c2
-rw-r--r--sound/pci/ice1712/wm8776.c2
-rw-r--r--sound/pci/korg1212/korg1212.c4
-rw-r--r--sound/pci/mixart/mixart.h2
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c2
-rw-r--r--sound/pci/riptide/riptide.c2
-rw-r--r--sound/pci/rme9652/hdsp.c4
-rw-r--r--sound/pci/rme9652/hdspm.c4
-rw-r--r--sound/pci/sonicvibes.c2
-rw-r--r--sound/pci/trident/trident_main.c2
-rw-r--r--sound/pci/via82xx.c2
-rw-r--r--sound/pci/vx222/vx222_ops.c12
-rw-r--r--sound/pci/ymfpci/ymfpci.h2
-rw-r--r--sound/pcmcia/vx/vxp_ops.c14
-rw-r--r--sound/ppc/snd_ps3.c2
-rw-r--r--sound/sh/sh_dac_audio.c2
-rw-r--r--sound/soc/Kconfig2
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/amd/acp-pcm-dma.c7
-rw-r--r--sound/soc/atmel/atmel-classd.c2
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c23
-rw-r--r--sound/soc/blackfin/bfin-eval-adau1373.c2
-rw-r--r--sound/soc/blackfin/bfin-eval-adav80x.c2
-rw-r--r--sound/soc/codecs/Kconfig55
-rw-r--r--sound/soc/codecs/Makefile16
-rw-r--r--sound/soc/codecs/adau17x1.c3
-rw-r--r--sound/soc/codecs/ak4613.c10
-rw-r--r--sound/soc/codecs/ak4642.c2
-rw-r--r--sound/soc/codecs/arizona.h1
-rw-r--r--sound/soc/codecs/cs35l35.c1580
-rw-r--r--sound/soc/codecs/cs35l35.h294
-rw-r--r--sound/soc/codecs/cs4271.c2
-rw-r--r--sound/soc/codecs/cs47l24.c8
-rw-r--r--sound/soc/codecs/cs53l30.c1
-rw-r--r--sound/soc/codecs/da7213.c13
-rw-r--r--sound/soc/codecs/da7218.c3
-rw-r--r--sound/soc/codecs/dio2125.c120
-rw-r--r--sound/soc/codecs/es7134.c116
-rw-r--r--sound/soc/codecs/es8328-i2c.c2
-rw-r--r--sound/soc/codecs/es8328.c71
-rw-r--r--sound/soc/codecs/hdac_hdmi.c1333
-rw-r--r--sound/soc/codecs/hdac_hdmi.h5
-rw-r--r--sound/soc/codecs/hdmi-codec.c403
-rw-r--r--sound/soc/codecs/max98090.c2
-rw-r--r--sound/soc/codecs/max9867.c9
-rw-r--r--sound/soc/codecs/max98927.c841
-rw-r--r--sound/soc/codecs/max98927.h272
-rw-r--r--sound/soc/codecs/nau8540.c835
-rw-r--r--sound/soc/codecs/nau8540.h222
-rw-r--r--sound/soc/codecs/nau8824.c1831
-rw-r--r--sound/soc/codecs/nau8824.h466
-rw-r--r--sound/soc/codecs/nau8825.c29
-rw-r--r--sound/soc/codecs/nau8825.h7
-rw-r--r--sound/soc/codecs/pcm3168a.c2
-rw-r--r--sound/soc/codecs/rt298.c7
-rw-r--r--sound/soc/codecs/rt5514-spi.c1
-rw-r--r--sound/soc/codecs/rt5514.c36
-rw-r--r--sound/soc/codecs/rt5640.c13
-rw-r--r--sound/soc/codecs/rt5645.c27
-rw-r--r--sound/soc/codecs/rt5659.c91
-rw-r--r--sound/soc/codecs/rt5660.c6
-rw-r--r--sound/soc/codecs/rt5665.c232
-rw-r--r--sound/soc/codecs/rt5665.h4
-rw-r--r--sound/soc/codecs/rt5670.c22
-rw-r--r--sound/soc/codecs/rt5677-spi.c1
-rw-r--r--sound/soc/codecs/rt5677.c7
-rw-r--r--sound/soc/codecs/sgtl5000.c19
-rw-r--r--sound/soc/codecs/ssm4567.c9
-rw-r--r--sound/soc/codecs/tas2552.c6
-rw-r--r--sound/soc/codecs/tlv320aic3x.c19
-rw-r--r--sound/soc/codecs/wm0010.c1
-rw-r--r--sound/soc/codecs/wm5102.c7
-rw-r--r--sound/soc/codecs/wm5110.c10
-rw-r--r--sound/soc/codecs/wm8731.h2
-rw-r--r--sound/soc/codecs/wm8741.c2
-rw-r--r--sound/soc/codecs/wm8753.c3
-rw-r--r--sound/soc/codecs/wm8997.c6
-rw-r--r--sound/soc/codecs/wm8998.c6
-rw-r--r--sound/soc/codecs/wm_adsp.c433
-rw-r--r--sound/soc/codecs/wm_adsp.h35
-rw-r--r--sound/soc/codecs/wm_hubs.c2
-rw-r--r--sound/soc/davinci/davinci-evm.c13
-rw-r--r--sound/soc/dwc/Kconfig4
-rw-r--r--sound/soc/dwc/Makefile6
-rw-r--r--sound/soc/dwc/dwc-i2s.c (renamed from sound/soc/dwc/designware_i2s.c)34
-rw-r--r--sound/soc/dwc/dwc-pcm.c (renamed from sound/soc/dwc/designware_pcm.c)100
-rw-r--r--sound/soc/dwc/local.h9
-rw-r--r--sound/soc/fsl/efika-audio-fabric.c1
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c2
-rw-r--r--sound/soc/fsl/fsl_asrc.c2
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c2
-rw-r--r--sound/soc/fsl/fsl_esai.c5
-rw-r--r--sound/soc/fsl/fsl_sai.c4
-rw-r--r--sound/soc/fsl/fsl_ssi.c101
-rw-r--r--sound/soc/fsl/imx-mc13783.c2
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c28
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c2
-rw-r--r--sound/soc/fsl/imx-wm8962.c72
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c1
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.h13
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c2
-rw-r--r--sound/soc/fsl/mx27vis-aic32x4.c2
-rw-r--r--sound/soc/fsl/p1022_ds.c2
-rw-r--r--sound/soc/fsl/p1022_rdk.c2
-rw-r--r--sound/soc/fsl/phycore-ac97.c2
-rw-r--r--sound/soc/fsl/wm1133-ev1.c2
-rw-r--r--sound/soc/generic/simple-card-utils.c7
-rw-r--r--sound/soc/generic/simple-card.c47
-rw-r--r--sound/soc/generic/simple-scu-card.c41
-rw-r--r--sound/soc/hisilicon/Kconfig5
-rw-r--r--sound/soc/hisilicon/Makefile1
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.c618
-rw-r--r--sound/soc/hisilicon/hi6210-i2s.h276
-rw-r--r--sound/soc/img/img-parallel-out.c2
-rw-r--r--sound/soc/intel/Kconfig75
-rw-r--r--sound/soc/intel/Makefile2
-rw-r--r--sound/soc/intel/atom/Makefile7
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c10
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c5
-rw-r--r--sound/soc/intel/atom/sst/sst_acpi.c89
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c6
-rw-r--r--sound/soc/intel/atom/sst/sst_stream.c2
-rw-r--r--sound/soc/intel/boards/Makefile4
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c5
-rw-r--r--sound/soc/intel/boards/broadwell.c1
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c173
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c81
-rw-r--r--sound/soc/intel/boards/bytcht_da7213.c283
-rw-r--r--sound/soc/intel/boards/bytcht_nocodec.c208
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c146
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c5
-rw-r--r--sound/soc/intel/boards/cht_bsw_rt5645.c397
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c34
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c33
-rw-r--r--sound/soc/intel/boards/skl_rt286.c30
-rw-r--r--sound/soc/intel/common/sst-dsp.c52
-rw-r--r--sound/soc/intel/haswell/sst-haswell-ipc.c6
-rw-r--r--sound/soc/intel/skylake/bxt-sst.c174
-rw-r--r--sound/soc/intel/skylake/skl-messages.c23
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c65
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c289
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c26
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.h2
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.c6
-rw-r--r--sound/soc/intel/skylake/skl-sst-dsp.h40
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.c76
-rw-r--r--sound/soc/intel/skylake/skl-sst-ipc.h22
-rw-r--r--sound/soc/intel/skylake/skl-sst-utils.c140
-rw-r--r--sound/soc/intel/skylake/skl-sst.c178
-rw-r--r--sound/soc/intel/skylake/skl-topology.c344
-rw-r--r--sound/soc/intel/skylake/skl-topology.h14
-rw-r--r--sound/soc/intel/skylake/skl-tplg-interface.h12
-rw-r--r--sound/soc/intel/skylake/skl.c14
-rw-r--r--sound/soc/intel/skylake/skl.h6
-rw-r--r--sound/soc/mediatek/Kconfig12
-rw-r--r--sound/soc/mediatek/mt2701/Makefile1
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c18
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-cs42448.c2
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c176
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c16
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c2
-rw-r--r--sound/soc/mxs/mxs-saif.c34
-rw-r--r--sound/soc/omap/am3517evm.c2
-rw-r--r--sound/soc/omap/mcbsp.h3
-rw-r--r--sound/soc/omap/n810.c2
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c2
-rw-r--r--sound/soc/omap/omap-mcbsp.c48
-rw-r--r--sound/soc/omap/omap-twl4030.c2
-rw-r--r--sound/soc/omap/omap3pandora.c2
-rw-r--r--sound/soc/omap/osk5912.c2
-rw-r--r--sound/soc/omap/rx51.c7
-rw-r--r--sound/soc/pxa/brownstone.c2
-rw-r--r--sound/soc/pxa/corgi.c2
-rw-r--r--sound/soc/pxa/e740_wm9705.c3
-rw-r--r--sound/soc/pxa/e750_wm9705.c4
-rw-r--r--sound/soc/pxa/e800_wm9712.c4
-rw-r--r--sound/soc/pxa/em-x270.c4
-rw-r--r--sound/soc/pxa/hx4700.c2
-rw-r--r--sound/soc/pxa/imote2.c2
-rw-r--r--sound/soc/pxa/magician.c4
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c3
-rw-r--r--sound/soc/pxa/mmp-pcm.c1
-rw-r--r--sound/soc/pxa/mmp-sspa.c1
-rw-r--r--sound/soc/pxa/palm27x.c2
-rw-r--r--sound/soc/pxa/poodle.c2
-rw-r--r--sound/soc/pxa/pxa-ssp.c15
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c7
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.h17
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c8
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c2
-rw-r--r--sound/soc/pxa/raumfeld.c8
-rw-r--r--sound/soc/pxa/spitz.c6
-rw-r--r--sound/soc/pxa/tosa.c6
-rw-r--r--sound/soc/pxa/z2.c6
-rw-r--r--sound/soc/pxa/zylonite.c3
-rw-r--r--sound/soc/qcom/lpass-apq8016.c27
-rw-r--r--sound/soc/qcom/lpass-cpu.c123
-rw-r--r--sound/soc/qcom/lpass-ipq806x.c6
-rw-r--r--sound/soc/qcom/lpass-platform.c106
-rw-r--r--sound/soc/qcom/lpass.h4
-rw-r--r--sound/soc/qcom/storm.c22
-rw-r--r--sound/soc/rockchip/Kconfig9
-rw-r--r--sound/soc/rockchip/Makefile2
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c302
-rw-r--r--sound/soc/samsung/Kconfig10
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/bells.c1
-rw-r--r--sound/soc/samsung/dmaengine.c8
-rw-r--r--sound/soc/samsung/i2s-regs.h2
-rw-r--r--sound/soc/samsung/i2s.c207
-rw-r--r--sound/soc/samsung/odroid.c219
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c1
-rw-r--r--sound/soc/samsung/s3c2412-i2s.c2
-rw-r--r--sound/soc/samsung/s3c24xx-i2s.c2
-rw-r--r--sound/soc/samsung/smdk_wm8580.c5
-rw-r--r--sound/soc/samsung/tm2_wm5110.c1
-rw-r--r--sound/soc/sh/rcar/adg.c75
-rw-r--r--sound/soc/sh/rcar/cmd.c36
-rw-r--r--sound/soc/sh/rcar/core.c117
-rw-r--r--sound/soc/sh/rcar/dma.c18
-rw-r--r--sound/soc/sh/rcar/dvc.c24
-rw-r--r--sound/soc/sh/rcar/rsnd.h59
-rw-r--r--sound/soc/sh/rcar/src.c9
-rw-r--r--sound/soc/sh/rcar/ssi.c9
-rw-r--r--sound/soc/sh/rcar/ssiu.c6
-rw-r--r--sound/soc/sirf/sirf-audio-port.c1
-rw-r--r--sound/soc/sirf/sirf-audio.c1
-rw-r--r--sound/soc/sirf/sirf-usp.c3
-rw-r--r--sound/soc/soc-ac97.c2
-rw-r--r--sound/soc/soc-core.c251
-rw-r--r--sound/soc/soc-dapm.c62
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c12
-rw-r--r--sound/soc/soc-jack.c48
-rw-r--r--sound/soc/soc-ops.c2
-rw-r--r--sound/soc/soc-pcm.c59
-rw-r--r--sound/soc/soc-topology.c27
-rw-r--r--sound/soc/sti/uniperif.h1
-rw-r--r--sound/soc/sti/uniperif_player.c37
-rw-r--r--sound/soc/sti/uniperif_reader.c27
-rw-r--r--sound/soc/stm/Kconfig8
-rw-r--r--sound/soc/stm/Makefile6
-rw-r--r--sound/soc/stm/stm32_sai.c115
-rw-r--r--sound/soc/stm/stm32_sai.h200
-rw-r--r--sound/soc/stm/stm32_sai_sub.c884
-rw-r--r--sound/soc/sunxi/Kconfig13
-rw-r--r--sound/soc/sunxi/Makefile1
-rw-r--r--sound/soc/sunxi/sun4i-codec.c1
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c61
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c60
-rw-r--r--sound/soc/sunxi/sun8i-codec-analog.c198
-rw-r--r--sound/soc/sunxi/sun8i-codec.c489
-rw-r--r--sound/soc/zte/zx-i2s.c43
-rw-r--r--sound/synth/emux/emux_seq.c14
-rw-r--r--sound/usb/6fire/midi.c4
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/bcd2000/bcd2000.c4
-rw-r--r--sound/usb/caiaq/midi.c4
-rw-r--r--sound/usb/card.c1
-rw-r--r--sound/usb/endpoint.c40
-rw-r--r--sound/usb/endpoint.h2
-rw-r--r--sound/usb/hiface/pcm.c2
-rw-r--r--sound/usb/line6/driver.c49
-rw-r--r--sound/usb/line6/driver.h9
-rw-r--r--sound/usb/line6/midi.c4
-rw-r--r--sound/usb/line6/podhd.c26
-rw-r--r--sound/usb/midi.c4
-rw-r--r--sound/usb/mixer.c3
-rw-r--r--sound/usb/mixer_quirks.c5
-rw-r--r--sound/usb/mixer_us16x08.c1419
-rw-r--r--sound/usb/mixer_us16x08.h121
-rw-r--r--sound/usb/pcm.c41
-rw-r--r--sound/usb/quirks.c54
-rw-r--r--sound/usb/usx2y/us122l.c5
-rw-r--r--sound/usb/usx2y/usX2Yhwdep.c7
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c5
-rw-r--r--sound/x86/Kconfig17
-rw-r--r--sound/x86/Makefile4
-rw-r--r--sound/x86/intel_hdmi_audio.c1867
-rw-r--r--sound/x86/intel_hdmi_audio.h136
-rw-r--r--sound/x86/intel_hdmi_lpe_audio.h328
401 files changed, 21242 insertions, 3300 deletions
diff --git a/sound/Kconfig b/sound/Kconfig
index 5a240e050ae6..ee2e69a9ecd1 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -108,6 +108,8 @@ source "sound/parisc/Kconfig"
source "sound/soc/Kconfig"
+source "sound/x86/Kconfig"
+
endif # SND
menuconfig SOUND_PRIME
diff --git a/sound/Makefile b/sound/Makefile
index c41bdf5fdf24..6de45d2c32f7 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
- firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
+ firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff --git a/sound/core/control.c b/sound/core/control.c
index fb096cb20a80..c109b82eef4b 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/info.h>
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index e2f27022b363..1ac0c423903e 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -58,7 +58,7 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
/* calculate the drift */
delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt));
- if (delta.tv64 > 0)
+ if (delta > 0)
ticks += ktime_divns(delta, ticks * resolution);
snd_timer_interrupt(stime->timer, ticks);
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 36d2416f90d9..9602a7e38d8a 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -25,6 +25,7 @@
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/module.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/minors.h>
diff --git a/sound/core/misc.c b/sound/core/misc.c
index f2e8226c88fb..21b228046e88 100644
--- a/sound/core/misc.c
+++ b/sound/core/misc.c
@@ -71,6 +71,7 @@ void __snd_printk(unsigned int level, const char *path, int line,
int kern_level;
struct va_format vaf;
char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
+ bool level_found = false;
#endif
#ifdef CONFIG_SND_DEBUG
@@ -83,15 +84,22 @@ void __snd_printk(unsigned int level, const char *path, int line,
vaf.fmt = format;
vaf.va = &args;
- kern_level = printk_get_level(format);
- if (kern_level) {
- const char *end_of_header = printk_skip_level(format);
- memcpy(verbose_fmt, format, end_of_header - format);
+ while ((kern_level = printk_get_level(vaf.fmt)) != 0) {
+ const char *end_of_header = printk_skip_level(vaf.fmt);
+
+ /* Ignore KERN_CONT. We print filename:line for each piece. */
+ if (kern_level >= '0' && kern_level <= '7') {
+ memcpy(verbose_fmt, vaf.fmt, end_of_header - vaf.fmt);
+ level_found = true;
+ }
+
vaf.fmt = end_of_header;
- } else if (level)
+ }
+
+ if (!level_found && level)
memcpy(verbose_fmt, KERN_DEBUG, sizeof(KERN_DEBUG) - 1);
- printk(verbose_fmt, sanity_file_name(path), line, &vaf);
+ printk(verbose_fmt, sanity_file_name(path), line, &vaf);
#else
vprintk(format, args);
#endif
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index ebc9fdfe64df..36baf962f9b0 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -28,6 +28,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
@@ -2501,7 +2502,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
return put_user(SNDRV_OSS_VERSION, p);
if (cmd == OSS_ALSAEMULVER)
return put_user(1, p);
-#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE))
+#if IS_REACHABLE(CONFIG_SND_MIXER_OSS)
if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */
struct snd_pcm_substream *substream;
int idx;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index bb1261591a1f..5088d4b8db22 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -21,6 +21,7 @@
*/
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/math64.h>
#include <linux/export.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 9d33c1e85c79..13dec5ec93f2 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/file.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/time.h>
#include <linux/pm_qos.h>
#include <linux/io.h>
@@ -3245,10 +3246,9 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
/*
* mmap status record
*/
-static int snd_pcm_mmap_status_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_pcm_mmap_status_fault(struct vm_fault *vmf)
{
- struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
if (substream == NULL)
@@ -3282,10 +3282,9 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file
/*
* mmap control record
*/
-static int snd_pcm_mmap_control_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_pcm_mmap_control_fault(struct vm_fault *vmf)
{
- struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
if (substream == NULL)
@@ -3341,10 +3340,9 @@ snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
/*
* fault callback for mmapping a RAM page
*/
-static int snd_pcm_mmap_data_fault(struct vm_area_struct *area,
- struct vm_fault *vmf)
+static int snd_pcm_mmap_data_fault(struct vm_fault *vmf)
{
- struct snd_pcm_substream *substream = area->vm_private_data;
+ struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
struct snd_pcm_runtime *runtime;
unsigned long offset;
struct page * page;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index b450a27588c8..ab890336175f 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -22,7 +22,7 @@
#include <sound/core.h>
#include <linux/major.h>
#include <linux/init.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
@@ -1610,7 +1610,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device)
return snd_rawmidi_free(rmidi);
}
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
+#if IS_REACHABLE(CONFIG_SND_SEQUENCER)
static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device)
{
struct snd_rawmidi *rmidi = device->private_data;
@@ -1691,7 +1691,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
}
}
rmidi->proc_entry = entry;
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
+#if IS_REACHABLE(CONFIG_SND_SEQUENCER)
if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
rmidi->seq_dev->private_data = rmidi;
@@ -1749,7 +1749,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
* Sets the rawmidi operators for the given stream direction.
*/
void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
- struct snd_rawmidi_ops *ops)
+ const struct snd_rawmidi_ops *ops)
{
struct snd_rawmidi_substream *substream;
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index d7b4d016b547..afa007c0cc2d 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -24,7 +24,7 @@
#include <linux/time.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/seq_oss.h>
#include <sound/rawmidi.h>
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
index 1f6788a18444..5e04f4df10e4 100644
--- a/sound/core/seq/oss/seq_oss_writeq.c
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -28,6 +28,7 @@
#include "../seq_clientmgr.h"
#include <linux/wait.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
/*
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 4c935202ce23..f3b1d7f50b81 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -1832,6 +1832,7 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
info->output_pool != client->pool->size)) {
if (snd_seq_write_pool_allocated(client)) {
/* remove all existing cells */
+ snd_seq_pool_mark_closing(client->pool);
snd_seq_queue_client_leave_cells(client->number);
snd_seq_pool_done(client->pool);
}
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 1d5acbe0c08b..01c4cfe30c9f 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -21,6 +21,8 @@
#include <sound/core.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
+
#include "seq_fifo.h"
#include "seq_lock.h"
@@ -70,6 +72,9 @@ void snd_seq_fifo_delete(struct snd_seq_fifo **fifo)
return;
*fifo = NULL;
+ if (f->pool)
+ snd_seq_pool_mark_closing(f->pool);
+
snd_seq_fifo_clear(f);
/* wake up clients if any */
@@ -135,6 +140,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
f->tail = cell;
if (f->head == NULL)
f->head = cell;
+ cell->next = NULL;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
@@ -214,6 +220,8 @@ void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
spin_lock_irqsave(&f->lock, flags);
cell->next = f->head;
f->head = cell;
+ if (!f->tail)
+ f->tail = cell;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
}
@@ -259,6 +267,10 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize)
/* NOTE: overflow flag is not cleared */
spin_unlock_irqrestore(&f->lock, flags);
+ /* close the old pool and wait until all users are gone */
+ snd_seq_pool_mark_closing(oldpool);
+ snd_use_lock_sync(&f->use_lock);
+
/* release cells in old pool */
for (cell = oldhead; cell; cell = next) {
next = cell->next;
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index c850345c43b5..d4c61ec9be13 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -23,6 +23,7 @@
#include <linux/init.h>
#include <linux/export.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <linux/vmalloc.h>
#include <sound/core.h>
@@ -414,32 +415,33 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
return 0;
}
+/* refuse the further insertion to the pool */
+void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
+{
+ unsigned long flags;
+
+ if (snd_BUG_ON(!pool))
+ return;
+ spin_lock_irqsave(&pool->lock, flags);
+ pool->closing = 1;
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+
/* remove events */
int snd_seq_pool_done(struct snd_seq_pool *pool)
{
unsigned long flags;
struct snd_seq_event_cell *ptr;
- int max_count = 5 * HZ;
if (snd_BUG_ON(!pool))
return -EINVAL;
/* wait for closing all threads */
- spin_lock_irqsave(&pool->lock, flags);
- pool->closing = 1;
- spin_unlock_irqrestore(&pool->lock, flags);
-
if (waitqueue_active(&pool->output_sleep))
wake_up(&pool->output_sleep);
- while (atomic_read(&pool->counter) > 0) {
- if (max_count == 0) {
- pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
- break;
- }
+ while (atomic_read(&pool->counter) > 0)
schedule_timeout_uninterruptible(1);
- max_count--;
- }
/* release all resources */
spin_lock_irqsave(&pool->lock, flags);
@@ -491,6 +493,7 @@ int snd_seq_pool_delete(struct snd_seq_pool **ppool)
*ppool = NULL;
if (pool == NULL)
return 0;
+ snd_seq_pool_mark_closing(pool);
snd_seq_pool_done(pool);
kfree(pool);
return 0;
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 4a2ec779b8a7..32f959c17786 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -84,6 +84,7 @@ static inline int snd_seq_total_cells(struct snd_seq_pool *pool)
int snd_seq_pool_init(struct snd_seq_pool *pool);
/* done pool - free events */
+void snd_seq_pool_mark_closing(struct snd_seq_pool *pool);
int snd_seq_pool_done(struct snd_seq_pool *pool);
/* create pool */
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 0bec02e89d51..450c5187eecb 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -181,6 +181,8 @@ void __exit snd_seq_queues_delete(void)
}
}
+static void queue_use(struct snd_seq_queue *queue, int client, int use);
+
/* allocate a new queue -
* return queue index value or negative value for error
*/
@@ -192,11 +194,11 @@ int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
if (q == NULL)
return -ENOMEM;
q->info_flags = info_flags;
+ queue_use(q, client, 1);
if (queue_list_add(q) < 0) {
queue_delete(q);
return -ENOMEM;
}
- snd_seq_queue_use(q->queue, client, 1); /* use this queue */
return q->queue;
}
@@ -502,19 +504,9 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client,
return result;
}
-
-/* use or unuse this queue -
- * if it is the first client, starts the timer.
- * if it is not longer used by any clients, stop the timer.
- */
-int snd_seq_queue_use(int queueid, int client, int use)
+/* use or unuse this queue */
+static void queue_use(struct snd_seq_queue *queue, int client, int use)
{
- struct snd_seq_queue *queue;
-
- queue = queueptr(queueid);
- if (queue == NULL)
- return -EINVAL;
- mutex_lock(&queue->timer_mutex);
if (use) {
if (!test_and_set_bit(client, queue->clients_bitmap))
queue->clients++;
@@ -529,6 +521,21 @@ int snd_seq_queue_use(int queueid, int client, int use)
} else {
snd_seq_timer_close(queue);
}
+}
+
+/* use or unuse this queue -
+ * if it is the first client, starts the timer.
+ * if it is not longer used by any clients, stop the timer.
+ */
+int snd_seq_queue_use(int queueid, int client, int use)
+{
+ struct snd_seq_queue *queue;
+
+ queue = queueptr(queueid);
+ if (queue == NULL)
+ return -EINVAL;
+ mutex_lock(&queue->timer_mutex);
+ queue_use(queue, client, use);
mutex_unlock(&queue->timer_mutex);
queuefree(queue);
return 0;
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index c82ed3e70506..52f31f1498f9 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -349,13 +349,13 @@ static int snd_virmidi_unuse(void *private_data,
* Register functions
*/
-static struct snd_rawmidi_ops snd_virmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_virmidi_input_ops = {
.open = snd_virmidi_input_open,
.close = snd_virmidi_input_close,
.trigger = snd_virmidi_input_trigger,
};
-static struct snd_rawmidi_ops snd_virmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_virmidi_output_ops = {
.open = snd_virmidi_output_open,
.close = snd_virmidi_output_close,
.trigger = snd_virmidi_output_trigger,
diff --git a/sound/core/timer.c b/sound/core/timer.c
index fc144f43faa6..6d4fbc439246 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -27,6 +27,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/control.h>
@@ -1702,9 +1703,21 @@ static int snd_timer_user_params(struct file *file,
return -EBADFD;
if (copy_from_user(&params, _params, sizeof(params)))
return -EFAULT;
- if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
- err = -EINVAL;
- goto _end;
+ if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
+ u64 resolution;
+
+ if (params.ticks < 1) {
+ err = -EINVAL;
+ goto _end;
+ }
+
+ /* Don't allow resolution less than 1ms */
+ resolution = snd_timer_resolution(tu->timeri);
+ resolution *= params.ticks;
+ if (resolution < 1000000) {
+ err = -EINVAL;
+ goto _end;
+ }
}
if (params.queue_size > 0 &&
(params.queue_size < 32 || params.queue_size > 1024)) {
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 776596b5ee05..3a7c317ae012 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -481,14 +481,14 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
*/
-static struct snd_rawmidi_ops snd_mpu401_uart_output =
+static const struct snd_rawmidi_ops snd_mpu401_uart_output =
{
.open = snd_mpu401_uart_output_open,
.close = snd_mpu401_uart_output_close,
.trigger = snd_mpu401_uart_output_trigger,
};
-static struct snd_rawmidi_ops snd_mpu401_uart_input =
+static const struct snd_rawmidi_ops snd_mpu401_uart_input =
{
.open = snd_mpu401_uart_input_open,
.close = snd_mpu401_uart_input_close,
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index 30e8a1d5bc87..00b31f92c504 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -600,13 +600,13 @@ static int snd_mtpav_get_ISA(struct mtpav *mcard)
/*
*/
-static struct snd_rawmidi_ops snd_mtpav_output = {
+static const struct snd_rawmidi_ops snd_mtpav_output = {
.open = snd_mtpav_output_open,
.close = snd_mtpav_output_close,
.trigger = snd_mtpav_output_trigger,
};
-static struct snd_rawmidi_ops snd_mtpav_input = {
+static const struct snd_rawmidi_ops snd_mtpav_input = {
.open = snd_mtpav_input_open,
.close = snd_mtpav_input_close,
.trigger = snd_mtpav_input_trigger,
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index fd4d18df84d3..f32e81342247 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -749,13 +749,13 @@ static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substr
spin_unlock_irqrestore(&mts->lock, flags);
}
-static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
.open = snd_mts64_rawmidi_open,
.close = snd_mts64_rawmidi_close,
.trigger = snd_mts64_rawmidi_output_trigger
};
-static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
.open = snd_mts64_rawmidi_open,
.close = snd_mts64_rawmidi_close,
.trigger = snd_mts64_rawmidi_input_trigger
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 369cef212ea9..cd9e9f31720f 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -528,7 +528,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
opl3->hwdep = hw;
opl3->seq_dev_num = seq_device;
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
+#if IS_REACHABLE(CONFIG_SND_SEQUENCER)
if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3,
sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) {
strcpy(opl3->seq_dev->name, hw->name);
diff --git a/sound/drivers/pcsp/pcsp_lib.c b/sound/drivers/pcsp/pcsp_lib.c
index 3689f5f6be64..aca2d7d5f059 100644
--- a/sound/drivers/pcsp/pcsp_lib.c
+++ b/sound/drivers/pcsp/pcsp_lib.c
@@ -166,7 +166,7 @@ static int pcsp_start_playing(struct snd_pcsp *chip)
atomic_set(&chip->timer_active, 1);
chip->thalf = 0;
- hrtimer_start(&pcsp_chip.timer, ktime_set(0, 0), HRTIMER_MODE_REL);
+ hrtimer_start(&pcsp_chip.timer, 0, HRTIMER_MODE_REL);
return 0;
}
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index 189e3e7028af..ec8a94325ef6 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -546,13 +546,13 @@ static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substr
spin_unlock_irqrestore(&pm->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_portman_midi_output = {
+static const struct snd_rawmidi_ops snd_portman_midi_output = {
.open = snd_portman_midi_open,
.close = snd_portman_midi_close,
.trigger = snd_portman_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_portman_midi_input = {
+static const struct snd_rawmidi_ops snd_portman_midi_input = {
.open = snd_portman_midi_open,
.close = snd_portman_midi_close,
.trigger = snd_portman_midi_input_trigger,
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 1927b89e1d1f..60d51ac4ccfe 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -752,14 +752,14 @@ static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream
snd_uart16550_output_write(substream);
}
-static struct snd_rawmidi_ops snd_uart16550_output =
+static const struct snd_rawmidi_ops snd_uart16550_output =
{
.open = snd_uart16550_output_open,
.close = snd_uart16550_output_close,
.trigger = snd_uart16550_output_trigger,
};
-static struct snd_rawmidi_ops snd_uart16550_input =
+static const struct snd_rawmidi_ops snd_uart16550_input =
{
.open = snd_uart16550_input_open,
.close = snd_uart16550_input_close,
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 11467272089e..ea7b377f0378 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -1015,7 +1015,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
int size, space, count;
struct snd_pcm_runtime *runtime = subs->runtime;
- if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
+ if (!pipe->running || (chip->chip_status & VX_STAT_IS_STALE))
return;
size = runtime->buffer_size - snd_pcm_capture_avail(runtime);
@@ -1048,8 +1048,10 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
/* ok, let's accelerate! */
int align = pipe->align * 3;
space = (count / align) * align;
- vx_pseudo_dma_read(chip, runtime, pipe, space);
- count -= space;
+ if (space > 0) {
+ vx_pseudo_dma_read(chip, runtime, pipe, space);
+ count -= space;
+ }
}
/* read the rest of bytes */
while (count > 0) {
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index ab894ed1ff67..9f00696c4e4a 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -34,6 +34,7 @@ config SND_OXFW
* LaCie Firewire Speakers
* Behringer F-Control Audio 202
* Mackie(Loud) Onyx-i series (former models)
+ * Mackie(Loud) Onyx 1640i (former model)
* Mackie(Loud) Onyx Satellite
* Mackie(Loud) Tapco Link.Firewire
* Mackie(Loud) d.2 pro/d.4 pro
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index 3469ac14c89c..730ea91d9be8 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -172,12 +172,12 @@ get_saffire_spec(struct fw_unit *unit)
static bool
check_audiophile_booted(struct fw_unit *unit)
{
- char name[24] = {0};
+ char name[28] = {0};
if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0)
return false;
- return strncmp(name, "FW Audiophile Bootloader", 15) != 0;
+ return strncmp(name, "FW Audiophile Bootloader", 24) != 0;
}
static void
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index 175da875162d..17678d6ab5a2 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -17,6 +17,7 @@
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c
index ce731f4d8b4f..2b367c21b80c 100644
--- a/sound/firewire/bebob/bebob_hwdep.c
+++ b/sound/firewire/bebob/bebob_hwdep.c
@@ -172,16 +172,15 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -190,7 +189,7 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
goto end;
strcpy(hwdep->name, "BeBoB");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = bebob;
hwdep->exclusive = true;
end:
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c
index 868eb0decbec..3befa3eca6ef 100644
--- a/sound/firewire/bebob/bebob_midi.c
+++ b/sound/firewire/bebob/bebob_midi.c
@@ -106,18 +106,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&bebob->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_bebob *bebob,
struct snd_rawmidi_str *str)
{
@@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
int err;
@@ -151,7 +149,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
@@ -162,7 +160,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index 5d7b9343fa85..9e27eb8e1dd4 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -359,32 +359,31 @@ pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&bebob->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -395,8 +394,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
pcm->private_data = bebob;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", bebob->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
end:
return err;
}
diff --git a/sound/firewire/dice/dice-interface.h b/sound/firewire/dice/dice-interface.h
index 27b044f84c81..47f2c0a6f5d9 100644
--- a/sound/firewire/dice/dice-interface.h
+++ b/sound/firewire/dice/dice-interface.h
@@ -251,6 +251,7 @@
/*
* The speed at which the packets are sent, SCODE_100-_400; read/write.
+ * SCODE_800 is only available in Dice III.
*/
#define TX_SPEED 0x014
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
index a040617505a7..8ff6da3c51f7 100644
--- a/sound/firewire/dice/dice-midi.c
+++ b/sound/firewire/dice/dice-midi.c
@@ -78,18 +78,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&dice->lock, flags);
}
-static struct snd_rawmidi_ops capture_ops = {
- .open = midi_open,
- .close = midi_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops playback_ops = {
- .open = midi_open,
- .close = midi_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_dice *dice,
struct snd_rawmidi_str *str)
{
@@ -103,6 +91,16 @@ static void set_midi_substream_names(struct snd_dice *dice,
int snd_dice_create_midi(struct snd_dice *dice)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_playback_trigger,
+ };
__be32 reg;
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index ec4db3a514fc..8573289c381e 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -195,6 +195,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
unsigned int i, pcm_chs, midi_ports;
struct amdtp_stream *streams;
struct fw_iso_resources *resources;
+ struct fw_device *fw_dev = fw_parent_device(dice->unit);
int err = 0;
if (dir == AMDTP_IN_STREAM) {
@@ -237,8 +238,17 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
if (err < 0)
return err;
+ if (dir == AMDTP_IN_STREAM) {
+ reg[0] = cpu_to_be32(fw_dev->max_speed);
+ err = snd_dice_transaction_write_tx(dice,
+ params->size * i + TX_SPEED,
+ reg, sizeof(reg[0]));
+ if (err < 0)
+ return err;
+ }
+
err = amdtp_stream_start(&streams[i], resources[i].channel,
- fw_parent_device(dice->unit)->max_speed);
+ fw_dev->max_speed);
if (err < 0)
return err;
}
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index e6c07857f475..da00e75e09d4 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/sched/signal.h>
#include <sound/control.h>
#include <sound/core.h>
diff --git a/sound/firewire/digi00x/digi00x-hwdep.c b/sound/firewire/digi00x/digi00x-hwdep.c
index f188e4758fd2..463c6b8e864d 100644
--- a/sound/firewire/digi00x/digi00x-hwdep.c
+++ b/sound/firewire/digi00x/digi00x-hwdep.c
@@ -173,16 +173,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -192,7 +191,7 @@ int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
strcpy(hwdep->name, "Digi00x");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = dg00x;
hwdep->exclusive = true;
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c
index 1a72a382b384..915d2a21223e 100644
--- a/sound/firewire/digi00x/digi00x-midi.c
+++ b/sound/firewire/digi00x/digi00x-midi.c
@@ -76,18 +76,6 @@ static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&dg00x->lock, flags);
}
-static struct snd_rawmidi_ops midi_phys_capture_ops = {
- .open = midi_phys_open,
- .close = midi_phys_close,
- .trigger = midi_phys_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_phys_playback_ops = {
- .open = midi_phys_open,
- .close = midi_phys_close,
- .trigger = midi_phys_playback_trigger,
-};
-
static int midi_ctl_open(struct snd_rawmidi_substream *substream)
{
/* Do nothing. */
@@ -139,18 +127,6 @@ static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&dg00x->lock, flags);
}
-static struct snd_rawmidi_ops midi_ctl_capture_ops = {
- .open = midi_ctl_open,
- .close = midi_ctl_capture_close,
- .trigger = midi_ctl_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_ctl_playback_ops = {
- .open = midi_ctl_open,
- .close = midi_ctl_playback_close,
- .trigger = midi_ctl_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_dg00x *dg00x,
struct snd_rawmidi_str *str,
bool is_ctl)
@@ -172,6 +148,26 @@ static void set_midi_substream_names(struct snd_dg00x *dg00x,
int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
{
+ static const struct snd_rawmidi_ops phys_capture_ops = {
+ .open = midi_phys_open,
+ .close = midi_phys_close,
+ .trigger = midi_phys_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops phys_playback_ops = {
+ .open = midi_phys_open,
+ .close = midi_phys_close,
+ .trigger = midi_phys_playback_trigger,
+ };
+ static const struct snd_rawmidi_ops ctl_capture_ops = {
+ .open = midi_ctl_open,
+ .close = midi_ctl_capture_close,
+ .trigger = midi_ctl_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops ctl_playback_ops = {
+ .open = midi_ctl_open,
+ .close = midi_ctl_playback_close,
+ .trigger = midi_ctl_playback_trigger,
+ };
struct snd_rawmidi *rmidi[2];
struct snd_rawmidi_str *str;
unsigned int i;
@@ -187,9 +183,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
"%s MIDI", dg00x->card->shortname);
snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_phys_capture_ops);
+ &phys_capture_ops);
snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_phys_playback_ops);
+ &phys_playback_ops);
/* Add a pair of control midi ports. */
err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1,
@@ -201,9 +197,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
"%s control", dg00x->card->shortname);
snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_ctl_capture_ops);
+ &ctl_capture_ops);
snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_ctl_playback_ops);
+ &ctl_playback_ops);
for (i = 0; i < ARRAY_SIZE(rmidi); i++) {
rmidi[i]->private_data = dg00x;
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index 613f05872770..68d1c52db051 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -329,33 +329,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -366,8 +364,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
pcm->private_data = dg00x;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", dg00x->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
return 0;
}
diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h
index 2cd465c0caae..9dc761bdacca 100644
--- a/sound/firewire/digi00x/digi00x.h
+++ b/sound/firewire/digi00x/digi00x.h
@@ -16,6 +16,7 @@
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h
index d73c12b8753d..9b19c7f05d57 100644
--- a/sound/firewire/fireworks/fireworks.h
+++ b/sound/firewire/fireworks/fireworks.h
@@ -17,6 +17,7 @@
#include <linux/mod_devicetable.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/firewire/fireworks/fireworks_hwdep.c b/sound/firewire/fireworks/fireworks_hwdep.c
index 2e1d9a23920c..a3a3a16f5e08 100644
--- a/sound/firewire/fireworks/fireworks_hwdep.c
+++ b/sound/firewire/fireworks/fireworks_hwdep.c
@@ -303,17 +303,16 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .write = hwdep_write,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_efw_create_hwdep_device(struct snd_efw *efw)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .write = hwdep_write,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -322,7 +321,7 @@ int snd_efw_create_hwdep_device(struct snd_efw *efw)
goto end;
strcpy(hwdep->name, "Fireworks");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = efw;
hwdep->exclusive = true;
end:
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c
index 3e8c4cf9fe1e..f5da2cd4ce42 100644
--- a/sound/firewire/fireworks/fireworks_midi.c
+++ b/sound/firewire/fireworks/fireworks_midi.c
@@ -107,18 +107,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&efw->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_efw *efw,
struct snd_rawmidi_str *str)
{
@@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_efw *efw,
int snd_efw_create_midi_devices(struct snd_efw *efw)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
int err;
@@ -151,7 +149,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
@@ -162,7 +160,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index f4fbf75ed198..9171702f7d0b 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -383,33 +383,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&efw->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_efw_create_pcm_devices(struct snd_efw *efw)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -419,8 +417,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
pcm->private_data = efw;
snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
end:
return err;
}
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c
index ee47924aef0d..827161bc269c 100644
--- a/sound/firewire/fireworks/fireworks_stream.c
+++ b/sound/firewire/fireworks/fireworks_stream.c
@@ -117,7 +117,7 @@ destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream)
conn = &efw->in_conn;
amdtp_stream_destroy(stream);
- cmp_connection_destroy(&efw->out_conn);
+ cmp_connection_destroy(conn);
}
static int
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
index ca4dfcf43175..7683238283b6 100644
--- a/sound/firewire/lib.c
+++ b/sound/firewire/lib.c
@@ -114,7 +114,7 @@ static void async_midi_port_callback(struct fw_card *card, int rcode,
snd_rawmidi_transmit_ack(substream, port->consume_bytes);
else if (!rcode_is_permanent_error(rcode))
/* To start next transaction immediately for recovery. */
- port->next_ktime = ktime_set(0, 0);
+ port->next_ktime = 0;
else
/* Don't continue processing. */
port->error = true;
@@ -156,7 +156,7 @@ static void midi_port_work(struct work_struct *work)
if (port->consume_bytes <= 0) {
/* Do it in next chance, immediately. */
if (port->consume_bytes == 0) {
- port->next_ktime = ktime_set(0, 0);
+ port->next_ktime = 0;
schedule_work(&port->work);
} else {
/* Fatal error. */
@@ -219,7 +219,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
port->addr = addr;
port->fill = fill;
port->idling = true;
- port->next_ktime = ktime_set(0, 0);
+ port->next_ktime = 0;
port->error = false;
INIT_WORK(&port->work, midi_port_work);
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
index 8665e1043d41..b7bbd77dfff1 100644
--- a/sound/firewire/oxfw/oxfw-midi.c
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -116,18 +116,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&oxfw->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
static void set_midi_substream_names(struct snd_oxfw *oxfw,
struct snd_rawmidi_str *str)
{
@@ -142,6 +130,16 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw,
int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *str;
int err;
@@ -164,7 +162,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
@@ -175,7 +173,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c
index f897c9831077..93209ebd9121 100644
--- a/sound/firewire/oxfw/oxfw-scs1x.c
+++ b/sound/firewire/oxfw/oxfw-scs1x.c
@@ -297,7 +297,7 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up)
}
}
-static struct snd_rawmidi_ops midi_capture_ops = {
+static const struct snd_rawmidi_ops midi_capture_ops = {
.open = midi_capture_open,
.close = midi_capture_close,
.trigger = midi_capture_trigger,
@@ -338,12 +338,6 @@ static void midi_playback_drain(struct snd_rawmidi_substream *stream)
wait_event(scs->idle_wait, scs->output_idle);
}
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
- .drain = midi_playback_drain,
-};
static int register_address(struct snd_oxfw *oxfw)
{
struct fw_scs1x *scs = oxfw->spec;
@@ -369,6 +363,12 @@ void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw)
int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
{
+ static const struct snd_rawmidi_ops midi_playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ .drain = midi_playback_drain,
+ };
struct snd_rawmidi *rmidi;
struct fw_scs1x *scs;
int err;
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
index e629b88f7d93..74d7fb6efce6 100644
--- a/sound/firewire/oxfw/oxfw.c
+++ b/sound/firewire/oxfw/oxfw.c
@@ -43,6 +43,7 @@ static bool detect_loud_models(struct fw_unit *unit)
const char *const models[] = {
"Onyxi",
"Onyx-i",
+ "Onyx 1640i",
"d.Pro",
"Mackie Onyx Satellite",
"Tapco LINK.firewire 4x6",
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 2047dcb27625..d54d4a9ac4a1 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
+#include <linux/sched/signal.h>
#include <sound/control.h>
#include <sound/core.h>
diff --git a/sound/firewire/tascam/tascam-hwdep.c b/sound/firewire/tascam/tascam-hwdep.c
index 106406cbfaa3..8c4437d0051d 100644
--- a/sound/firewire/tascam/tascam-hwdep.c
+++ b/sound/firewire/tascam/tascam-hwdep.c
@@ -163,16 +163,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
#define hwdep_compat_ioctl NULL
#endif
-static const struct snd_hwdep_ops hwdep_ops = {
- .read = hwdep_read,
- .release = hwdep_release,
- .poll = hwdep_poll,
- .ioctl = hwdep_ioctl,
- .ioctl_compat = hwdep_compat_ioctl,
-};
-
int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
struct snd_hwdep *hwdep;
int err;
@@ -182,7 +181,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
strcpy(hwdep->name, "Tascam");
hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM;
- hwdep->ops = hwdep_ops;
+ hwdep->ops = ops;
hwdep->private_data = tscm;
hwdep->exclusive = true;
diff --git a/sound/firewire/tascam/tascam-midi.c b/sound/firewire/tascam/tascam-midi.c
index 41f842079d9d..df4f95d65925 100644
--- a/sound/firewire/tascam/tascam-midi.c
+++ b/sound/firewire/tascam/tascam-midi.c
@@ -68,20 +68,18 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
spin_unlock_irqrestore(&tscm->lock, flags);
}
-static struct snd_rawmidi_ops midi_capture_ops = {
- .open = midi_capture_open,
- .close = midi_capture_close,
- .trigger = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
- .open = midi_playback_open,
- .close = midi_playback_close,
- .trigger = midi_playback_trigger,
-};
-
int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
{
+ static const struct snd_rawmidi_ops capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+ };
+ static const struct snd_rawmidi_ops playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+ };
struct snd_rawmidi *rmidi;
struct snd_rawmidi_str *stream;
struct snd_rawmidi_substream *subs;
@@ -100,7 +98,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &midi_capture_ops);
+ &capture_ops);
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
/* Set port names for MIDI input. */
@@ -116,7 +114,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &midi_playback_ops);
+ &playback_ops);
stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
/* Set port names for MIDI ourput. */
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index 79db1b651f5c..f5dd6ce6b6f1 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -268,33 +268,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
return amdtp_stream_pcm_pointer(&tscm->rx_stream);
}
-static const struct snd_pcm_ops pcm_capture_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_capture_hw_params,
- .hw_free = pcm_capture_hw_free,
- .prepare = pcm_capture_prepare,
- .trigger = pcm_capture_trigger,
- .pointer = pcm_capture_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
- .open = pcm_open,
- .close = pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pcm_playback_hw_params,
- .hw_free = pcm_playback_hw_free,
- .prepare = pcm_playback_prepare,
- .trigger = pcm_playback_trigger,
- .pointer = pcm_playback_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
-};
-
int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
{
+ static const struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ };
+ static const struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
struct snd_pcm *pcm;
int err;
@@ -305,8 +303,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
pcm->private_data = tscm;
snprintf(pcm->name, sizeof(pcm->name),
"%s PCM", tscm->card->shortname);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
return 0;
}
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c
index 4ad3bd7fd445..f1657a4e0621 100644
--- a/sound/firewire/tascam/tascam-stream.c
+++ b/sound/firewire/tascam/tascam-stream.c
@@ -343,7 +343,7 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm)
if (err < 0)
amdtp_stream_destroy(&tscm->rx_stream);
- return 0;
+ return err;
}
/* At bus reset, streaming is stopped and some registers are clear. */
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index 1f61011579a7..d3cd4065722b 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -17,6 +17,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
+#include <linux/sched/signal.h>
#include <sound/core.h>
#include <sound/initval.h>
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index 3be051ab5533..c96d7a7a36af 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -128,14 +128,17 @@ void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
{
struct hdac_stream *hstream = &stream->hstream;
struct hdac_bus *bus = &ebus->bus;
+ u32 val;
+ int mask = AZX_PPCTL_PROCEN(hstream->index);
spin_lock_irq(&bus->reg_lock);
- if (decouple)
- snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0,
- AZX_PPCTL_PROCEN(hstream->index));
- else
- snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
- AZX_PPCTL_PROCEN(hstream->index), 0);
+ val = readw(bus->ppcap + AZX_REG_PP_PPCTL) & mask;
+
+ if (decouple && !val)
+ snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, mask);
+ else if (!decouple && val)
+ snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, mask, 0);
+
stream->decoupled = decouple;
spin_unlock_irq(&bus->reg_lock);
}
diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c
index 043065867656..6f1e99c9fed9 100644
--- a/sound/hda/hdac_controller.c
+++ b/sound/hda/hdac_controller.c
@@ -268,7 +268,7 @@ int snd_hdac_bus_parse_capabilities(struct hdac_bus *bus)
unsigned int offset;
unsigned int counter = 0;
- offset = snd_hdac_chip_readl(bus, LLCH);
+ offset = snd_hdac_chip_readw(bus, LLCH);
/* Lets walk the linked capabilities list */
do {
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index c9af022676c2..0659bf389489 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -193,6 +193,7 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
* snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate
* @codec: HDA codec
* @nid: the pin widget NID
+ * @dev_id: device identifier
* @rate: the sample rate to set
*
* This function is supposed to be used only by a HD-audio controller
@@ -201,18 +202,20 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
* This function sets N/CTS value based on the given sample rate.
* Returns zero for success, or a negative error code.
*/
-int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
+int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
+ int dev_id, int rate)
{
struct hdac_bus *bus = codec->bus;
struct i915_audio_component *acomp = bus->audio_component;
- int port;
+ int port, pipe;
if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
return -ENODEV;
port = pin2port(codec, nid);
if (port < 0)
return -EINVAL;
- return acomp->ops->sync_audio_rate(acomp->dev, port, rate);
+ pipe = dev_id;
+ return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
}
EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
@@ -220,6 +223,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
* snd_hdac_acomp_get_eld - Get the audio state and ELD via component
* @codec: HDA codec
* @nid: the pin widget NID
+ * @dev_id: device identifier
* @audio_enabled: the pointer to store the current audio state
* @buffer: the buffer pointer to store ELD bytes
* @max_bytes: the max bytes to be stored on @buffer
@@ -236,12 +240,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
* thus it may be over @max_bytes. If it's over @max_bytes, it implies
* that only a part of ELD bytes have been fetched.
*/
-int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
+int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int dev_id,
bool *audio_enabled, char *buffer, int max_bytes)
{
struct hdac_bus *bus = codec->bus;
struct i915_audio_component *acomp = bus->audio_component;
- int port;
+ int port, pipe;
if (!acomp || !acomp->ops || !acomp->ops->get_eld)
return -ENODEV;
@@ -249,7 +253,9 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
port = pin2port(codec, nid);
if (port < 0)
return -EINVAL;
- return acomp->ops->get_eld(acomp->dev, port, audio_enabled,
+
+ pipe = dev_id;
+ return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
buffer, max_bytes);
}
EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index 38990a77d7b7..c6994ebb4567 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -465,7 +465,7 @@ int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
}
EXPORT_SYMBOL_GPL(snd_hdac_stream_set_params);
-static cycle_t azx_cc_read(const struct cyclecounter *cc)
+static u64 azx_cc_read(const struct cyclecounter *cc)
{
struct hdac_stream *azx_dev = container_of(cc, struct hdac_stream, cc);
@@ -473,7 +473,7 @@ static cycle_t azx_cc_read(const struct cyclecounter *cc)
}
static void azx_timecounter_init(struct hdac_stream *azx_dev,
- bool force, cycle_t last)
+ bool force, u64 last)
{
struct timecounter *tc = &azx_dev->tc;
struct cyclecounter *cc = &azx_dev->cc;
@@ -523,7 +523,7 @@ void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
struct snd_pcm_runtime *runtime = azx_dev->substream->runtime;
struct hdac_stream *s;
bool inited = false;
- cycle_t cycle_last = 0;
+ u64 cycle_last = 0;
int i = 0;
list_for_each_entry(s, &bus->stream_list, list) {
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index 25f6788ccef3..06505999155f 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -27,6 +27,8 @@
#include <asm/dma.h>
#include <linux/slab.h>
+#include <linux/sched/signal.h>
+
#include <sound/core.h>
#include <sound/control.h>
#include <sound/gus.h>
diff --git a/sound/isa/gus/gus_uart.c b/sound/isa/gus/gus_uart.c
index 3992912743f5..ac5f5687d1a3 100644
--- a/sound/isa/gus/gus_uart.c
+++ b/sound/isa/gus/gus_uart.c
@@ -227,14 +227,14 @@ static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream,
spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
}
-static struct snd_rawmidi_ops snd_gf1_uart_output =
+static const struct snd_rawmidi_ops snd_gf1_uart_output =
{
.open = snd_gf1_uart_output_open,
.close = snd_gf1_uart_output_close,
.trigger = snd_gf1_uart_output_trigger,
};
-static struct snd_rawmidi_ops snd_gf1_uart_input =
+static const struct snd_rawmidi_ops snd_gf1_uart_input =
{
.open = snd_gf1_uart_input_open,
.close = snd_gf1_uart_input_close,
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
index 835d4aa26761..8109ab3d29d1 100644
--- a/sound/isa/msnd/msnd.c
+++ b/sound/isa/msnd/msnd.c
@@ -36,6 +36,7 @@
********************************************************************/
#include <linux/kernel.h>
+#include <linux/sched/signal.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/io.h>
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
index ffc67fd80c23..912b5a9ccbab 100644
--- a/sound/isa/msnd/msnd_midi.c
+++ b/sound/isa/msnd/msnd_midi.c
@@ -142,7 +142,7 @@ void snd_msndmidi_input_read(void *mpuv)
}
EXPORT_SYMBOL(snd_msndmidi_input_read);
-static struct snd_rawmidi_ops snd_msndmidi_input = {
+static const struct snd_rawmidi_ops snd_msndmidi_input = {
.open = snd_msndmidi_input_open,
.close = snd_msndmidi_input_close,
.trigger = snd_msndmidi_input_trigger,
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
index 94c411299e5a..ec180708f160 100644
--- a/sound/isa/sb/emu8000.c
+++ b/sound/isa/sb/emu8000.c
@@ -21,7 +21,7 @@
*/
#include <linux/wait.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/export.h>
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 71d13c0bb746..c2e41d2762f7 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -20,6 +20,8 @@
*/
#include "emu8000_local.h"
+
+#include <linux/sched/signal.h>
#include <linux/uaccess.h>
#include <linux/moduleparam.h>
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index 250fd0006b53..32f234f494e5 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -19,6 +19,8 @@
*/
#include "emu8000_local.h"
+
+#include <linux/sched/signal.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <sound/initval.h>
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c
index d551c50e549f..bd672abb4854 100644
--- a/sound/isa/sb/sb8_midi.c
+++ b/sound/isa/sb/sb8_midi.c
@@ -247,14 +247,14 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
snd_sb8dsp_midi_output_write(substream);
}
-static struct snd_rawmidi_ops snd_sb8dsp_midi_output =
+static const struct snd_rawmidi_ops snd_sb8dsp_midi_output =
{
.open = snd_sb8dsp_midi_output_open,
.close = snd_sb8dsp_midi_output_close,
.trigger = snd_sb8dsp_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_sb8dsp_midi_input =
+static const struct snd_rawmidi_ops snd_sb8dsp_midi_input =
{
.open = snd_sb8dsp_midi_input_open,
.close = snd_sb8dsp_midi_input_close,
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c
index 8a80fc6a616b..2aa05f3aaa38 100644
--- a/sound/isa/wavefront/wavefront_midi.c
+++ b/sound/isa/wavefront/wavefront_midi.c
@@ -559,14 +559,14 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
return 0;
}
-struct snd_rawmidi_ops snd_wavefront_midi_output =
+const struct snd_rawmidi_ops snd_wavefront_midi_output =
{
.open = snd_wavefront_midi_output_open,
.close = snd_wavefront_midi_output_close,
.trigger = snd_wavefront_midi_output_trigger,
};
-struct snd_rawmidi_ops snd_wavefront_midi_input =
+const struct snd_rawmidi_ops snd_wavefront_midi_input =
{
.open = snd_wavefront_midi_input_open,
.close = snd_wavefront_midi_input_close,
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 718d5e3b7806..4dae9ff9ef5a 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/wait.h>
+#include <linux/sched/signal.h>
#include <linux/firmware.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
diff --git a/sound/mips/hal2.c b/sound/mips/hal2.c
index ede449f0b50d..00fc9241d266 100644
--- a/sound/mips/hal2.c
+++ b/sound/mips/hal2.c
@@ -219,6 +219,8 @@ static int hal2_gain_get(struct snd_kcontrol *kcontrol,
l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15;
r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15;
break;
+ default:
+ return -EINVAL;
}
ucontrol->value.integer.value[0] = l;
ucontrol->value.integer.value[1] = r;
@@ -256,6 +258,8 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol,
new |= (r << H2I_C2_R_GAIN_SHIFT);
hal2_i_write32(hal2, H2I_ADC_C2, new);
break;
+ default:
+ return -EINVAL;
}
return old != new;
}
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 6368e5c7d0ba..f6156d8169d0 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -121,11 +121,6 @@ static bool deskpro_xl;
static bool deskpro_m;
static bool soundpro;
-static volatile signed char irq2dev[17] = {
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1
-};
-
#ifndef EXCLUDE_TIMERS
static int timer_installed = -1;
#endif
@@ -2060,7 +2055,7 @@ int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback,
else
devc->irq_ok = 1; /* Couldn't test. assume it's OK */
} else if (irq < 0)
- irq2dev[-irq] = devc->dev_no = my_dev;
+ devc->dev_no = my_dev;
#ifndef EXCLUDE_TIMERS
if ((capabilities[devc->model].flags & CAP_F_TIMER) &&
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index e3f29132d3ac..c5dd396c66a2 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -27,6 +27,8 @@
#include <linux/mm.h>
#include <linux/gfp.h>
+#include <linux/sched/signal.h>
+
#include "sound_config.h"
#include "sleep.h"
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index 1c56bf58eff9..a1a2979c0bb1 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -22,7 +22,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/atariints.h>
#include <asm/atari_stram.h>
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index f4ee85a4c42f..fb3bbceb1fef 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -182,8 +182,9 @@
#include <linux/soundcard.h>
#include <linux/poll.h>
#include <linux/mutex.h>
+#include <linux/sched/signal.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "dmasound.h"
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
index 3f653618614d..81eb82c4675a 100644
--- a/sound/oss/dmasound/dmasound_paula.c
+++ b/sound/oss/dmasound/dmasound_paula.c
@@ -23,7 +23,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/amigaints.h>
diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
index 99bcb21c2281..be4fe15cfd6b 100644
--- a/sound/oss/dmasound/dmasound_q40.c
+++ b/sound/oss/dmasound/dmasound_q40.c
@@ -20,7 +20,7 @@
#include <linux/soundcard.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/q40ints.h>
#include <asm/q40_master.h>
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index 8f45cd999965..701c7625c971 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -16,6 +16,8 @@
#include <linux/stddef.h>
#include <linux/kmod.h>
#include <linux/spinlock.h>
+#include <linux/sched/signal.h>
+
#define MIDIBUF_C
#include "sound_config.h"
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c
index c0cc951ba97d..b63010ad22f1 100644
--- a/sound/oss/msnd.c
+++ b/sound/oss/msnd.c
@@ -32,7 +32,7 @@
#include <linux/interrupt.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/spinlock.h>
#include <asm/irq.h>
#include "msnd.h"
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index a8bb4a06ba6f..f34ec01d2239 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -41,6 +41,8 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/gfp.h>
+#include <linux/sched/signal.h>
+
#include <asm/irq.h>
#include <asm/io.h>
#include "sound_config.h"
diff --git a/sound/oss/os.h b/sound/oss/os.h
index 75ad0cd0c0ab..0bf89e1d679c 100644
--- a/sound/oss/os.h
+++ b/sound/oss/os.h
@@ -17,7 +17,7 @@
#include <linux/ioport.h>
#include <asm/page.h>
#include <linux/vmalloc.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/poll.h>
#include <linux/pci.h>
#endif
diff --git a/sound/oss/sound_config.h b/sound/oss/sound_config.h
index f2554ab78f5e..5253b0a70437 100644
--- a/sound/oss/sound_config.h
+++ b/sound/oss/sound_config.h
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/sound.h>
+#include <linux/sched/signal.h>
#include "os.h"
#include "soundvers.h"
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 213a416b6e0b..97899352b15f 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -64,7 +64,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
@@ -80,7 +80,7 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 82259ca61e64..1ef7cdf1d3e8 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1907,7 +1907,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem)
* write). The other callbacks, wait and reset, are not mandatory.
*
* The clock is set to 48000. If another clock is needed, set
- * (*rbus)->clock manually.
+ * ``(*rbus)->clock`` manually.
*
* The AC97 bus instance is registered as a low-level device, so you don't
* have to release it manually.
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index f4234edb878c..8cf0dc7a07a4 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -3093,7 +3093,7 @@ static int patch_cm9739(struct snd_ac97 * ac97)
/* set-up multi channel */
/* bit 14: 0 = SPDIF, 1 = EAPD */
/* bit 13: enable internal vref output for mic */
- /* bit 12: disable center/lfe (swithable) */
+ /* bit 12: disable center/lfe (switchable) */
/* bit 10: disable surround/line (switchable) */
/* bit 9: mix 2 surround off */
/* bit 4: undocumented; 0 mutes the CM9739A, which defaults to 1 */
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index edabe1371660..92bc06d01288 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -84,7 +84,7 @@ MODULE_DESCRIPTION("Avance Logic ALS4000");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
index 151815b857a0..53abcd3eccbd 100644
--- a/sound/pci/au88x0/au88x0_game.c
+++ b/sound/pci/au88x0/au88x0_game.c
@@ -36,7 +36,7 @@
#include <linux/gameport.h>
#include <linux/export.h>
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define VORTEX_GAME_DWAIT 20 /* 20 ms */
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 80c4a4456197..79b2e6b7d88b 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -212,7 +212,7 @@ MODULE_DESCRIPTION("Aztech AZF3328 (PCI168)");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_GAMEPORT 1
#endif
diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c
index b91c7f6d19f9..4d4d385205eb 100644
--- a/sound/pci/ca0106/ca_midi.c
+++ b/sound/pci/ca0106/ca_midi.c
@@ -255,14 +255,14 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int
}
}
-static struct snd_rawmidi_ops ca_midi_output =
+static const struct snd_rawmidi_ops ca_midi_output =
{
.open = ca_midi_output_open,
.close = ca_midi_output_close,
.trigger = ca_midi_output_trigger,
};
-static struct snd_rawmidi_ops ca_midi_input =
+static const struct snd_rawmidi_ops ca_midi_input =
{
.open = ca_midi_input_open,
.close = ca_midi_input_close,
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 73f593526b2d..aeedc270ed9b 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -48,7 +48,7 @@ MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8738},"
"{C-Media,CMI8338A},"
"{C-Media,CMI8338B}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 615d8a99d8c8..fa7c51684dd2 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1194,7 +1194,7 @@ static void snd_cs4281_proc_init(struct cs4281 *chip)
* joystick support
*/
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
static void snd_cs4281_gameport_trigger(struct gameport *gameport)
{
@@ -1767,14 +1767,14 @@ static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substre
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_cs4281_midi_output =
+static const struct snd_rawmidi_ops snd_cs4281_midi_output =
{
.open = snd_cs4281_midi_output_open,
.close = snd_cs4281_midi_output_close,
.trigger = snd_cs4281_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_cs4281_midi_input =
+static const struct snd_rawmidi_ops snd_cs4281_midi_input =
{
.open = snd_cs4281_midi_input_open,
.close = snd_cs4281_midi_input_close,
diff --git a/sound/pci/cs46xx/cs46xx_dsp_task_types.h b/sound/pci/cs46xx/cs46xx_dsp_task_types.h
index 5cf920bfda27..be5694718546 100644
--- a/sound/pci/cs46xx/cs46xx_dsp_task_types.h
+++ b/sound/pci/cs46xx/cs46xx_dsp_task_types.h
@@ -203,7 +203,7 @@ struct dsp_task_tree_context_block {
u32 saverfe;
- /* Value may be overwriten by stack save algorithm.
+ /* Value may be overwritten by stack save algorithm.
Retain the size of the stack data saved here if used */
___DSP_DUAL_16BIT_ALLOC(
reserved1,
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 528102cc2d5d..e4cf3187b4dd 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -72,18 +72,18 @@
static void amp_voyetra(struct snd_cs46xx *chip, int change);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-static struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
#endif
-static struct snd_pcm_ops snd_cs46xx_playback_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
-static struct snd_pcm_ops snd_cs46xx_capture_ops;
-static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
+static const struct snd_pcm_ops snd_cs46xx_capture_ops;
+static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
unsigned short reg,
@@ -1654,7 +1654,7 @@ static int snd_cs46xx_capture_close(struct snd_pcm_substream *substream)
}
#ifdef CONFIG_SND_CS46XX_NEW_DSP
-static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
.open = snd_cs46xx_playback_open_rear,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1665,7 +1665,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
.open = snd_cs46xx_playback_open_rear,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1677,7 +1677,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
.ack = snd_cs46xx_playback_transfer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
.open = snd_cs46xx_playback_open_clfe,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1688,7 +1688,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
.open = snd_cs46xx_playback_open_clfe,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1700,7 +1700,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
.ack = snd_cs46xx_playback_transfer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
.open = snd_cs46xx_playback_open_iec958,
.close = snd_cs46xx_playback_close_iec958,
.ioctl = snd_pcm_lib_ioctl,
@@ -1711,7 +1711,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
.open = snd_cs46xx_playback_open_iec958,
.close = snd_cs46xx_playback_close_iec958,
.ioctl = snd_pcm_lib_ioctl,
@@ -1725,7 +1725,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
#endif
-static struct snd_pcm_ops snd_cs46xx_playback_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_ops = {
.open = snd_cs46xx_playback_open,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1736,7 +1736,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_ops = {
.pointer = snd_cs46xx_playback_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
.open = snd_cs46xx_playback_open,
.close = snd_cs46xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1748,7 +1748,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
.ack = snd_cs46xx_playback_transfer,
};
-static struct snd_pcm_ops snd_cs46xx_capture_ops = {
+static const struct snd_pcm_ops snd_cs46xx_capture_ops = {
.open = snd_cs46xx_capture_open,
.close = snd_cs46xx_capture_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -1759,7 +1759,7 @@ static struct snd_pcm_ops snd_cs46xx_capture_ops = {
.pointer = snd_cs46xx_capture_direct_pointer,
};
-static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
+static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
.open = snd_cs46xx_capture_open,
.close = snd_cs46xx_capture_close,
.ioctl = snd_pcm_lib_ioctl,
@@ -2683,14 +2683,14 @@ static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substre
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_cs46xx_midi_output =
+static const struct snd_rawmidi_ops snd_cs46xx_midi_output =
{
.open = snd_cs46xx_midi_output_open,
.close = snd_cs46xx_midi_output_close,
.trigger = snd_cs46xx_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_cs46xx_midi_input =
+static const struct snd_rawmidi_ops snd_cs46xx_midi_input =
{
.open = snd_cs46xx_midi_input_open,
.close = snd_cs46xx_midi_input_close,
@@ -2718,7 +2718,7 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device)
* gameport interface
*/
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
static void snd_cs46xx_gameport_trigger(struct gameport *gameport)
{
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 4a0cbd2241d8..aa61615288ff 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -107,7 +107,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32
dev_dbg(chip->card->dev,
"handle_wideop:[2] %05x:%05x addr %04x\n",
- hival, loval, address); nreallocated++;
+ hival, loval, address);
+ nreallocated++;
} /* wide_opcodes[j] == wide_op */
} /* for */
} /* mod_type == 0 ... */
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c
index 06ac5d8da362..82bd10b68a77 100644
--- a/sound/pci/cs5535audio/cs5535audio_pm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pm.c
@@ -55,7 +55,7 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
}
-static int snd_cs5535audio_suspend(struct device *dev)
+static int __maybe_unused snd_cs5535audio_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
@@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev)
return 0;
}
-static int snd_cs5535audio_resume(struct device *dev)
+static int __maybe_unused snd_cs5535audio_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct cs5535audio *cs5535au = card->private_data;
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 9667cbfb0ca2..79edd88d5cd0 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -27,12 +27,6 @@
#include "cthw20k1.h"
#include "ct20k1reg.h"
-#if BITS_PER_LONG == 32
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-#else
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-#endif
-
struct hw20k1 {
struct hw hw;
spinlock_t reg_20k1_lock;
@@ -1904,19 +1898,18 @@ static int hw_card_start(struct hw *hw)
{
int err;
struct pci_dev *pci = hw->pci;
+ const unsigned int dma_bits = BITS_PER_LONG;
err = pci_enable_device(pci);
if (err < 0)
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
- dev_err(hw->card->dev,
- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
- CT_XFI_DMA_MASK);
- err = -ENXIO;
- goto error1;
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
+ } else {
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
}
if (!hw->io_base) {
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 6414ecf93efa..18ee7768b7c4 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -26,12 +26,6 @@
#include "cthw20k2.h"
#include "ct20k2reg.h"
-#if BITS_PER_LONG == 32
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-#else
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-#endif
-
struct hw20k2 {
struct hw hw;
/* for i2c */
@@ -2029,19 +2023,18 @@ static int hw_card_start(struct hw *hw)
int err = 0;
struct pci_dev *pci = hw->pci;
unsigned int gctl;
+ const unsigned int dma_bits = BITS_PER_LONG;
err = pci_enable_device(pci);
if (err < 0)
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
- dev_err(hw->card->dev,
- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
- CT_XFI_DMA_MASK);
- err = -ENXIO;
- goto error1;
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
+ } else {
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
}
if (!hw->io_base) {
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index df28e5117359..c02bc1dcc170 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -135,7 +135,7 @@ static int load_asic(struct echoaudio *chip)
err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC,
FW_LAYLA24_2S_ASIC);
if (err < 0)
- return false;
+ return err;
/* Now give the external ASIC a little time to set up */
mdelay(10);
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index a8fe58335ddc..8c685ddb1a41 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -288,13 +288,13 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
-static struct snd_rawmidi_ops snd_echo_midi_input = {
+static const struct snd_rawmidi_ops snd_echo_midi_input = {
.open = snd_echo_midi_input_open,
.close = snd_echo_midi_input_close,
.trigger = snd_echo_midi_input_trigger,
};
-static struct snd_rawmidi_ops snd_echo_midi_output = {
+static const struct snd_rawmidi_ops snd_echo_midi_output = {
.open = snd_echo_midi_output_open,
.close = snd_echo_midi_output_close,
.trigger = snd_echo_midi_output_trigger,
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index db7a2e5e4a14..6a0e49ac5273 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -37,7 +37,7 @@ MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS},"
"{Creative Labs,SB Audigy}}");
-#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
+#if IS_REACHABLE(CONFIG_SND_SEQUENCER)
#define ENABLE_SYNTH
#include <sound/emu10k1_synth.h>
#endif
@@ -194,6 +194,9 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci,
if ((err = snd_card_register(card)) < 0)
goto error;
+ if (emu->card_capabilities->emu_model)
+ schedule_delayed_work(&emu->emu1010.firmware_work, 0);
+
pci_set_drvdata(pci, card);
dev++;
return 0;
@@ -219,6 +222,8 @@ static int snd_emu10k1_suspend(struct device *dev)
emu->suspend = 1;
+ cancel_delayed_work_sync(&emu->emu1010.firmware_work);
+
snd_pcm_suspend_all(emu->pcm);
snd_pcm_suspend_all(emu->pcm_mic);
snd_pcm_suspend_all(emu->pcm_efx);
@@ -252,6 +257,10 @@ static int snd_emu10k1_resume(struct device *dev)
emu->suspend = 0;
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+
+ if (emu->card_capabilities->emu_model)
+ schedule_delayed_work(&emu->emu1010.firmware_work, 0);
+
return 0;
}
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index d2c7ea3a7610..aa2cc27b8491 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -61,7 +61,7 @@ static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
/*
* set up operators
*/
-static struct snd_emux_operators emu10k1_ops = {
+static const struct snd_emux_operators emu10k1_ops = {
.owner = THIS_MODULE,
.get_voice = get_voice,
.prepare = start_voice,
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 891453451543..ccf4415a1c7b 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -32,7 +32,6 @@
*/
#include <linux/sched.h>
-#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -662,7 +661,7 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
return 0;
}
-static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu,
+static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu,
const struct firmware *fw_entry)
{
int n, i;
@@ -708,98 +707,104 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu,
return 0;
}
-static int emu1010_firmware_thread(void *data)
+/* firmware file names, per model, init-fw and dock-fw (optional) */
+static const char * const firmware_names[5][2] = {
+ [EMU_MODEL_EMU1010] = {
+ HANA_FILENAME, DOCK_FILENAME
+ },
+ [EMU_MODEL_EMU1010B] = {
+ EMU1010B_FILENAME, MICRO_DOCK_FILENAME
+ },
+ [EMU_MODEL_EMU1616] = {
+ EMU1010_NOTEBOOK_FILENAME, MICRO_DOCK_FILENAME
+ },
+ [EMU_MODEL_EMU0404] = {
+ EMU0404_FILENAME, NULL
+ },
+};
+
+static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
+ const struct firmware **fw)
{
- struct snd_emu10k1 *emu = data;
+ const char *filename;
+ int err;
+
+ if (!*fw) {
+ filename = firmware_names[emu->card_capabilities->emu_model][dock];
+ if (!filename)
+ return 0;
+ err = request_firmware(fw, filename, &emu->pci->dev);
+ if (err)
+ return err;
+ }
+
+ return snd_emu1010_load_firmware_entry(emu, *fw);
+}
+
+static void emu1010_firmware_work(struct work_struct *work)
+{
+ struct snd_emu10k1 *emu;
u32 tmp, tmp2, reg;
- u32 last_reg = 0;
int err;
- for (;;) {
- /* Delay to allow Audio Dock to settle */
- msleep_interruptible(1000);
- if (kthread_should_stop())
- break;
+ emu = container_of(work, struct snd_emu10k1,
+ emu1010.firmware_work.work);
+ if (emu->card->shutdown)
+ return;
#ifdef CONFIG_PM_SLEEP
- if (emu->suspend)
- continue;
+ if (emu->suspend)
+ return;
#endif
- snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
- snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
- if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
- /* Audio Dock attached */
- /* Return to Audio Dock programming mode */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware\n");
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK);
-
- if (!emu->dock_fw) {
- const char *filename = NULL;
- switch (emu->card_capabilities->emu_model) {
- case EMU_MODEL_EMU1010:
- filename = DOCK_FILENAME;
- break;
- case EMU_MODEL_EMU1010B:
- filename = MICRO_DOCK_FILENAME;
- break;
- case EMU_MODEL_EMU1616:
- filename = MICRO_DOCK_FILENAME;
- break;
- }
- if (filename) {
- err = request_firmware(&emu->dock_fw,
- filename,
- &emu->pci->dev);
- if (err)
- continue;
- }
- }
-
- if (emu->dock_fw) {
- err = snd_emu1010_load_firmware(emu, emu->dock_fw);
- if (err)
- continue;
- }
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */
+ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, &reg); /* OPTIONS: Which cards are attached to the EMU */
+ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
+ /* Audio Dock attached */
+ /* Return to Audio Dock programming mode */
+ dev_info(emu->card->dev,
+ "emu1010: Loading Audio Dock Firmware\n");
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG,
+ EMU_HANA_FPGA_CONFIG_AUDIODOCK);
+ err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
+ if (err < 0)
+ goto next;
- snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
- snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg);
- dev_info(emu->card->dev,
- "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n",
- reg);
- /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
- snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg);
- dev_info(emu->card->dev,
- "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg);
- if ((reg & 0x1f) != 0x15) {
- /* FPGA failed to be programmed */
- dev_info(emu->card->dev,
- "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
- reg);
- continue;
- }
- dev_info(emu->card->dev,
- "emu1010: Audio Dock Firmware loaded\n");
- snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
- snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
- dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n",
- tmp, tmp2);
- /* Sync clocking between 1010 and Dock */
- /* Allow DLL to settle */
- msleep(10);
- /* Unmute all. Default is muted after a firmware load */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
- } else if (!reg && last_reg) {
- /* Audio Dock removed */
+ snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
+ snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp);
+ dev_info(emu->card->dev,
+ "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp);
+ /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
+ snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
+ dev_info(emu->card->dev,
+ "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
+ if ((tmp & 0x1f) != 0x15) {
+ /* FPGA failed to be programmed */
dev_info(emu->card->dev,
- "emu1010: Audio Dock detached\n");
- /* Unmute all */
- snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
+ "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n",
+ tmp);
+ goto next;
}
-
- last_reg = reg;
+ dev_info(emu->card->dev,
+ "emu1010: Audio Dock Firmware loaded\n");
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
+ snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
+ dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
+ /* Sync clocking between 1010 and Dock */
+ /* Allow DLL to settle */
+ msleep(10);
+ /* Unmute all. Default is muted after a firmware load */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
+ } else if (!reg && emu->emu1010.last_reg) {
+ /* Audio Dock removed */
+ dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
+ /* Unmute all */
+ snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
}
- dev_info(emu->card->dev, "emu1010: firmware thread stopping\n");
- return 0;
+
+ next:
+ emu->emu1010.last_reg = reg;
+ if (!emu->card->shutdown)
+ schedule_delayed_work(&emu->emu1010.firmware_work,
+ msecs_to_jiffies(1000));
}
/*
@@ -881,39 +886,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
}
dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg);
- if (!emu->firmware) {
- const char *filename;
- switch (emu->card_capabilities->emu_model) {
- case EMU_MODEL_EMU1010:
- filename = HANA_FILENAME;
- break;
- case EMU_MODEL_EMU1010B:
- filename = EMU1010B_FILENAME;
- break;
- case EMU_MODEL_EMU1616:
- filename = EMU1010_NOTEBOOK_FILENAME;
- break;
- case EMU_MODEL_EMU0404:
- filename = EMU0404_FILENAME;
- break;
- default:
- return -ENODEV;
- }
-
- err = request_firmware(&emu->firmware, filename, &emu->pci->dev);
- if (err != 0) {
- dev_info(emu->card->dev,
- "emu1010: firmware: %s not found. Err = %d\n",
- filename, err);
- return err;
- }
- dev_info(emu->card->dev,
- "emu1010: firmware file = %s, size = 0x%zx\n",
- filename, emu->firmware->size);
- }
-
- err = snd_emu1010_load_firmware(emu, emu->firmware);
- if (err != 0) {
+ err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
+ if (err < 0) {
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
return err;
}
@@ -1136,22 +1110,6 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp);
snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */
- /* Start Micro/Audio Dock firmware loader thread */
- if (!emu->emu1010.firmware_thread) {
- emu->emu1010.firmware_thread =
- kthread_create(emu1010_firmware_thread, emu,
- "emu1010_firmware");
- if (IS_ERR(emu->emu1010.firmware_thread)) {
- err = PTR_ERR(emu->emu1010.firmware_thread);
- emu->emu1010.firmware_thread = NULL;
- dev_info(emu->card->dev,
- "emu1010: Creating thread failed\n");
- return err;
- }
-
- wake_up_process(emu->emu1010.firmware_thread);
- }
-
#if 0
snd_emu1010_fpga_link_dst_src_write(emu,
EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */
@@ -1309,8 +1267,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
/* Disable 48Volt power to Audio Dock */
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0);
}
- if (emu->emu1010.firmware_thread)
- kthread_stop(emu->emu1010.firmware_thread);
+ cancel_delayed_work_sync(&emu->emu1010.firmware_work);
release_firmware(emu->firmware);
release_firmware(emu->dock_fw);
if (emu->irq >= 0)
@@ -1852,6 +1809,7 @@ int snd_emu10k1_create(struct snd_card *card,
emu->irq = -1;
emu->synth = NULL;
emu->get_synth_voice = NULL;
+ INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work);
/* read revision & serial */
emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 921037ed8468..32842734ada6 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1486,14 +1486,14 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst
*/
-static struct snd_rawmidi_ops snd_emu10k1x_midi_output =
+static const struct snd_rawmidi_ops snd_emu10k1x_midi_output =
{
.open = snd_emu10k1x_midi_output_open,
.close = snd_emu10k1x_midi_output_close,
.trigger = snd_emu10k1x_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_emu10k1x_midi_input =
+static const struct snd_rawmidi_ops snd_emu10k1x_midi_input =
{
.open = snd_emu10k1x_midi_input_open,
.close = snd_emu10k1x_midi_input_close,
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
index fdf2b0ada489..b6650f5c1621 100644
--- a/sound/pci/emu10k1/emumpu401.c
+++ b/sound/pci/emu10k1/emumpu401.c
@@ -308,14 +308,14 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr
*/
-static struct snd_rawmidi_ops snd_emu10k1_midi_output =
+static const struct snd_rawmidi_ops snd_emu10k1_midi_output =
{
.open = snd_emu10k1_midi_output_open,
.close = snd_emu10k1_midi_output_close,
.trigger = snd_emu10k1_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_emu10k1_midi_input =
+static const struct snd_rawmidi_ops snd_emu10k1_midi_input =
{
.open = snd_emu10k1_midi_input_open,
.close = snd_emu10k1_midi_input_close,
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 7e760fed0728..164adad91650 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -79,7 +79,7 @@ MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI ES1371/73},"
"{Ectiva,EV1938}}");
#endif
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK
#endif
@@ -2317,14 +2317,14 @@ static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substr
spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
}
-static struct snd_rawmidi_ops snd_ensoniq_midi_output =
+static const struct snd_rawmidi_ops snd_ensoniq_midi_output =
{
.open = snd_ensoniq_midi_output_open,
.close = snd_ensoniq_midi_output_close,
.trigger = snd_ensoniq_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_ensoniq_midi_input =
+static const struct snd_rawmidi_ops snd_ensoniq_midi_input =
{
.open = snd_ensoniq_midi_input_open,
.close = snd_ensoniq_midi_input_close,
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 681355829484..e8d943071a8c 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -72,7 +72,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1938},"
"{ESS,ES1969},"
"{TerraTec,128i PCI}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 8146fb76a4ad..2ec2b1ce0af6 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -126,7 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,Maestro 2e},"
"{ESS,Maestro 1},"
"{TerraTec,DMX}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 7f57a145a47e..a03cf68d0bcd 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -884,6 +884,8 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action)
}
EXPORT_SYMBOL_GPL(snd_hda_apply_fixup);
+#define IGNORE_SEQ_ASSOC (~(AC_DEFCFG_SEQUENCE | AC_DEFCFG_DEF_ASSOC))
+
static bool pin_config_match(struct hda_codec *codec,
const struct hda_pintbl *pins)
{
@@ -901,7 +903,7 @@ static bool pin_config_match(struct hda_codec *codec,
for (; t_pins->nid; t_pins++) {
if (t_pins->nid == nid) {
found = 1;
- if (t_pins->val == cfg)
+ if ((t_pins->val & IGNORE_SEQ_ASSOC) == (cfg & IGNORE_SEQ_ASSOC))
break;
else if ((cfg & 0xf0000000) == 0x40000000 && (t_pins->val & 0xf0000000) == 0x40000000)
break;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 9913be8532ab..8fd745cb3f36 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -311,9 +311,15 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
}
EXPORT_SYMBOL_GPL(snd_hda_get_conn_index);
-
-/* return DEVLIST_LEN parameter of the given widget */
-static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
+/**
+ * snd_hda_get_num_devices - get DEVLIST_LEN parameter of the given widget
+ * @codec: the HDA codec
+ * @nid: NID of the pin to parse
+ *
+ * Get the device entry number on the given widget. This is a feature of
+ * DP MST audio. Each pin can have several device entries in it.
+ */
+unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid)
{
unsigned int wcaps = get_wcaps(codec, nid);
unsigned int parm;
@@ -327,6 +333,7 @@ static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid)
parm = 0;
return parm & AC_DEV_LIST_LEN_MASK;
}
+EXPORT_SYMBOL_GPL(snd_hda_get_num_devices);
/**
* snd_hda_get_devices - copy device list without cache
@@ -344,7 +351,7 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
int i, dev_len, devices;
- parm = get_num_devices(codec, nid);
+ parm = snd_hda_get_num_devices(codec, nid);
if (!parm) /* not multi-stream capable */
return 0;
@@ -368,6 +375,63 @@ int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
return devices;
}
+/**
+ * snd_hda_get_dev_select - get device entry select on the pin
+ * @codec: the HDA codec
+ * @nid: NID of the pin to get device entry select
+ *
+ * Get the devcie entry select on the pin. Return the device entry
+ * id selected on the pin. Return 0 means the first device entry
+ * is selected or MST is not supported.
+ */
+int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid)
+{
+ /* not support dp_mst will always return 0, using first dev_entry */
+ if (!codec->dp_mst)
+ return 0;
+
+ return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_DEVICE_SEL, 0);
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_dev_select);
+
+/**
+ * snd_hda_set_dev_select - set device entry select on the pin
+ * @codec: the HDA codec
+ * @nid: NID of the pin to set device entry select
+ * @dev_id: device entry id to be set
+ *
+ * Set the device entry select on the pin nid.
+ */
+int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id)
+{
+ int ret, num_devices;
+
+ /* not support dp_mst will always return 0, using first dev_entry */
+ if (!codec->dp_mst)
+ return 0;
+
+ /* AC_PAR_DEVLIST_LEN is 0 based. */
+ num_devices = snd_hda_get_num_devices(codec, nid) + 1;
+ /* If Device List Length is 0 (num_device = 1),
+ * the pin is not multi stream capable.
+ * Do nothing in this case.
+ */
+ if (num_devices == 1)
+ return 0;
+
+ /* Behavior of setting index being equal to or greater than
+ * Device List Length is not predictable
+ */
+ if (num_devices <= dev_id)
+ return -EINVAL;
+
+ ret = snd_hda_codec_write(codec, nid, 0,
+ AC_VERB_SET_DEVICE_SEL, dev_id);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hda_set_dev_select);
+
/*
* read widget caps for each widget and store in cache
*/
@@ -403,6 +467,10 @@ static int read_pin_defaults(struct hda_codec *codec)
pin->nid = nid;
pin->cfg = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONFIG_DEFAULT, 0);
+ /*
+ * all device entries are the same widget control so far
+ * fixme: if any codec is different, need fix here
+ */
pin->ctrl = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL,
0);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 373fcad840ea..f17f25245e52 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -347,8 +347,11 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
const hda_nid_t *list);
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
hda_nid_t nid, int recursive);
+unsigned int snd_hda_get_num_devices(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid,
u8 *dev_list, int max_devices);
+int snd_hda_get_dev_select(struct hda_codec *codec, hda_nid_t nid);
+int snd_hda_set_dev_select(struct hda_codec *codec, hda_nid_t nid, int dev_id);
struct hda_verb {
hda_nid_t nid;
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index 500878556578..3715a5725613 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -861,6 +861,10 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
return -EIO;
}
+ /* no fallback mechanism? */
+ if (!chip->fallback_to_single_cmd)
+ return -EIO;
+
/* a fatal communication error; need either to reset or to fallback
* to the single_cmd mode
*/
diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h
index a50e0532622a..35a9ab2cac46 100644
--- a/sound/pci/hda/hda_controller.h
+++ b/sound/pci/hda/hda_controller.h
@@ -150,6 +150,7 @@ struct azx {
int bdl_pos_adj;
int poll_count;
unsigned int running:1;
+ unsigned int fallback_to_single_cmd:1;
unsigned int single_cmd:1;
unsigned int polling_mode:1;
unsigned int msi:1;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index c64d986009a9..c8256a89375a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -128,7 +128,7 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
static int probe_only[SNDRV_CARDS];
static int jackpoll_ms[SNDRV_CARDS];
-static bool single_cmd;
+static int single_cmd = -1;
static int enable_msi = -1;
#ifdef CONFIG_SND_HDA_PATCH_LOADER
static char *patch[SNDRV_CARDS];
@@ -157,7 +157,7 @@ module_param_array(probe_only, int, NULL, 0444);
MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
module_param_array(jackpoll_ms, int, NULL, 0444);
MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)");
-module_param(single_cmd, bool, 0444);
+module_param(single_cmd, bint, 0444);
MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
"(for debugging only).");
module_param(enable_msi, bint, 0444);
@@ -1596,7 +1596,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
check_probe_mask(chip, dev);
- chip->single_cmd = single_cmd;
+ if (single_cmd < 0) /* allow fallback to single_cmd at errors */
+ chip->fallback_to_single_cmd = 1;
+ else /* explicitly set to single_cmd or not */
+ chip->single_cmd = single_cmd;
+
azx_check_snoop_available(chip);
if (bdl_pos_adj[dev] < 0)
@@ -1774,6 +1778,14 @@ static int azx_first_init(struct azx *chip)
chip->playback_index_offset = chip->capture_streams;
chip->num_streams = chip->playback_streams + chip->capture_streams;
+ /* sanity check for the SDxCTL.STRM field overflow */
+ if (chip->num_streams > 15 &&
+ (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) == 0) {
+ dev_warn(chip->card->dev, "number of I/O streams is %d, "
+ "forcing separate stream tags", chip->num_streams);
+ chip->driver_caps |= AZX_DCAPS_SEPARATE_STREAM_TAG;
+ }
+
/* initialize streams */
err = azx_init_streams(chip);
if (err < 0)
@@ -2155,7 +2167,20 @@ static void azx_remove(struct pci_dev *pci)
/* cancel the pending probing work */
chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip);
+ /* FIXME: below is an ugly workaround.
+ * Both device_release_driver() and driver_probe_device()
+ * take *both* the device's and its parent's lock before
+ * calling the remove() and probe() callbacks. The codec
+ * probe takes the locks of both the codec itself and its
+ * parent, i.e. the PCI controller dev. Meanwhile, when
+ * the PCI controller is unbound, it takes its lock, too
+ * ==> ouch, a deadlock!
+ * As a workaround, we unlock temporarily here the controller
+ * device during cancel_work_sync() call.
+ */
+ device_unlock(&pci->dev);
cancel_work_sync(&hda->probe_work);
+ device_lock(&pci->dev);
snd_card_free(card);
}
@@ -2197,9 +2222,9 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lewisburg */
{ PCI_DEVICE(0x8086, 0xa1f0),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
{ PCI_DEVICE(0x8086, 0xa270),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
@@ -2230,6 +2255,9 @@ static const struct pci_device_id azx_ids[] = {
/* Broxton-T */
{ PCI_DEVICE(0x8086, 0x1a98),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
+ /* Gemini-Lake */
+ { PCI_DEVICE(0x8086, 0x3198),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index ad06866d7c69..07a9deb17477 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -780,6 +780,7 @@ static const struct hda_pintbl alienware_pincfgs[] = {
static const struct snd_pci_quirk ca0132_quirks[] = {
SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
+ SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE),
{}
};
@@ -1481,6 +1482,9 @@ static int dspio_scp(struct hda_codec *codec,
} else if (ret_size != reply_data_size) {
codec_dbg(codec, "RetLen and HdrLen .NE.\n");
return -EINVAL;
+ } else if (!reply) {
+ codec_dbg(codec, "NULL reply\n");
+ return -EINVAL;
} else {
*reply_len = ret_size*sizeof(unsigned int);
memcpy(reply, scp_reply.data, *reply_len);
@@ -2862,7 +2866,7 @@ static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info,
#define CA0132_CODEC_MUTE(xname, nid, dir) \
CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir)
-/* The followings are for tuning of products */
+/* The following are for tuning of products */
#ifdef ENABLE_TUNING_CONTROLS
static unsigned int voice_focus_vals_lookup[] = {
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index ed62748a6d55..69266b8ea2ad 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -261,7 +261,9 @@ enum {
CXT_FIXUP_HP_530,
CXT_FIXUP_CAP_MIX_AMP_5047,
CXT_FIXUP_MUTE_LED_EAPD,
+ CXT_FIXUP_HP_DOCK,
CXT_FIXUP_HP_SPECTRE,
+ CXT_FIXUP_HP_GATE_MIC,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -633,6 +635,17 @@ static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
(1 << AC_AMPCAP_MUTE_SHIFT));
}
+static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ /* the mic pin (0x19) doesn't give an unsolicited event;
+ * probe the mic pin together with the headphone pin (0x16)
+ */
+ if (action == HDA_FIXUP_ACT_PROBE)
+ snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
+}
+
/* ThinkPad X200 & co with cxt5051 */
static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
@@ -766,6 +779,14 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_mute_led_eapd,
},
+ [CXT_FIXUP_HP_DOCK] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x16, 0x21011020 }, /* line-out */
+ { 0x18, 0x2181103f }, /* line-in */
+ { }
+ }
+ },
[CXT_FIXUP_HP_SPECTRE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -774,6 +795,10 @@ static const struct hda_fixup cxt_fixups[] = {
{ }
}
},
+ [CXT_FIXUP_HP_GATE_MIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_hp_gate_mic_jack,
+ },
};
static const struct snd_pci_quirk cxt5045_fixups[] = {
@@ -823,7 +848,9 @@ 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_ASPIRE_DMIC),
SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
+ SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
+ SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
@@ -854,6 +881,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
{ .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" },
{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
+ { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
{}
};
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 56e5204ac9c1..1461ef8eb749 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -76,6 +76,7 @@ struct hdmi_spec_per_cvt {
struct hdmi_spec_per_pin {
hda_nid_t pin_nid;
+ int dev_id;
/* pin idx, different device entries on the same pin use the same idx */
int pin_nid_idx;
int num_mux_nids;
@@ -130,7 +131,23 @@ struct hdmi_spec {
struct snd_array cvts; /* struct hdmi_spec_per_cvt */
hda_nid_t cvt_nids[4]; /* only for haswell fix */
+ /*
+ * num_pins is the number of virtual pins
+ * for example, there are 3 pins, and each pin
+ * has 4 device entries, then the num_pins is 12
+ */
int num_pins;
+ /*
+ * num_nids is the number of real pins
+ * In the above example, num_nids is 3
+ */
+ int num_nids;
+ /*
+ * dev_num is the number of device entries
+ * on each pin.
+ * In the above example, dev_num is 4
+ */
+ int dev_num;
struct snd_array pins; /* struct hdmi_spec_per_pin */
struct hdmi_pcm pcm_rec[16];
struct mutex pcm_lock;
@@ -217,14 +234,26 @@ union audio_infoframe {
/* obtain hda_pcm object assigned to idx */
#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
-static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid)
+static int pin_id_to_pin_index(struct hda_codec *codec,
+ hda_nid_t pin_nid, int dev_id)
{
struct hdmi_spec *spec = codec->spec;
int pin_idx;
+ struct hdmi_spec_per_pin *per_pin;
+
+ /*
+ * (dev_id == -1) means it is NON-MST pin
+ * return the first virtual pin on this port
+ */
+ if (dev_id == -1)
+ dev_id = 0;
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++)
- if (get_pin(spec, pin_idx)->pin_nid == pin_nid)
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ per_pin = get_pin(spec, pin_idx);
+ if ((per_pin->pin_nid == pin_nid) &&
+ (per_pin->dev_id == dev_id))
return pin_idx;
+ }
codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid);
return -EINVAL;
@@ -724,10 +753,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
-static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
+static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
+ int dev_id)
{
struct hdmi_spec *spec = codec->spec;
- int pin_idx = pin_nid_to_pin_index(codec, nid);
+ int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
if (pin_idx < 0)
return;
@@ -738,7 +768,8 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid)
static void jack_callback(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
- check_presence_and_report(codec, jack->nid);
+ /* hda_jack don't support DP MST */
+ check_presence_and_report(codec, jack->nid, 0);
}
static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -747,6 +778,12 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
struct hda_jack_tbl *jack;
int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
+ /*
+ * assume DP MST uses dyn_pcm_assign and acomp and
+ * never comes here
+ * if DP MST supports unsol event, below code need
+ * consider dev_entry
+ */
jack = snd_hda_jack_tbl_get_from_tag(codec, tag);
if (!jack)
return;
@@ -757,7 +794,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res)
codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA),
!!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
- check_presence_and_report(codec, jack->nid);
+ /* hda_jack don't support DP MST */
+ check_presence_and_report(codec, jack->nid, 0);
}
static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
@@ -970,28 +1008,60 @@ static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
* by any other pins.
*/
static void intel_not_share_assigned_cvt(struct hda_codec *codec,
- hda_nid_t pin_nid, int mux_idx)
+ hda_nid_t pin_nid,
+ int dev_id, int mux_idx)
{
struct hdmi_spec *spec = codec->spec;
hda_nid_t nid;
int cvt_idx, curr;
struct hdmi_spec_per_cvt *per_cvt;
+ struct hdmi_spec_per_pin *per_pin;
+ int pin_idx;
+
+ /* configure the pins connections */
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ int dev_id_saved;
+ int dev_num;
- /* configure all pins, including "no physical connection" ones */
- for_each_hda_codec_node(nid, codec) {
- unsigned int wid_caps = get_wcaps(codec, nid);
- unsigned int wid_type = get_wcaps_type(wid_caps);
+ per_pin = get_pin(spec, pin_idx);
+ /*
+ * pin not connected to monitor
+ * no need to operate on it
+ */
+ if (!per_pin->pcm)
+ continue;
- if (wid_type != AC_WID_PIN)
+ if ((per_pin->pin_nid == pin_nid) &&
+ (per_pin->dev_id == dev_id))
continue;
- if (nid == pin_nid)
+ /*
+ * if per_pin->dev_id >= dev_num,
+ * snd_hda_get_dev_select() will fail,
+ * and the following operation is unpredictable.
+ * So skip this situation.
+ */
+ dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
+ if (per_pin->dev_id >= dev_num)
continue;
+ nid = per_pin->pin_nid;
+
+ /*
+ * Calling this function should not impact
+ * on the device entry selection
+ * So let's save the dev id for each pin,
+ * and restore it when return
+ */
+ dev_id_saved = snd_hda_get_dev_select(codec, nid);
+ snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
curr = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_CONNECT_SEL, 0);
- if (curr != mux_idx)
+ if (curr != mux_idx) {
+ snd_hda_set_dev_select(codec, nid, dev_id_saved);
continue;
+ }
+
/* choose an unassigned converter. The conveters in the
* connection list are in the same order as in the codec.
@@ -1008,12 +1078,13 @@ static void intel_not_share_assigned_cvt(struct hda_codec *codec,
break;
}
}
+ snd_hda_set_dev_select(codec, nid, dev_id_saved);
}
}
/* A wrapper of intel_not_share_asigned_cvt() */
static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
- hda_nid_t pin_nid, hda_nid_t cvt_nid)
+ hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
{
int mux_idx;
struct hdmi_spec *spec = codec->spec;
@@ -1025,7 +1096,7 @@ static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
*/
mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
if (mux_idx >= 0)
- intel_not_share_assigned_cvt(codec, pin_nid, mux_idx);
+ intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
}
/* skeleton caller of pin_cvt_fixup ops */
@@ -1140,6 +1211,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
per_pin->cvt_nid = per_cvt->cvt_nid;
hinfo->nid = per_cvt->cvt_nid;
+ snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
per_pin->mux_idx);
@@ -1198,6 +1270,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
return -EINVAL;
}
+ /* all the device entries on the same pin have the same conn list */
per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
per_pin->mux_nids,
HDA_MAX_CONNECTIONS);
@@ -1215,13 +1288,13 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
return per_pin->pin_nid_idx;
/* have a second try; check the "reserved area" over num_pins */
- for (i = spec->num_pins; i < spec->pcm_used; i++) {
+ for (i = spec->num_nids; i < spec->pcm_used; i++) {
if (!test_bit(i, &spec->pcm_bitmap))
return i;
}
/* the last try; check the empty slots in pins */
- for (i = 0; i < spec->num_pins; i++) {
+ for (i = 0; i < spec->num_nids; i++) {
if (!test_bit(i, &spec->pcm_bitmap))
return i;
}
@@ -1296,10 +1369,13 @@ static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
per_pin->cvt_nid = hinfo->nid;
mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
- if (mux_idx < per_pin->num_mux_nids)
+ if (mux_idx < per_pin->num_mux_nids) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
mux_idx);
+ }
snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
@@ -1467,6 +1543,11 @@ static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
jack = spec->pcm_rec[per_pin->pcm_idx].jack;
else if (!spec->dyn_pcm_assign) {
+ /*
+ * jack tbl doesn't support DP MST
+ * DP MST will use dyn_pcm_assign,
+ * so DP MST will never come here
+ */
jack_tbl = snd_hda_jack_tbl_get(codec, per_pin->pin_nid);
if (jack_tbl)
jack = jack_tbl->jack;
@@ -1486,8 +1567,8 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
mutex_lock(&per_pin->lock);
eld->monitor_present = false;
size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
- &eld->monitor_present, eld->eld_buffer,
- ELD_MAX_SIZE);
+ per_pin->dev_id, &eld->monitor_present,
+ eld->eld_buffer, ELD_MAX_SIZE);
if (size > 0) {
size = min(size, ELD_MAX_SIZE);
if (snd_hdmi_parse_eld(codec, &eld->info,
@@ -1565,38 +1646,81 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
int pin_idx;
struct hdmi_spec_per_pin *per_pin;
int err;
+ int dev_num, i;
caps = snd_hda_query_pin_caps(codec, pin_nid);
if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
return 0;
+ /*
+ * For DP MST audio, Configuration Default is the same for
+ * all device entries on the same pin
+ */
config = snd_hda_codec_get_pincfg(codec, pin_nid);
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
return 0;
- if (is_haswell_plus(codec))
- intel_haswell_fixup_connect_list(codec, pin_nid);
-
- pin_idx = spec->num_pins;
- per_pin = snd_array_new(&spec->pins);
- if (!per_pin)
- return -ENOMEM;
-
- per_pin->pin_nid = pin_nid;
- per_pin->non_pcm = false;
- if (spec->dyn_pcm_assign)
- per_pin->pcm_idx = -1;
- else {
- per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
- per_pin->pcm_idx = pin_idx;
+ /*
+ * To simplify the implementation, malloc all
+ * the virtual pins in the initialization statically
+ */
+ if (is_haswell_plus(codec)) {
+ /*
+ * On Intel platforms, device entries number is
+ * changed dynamically. If there is a DP MST
+ * hub connected, the device entries number is 3.
+ * Otherwise, it is 1.
+ * Here we manually set dev_num to 3, so that
+ * we can initialize all the device entries when
+ * bootup statically.
+ */
+ dev_num = 3;
+ spec->dev_num = 3;
+ } else if (spec->dyn_pcm_assign && codec->dp_mst) {
+ dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
+ /*
+ * spec->dev_num is the maxinum number of device entries
+ * among all the pins
+ */
+ spec->dev_num = (spec->dev_num > dev_num) ?
+ spec->dev_num : dev_num;
+ } else {
+ /*
+ * If the platform doesn't support DP MST,
+ * manually set dev_num to 1. This means
+ * the pin has only one device entry.
+ */
+ dev_num = 1;
+ spec->dev_num = 1;
}
- per_pin->pin_nid_idx = pin_idx;
- err = hdmi_read_pin_conn(codec, pin_idx);
- if (err < 0)
- return err;
+ for (i = 0; i < dev_num; i++) {
+ pin_idx = spec->num_pins;
+ per_pin = snd_array_new(&spec->pins);
- spec->num_pins++;
+ if (!per_pin)
+ return -ENOMEM;
+
+ if (spec->dyn_pcm_assign) {
+ per_pin->pcm = NULL;
+ per_pin->pcm_idx = -1;
+ } else {
+ per_pin->pcm = get_hdmi_pcm(spec, pin_idx);
+ per_pin->pcm_idx = pin_idx;
+ }
+ per_pin->pin_nid = pin_nid;
+ per_pin->pin_nid_idx = spec->num_nids;
+ per_pin->dev_id = i;
+ per_pin->non_pcm = false;
+ snd_hda_set_dev_select(codec, pin_nid, i);
+ if (is_haswell_plus(codec))
+ intel_haswell_fixup_connect_list(codec, pin_nid);
+ err = hdmi_read_pin_conn(codec, pin_idx);
+ if (err < 0)
+ return err;
+ spec->num_pins++;
+ }
+ spec->num_nids++;
return 0;
}
@@ -1744,7 +1868,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
/* Todo: add DP1.2 MST audio support later */
if (codec_has_acomp(codec))
- snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);
+ snd_hdac_sync_audio_rate(&codec->core, pin_nid, per_pin->dev_id,
+ runtime->rate);
non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
mutex_lock(&per_pin->lock);
@@ -1761,6 +1886,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
pinctl | PIN_OUT);
}
+ /* snd_hda_set_dev_select() has been called before */
err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
stream_tag, format);
mutex_unlock(&spec->pcm_lock);
@@ -1896,17 +2022,23 @@ static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
static int generic_hdmi_build_pcms(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
- int pin_idx;
+ int idx;
- for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ /*
+ * for non-mst mode, pcm number is the same as before
+ * for DP MST mode, pcm number is (nid number + dev_num - 1)
+ * dev_num is the device entry number in a pin
+ *
+ */
+ for (idx = 0; idx < spec->num_nids + spec->dev_num - 1; idx++) {
struct hda_pcm *info;
struct hda_pcm_stream *pstr;
- info = snd_hda_codec_pcm_new(codec, "HDMI %d", pin_idx);
+ info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
if (!info)
return -ENOMEM;
- spec->pcm_rec[pin_idx].pcm = info;
+ spec->pcm_rec[idx].pcm = info;
spec->pcm_used++;
info->pcm_type = HDA_PCM_TYPE_HDMI;
info->own_chmap = true;
@@ -1914,6 +2046,9 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
pstr->substreams = 1;
pstr->ops = generic_ops;
+ /* pcm number is less than 16 */
+ if (spec->pcm_used >= 16)
+ break;
/* other pstr fields are set in open */
}
@@ -2069,7 +2204,9 @@ static int generic_hdmi_init(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);
hda_nid_t pin_nid = per_pin->pin_nid;
+ int dev_id = per_pin->dev_id;
+ snd_hda_set_dev_select(codec, pin_nid, dev_id);
hdmi_init_pin(codec, pin_nid);
if (!codec_has_acomp(codec))
snd_hda_jack_detect_enable_callback(codec, pin_nid,
@@ -2177,6 +2314,7 @@ static int alloc_generic_hdmi(struct hda_codec *codec)
return -ENOMEM;
spec->ops = generic_standard_hdmi_ops;
+ spec->dev_num = 1; /* initialize to 1 */
mutex_init(&spec->pcm_lock);
snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
@@ -2290,10 +2428,11 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
snd_hda_codec_set_power_to_all(codec, fg, power_state);
}
-static void intel_pin_eld_notify(void *audio_ptr, int port)
+static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
{
struct hda_codec *codec = audio_ptr;
int pin_nid;
+ int dev_id = pipe;
/* we assume only from port-B to port-D */
if (port < 1 || port > 3)
@@ -2320,7 +2459,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
return;
snd_hdac_i915_set_bclk(&codec->bus->core);
- check_presence_and_report(codec, pin_nid);
+ check_presence_and_report(codec, pin_nid, dev_id);
}
/* register i915 component pin_eld_notify callback */
@@ -2353,11 +2492,13 @@ static void i915_pin_cvt_fixup(struct hda_codec *codec,
hda_nid_t cvt_nid)
{
if (per_pin) {
+ snd_hda_set_dev_select(codec, per_pin->pin_nid,
+ per_pin->dev_id);
intel_verify_pin_cvt_connect(codec, per_pin);
intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
- per_pin->mux_idx);
+ per_pin->dev_id, per_pin->mux_idx);
} else {
- intel_not_share_assigned_cvt_nid(codec, 0, cvt_nid);
+ intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
}
}
@@ -2377,6 +2518,8 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
if (err < 0)
return err;
spec = codec->spec;
+ codec->dp_mst = true;
+ spec->dyn_pcm_assign = true;
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
@@ -2388,7 +2531,6 @@ static int patch_i915_hsw_hdmi(struct hda_codec *codec)
codec->core.link_power_control = 1;
codec->patch_ops.set_power_state = haswell_set_power_state;
- codec->dp_mst = true;
codec->depop_delay = 0;
codec->auto_runtime_pm = 1;
@@ -3638,6 +3780,7 @@ HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi),
HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI", patch_nvhdmi_2ch),
@@ -3657,6 +3800,7 @@ HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_hsw_hdmi),
HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_i915_byt_hdmi),
HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_i915_byt_hdmi),
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index ea81c08ddc7a..299835d1fbaa 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -337,6 +337,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
case 0x10ec0288:
case 0x10ec0295:
case 0x10ec0298:
+ case 0x10ec0299:
alc_update_coef_idx(codec, 0x10, 1<<9, 0);
break;
case 0x10ec0285:
@@ -379,6 +380,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
break;
case 0x10ec0899:
case 0x10ec0900:
+ case 0x10ec1220:
alc_update_coef_idx(codec, 0x7, 1<<1, 0);
break;
}
@@ -420,7 +422,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
}
/* generic shutup callback;
- * just turning off EPAD and a little pause for avoiding pop-noise
+ * just turning off EAPD and a little pause for avoiding pop-noise
*/
static void alc_eapd_shutup(struct hda_codec *codec)
{
@@ -912,6 +914,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
{ 0x10ec0256, 0x1028, 0, "ALC3246" },
{ 0x10ec0225, 0x1028, 0, "ALC3253" },
{ 0x10ec0295, 0x1028, 0, "ALC3254" },
+ { 0x10ec0299, 0x1028, 0, "ALC3271" },
{ 0x10ec0670, 0x1025, 0, "ALC669X" },
{ 0x10ec0676, 0x1025, 0, "ALC679X" },
{ 0x10ec0282, 0x1043, 0, "ALC3229" },
@@ -2230,6 +2233,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
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(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
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),
@@ -2308,6 +2312,7 @@ static int patch_alc882(struct hda_codec *codec)
case 0x10ec0882:
case 0x10ec0885:
case 0x10ec0900:
+ case 0x10ec1220:
break;
default:
/* ALC883 and variants */
@@ -3716,6 +3721,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0867:
@@ -3811,6 +3817,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
case 0x10ec0867:
alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
/* fallthru */
+ case 0x10ec0221:
case 0x10ec0662:
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
@@ -3823,6 +3830,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
alc_process_coef_fw(codec, coef0225);
@@ -3881,6 +3889,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
switch (codec->core.vendor_id) {
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0255:
@@ -3996,6 +4005,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
case 0x10ec0867:
@@ -4089,6 +4099,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
break;
}
@@ -4173,6 +4184,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
alc_process_coef_fw(codec, coef0225);
msleep(800);
val = alc_read_coef_idx(codec, 0x46);
@@ -4400,7 +4412,7 @@ static void alc_no_shutup(struct hda_codec *codec)
static void alc_fixup_no_shutup(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ if (action == HDA_FIXUP_ACT_PROBE) {
struct alc_spec *spec = codec->spec;
spec->shutup = alc_no_shutup;
}
@@ -4835,6 +4847,7 @@ enum {
ALC286_FIXUP_HP_GPIO_LED,
ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
ALC280_FIXUP_HP_DOCK_PINS,
+ ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED,
ALC280_FIXUP_HP_9480M,
ALC288_FIXUP_DELL_HEADSET_MODE,
ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -4845,6 +4858,7 @@ enum {
ALC292_FIXUP_DISABLE_AAMIX,
ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK,
ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
ALC275_FIXUP_DELL_XPS,
ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
ALC293_FIXUP_LENOVO_SPK_NOISE,
@@ -4856,6 +4870,8 @@ enum {
ALC292_FIXUP_TPT460,
ALC298_FIXUP_SPK_VOLUME,
ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
+ ALC269_FIXUP_ATIV_BOOK_8,
+ ALC221_FIXUP_HP_MIC_NO_PRESENCE,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -5374,6 +5390,16 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC280_FIXUP_HP_GPIO4
},
+ [ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x1b, 0x21011020 }, /* line-out */
+ { 0x18, 0x2181103f }, /* line-in */
+ { },
+ },
+ .chained = true,
+ .chain_id = ALC269_FIXUP_HP_GPIO_MIC1_LED
+ },
[ALC280_FIXUP_HP_9480M] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc280_fixup_hp_9480m,
@@ -5445,6 +5471,15 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_HEADSET_MODE
},
+ [ALC298_FIXUP_DELL_AIO_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_MODE
+ },
[ALC275_FIXUP_DELL_XPS] = {
.type = HDA_FIXUP_VERBS,
.v.verbs = (const struct hda_verb[]) {
@@ -5517,7 +5552,7 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc298_fixup_speaker_volume,
.chained = true,
- .chain_id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+ .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
},
[ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
.type = HDA_FIXUP_PINS,
@@ -5528,6 +5563,22 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
},
+ [ALC269_FIXUP_ATIV_BOOK_8] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_auto_mute_via_amp,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_NO_SHUTUP
+ },
+ [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, 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 = ALC269_FIXUP_HEADSET_MODE
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5576,6 +5627,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
+ SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5616,7 +5668,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
- SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+ SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED),
SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -5638,6 +5690,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
+ SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
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),
@@ -5664,6 +5718,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
@@ -5691,6 +5746,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+ SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
@@ -5781,6 +5837,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, .name = "headset-mode-no-hp-mic"},
{.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
{.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
+ {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic1-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-dac-wcaps"},
@@ -5917,6 +5974,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x12, 0x90a60180},
{0x14, 0x90170120},
{0x21, 0x02211030}),
+ SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+ {0x1b, 0x01011020},
+ {0x21, 0x02211010}),
SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60160},
{0x14, 0x90170120},
@@ -6052,6 +6112,8 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
ALC295_STANDARD_PINS,
{0x17, 0x21014040},
{0x18, 0x21a19050}),
+ SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+ ALC295_STANDARD_PINS),
SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_STANDARD_PINS,
{0x17, 0x90170110}),
@@ -6061,6 +6123,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_STANDARD_PINS,
{0x17, 0x90170150}),
+ SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
+ {0x12, 0xb7a60140},
+ {0x13, 0xb7a60150},
+ {0x17, 0x90170110},
+ {0x1a, 0x03011020},
+ {0x21, 0x03211030}),
{}
};
@@ -6208,6 +6276,7 @@ static int patch_alc269(struct hda_codec *codec)
break;
case 0x10ec0225:
case 0x10ec0295:
+ case 0x10ec0299:
spec->codec_variant = ALC269_TYPE_ALC225;
break;
case 0x10ec0234:
@@ -6561,6 +6630,30 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec,
}
}
+static void alc662_usi_automute_hook(struct hda_codec *codec,
+ struct hda_jack_callback *jack)
+{
+ struct alc_spec *spec = codec->spec;
+ int vref;
+ msleep(200);
+ snd_hda_gen_hp_automute(codec, jack);
+
+ vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+ msleep(100);
+ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ vref);
+}
+
+static void alc662_fixup_usi_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;
+ spec->gen.hp_automute_hook = alc662_usi_automute_hook;
+ }
+}
+
static struct coef_fw alc668_coefs[] = {
WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
@@ -6626,6 +6719,8 @@ enum {
ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
ALC662_FIXUP_ACER_VERITON,
ALC892_FIXUP_ASROCK_MOBO,
+ ALC662_FIXUP_USI_FUNC,
+ ALC662_FIXUP_USI_HEADSET_MODE,
};
static const struct hda_fixup alc662_fixups[] = {
@@ -6910,6 +7005,20 @@ static const struct hda_fixup alc662_fixups[] = {
{ }
}
},
+ [ALC662_FIXUP_USI_FUNC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc662_fixup_usi_headset_mic,
+ },
+ [ALC662_FIXUP_USI_HEADSET_MODE] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
+ { 0x18, 0x01a1903d },
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC662_FIXUP_USI_FUNC
+ },
};
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -6940,11 +7049,13 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
+ SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_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),
+ SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
@@ -7204,6 +7315,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
+ HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
@@ -7235,6 +7347,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
+ HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
{} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 37b70f8e878f..faa3d38bac0b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -166,6 +166,7 @@ enum {
STAC_D965_VERBS,
STAC_DELL_3ST,
STAC_DELL_BIOS,
+ STAC_NEMO_DEFAULT,
STAC_DELL_BIOS_AMIC,
STAC_DELL_BIOS_SPDIF,
STAC_927X_DELL_DMIC,
@@ -1360,6 +1361,27 @@ static const struct hda_pintbl oqo9200_pin_configs[] = {
{}
};
+/*
+ * STAC 92HD700
+ * 18881000 Amigaone X1000
+ */
+static const struct hda_pintbl nemo_pin_configs[] = {
+ { 0x0a, 0x02214020 }, /* Front panel HP socket */
+ { 0x0b, 0x02a19080 }, /* Front Mic */
+ { 0x0c, 0x0181304e }, /* Line in */
+ { 0x0d, 0x01014010 }, /* Line out */
+ { 0x0e, 0x01a19040 }, /* Rear Mic */
+ { 0x0f, 0x01011012 }, /* Rear speakers */
+ { 0x10, 0x01016011 }, /* Center speaker */
+ { 0x11, 0x01012014 }, /* Side speakers (7.1) */
+ { 0x12, 0x103301f0 }, /* Motherboard CD line in connector */
+ { 0x13, 0x411111f0 }, /* Unused */
+ { 0x14, 0x411111f0 }, /* Unused */
+ { 0x21, 0x01442170 }, /* S/PDIF line out */
+ { 0x22, 0x411111f0 }, /* Unused */
+ { 0x23, 0x411111f0 }, /* Unused */
+ {}
+};
static void stac9200_fixup_panasonic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -3883,6 +3905,10 @@ static const struct hda_fixup stac927x_fixups[] = {
.type = HDA_FIXUP_PINS,
.v.pins = d965_5st_no_fp_pin_configs,
},
+ [STAC_NEMO_DEFAULT] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = nemo_pin_configs,
+ },
[STAC_DELL_3ST] = {
.type = HDA_FIXUP_PINS,
.v.pins = dell_3st_pin_configs,
@@ -3939,6 +3965,7 @@ static const struct hda_model_fixup stac927x_models[] = {
{ .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
{ .id = STAC_DELL_3ST, .name = "dell-3stack" },
{ .id = STAC_DELL_BIOS, .name = "dell-bios" },
+ { .id = STAC_NEMO_DEFAULT, .name = "nemo-default" },
{ .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
{ .id = STAC_927X_VOLKNOB, .name = "volknob" },
{}
@@ -3977,6 +4004,8 @@ static const struct snd_pci_quirk stac927x_fixup_tbl[] = {
"Intel D965", STAC_D965_5ST),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
"Intel D965", STAC_D965_5ST),
+ /* Nemo */
+ SND_PCI_QUIRK(0x1888, 0x1000, "AmigaOne X1000", STAC_NEMO_DEFAULT),
/* volume-knob fixes */
SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
{} /* terminator */
@@ -5036,6 +5065,7 @@ static const struct hda_device_id snd_hda_id_sigmatel[] = {
HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
+ HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index e5c52ed9b674..842744e7a139 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -367,7 +367,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
} while (time_after(timeout, jiffies));
}
-static struct snd_rawmidi_ops vt1724_midi_output_ops = {
+static const struct snd_rawmidi_ops vt1724_midi_output_ops = {
.open = vt1724_midi_output_open,
.close = vt1724_midi_output_close,
.trigger = vt1724_midi_output_trigger,
@@ -402,7 +402,7 @@ static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up)
spin_unlock_irqrestore(&ice->reg_lock, flags);
}
-static struct snd_rawmidi_ops vt1724_midi_input_ops = {
+static const struct snd_rawmidi_ops vt1724_midi_input_ops = {
.open = vt1724_midi_input_open,
.close = vt1724_midi_input_close,
.trigger = vt1724_midi_input_trigger,
diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c
index f7ac8d5e862c..27c03e40c9b1 100644
--- a/sound/pci/ice1712/wm8766.c
+++ b/sound/pci/ice1712/wm8766.c
@@ -254,7 +254,7 @@ static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol,
int n = kcontrol->private_value;
u16 val, regval1, regval2;
- /* this also works for enum because value is an union */
+ /* this also works for enum because value is a union */
regval1 = ucontrol->value.integer.value[0];
regval2 = ucontrol->value.integer.value[1];
if (wm->ctl[n].flags & WM8766_FLAG_INVERT) {
diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c
index ebd2fe4b4a57..553669b103c2 100644
--- a/sound/pci/ice1712/wm8776.c
+++ b/sound/pci/ice1712/wm8776.c
@@ -528,7 +528,7 @@ static int snd_wm8776_ctl_put(struct snd_kcontrol *kcontrol,
int n = kcontrol->private_value;
u16 val, regval1, regval2;
- /* this also works for enum because value is an union */
+ /* this also works for enum because value is a union */
regval1 = ucontrol->value.integer.value[0];
regval2 = ucontrol->value.integer.value[1];
if (wm->ctl[n].flags & WM8776_FLAG_INVERT) {
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 565f7f55c3ca..1e25095fd144 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2051,7 +2051,7 @@ static void snd_korg1212_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, korg1212->card->longname);
snd_iprintf(buffer, " (index #%d)\n", korg1212->card->number + 1);
snd_iprintf(buffer, "\nGeneral settings\n");
- snd_iprintf(buffer, " period size: %Zd bytes\n", K1212_PERIOD_BYTES);
+ snd_iprintf(buffer, " period size: %zd bytes\n", K1212_PERIOD_BYTES);
snd_iprintf(buffer, " clock mode: %s\n", clockSourceName[korg1212->clkSrcRate] );
snd_iprintf(buffer, " left ADC Sens: %d\n", korg1212->leftADCInSens );
snd_iprintf(buffer, " right ADC Sens: %d\n", korg1212->rightADCInSens );
@@ -2276,7 +2276,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci,
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
sizeof(struct KorgSharedBuffer), &korg1212->dma_shared) < 0) {
- snd_printk(KERN_ERR "korg1212: can not allocate shared buffer memory (%Zd bytes)\n", sizeof(struct KorgSharedBuffer));
+ snd_printk(KERN_ERR "korg1212: can not allocate shared buffer memory (%zd bytes)\n", sizeof(struct KorgSharedBuffer));
snd_korg1212_free(korg1212);
return -ENOMEM;
}
diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
index 0cc17e0ea34a..426743871540 100644
--- a/sound/pci/mixart/mixart.h
+++ b/sound/pci/mixart/mixart.h
@@ -86,7 +86,7 @@ struct mixart_mgr {
u32 msg_fifo[MSG_FIFO_SIZE];
int msg_fifo_readptr;
int msg_fifo_writeptr;
- atomic_t msg_processed; /* number of messages to be processed in takslet */
+ atomic_t msg_processed; /* number of messages to be processed in tasklet */
struct mutex lock; /* interrupt lock */
struct mutex msg_lock; /* mailbox lock */
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 80633055e17e..a99808ab01fe 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -292,7 +292,7 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index,
int err, card_index;
dev_dbg(&mgr->pci->dev,
- "loading dsp [%d] size = %Zd\n", index, dsp->size);
+ "loading dsp [%d] size = %zd\n", index, dsp->size);
switch (index) {
case PCXHR_FIRMWARE_XLX_INT_INDEX:
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index ada5f01d479c..19c9df6b0f3d 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -110,7 +110,7 @@
#include <sound/opl3.h>
#include <sound/initval.h>
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index b94fc6357139..fc0face6cdc6 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1510,14 +1510,14 @@ static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
return 0;
}
-static struct snd_rawmidi_ops snd_hdsp_midi_output =
+static const struct snd_rawmidi_ops snd_hdsp_midi_output =
{
.open = snd_hdsp_midi_output_open,
.close = snd_hdsp_midi_output_close,
.trigger = snd_hdsp_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_hdsp_midi_input =
+static const struct snd_rawmidi_ops snd_hdsp_midi_input =
{
.open = snd_hdsp_midi_input_open,
.close = snd_hdsp_midi_input_close,
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 14bbf55c1ef9..c48acdb0e186 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -2043,14 +2043,14 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream)
return 0;
}
-static struct snd_rawmidi_ops snd_hdspm_midi_output =
+static const struct snd_rawmidi_ops snd_hdspm_midi_output =
{
.open = snd_hdspm_midi_output_open,
.close = snd_hdspm_midi_output_close,
.trigger = snd_hdspm_midi_output_trigger,
};
-static struct snd_rawmidi_ops snd_hdspm_midi_input =
+static const struct snd_rawmidi_ops snd_hdspm_midi_input =
{
.open = snd_hdspm_midi_input_open,
.close = snd_hdspm_midi_input_close,
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index e1a13870bb80..a6aa48c5b969 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -45,7 +45,7 @@ MODULE_DESCRIPTION("S3 SonicVibes PCI");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 27f0ed840979..92ad2d7a6bf8 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3120,7 +3120,7 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device)
* gameport interface
*/
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
static unsigned char snd_trident_gameport_read(struct gameport *gameport)
{
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 38a17b4342a6..2d8c14e3f8d2 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -72,7 +72,7 @@ MODULE_DESCRIPTION("VIA VT82xx audio");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}");
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK 1
#endif
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index af83b3b38052..8e457ea27f89 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -269,12 +269,12 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
/* Transfer using pseudo-dma.
*/
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0) {
+ for (; length > 0; length--) {
outl(cpu_to_le32(*addr), port);
addr++;
}
@@ -284,7 +284,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 0) {
+ for (; count > 0; count--) {
outl(cpu_to_le32(*addr), port);
addr++;
}
@@ -307,12 +307,12 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
vx2_setup_pseudo_dma(chip, 0);
/* Transfer using pseudo-dma.
*/
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0)
+ for (; length > 0; length--)
*addr++ = le32_to_cpu(inl(port));
addr = (u32 *)runtime->dma_area;
pipe->hw_ptr = 0;
@@ -320,7 +320,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 0)
+ for (; count > 0; count--)
*addr++ = le32_to_cpu(inl(port));
vx2_release_pseudo_dma(chip);
diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h
index 149d4cb46998..aa9bb065f385 100644
--- a/sound/pci/ymfpci/ymfpci.h
+++ b/sound/pci/ymfpci/ymfpci.h
@@ -176,7 +176,7 @@
#define YMFPCI_LEGACY2_IMOD (1 << 15) /* legacy IRQ mode */
/* SIEN:IMOD 0:0 = legacy irq, 0:1 = INTA, 1:0 = serialized IRQ */
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#if IS_REACHABLE(CONFIG_GAMEPORT)
#define SUPPORT_JOYSTICK
#endif
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 281972913c32..5f97791f00d7 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -201,7 +201,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware *
c |= (int)vx_inb(chip, RXM) << 8;
c |= vx_inb(chip, RXL);
- snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%Zx\n", c, fw->size);
+ snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%zx\n", c, fw->size);
vx_outb(chip, ICR, ICR_HF0);
@@ -369,12 +369,12 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
vx_setup_pseudo_dma(chip, 1);
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0) {
+ for (; length > 0; length--) {
outw(cpu_to_le16(*addr), port);
addr++;
}
@@ -384,7 +384,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 0) {
+ for (; count > 0; count--) {
outw(cpu_to_le16(*addr), port);
addr++;
}
@@ -411,12 +411,12 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
if (snd_BUG_ON(count % 2))
return;
vx_setup_pseudo_dma(chip, 0);
- if (offset + count > pipe->buffer_bytes) {
+ if (offset + count >= pipe->buffer_bytes) {
int length = pipe->buffer_bytes - offset;
count -= length;
length >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (length-- > 0)
+ for (; length > 0; length--)
*addr++ = le16_to_cpu(inw(port));
addr = (unsigned short *)runtime->dma_area;
pipe->hw_ptr = 0;
@@ -424,7 +424,7 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
pipe->hw_ptr += count;
count >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
- while (count-- > 1)
+ for (; count > 1; count--)
*addr++ = le16_to_cpu(inw(port));
/* Disable DMA */
pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK;
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index b84d7d34f188..cdd44abfc9e0 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -883,7 +883,7 @@ static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
{
/*
- * avsetting driver seems to never change the followings
+ * avsetting driver seems to never change the following
* so, init them here once
*/
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index abf9c0cab1e2..461b310c7872 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -87,7 +87,7 @@ static void dac_audio_reset(struct snd_sh_dac *chip)
static void dac_audio_set_rate(struct snd_sh_dac *chip)
{
- chip->wakeups_per_second = ktime_set(0, 1000000000 / chip->rate);
+ chip->wakeups_per_second = 1000000000 / chip->rate;
}
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 182d92efc7c8..c0abad2067e1 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -47,6 +47,7 @@ source "sound/soc/cirrus/Kconfig"
source "sound/soc/davinci/Kconfig"
source "sound/soc/dwc/Kconfig"
source "sound/soc/fsl/Kconfig"
+source "sound/soc/hisilicon/Kconfig"
source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
@@ -63,6 +64,7 @@ source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/sti/Kconfig"
+source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 9a30f21d16ee..39c27a58158d 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC) += cirrus/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += dwc/
obj-$(CONFIG_SND_SOC) += fsl/
+obj-$(CONFIG_SND_SOC) += hisilicon/
obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += img/
obj-$(CONFIG_SND_SOC) += intel/
@@ -43,6 +44,7 @@ obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += sti/
+obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 504c7cd7f58a..08b1399d1da2 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -89,7 +89,7 @@ static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg)
writel(val, acp_mmio + (reg * 4));
}
-/* Configure a given dma channel parameters - enable/disble,
+/* Configure a given dma channel parameters - enable/disable,
* number of descriptors, priority
*/
static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num,
@@ -506,7 +506,7 @@ static int acp_init(void __iomem *acp_mmio)
return 0;
}
-/* Deintialize ACP */
+/* Deinitialize ACP */
static int acp_deinit(void __iomem *acp_mmio)
{
u32 val;
@@ -670,13 +670,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
{
int status;
uint64_t size;
- struct snd_dma_buffer *dma_buffer;
struct page *pg;
struct snd_pcm_runtime *runtime;
struct audio_substream_data *rtd;
- dma_buffer = &substream->dma_buffer;
-
runtime = substream->runtime;
rtd = runtime->private_data;
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index 89ac5f5a93eb..7ae46c2647d4 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -349,7 +349,7 @@ static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai,
}
#define CLASSD_ACLK_RATE_11M2896_MPY_8 (112896 * 100 * 8)
-#define CLASSD_ACLK_RATE_12M288_MPY_8 (12228 * 1000 * 8)
+#define CLASSD_ACLK_RATE_12M288_MPY_8 (12288 * 1000 * 8)
static struct {
int rate;
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index ac6a814c8ecf..a72c7d642026 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -51,11 +51,7 @@
#include <sound/soc.h>
#include <sound/pcm_params.h>
-#include "atmel_ssc_dai.h"
-
struct tse850_priv {
- int ssc_id;
-
struct gpio_desc *add;
struct gpio_desc *loop1;
struct gpio_desc *loop2;
@@ -329,23 +325,20 @@ static int tse850_dt_init(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *codec_np, *cpu_np;
- struct snd_soc_card *card = &tse850_card;
struct snd_soc_dai_link *dailink = &tse850_dailink;
- struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
if (!np) {
dev_err(&pdev->dev, "only device tree supported\n");
return -EINVAL;
}
- cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0);
+ cpu_np = of_parse_phandle(np, "axentia,cpu-dai", 0);
if (!cpu_np) {
- dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+ dev_err(&pdev->dev, "failed to get cpu dai\n");
return -EINVAL;
}
dailink->cpu_of_node = cpu_np;
dailink->platform_of_node = cpu_np;
- tse850->ssc_id = of_alias_get_id(cpu_np, "ssc");
of_node_put(cpu_np);
codec_np = of_parse_phandle(np, "axentia,audio-codec", 0);
@@ -415,23 +408,14 @@ static int tse850_probe(struct platform_device *pdev)
return ret;
}
- ret = atmel_ssc_set_audio(tse850->ssc_id);
- if (ret != 0) {
- dev_err(dev,
- "failed to set SSC %d for audio\n", tse850->ssc_id);
- goto err_disable_ana;
- }
-
ret = snd_soc_register_card(card);
if (ret) {
dev_err(dev, "snd_soc_register_card failed\n");
- goto err_put_audio;
+ goto err_disable_ana;
}
return 0;
-err_put_audio:
- atmel_ssc_put_audio(tse850->ssc_id);
err_disable_ana:
regulator_disable(tse850->ana);
return ret;
@@ -443,7 +427,6 @@ static int tse850_remove(struct platform_device *pdev)
struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card);
- atmel_ssc_put_audio(tse850->ssc_id);
regulator_disable(tse850->ana);
return 0;
diff --git a/sound/soc/blackfin/bfin-eval-adau1373.c b/sound/soc/blackfin/bfin-eval-adau1373.c
index 72ac78988426..64b88fdc1f6c 100644
--- a/sound/soc/blackfin/bfin-eval-adau1373.c
+++ b/sound/soc/blackfin/bfin-eval-adau1373.c
@@ -119,7 +119,7 @@ static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
-static struct snd_soc_ops bfin_eval_adau1373_ops = {
+static const struct snd_soc_ops bfin_eval_adau1373_ops = {
.hw_params = bfin_eval_adau1373_hw_params,
};
diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c
index 1037477d10b2..99e5ecabdcda 100644
--- a/sound/soc/blackfin/bfin-eval-adav80x.c
+++ b/sound/soc/blackfin/bfin-eval-adav80x.c
@@ -64,7 +64,7 @@ static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static struct snd_soc_ops bfin_eval_adav80x_ops = {
+static const struct snd_soc_ops bfin_eval_adav80x_ops = {
.hw_params = bfin_eval_adav80x_hw_params,
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9e1718a8cb1c..883ed4c8a551 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -45,10 +45,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5623 if I2C
select SND_SOC_ALC5632 if I2C
select SND_SOC_BT_SCO
- select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+ select SND_SOC_CQ0093VC
select SND_SOC_CS35L32 if I2C
select SND_SOC_CS35L33 if I2C
select SND_SOC_CS35L34 if I2C
+ select SND_SOC_CS35L35 if I2C
select SND_SOC_CS42L42 if I2C
select SND_SOC_CS42L51_I2C if I2C
select SND_SOC_CS42L52 if I2C && INPUT
@@ -69,9 +70,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA7219 if I2C
select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
+ select SND_SOC_DIO2125
select SND_SOC_DMIC
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
+ select SND_SOC_ES7134
select SND_SOC_GTM601
select SND_SOC_HDAC_HDMI
select SND_SOC_ICS43432
@@ -89,13 +92,16 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9867 if I2C
select SND_SOC_MAX98925 if I2C
select SND_SOC_MAX98926 if I2C
+ select SND_SOC_MAX98927 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9860 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_MC13783 if MFD_MC13XXX
select SND_SOC_ML26124 if I2C
+ select SND_SOC_NAU8540 if I2C
select SND_SOC_NAU8810 if I2C
+ select SND_SOC_NAU8824 if I2C
select SND_SOC_NAU8825 if I2C
select SND_SOC_HDMI_CODEC
select SND_SOC_PCM1681 if I2C
@@ -117,8 +123,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5651 if I2C
select SND_SOC_RT5659 if I2C
select SND_SOC_RT5660 if I2C
- select SND_SOC_RT5665 if I2C
select SND_SOC_RT5663 if I2C
+ select SND_SOC_RT5665 if I2C
select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C
@@ -302,12 +308,14 @@ config SND_SOC_ADAU1761
select SND_SOC_ADAU17X1
config SND_SOC_ADAU1761_I2C
- tristate
+ tristate "Analog Devices AU1761 CODEC - I2C"
+ depends on I2C
select SND_SOC_ADAU1761
select REGMAP_I2C
config SND_SOC_ADAU1761_SPI
- tristate
+ tristate "Analog Devices AU1761 CODEC - SPI"
+ depends on SPI
select SND_SOC_ADAU1761
select REGMAP_SPI
@@ -407,6 +415,10 @@ config SND_SOC_CS35L34
tristate "Cirrus Logic CS35L34 CODEC"
depends on I2C
+config SND_SOC_CS35L35
+ tristate "Cirrus Logic CS35L35 CODEC"
+ depends on I2C
+
config SND_SOC_CS42L42
tristate "Cirrus Logic CS42L42 CODEC"
depends on I2C
@@ -515,6 +527,10 @@ config SND_SOC_DA732X
config SND_SOC_DA9055
tristate
+config SND_SOC_DIO2125
+ tristate "Dioo DIO2125 Amplifier"
+ select GPIOLIB
+
config SND_SOC_DMIC
tristate
@@ -524,15 +540,20 @@ config SND_SOC_HDMI_CODEC
select SND_PCM_IEC958
select HDMI
+config SND_SOC_ES7134
+ tristate "Everest Semi ES7134 CODEC"
+
config SND_SOC_ES8328
- tristate "Everest Semi ES8328 CODEC"
+ tristate
config SND_SOC_ES8328_I2C
- tristate
+ tristate "Everest Semi ES8328 CODEC (I2C)"
+ depends on I2C
select SND_SOC_ES8328
config SND_SOC_ES8328_SPI
- tristate
+ tristate "Everest Semi ES8328 CODEC (SPI)"
+ depends on SPI_MASTER
select SND_SOC_ES8328
config SND_SOC_GTM601
@@ -585,6 +606,10 @@ config SND_SOC_MAX98925
config SND_SOC_MAX98926
tristate
+config SND_SOC_MAX98927
+ tristate "Maxim Integrated MAX98927 Speaker Amplifier"
+ depends on I2C
+
config SND_SOC_MAX9850
tristate
@@ -668,8 +693,8 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5651=y
default y if SND_SOC_RT5659=y
default y if SND_SOC_RT5660=y
- default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5663=y
+ default y if SND_SOC_RT5665=y
default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y
default m if SND_SOC_RT5514=m
@@ -679,8 +704,8 @@ config SND_SOC_RL6231
default m if SND_SOC_RT5651=m
default m if SND_SOC_RT5659=m
default m if SND_SOC_RT5660=m
- default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5663=m
+ default m if SND_SOC_RT5665=m
default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m
@@ -728,10 +753,10 @@ config SND_SOC_RT5659
config SND_SOC_RT5660
tristate
-config SND_SOC_RT5665
+config SND_SOC_RT5663
tristate
-config SND_SOC_RT5663
+config SND_SOC_RT5665
tristate
config SND_SOC_RT5670
@@ -1105,10 +1130,18 @@ config SND_SOC_MC13783
config SND_SOC_ML26124
tristate
+config SND_SOC_NAU8540
+ tristate "Nuvoton Technology Corporation NAU85L40 CODEC"
+ depends on I2C
+
config SND_SOC_NAU8810
tristate "Nuvoton Technology Corporation NAU88C10 CODEC"
depends on I2C
+config SND_SOC_NAU8824
+ tristate "Nuvoton Technology Corporation NAU88L24 CODEC"
+ depends on I2C
+
config SND_SOC_NAU8825
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7e1dad79610b..28a63fdaf982 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -39,6 +39,7 @@ snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs35l32-objs := cs35l32.o
snd-soc-cs35l33-objs := cs35l33.o
snd-soc-cs35l34-objs := cs35l34.o
+snd-soc-cs35l35-objs := cs35l35.o
snd-soc-cs42l42-objs := cs42l42.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o
@@ -63,6 +64,7 @@ snd-soc-da7219-objs := da7219.o da7219-aad.o
snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-dmic-objs := dmic.o
+snd-soc-es7134-objs := es7134.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o
@@ -84,13 +86,16 @@ snd-soc-max98371-objs := max98371.o
snd-soc-max9867-objs := max9867.o
snd-soc-max98925-objs := max98925.o
snd-soc-max98926-objs := max98926.o
+snd-soc-max98927-objs := max98927.o
snd-soc-max9850-objs := max9850.o
snd-soc-max9860-objs := max9860.o
snd-soc-mc13783-objs := mc13783.o
snd-soc-ml26124-objs := ml26124.o
snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o
snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o
+snd-soc-nau8540-objs := nau8540.o
snd-soc-nau8810-objs := nau8810.o
+snd-soc-nau8824-objs := nau8824.o
snd-soc-nau8825-objs := nau8825.o
snd-soc-hdmi-codec-objs := hdmi-codec.o
snd-soc-pcm1681-objs := pcm1681.o
@@ -118,8 +123,8 @@ snd-soc-rt5645-objs := rt5645.o
snd-soc-rt5651-objs := rt5651.o
snd-soc-rt5659-objs := rt5659.o
snd-soc-rt5660-objs := rt5660.o
-snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5663-objs := rt5663.o
+snd-soc-rt5665-objs := rt5665.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
@@ -220,6 +225,7 @@ snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
# Amp
+snd-soc-dio2125-objs := dio2125.o
snd-soc-max9877-objs := max9877.o
snd-soc-max98504-objs := max98504.o
snd-soc-tpa6130a2-objs := tpa6130a2.o
@@ -268,6 +274,7 @@ obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o
obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o
obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o
+obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o
obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o
@@ -292,6 +299,7 @@ obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_ES7134) += snd-soc-es7134.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
@@ -312,13 +320,16 @@ obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o
obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o
obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o
obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o
+obj-$(CONFIG_SND_SOC_MAX98927) += snd-soc-max98927.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o
obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o
obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o
+obj-$(CONFIG_SND_SOC_NAU8540) += snd-soc-nau8540.o
obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o
+obj-$(CONFIG_SND_SOC_NAU8824) += snd-soc-nau8824.o
obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o
obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
@@ -346,8 +357,8 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o
obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o
-obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o
+obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
@@ -446,6 +457,7 @@ obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
# Amp
+obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index b36511d965c8..2c1bd2763864 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -65,7 +65,6 @@ static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
- int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) {
adau->pll_regs[5] = 1;
@@ -78,7 +77,7 @@ static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
}
/* The PLL register is 6 bytes long and can only be written at once. */
- ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
+ regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,
adau->pll_regs, ARRAY_SIZE(adau->pll_regs));
if (SND_SOC_DAPM_EVENT_ON(event)) {
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index e819dd8c82fd..b2dfddead227 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -75,6 +75,12 @@
#define DFS_DOUBLE_SPEED (1 << 2)
#define DFS_QUAD_SPEED (2 << 2)
+/* ICTRL */
+#define ICTRL_MASK (0x3)
+
+/* OCTRL */
+#define OCTRL_MASK (0x3F)
+
struct ak4613_formats {
unsigned int width;
unsigned int fmt;
@@ -365,8 +371,8 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl);
snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2);
- snd_soc_write(codec, ICTRL, priv->ic);
- snd_soc_write(codec, OCTRL, priv->oc);
+ snd_soc_update_bits(codec, ICTRL, ICTRL_MASK, priv->ic);
+ snd_soc_update_bits(codec, OCTRL, OCTRL_MASK, priv->oc);
hw_params_end:
if (ret < 0)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 2609f95b7d19..23ab9646c351 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -189,7 +189,7 @@ static int ak4642_lout_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
case SND_SOC_DAPM_POST_PMD:
/* Power save mode OFF */
- mdelay(300);
+ msleep(300);
snd_soc_update_bits(codec, SG_SL2, LOPS, 0);
break;
}
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h
index 56707860657c..1822e3b3de80 100644
--- a/sound/soc/codecs/arizona.h
+++ b/sound/soc/codecs/arizona.h
@@ -192,6 +192,7 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
#define ARIZONA_DSP_ROUTES(name) \
{ name, NULL, name " Preloader"}, \
{ name " Preloader", NULL, "SYSCLK" }, \
+ { name " Preload", NULL, name " Preloader"}, \
{ name, NULL, name " Aux 1" }, \
{ name, NULL, name " Aux 2" }, \
{ name, NULL, name " Aux 3" }, \
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
new file mode 100644
index 000000000000..f8aef5869b03
--- /dev/null
+++ b/sound/soc/codecs/cs35l35.c
@@ -0,0 +1,1580 @@
+/*
+ * cs35l35.c -- CS35L35 ALSA SoC audio driver
+ *
+ * Copyright 2017 Cirrus Logic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs35l35.h>
+#include <linux/of_irq.h>
+#include <linux/completion.h>
+
+#include "cs35l35.h"
+
+/*
+ * Some fields take zero as a valid value so use a high bit flag that won't
+ * get written to the device to mark those.
+ */
+#define CS35L35_VALID_PDATA 0x80000000
+
+static const struct reg_default cs35l35_reg[] = {
+ {CS35L35_PWRCTL1, 0x01},
+ {CS35L35_PWRCTL2, 0x11},
+ {CS35L35_PWRCTL3, 0x00},
+ {CS35L35_CLK_CTL1, 0x04},
+ {CS35L35_CLK_CTL2, 0x12},
+ {CS35L35_CLK_CTL3, 0xCF},
+ {CS35L35_SP_FMT_CTL1, 0x20},
+ {CS35L35_SP_FMT_CTL2, 0x00},
+ {CS35L35_SP_FMT_CTL3, 0x02},
+ {CS35L35_MAG_COMP_CTL, 0x00},
+ {CS35L35_AMP_INP_DRV_CTL, 0x01},
+ {CS35L35_AMP_DIG_VOL_CTL, 0x12},
+ {CS35L35_AMP_DIG_VOL, 0x00},
+ {CS35L35_ADV_DIG_VOL, 0x00},
+ {CS35L35_PROTECT_CTL, 0x06},
+ {CS35L35_AMP_GAIN_AUD_CTL, 0x13},
+ {CS35L35_AMP_GAIN_PDM_CTL, 0x00},
+ {CS35L35_AMP_GAIN_ADV_CTL, 0x00},
+ {CS35L35_GPI_CTL, 0x00},
+ {CS35L35_BST_CVTR_V_CTL, 0x00},
+ {CS35L35_BST_PEAK_I, 0x07},
+ {CS35L35_BST_RAMP_CTL, 0x85},
+ {CS35L35_BST_CONV_COEF_1, 0x24},
+ {CS35L35_BST_CONV_COEF_2, 0x24},
+ {CS35L35_BST_CONV_SLOPE_COMP, 0x4E},
+ {CS35L35_BST_CONV_SW_FREQ, 0x04},
+ {CS35L35_CLASS_H_CTL, 0x0B},
+ {CS35L35_CLASS_H_HEADRM_CTL, 0x0B},
+ {CS35L35_CLASS_H_RELEASE_RATE, 0x08},
+ {CS35L35_CLASS_H_FET_DRIVE_CTL, 0x41},
+ {CS35L35_CLASS_H_VP_CTL, 0xC5},
+ {CS35L35_VPBR_CTL, 0x0A},
+ {CS35L35_VPBR_VOL_CTL, 0x90},
+ {CS35L35_VPBR_TIMING_CTL, 0x6A},
+ {CS35L35_VPBR_MODE_VOL_CTL, 0x00},
+ {CS35L35_SPKR_MON_CTL, 0xC0},
+ {CS35L35_IMON_SCALE_CTL, 0x30},
+ {CS35L35_AUDIN_RXLOC_CTL, 0x00},
+ {CS35L35_ADVIN_RXLOC_CTL, 0x80},
+ {CS35L35_VMON_TXLOC_CTL, 0x00},
+ {CS35L35_IMON_TXLOC_CTL, 0x80},
+ {CS35L35_VPMON_TXLOC_CTL, 0x04},
+ {CS35L35_VBSTMON_TXLOC_CTL, 0x84},
+ {CS35L35_VPBR_STATUS_TXLOC_CTL, 0x04},
+ {CS35L35_ZERO_FILL_LOC_CTL, 0x00},
+ {CS35L35_AUDIN_DEPTH_CTL, 0x0F},
+ {CS35L35_SPKMON_DEPTH_CTL, 0x0F},
+ {CS35L35_SUPMON_DEPTH_CTL, 0x0F},
+ {CS35L35_ZEROFILL_DEPTH_CTL, 0x00},
+ {CS35L35_MULT_DEV_SYNCH1, 0x02},
+ {CS35L35_MULT_DEV_SYNCH2, 0x80},
+ {CS35L35_PROT_RELEASE_CTL, 0x00},
+ {CS35L35_DIAG_MODE_REG_LOCK, 0x00},
+ {CS35L35_DIAG_MODE_CTL_1, 0x40},
+ {CS35L35_DIAG_MODE_CTL_2, 0x00},
+ {CS35L35_INT_MASK_1, 0xFF},
+ {CS35L35_INT_MASK_2, 0xFF},
+ {CS35L35_INT_MASK_3, 0xFF},
+ {CS35L35_INT_MASK_4, 0xFF},
+
+};
+
+static bool cs35l35_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L35_INT_STATUS_1:
+ case CS35L35_INT_STATUS_2:
+ case CS35L35_INT_STATUS_3:
+ case CS35L35_INT_STATUS_4:
+ case CS35L35_PLL_STATUS:
+ case CS35L35_OTP_TRIM_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs35l35_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L35_DEVID_AB ... CS35L35_PWRCTL3:
+ case CS35L35_CLK_CTL1 ... CS35L35_SP_FMT_CTL3:
+ case CS35L35_MAG_COMP_CTL ... CS35L35_AMP_GAIN_AUD_CTL:
+ case CS35L35_AMP_GAIN_PDM_CTL ... CS35L35_BST_PEAK_I:
+ case CS35L35_BST_RAMP_CTL ... CS35L35_BST_CONV_SW_FREQ:
+ case CS35L35_CLASS_H_CTL ... CS35L35_CLASS_H_VP_CTL:
+ case CS35L35_CLASS_H_STATUS:
+ case CS35L35_VPBR_CTL ... CS35L35_VPBR_MODE_VOL_CTL:
+ case CS35L35_VPBR_ATTEN_STATUS:
+ case CS35L35_SPKR_MON_CTL:
+ case CS35L35_IMON_SCALE_CTL ... CS35L35_ZEROFILL_DEPTH_CTL:
+ case CS35L35_MULT_DEV_SYNCH1 ... CS35L35_PROT_RELEASE_CTL:
+ case CS35L35_DIAG_MODE_REG_LOCK ... CS35L35_DIAG_MODE_CTL_2:
+ case CS35L35_INT_MASK_1 ... CS35L35_PLL_STATUS:
+ case CS35L35_OTP_TRIM_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs35l35_precious_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS35L35_INT_STATUS_1:
+ case CS35L35_INT_STATUS_2:
+ case CS35L35_INT_STATUS_3:
+ case CS35L35_INT_STATUS_4:
+ case CS35L35_PLL_STATUS:
+ case CS35L35_OTP_TRIM_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int cs35l35_wait_for_pdn(struct cs35l35_private *cs35l35)
+{
+ int ret;
+
+ if (cs35l35->pdata.ext_bst) {
+ usleep_range(5000, 5500);
+ return 0;
+ }
+
+ reinit_completion(&cs35l35->pdn_done);
+
+ ret = wait_for_completion_timeout(&cs35l35->pdn_done,
+ msecs_to_jiffies(100));
+ if (ret == 0) {
+ dev_err(cs35l35->dev, "PDN_DONE did not complete\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int cs35l35_sdin_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+ CS35L35_MCLK_DIS_MASK,
+ 0 << CS35L35_MCLK_DIS_SHIFT);
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+ CS35L35_DISCHG_FILT_MASK,
+ 0 << CS35L35_DISCHG_FILT_SHIFT);
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+ CS35L35_PDN_ALL_MASK, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+ CS35L35_DISCHG_FILT_MASK,
+ 1 << CS35L35_DISCHG_FILT_SHIFT);
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+ CS35L35_PDN_ALL_MASK, 1);
+
+ /* Already muted, so disable volume ramp for faster shutdown */
+ regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
+ CS35L35_AMP_DIGSFT_MASK, 0);
+
+ ret = cs35l35_wait_for_pdn(cs35l35);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+ CS35L35_MCLK_DIS_MASK,
+ 1 << CS35L35_MCLK_DIS_SHIFT);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_AMP_DIG_VOL_CTL,
+ CS35L35_AMP_DIGSFT_MASK,
+ 1 << CS35L35_AMP_DIGSFT_SHIFT);
+ break;
+ default:
+ dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int cs35l35_main_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+ unsigned int reg[4];
+ int i;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (cs35l35->pdata.bst_pdn_fet_on)
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_BST_MASK,
+ 0 << CS35L35_PDN_BST_FETON_SHIFT);
+ else
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_BST_MASK,
+ 0 << CS35L35_PDN_BST_FETOFF_SHIFT);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(5000, 5100);
+ /* If in PDM mode we must use VP for Voltage control */
+ if (cs35l35->pdm_mode)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_BST_CVTR_V_CTL,
+ CS35L35_BST_CTL_MASK,
+ 0 << CS35L35_BST_CTL_SHIFT);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+ CS35L35_AMP_MUTE_MASK, 0);
+
+ for (i = 0; i < 2; i++)
+ regmap_bulk_read(cs35l35->regmap, CS35L35_INT_STATUS_1,
+ &reg, ARRAY_SIZE(reg));
+
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+ CS35L35_AMP_MUTE_MASK,
+ 1 << CS35L35_AMP_MUTE_SHIFT);
+ if (cs35l35->pdata.bst_pdn_fet_on)
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_BST_MASK,
+ 1 << CS35L35_PDN_BST_FETON_SHIFT);
+ else
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_BST_MASK,
+ 1 << CS35L35_PDN_BST_FETOFF_SHIFT);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(5000, 5100);
+ /*
+ * If PDM mode we should switch back to pdata value
+ * for Voltage control when we go down
+ */
+ if (cs35l35->pdm_mode)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_BST_CVTR_V_CTL,
+ CS35L35_BST_CTL_MASK,
+ cs35l35->pdata.bst_vctl
+ << CS35L35_BST_CTL_SHIFT);
+
+ break;
+ default:
+ dev_err(codec->dev, "Invalid event = 0x%x\n", event);
+ }
+ return 0;
+}
+
+static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1);
+static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0);
+
+static const struct snd_kcontrol_new cs35l35_aud_controls[] = {
+ SOC_SINGLE_SX_TLV("Digital Audio Volume", CS35L35_AMP_DIG_VOL,
+ 0, 0x34, 0xE4, dig_vol_tlv),
+ SOC_SINGLE_TLV("Analog Audio Volume", CS35L35_AMP_GAIN_AUD_CTL, 0, 19, 0,
+ amp_gain_tlv),
+ SOC_SINGLE_TLV("PDM Volume", CS35L35_AMP_GAIN_PDM_CTL, 0, 19, 0,
+ amp_gain_tlv),
+};
+
+static const struct snd_kcontrol_new cs35l35_adv_controls[] = {
+ SOC_SINGLE_SX_TLV("Digital Advisory Volume", CS35L35_ADV_DIG_VOL,
+ 0, 0x34, 0xE4, dig_vol_tlv),
+ SOC_SINGLE_TLV("Analog Advisory Volume", CS35L35_AMP_GAIN_ADV_CTL, 0, 19, 0,
+ amp_gain_tlv),
+};
+
+static const struct snd_soc_dapm_widget cs35l35_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L35_PWRCTL3, 1, 1,
+ cs35l35_sdin_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L35_PWRCTL3, 2, 1),
+
+ SND_SOC_DAPM_OUTPUT("SPK"),
+
+ SND_SOC_DAPM_INPUT("VP"),
+ SND_SOC_DAPM_INPUT("VBST"),
+ SND_SOC_DAPM_INPUT("ISENSE"),
+ SND_SOC_DAPM_INPUT("VSENSE"),
+
+ SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L35_PWRCTL2, 7, 1),
+ SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L35_PWRCTL2, 6, 1),
+ SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L35_PWRCTL3, 3, 1),
+ SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L35_PWRCTL3, 4, 1),
+ SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L35_PWRCTL2, 5, 1),
+
+ SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L35_PWRCTL2, 0, 1, NULL, 0,
+ cs35l35_main_amp_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+};
+
+static const struct snd_soc_dapm_route cs35l35_audio_map[] = {
+ {"VPMON ADC", NULL, "VP"},
+ {"VBSTMON ADC", NULL, "VBST"},
+ {"IMON ADC", NULL, "ISENSE"},
+ {"VMON ADC", NULL, "VSENSE"},
+ {"SDOUT", NULL, "IMON ADC"},
+ {"SDOUT", NULL, "VMON ADC"},
+ {"SDOUT", NULL, "VBSTMON ADC"},
+ {"SDOUT", NULL, "VPMON ADC"},
+ {"AMP Capture", NULL, "SDOUT"},
+
+ {"SDIN", NULL, "AMP Playback"},
+ {"CLASS H", NULL, "SDIN"},
+ {"Main AMP", NULL, "CLASS H"},
+ {"SPK", NULL, "Main AMP"},
+};
+
+static int cs35l35_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+ CS35L35_MS_MASK, 1 << CS35L35_MS_SHIFT);
+ cs35l35->slave_mode = false;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+ CS35L35_MS_MASK, 0 << CS35L35_MS_SHIFT);
+ cs35l35->slave_mode = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ cs35l35->i2s_mode = true;
+ cs35l35->pdm_mode = false;
+ break;
+ case SND_SOC_DAIFMT_PDM:
+ cs35l35->pdm_mode = true;
+ cs35l35->i2s_mode = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct cs35l35_sysclk_config {
+ int sysclk;
+ int srate;
+ u8 clk_cfg;
+};
+
+static struct cs35l35_sysclk_config cs35l35_clk_ctl[] = {
+
+ /* SYSCLK, Sample Rate, Serial Port Cfg */
+ {5644800, 44100, 0x00},
+ {5644800, 88200, 0x40},
+ {6144000, 48000, 0x10},
+ {6144000, 96000, 0x50},
+ {11289600, 44100, 0x01},
+ {11289600, 88200, 0x41},
+ {11289600, 176400, 0x81},
+ {12000000, 44100, 0x03},
+ {12000000, 48000, 0x13},
+ {12000000, 88200, 0x43},
+ {12000000, 96000, 0x53},
+ {12000000, 176400, 0x83},
+ {12000000, 192000, 0x93},
+ {12288000, 48000, 0x11},
+ {12288000, 96000, 0x51},
+ {12288000, 192000, 0x91},
+ {13000000, 44100, 0x07},
+ {13000000, 48000, 0x17},
+ {13000000, 88200, 0x47},
+ {13000000, 96000, 0x57},
+ {13000000, 176400, 0x87},
+ {13000000, 192000, 0x97},
+ {22579200, 44100, 0x02},
+ {22579200, 88200, 0x42},
+ {22579200, 176400, 0x82},
+ {24000000, 44100, 0x0B},
+ {24000000, 48000, 0x1B},
+ {24000000, 88200, 0x4B},
+ {24000000, 96000, 0x5B},
+ {24000000, 176400, 0x8B},
+ {24000000, 192000, 0x9B},
+ {24576000, 48000, 0x12},
+ {24576000, 96000, 0x52},
+ {24576000, 192000, 0x92},
+ {26000000, 44100, 0x0F},
+ {26000000, 48000, 0x1F},
+ {26000000, 88200, 0x4F},
+ {26000000, 96000, 0x5F},
+ {26000000, 176400, 0x8F},
+ {26000000, 192000, 0x9F},
+};
+
+static int cs35l35_get_clk_config(int sysclk, int srate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cs35l35_clk_ctl); i++) {
+ if (cs35l35_clk_ctl[i].sysclk == sysclk &&
+ cs35l35_clk_ctl[i].srate == srate)
+ return cs35l35_clk_ctl[i].clk_cfg;
+ }
+ return -EINVAL;
+}
+
+static int cs35l35_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+ struct classh_cfg *classh = &cs35l35->pdata.classh_algo;
+ int srate = params_rate(params);
+ int ret = 0;
+ u8 sp_sclks;
+ int audin_format;
+ int errata_chk;
+
+ int clk_ctl = cs35l35_get_clk_config(cs35l35->sysclk, srate);
+
+ if (clk_ctl < 0) {
+ dev_err(codec->dev, "Invalid CLK:Rate %d:%d\n",
+ cs35l35->sysclk, srate);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL2,
+ CS35L35_CLK_CTL2_MASK, clk_ctl);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set port config %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Rev A0 Errata
+ * When configured for the weak-drive detection path (CH_WKFET_DIS = 0)
+ * the Class H algorithm does not enable weak-drive operation for
+ * nonzero values of CH_WKFET_DELAY if SP_RATE = 01 or 10
+ */
+ errata_chk = clk_ctl & CS35L35_SP_RATE_MASK;
+
+ if (classh->classh_wk_fet_disable == 0x00 &&
+ (errata_chk == 0x01 || errata_chk == 0x03)) {
+ ret = regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_FET_DRIVE_CTL,
+ CS35L35_CH_WKFET_DEL_MASK,
+ 0 << CS35L35_CH_WKFET_DEL_SHIFT);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set fet config %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ /*
+ * You can pull more Monitor data from the SDOUT pin than going to SDIN
+ * Just make sure your SCLK is fast enough to fill the frame
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ switch (params_width(params)) {
+ case 8:
+ audin_format = CS35L35_SDIN_DEPTH_8;
+ break;
+ case 16:
+ audin_format = CS35L35_SDIN_DEPTH_16;
+ break;
+ case 24:
+ audin_format = CS35L35_SDIN_DEPTH_24;
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported Width %d\n",
+ params_width(params));
+ return -EINVAL;
+ }
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_AUDIN_DEPTH_CTL,
+ CS35L35_AUDIN_DEPTH_MASK,
+ audin_format <<
+ CS35L35_AUDIN_DEPTH_SHIFT);
+ if (cs35l35->pdata.stereo) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_AUDIN_DEPTH_CTL,
+ CS35L35_ADVIN_DEPTH_MASK,
+ audin_format <<
+ CS35L35_ADVIN_DEPTH_SHIFT);
+ }
+ }
+
+ if (cs35l35->i2s_mode) {
+ /* We have to take the SCLK to derive num sclks
+ * to configure the CLOCK_CTL3 register correctly
+ */
+ if ((cs35l35->sclk / srate) % 4) {
+ dev_err(codec->dev, "Unsupported sclk/fs ratio %d:%d\n",
+ cs35l35->sclk, srate);
+ return -EINVAL;
+ }
+ sp_sclks = ((cs35l35->sclk / srate) / 4) - 1;
+
+ /* Only certain ratios are supported in I2S Slave Mode */
+ if (cs35l35->slave_mode) {
+ switch (sp_sclks) {
+ case CS35L35_SP_SCLKS_32FS:
+ case CS35L35_SP_SCLKS_48FS:
+ case CS35L35_SP_SCLKS_64FS:
+ break;
+ default:
+ dev_err(codec->dev, "ratio not supported\n");
+ return -EINVAL;
+ }
+ } else {
+ /* Only certain ratios supported in I2S MASTER Mode */
+ switch (sp_sclks) {
+ case CS35L35_SP_SCLKS_32FS:
+ case CS35L35_SP_SCLKS_64FS:
+ break;
+ default:
+ dev_err(codec->dev, "ratio not supported\n");
+ return -EINVAL;
+ }
+ }
+ ret = regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLK_CTL3,
+ CS35L35_SP_SCLKS_MASK, sp_sclks <<
+ CS35L35_SP_SCLKS_SHIFT);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set fsclk %d\n", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static const unsigned int cs35l35_src_rates[] = {
+ 44100, 48000, 88200, 96000, 176400, 192000
+};
+
+static const struct snd_pcm_hw_constraint_list cs35l35_constraints = {
+ .count = ARRAY_SIZE(cs35l35_src_rates),
+ .list = cs35l35_src_rates,
+};
+
+static int cs35l35_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+ if (!substream->runtime)
+ return 0;
+
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &cs35l35_constraints);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL,
+ CS35L35_PDM_MODE_MASK,
+ 0 << CS35L35_PDM_MODE_SHIFT);
+
+ return 0;
+}
+
+static const unsigned int cs35l35_pdm_rates[] = {
+ 44100, 48000, 88200, 96000
+};
+
+static const struct snd_pcm_hw_constraint_list cs35l35_pdm_constraints = {
+ .count = ARRAY_SIZE(cs35l35_pdm_rates),
+ .list = cs35l35_pdm_rates,
+};
+
+static int cs35l35_pdm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+ if (!substream->runtime)
+ return 0;
+
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &cs35l35_pdm_constraints);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_AMP_INP_DRV_CTL,
+ CS35L35_PDM_MODE_MASK,
+ 1 << CS35L35_PDM_MODE_SHIFT);
+
+ return 0;
+}
+
+static int cs35l35_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+
+ /* Need the SCLK Frequency regardless of sysclk source for I2S */
+ cs35l35->sclk = freq;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops cs35l35_ops = {
+ .startup = cs35l35_pcm_startup,
+ .set_fmt = cs35l35_set_dai_fmt,
+ .hw_params = cs35l35_hw_params,
+ .set_sysclk = cs35l35_dai_set_sysclk,
+};
+
+static const struct snd_soc_dai_ops cs35l35_pdm_ops = {
+ .startup = cs35l35_pdm_startup,
+ .set_fmt = cs35l35_set_dai_fmt,
+ .hw_params = cs35l35_hw_params,
+};
+
+static struct snd_soc_dai_driver cs35l35_dai[] = {
+ {
+ .name = "cs35l35-pcm",
+ .id = 0,
+ .playback = {
+ .stream_name = "AMP Playback",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS35L35_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AMP Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS35L35_FORMATS,
+ },
+ .ops = &cs35l35_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "cs35l35-pdm",
+ .id = 1,
+ .playback = {
+ .stream_name = "PDM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .formats = CS35L35_FORMATS,
+ },
+ .ops = &cs35l35_pdm_ops,
+ },
+};
+
+static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source, unsigned int freq,
+ int dir)
+{
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+ int clksrc;
+ int ret = 0;
+
+ switch (clk_id) {
+ case 0:
+ clksrc = CS35L35_CLK_SOURCE_MCLK;
+ break;
+ case 1:
+ clksrc = CS35L35_CLK_SOURCE_SCLK;
+ break;
+ case 2:
+ clksrc = CS35L35_CLK_SOURCE_PDM;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid CLK Source\n");
+ return -EINVAL;
+ }
+
+ switch (freq) {
+ case 5644800:
+ case 6144000:
+ case 11289600:
+ case 12000000:
+ case 12288000:
+ case 13000000:
+ case 22579200:
+ case 24000000:
+ case 24576000:
+ case 26000000:
+ cs35l35->sysclk = freq;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid CLK Frequency Input : %d\n", freq);
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+ CS35L35_CLK_SOURCE_MASK,
+ clksrc << CS35L35_CLK_SOURCE_SHIFT);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to set sysclk %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int cs35l35_codec_probe(struct snd_soc_codec *codec)
+{
+ struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
+ struct classh_cfg *classh = &cs35l35->pdata.classh_algo;
+ struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg;
+ int ret;
+
+ /* Set Platform Data */
+ if (cs35l35->pdata.bst_vctl)
+ regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL,
+ CS35L35_BST_CTL_MASK,
+ cs35l35->pdata.bst_vctl);
+
+ if (cs35l35->pdata.bst_ipk)
+ regmap_update_bits(cs35l35->regmap, CS35L35_BST_PEAK_I,
+ CS35L35_BST_IPK_MASK,
+ cs35l35->pdata.bst_ipk <<
+ CS35L35_BST_IPK_SHIFT);
+
+ if (cs35l35->pdata.gain_zc)
+ regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+ CS35L35_AMP_GAIN_ZC_MASK,
+ cs35l35->pdata.gain_zc <<
+ CS35L35_AMP_GAIN_ZC_SHIFT);
+
+ if (cs35l35->pdata.aud_channel)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_AUDIN_RXLOC_CTL,
+ CS35L35_AUD_IN_LR_MASK,
+ cs35l35->pdata.aud_channel <<
+ CS35L35_AUD_IN_LR_SHIFT);
+
+ if (cs35l35->pdata.stereo) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_ADVIN_RXLOC_CTL,
+ CS35L35_ADV_IN_LR_MASK,
+ cs35l35->pdata.adv_channel <<
+ CS35L35_ADV_IN_LR_SHIFT);
+ if (cs35l35->pdata.shared_bst)
+ regmap_update_bits(cs35l35->regmap, CS35L35_CLASS_H_CTL,
+ CS35L35_CH_STEREO_MASK,
+ 1 << CS35L35_CH_STEREO_SHIFT);
+ ret = snd_soc_add_codec_controls(codec, cs35l35_adv_controls,
+ ARRAY_SIZE(cs35l35_adv_controls));
+ if (ret)
+ return ret;
+ }
+
+ if (cs35l35->pdata.sp_drv_str)
+ regmap_update_bits(cs35l35->regmap, CS35L35_CLK_CTL1,
+ CS35L35_SP_DRV_MASK,
+ cs35l35->pdata.sp_drv_str <<
+ CS35L35_SP_DRV_SHIFT);
+ if (cs35l35->pdata.sp_drv_unused)
+ regmap_update_bits(cs35l35->regmap, CS35L35_SP_FMT_CTL3,
+ CS35L35_SP_I2S_DRV_MASK,
+ cs35l35->pdata.sp_drv_unused <<
+ CS35L35_SP_I2S_DRV_SHIFT);
+
+ if (classh->classh_algo_enable) {
+ if (classh->classh_bst_override)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_CTL,
+ CS35L35_CH_BST_OVR_MASK,
+ classh->classh_bst_override <<
+ CS35L35_CH_BST_OVR_SHIFT);
+ if (classh->classh_bst_max_limit)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_CTL,
+ CS35L35_CH_BST_LIM_MASK,
+ classh->classh_bst_max_limit <<
+ CS35L35_CH_BST_LIM_SHIFT);
+ if (classh->classh_mem_depth)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_CTL,
+ CS35L35_CH_MEM_DEPTH_MASK,
+ classh->classh_mem_depth <<
+ CS35L35_CH_MEM_DEPTH_SHIFT);
+ if (classh->classh_headroom)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_HEADRM_CTL,
+ CS35L35_CH_HDRM_CTL_MASK,
+ classh->classh_headroom <<
+ CS35L35_CH_HDRM_CTL_SHIFT);
+ if (classh->classh_release_rate)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_RELEASE_RATE,
+ CS35L35_CH_REL_RATE_MASK,
+ classh->classh_release_rate <<
+ CS35L35_CH_REL_RATE_SHIFT);
+ if (classh->classh_wk_fet_disable)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_FET_DRIVE_CTL,
+ CS35L35_CH_WKFET_DIS_MASK,
+ classh->classh_wk_fet_disable <<
+ CS35L35_CH_WKFET_DIS_SHIFT);
+ if (classh->classh_wk_fet_delay)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_FET_DRIVE_CTL,
+ CS35L35_CH_WKFET_DEL_MASK,
+ classh->classh_wk_fet_delay <<
+ CS35L35_CH_WKFET_DEL_SHIFT);
+ if (classh->classh_wk_fet_thld)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_FET_DRIVE_CTL,
+ CS35L35_CH_WKFET_THLD_MASK,
+ classh->classh_wk_fet_thld <<
+ CS35L35_CH_WKFET_THLD_SHIFT);
+ if (classh->classh_vpch_auto)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_VP_CTL,
+ CS35L35_CH_VP_AUTO_MASK,
+ classh->classh_vpch_auto <<
+ CS35L35_CH_VP_AUTO_SHIFT);
+ if (classh->classh_vpch_rate)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_VP_CTL,
+ CS35L35_CH_VP_RATE_MASK,
+ classh->classh_vpch_rate <<
+ CS35L35_CH_VP_RATE_SHIFT);
+ if (classh->classh_vpch_man)
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_CLASS_H_VP_CTL,
+ CS35L35_CH_VP_MAN_MASK,
+ classh->classh_vpch_man <<
+ CS35L35_CH_VP_MAN_SHIFT);
+ }
+
+ if (monitor_config->is_present) {
+ if (monitor_config->vmon_specs) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_SPKMON_DEPTH_CTL,
+ CS35L35_VMON_DEPTH_MASK,
+ monitor_config->vmon_dpth <<
+ CS35L35_VMON_DEPTH_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VMON_TXLOC_CTL,
+ CS35L35_MON_TXLOC_MASK,
+ monitor_config->vmon_loc <<
+ CS35L35_MON_TXLOC_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VMON_TXLOC_CTL,
+ CS35L35_MON_FRM_MASK,
+ monitor_config->vmon_frm <<
+ CS35L35_MON_FRM_SHIFT);
+ }
+ if (monitor_config->imon_specs) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_SPKMON_DEPTH_CTL,
+ CS35L35_IMON_DEPTH_MASK,
+ monitor_config->imon_dpth <<
+ CS35L35_IMON_DEPTH_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_IMON_TXLOC_CTL,
+ CS35L35_MON_TXLOC_MASK,
+ monitor_config->imon_loc <<
+ CS35L35_MON_TXLOC_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_IMON_TXLOC_CTL,
+ CS35L35_MON_FRM_MASK,
+ monitor_config->imon_frm <<
+ CS35L35_MON_FRM_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_IMON_SCALE_CTL,
+ CS35L35_IMON_SCALE_MASK,
+ monitor_config->imon_scale <<
+ CS35L35_IMON_SCALE_SHIFT);
+ }
+ if (monitor_config->vpmon_specs) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_SUPMON_DEPTH_CTL,
+ CS35L35_VPMON_DEPTH_MASK,
+ monitor_config->vpmon_dpth <<
+ CS35L35_VPMON_DEPTH_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VPMON_TXLOC_CTL,
+ CS35L35_MON_TXLOC_MASK,
+ monitor_config->vpmon_loc <<
+ CS35L35_MON_TXLOC_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VPMON_TXLOC_CTL,
+ CS35L35_MON_FRM_MASK,
+ monitor_config->vpmon_frm <<
+ CS35L35_MON_FRM_SHIFT);
+ }
+ if (monitor_config->vbstmon_specs) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_SUPMON_DEPTH_CTL,
+ CS35L35_VBSTMON_DEPTH_MASK,
+ monitor_config->vpmon_dpth <<
+ CS35L35_VBSTMON_DEPTH_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VBSTMON_TXLOC_CTL,
+ CS35L35_MON_TXLOC_MASK,
+ monitor_config->vbstmon_loc <<
+ CS35L35_MON_TXLOC_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VBSTMON_TXLOC_CTL,
+ CS35L35_MON_FRM_MASK,
+ monitor_config->vbstmon_frm <<
+ CS35L35_MON_FRM_SHIFT);
+ }
+ if (monitor_config->vpbrstat_specs) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_SUPMON_DEPTH_CTL,
+ CS35L35_VPBRSTAT_DEPTH_MASK,
+ monitor_config->vpbrstat_dpth <<
+ CS35L35_VPBRSTAT_DEPTH_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VPBR_STATUS_TXLOC_CTL,
+ CS35L35_MON_TXLOC_MASK,
+ monitor_config->vpbrstat_loc <<
+ CS35L35_MON_TXLOC_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_VPBR_STATUS_TXLOC_CTL,
+ CS35L35_MON_FRM_MASK,
+ monitor_config->vpbrstat_frm <<
+ CS35L35_MON_FRM_SHIFT);
+ }
+ if (monitor_config->zerofill_specs) {
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_SUPMON_DEPTH_CTL,
+ CS35L35_ZEROFILL_DEPTH_MASK,
+ monitor_config->zerofill_dpth <<
+ CS35L35_ZEROFILL_DEPTH_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_ZERO_FILL_LOC_CTL,
+ CS35L35_MON_TXLOC_MASK,
+ monitor_config->zerofill_loc <<
+ CS35L35_MON_TXLOC_SHIFT);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_ZERO_FILL_LOC_CTL,
+ CS35L35_MON_FRM_MASK,
+ monitor_config->zerofill_frm <<
+ CS35L35_MON_FRM_SHIFT);
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs35l35 = {
+ .probe = cs35l35_codec_probe,
+ .set_sysclk = cs35l35_codec_set_sysclk,
+ .component_driver = {
+ .dapm_widgets = cs35l35_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs35l35_dapm_widgets),
+
+ .dapm_routes = cs35l35_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs35l35_audio_map),
+
+ .controls = cs35l35_aud_controls,
+ .num_controls = ARRAY_SIZE(cs35l35_aud_controls),
+ },
+
+};
+
+static struct regmap_config cs35l35_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS35L35_MAX_REGISTER,
+ .reg_defaults = cs35l35_reg,
+ .num_reg_defaults = ARRAY_SIZE(cs35l35_reg),
+ .volatile_reg = cs35l35_volatile_register,
+ .readable_reg = cs35l35_readable_register,
+ .precious_reg = cs35l35_precious_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static irqreturn_t cs35l35_irq(int irq, void *data)
+{
+ struct cs35l35_private *cs35l35 = data;
+ unsigned int sticky1, sticky2, sticky3, sticky4;
+ unsigned int mask1, mask2, mask3, mask4, current1;
+
+ /* ack the irq by reading all status registers */
+ regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_4, &sticky4);
+ regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_3, &sticky3);
+ regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_2, &sticky2);
+ regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &sticky1);
+
+ regmap_read(cs35l35->regmap, CS35L35_INT_MASK_4, &mask4);
+ regmap_read(cs35l35->regmap, CS35L35_INT_MASK_3, &mask3);
+ regmap_read(cs35l35->regmap, CS35L35_INT_MASK_2, &mask2);
+ regmap_read(cs35l35->regmap, CS35L35_INT_MASK_1, &mask1);
+
+ /* Check to see if unmasked bits are active */
+ if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3)
+ && !(sticky4 & ~mask4))
+ return IRQ_NONE;
+
+ if (sticky2 & CS35L35_PDN_DONE)
+ complete(&cs35l35->pdn_done);
+
+ /* read the current values */
+ regmap_read(cs35l35->regmap, CS35L35_INT_STATUS_1, &current1);
+
+ /* handle the interrupts */
+ if (sticky1 & CS35L35_CAL_ERR) {
+ dev_crit(cs35l35->dev, "Calibration Error\n");
+
+ /* error is no longer asserted; safe to reset */
+ if (!(current1 & CS35L35_CAL_ERR)) {
+ pr_debug("%s : Cal error release\n", __func__);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_CAL_ERR_RLS, 0);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_CAL_ERR_RLS,
+ CS35L35_CAL_ERR_RLS);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_CAL_ERR_RLS, 0);
+ }
+ }
+
+ if (sticky1 & CS35L35_AMP_SHORT) {
+ dev_crit(cs35l35->dev, "AMP Short Error\n");
+ /* error is no longer asserted; safe to reset */
+ if (!(current1 & CS35L35_AMP_SHORT)) {
+ dev_dbg(cs35l35->dev, "Amp short error release\n");
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_SHORT_RLS, 0);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_SHORT_RLS,
+ CS35L35_SHORT_RLS);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_SHORT_RLS, 0);
+ }
+ }
+
+ if (sticky1 & CS35L35_OTW) {
+ dev_warn(cs35l35->dev, "Over temperature warning\n");
+
+ /* error is no longer asserted; safe to reset */
+ if (!(current1 & CS35L35_OTW)) {
+ dev_dbg(cs35l35->dev, "Over temperature warn release\n");
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_OTW_RLS, 0);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_OTW_RLS,
+ CS35L35_OTW_RLS);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_OTW_RLS, 0);
+ }
+ }
+
+ if (sticky1 & CS35L35_OTE) {
+ dev_crit(cs35l35->dev, "Over temperature error\n");
+ /* error is no longer asserted; safe to reset */
+ if (!(current1 & CS35L35_OTE)) {
+ dev_dbg(cs35l35->dev, "Over temperature error release\n");
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_OTE_RLS, 0);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_OTE_RLS,
+ CS35L35_OTE_RLS);
+ regmap_update_bits(cs35l35->regmap,
+ CS35L35_PROT_RELEASE_CTL,
+ CS35L35_OTE_RLS, 0);
+ }
+ }
+
+ if (sticky3 & CS35L35_BST_HIGH) {
+ dev_crit(cs35l35->dev, "VBST error: powering off!\n");
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_AMP, CS35L35_PDN_AMP);
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+ CS35L35_PDN_ALL, CS35L35_PDN_ALL);
+ }
+
+ if (sticky3 & CS35L35_LBST_SHORT) {
+ dev_crit(cs35l35->dev, "LBST error: powering off!\n");
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_AMP, CS35L35_PDN_AMP);
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
+ CS35L35_PDN_ALL, CS35L35_PDN_ALL);
+ }
+
+ if (sticky2 & CS35L35_VPBR_ERR)
+ dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n");
+
+ if (sticky4 & CS35L35_VMON_OVFL)
+ dev_dbg(cs35l35->dev, "Error: VMON overflow\n");
+
+ if (sticky4 & CS35L35_IMON_OVFL)
+ dev_dbg(cs35l35->dev, "Error: IMON overflow\n");
+
+ return IRQ_HANDLED;
+}
+
+
+static int cs35l35_handle_of_data(struct i2c_client *i2c_client,
+ struct cs35l35_platform_data *pdata)
+{
+ struct device_node *np = i2c_client->dev.of_node;
+ struct device_node *classh, *signal_format;
+ struct classh_cfg *classh_config = &pdata->classh_algo;
+ struct monitor_cfg *monitor_config = &pdata->mon_cfg;
+ unsigned int val32 = 0;
+ u8 monitor_array[4];
+ const int imon_array_size = ARRAY_SIZE(monitor_array);
+ const int mon_array_size = imon_array_size - 1;
+ int ret = 0;
+
+ if (!np)
+ return 0;
+
+ pdata->bst_pdn_fet_on = of_property_read_bool(np,
+ "cirrus,boost-pdn-fet-on");
+
+ ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val32);
+ if (ret >= 0) {
+ if (val32 < 2600 || val32 > 9000) {
+ dev_err(&i2c_client->dev,
+ "Invalid Boost Voltage %d mV\n", val32);
+ return -EINVAL;
+ }
+ pdata->bst_vctl = ((val32 - 2600) / 100) + 1;
+ }
+
+ ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val32);
+ if (ret >= 0) {
+ if (val32 < 1680 || val32 > 4480) {
+ dev_err(&i2c_client->dev,
+ "Invalid Boost Peak Current %u mA\n", val32);
+ return -EINVAL;
+ }
+
+ pdata->bst_ipk = (val32 - 1680) / 110;
+ }
+
+ if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0)
+ pdata->sp_drv_str = val32;
+ if (of_property_read_u32(np, "cirrus,sp-drv-unused", &val32) >= 0)
+ pdata->sp_drv_unused = val32 | CS35L35_VALID_PDATA;
+
+ pdata->stereo = of_property_read_bool(np, "cirrus,stereo-config");
+
+ if (pdata->stereo) {
+ ret = of_property_read_u32(np, "cirrus,audio-channel", &val32);
+ if (ret >= 0)
+ pdata->aud_channel = val32;
+
+ ret = of_property_read_u32(np, "cirrus,advisory-channel",
+ &val32);
+ if (ret >= 0)
+ pdata->adv_channel = val32;
+
+ pdata->shared_bst = of_property_read_bool(np,
+ "cirrus,shared-boost");
+ }
+
+ pdata->ext_bst = of_property_read_bool(np, "cirrus,external-boost");
+
+ pdata->gain_zc = of_property_read_bool(np, "cirrus,amp-gain-zc");
+
+ classh = of_get_child_by_name(np, "cirrus,classh-internal-algo");
+ classh_config->classh_algo_enable = classh ? true : false;
+
+ if (classh_config->classh_algo_enable) {
+ classh_config->classh_bst_override =
+ of_property_read_bool(np, "cirrus,classh-bst-overide");
+
+ ret = of_property_read_u32(classh,
+ "cirrus,classh-bst-max-limit",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_bst_max_limit = val32;
+ }
+
+ ret = of_property_read_u32(classh,
+ "cirrus,classh-bst-max-limit",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_bst_max_limit = val32;
+ }
+
+ ret = of_property_read_u32(classh, "cirrus,classh-mem-depth",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_mem_depth = val32;
+ }
+
+ ret = of_property_read_u32(classh, "cirrus,classh-release-rate",
+ &val32);
+ if (ret >= 0)
+ classh_config->classh_release_rate = val32;
+
+ ret = of_property_read_u32(classh, "cirrus,classh-headroom",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_headroom = val32;
+ }
+
+ ret = of_property_read_u32(classh,
+ "cirrus,classh-wk-fet-disable",
+ &val32);
+ if (ret >= 0)
+ classh_config->classh_wk_fet_disable = val32;
+
+ ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-delay",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_wk_fet_delay = val32;
+ }
+
+ ret = of_property_read_u32(classh, "cirrus,classh-wk-fet-thld",
+ &val32);
+ if (ret >= 0)
+ classh_config->classh_wk_fet_thld = val32;
+
+ ret = of_property_read_u32(classh, "cirrus,classh-vpch-auto",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_vpch_auto = val32;
+ }
+
+ ret = of_property_read_u32(classh, "cirrus,classh-vpch-rate",
+ &val32);
+ if (ret >= 0) {
+ val32 |= CS35L35_VALID_PDATA;
+ classh_config->classh_vpch_rate = val32;
+ }
+
+ ret = of_property_read_u32(classh, "cirrus,classh-vpch-man",
+ &val32);
+ if (ret >= 0)
+ classh_config->classh_vpch_man = val32;
+ }
+ of_node_put(classh);
+
+ /* frame depth location */
+ signal_format = of_get_child_by_name(np, "cirrus,monitor-signal-format");
+ monitor_config->is_present = signal_format ? true : false;
+ if (monitor_config->is_present) {
+ ret = of_property_read_u8_array(signal_format, "cirrus,imon",
+ monitor_array, imon_array_size);
+ if (!ret) {
+ monitor_config->imon_specs = true;
+ monitor_config->imon_dpth = monitor_array[0];
+ monitor_config->imon_loc = monitor_array[1];
+ monitor_config->imon_frm = monitor_array[2];
+ monitor_config->imon_scale = monitor_array[3];
+ }
+ ret = of_property_read_u8_array(signal_format, "cirrus,vmon",
+ monitor_array, mon_array_size);
+ if (!ret) {
+ monitor_config->vmon_specs = true;
+ monitor_config->vmon_dpth = monitor_array[0];
+ monitor_config->vmon_loc = monitor_array[1];
+ monitor_config->vmon_frm = monitor_array[2];
+ }
+ ret = of_property_read_u8_array(signal_format, "cirrus,vpmon",
+ monitor_array, mon_array_size);
+ if (!ret) {
+ monitor_config->vpmon_specs = true;
+ monitor_config->vpmon_dpth = monitor_array[0];
+ monitor_config->vpmon_loc = monitor_array[1];
+ monitor_config->vpmon_frm = monitor_array[2];
+ }
+ ret = of_property_read_u8_array(signal_format, "cirrus,vbstmon",
+ monitor_array, mon_array_size);
+ if (!ret) {
+ monitor_config->vbstmon_specs = true;
+ monitor_config->vbstmon_dpth = monitor_array[0];
+ monitor_config->vbstmon_loc = monitor_array[1];
+ monitor_config->vbstmon_frm = monitor_array[2];
+ }
+ ret = of_property_read_u8_array(signal_format, "cirrus,vpbrstat",
+ monitor_array, mon_array_size);
+ if (!ret) {
+ monitor_config->vpbrstat_specs = true;
+ monitor_config->vpbrstat_dpth = monitor_array[0];
+ monitor_config->vpbrstat_loc = monitor_array[1];
+ monitor_config->vpbrstat_frm = monitor_array[2];
+ }
+ ret = of_property_read_u8_array(signal_format, "cirrus,zerofill",
+ monitor_array, mon_array_size);
+ if (!ret) {
+ monitor_config->zerofill_specs = true;
+ monitor_config->zerofill_dpth = monitor_array[0];
+ monitor_config->zerofill_loc = monitor_array[1];
+ monitor_config->zerofill_frm = monitor_array[2];
+ }
+ }
+ of_node_put(signal_format);
+
+ return 0;
+}
+
+/* Errata Rev A0 */
+static const struct reg_sequence cs35l35_errata_patch[] = {
+
+ { 0x7F, 0x99 },
+ { 0x00, 0x99 },
+ { 0x52, 0x22 },
+ { 0x04, 0x14 },
+ { 0x6D, 0x44 },
+ { 0x24, 0x10 },
+ { 0x58, 0xC4 },
+ { 0x00, 0x98 },
+ { 0x18, 0x08 },
+ { 0x00, 0x00 },
+ { 0x7F, 0x00 },
+};
+
+static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs35l35_private *cs35l35;
+ struct device *dev = &i2c_client->dev;
+ struct cs35l35_platform_data *pdata = dev_get_platdata(dev);
+ int i;
+ int ret;
+ unsigned int devid = 0;
+ unsigned int reg;
+
+ cs35l35 = devm_kzalloc(dev, sizeof(struct cs35l35_private), GFP_KERNEL);
+ if (!cs35l35)
+ return -ENOMEM;
+
+ cs35l35->dev = dev;
+
+ i2c_set_clientdata(i2c_client, cs35l35);
+ cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap);
+ if (IS_ERR(cs35l35->regmap)) {
+ ret = PTR_ERR(cs35l35->regmap);
+ dev_err(dev, "regmap_init() failed: %d\n", ret);
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cs35l35_supplies); i++)
+ cs35l35->supplies[i].supply = cs35l35_supplies[i];
+
+ cs35l35->num_supplies = ARRAY_SIZE(cs35l35_supplies);
+
+ ret = devm_regulator_bulk_get(dev, cs35l35->num_supplies,
+ cs35l35->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to request core supplies: %d\n", ret);
+ return ret;
+ }
+
+ if (pdata) {
+ cs35l35->pdata = *pdata;
+ } else {
+ pdata = devm_kzalloc(dev, sizeof(struct cs35l35_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ if (i2c_client->dev.of_node) {
+ ret = cs35l35_handle_of_data(i2c_client, pdata);
+ if (ret != 0)
+ return ret;
+
+ }
+ cs35l35->pdata = *pdata;
+ }
+
+ ret = regulator_bulk_enable(cs35l35->num_supplies,
+ cs35l35->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable core supplies: %d\n", ret);
+ return ret;
+ }
+
+ /* returning NULL can be valid if in stereo mode */
+ cs35l35->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(cs35l35->reset_gpio)) {
+ ret = PTR_ERR(cs35l35->reset_gpio);
+ cs35l35->reset_gpio = NULL;
+ if (ret == -EBUSY) {
+ dev_info(dev,
+ "Reset line busy, assuming shared reset\n");
+ } else {
+ dev_err(dev, "Failed to get reset GPIO: %d\n", ret);
+ goto err;
+ }
+ }
+
+ gpiod_set_value_cansleep(cs35l35->reset_gpio, 1);
+
+ init_completion(&cs35l35->pdn_done);
+
+ ret = devm_request_threaded_irq(dev, i2c_client->irq, NULL, cs35l35_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW |
+ IRQF_SHARED, "cs35l35", cs35l35);
+ if (ret != 0) {
+ dev_err(dev, "Failed to request IRQ: %d\n", ret);
+ goto err;
+ }
+ /* initialize codec */
+ ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_AB, &reg);
+
+ devid = (reg & 0xFF) << 12;
+ ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_CD, &reg);
+ devid |= (reg & 0xFF) << 4;
+ ret = regmap_read(cs35l35->regmap, CS35L35_DEVID_E, &reg);
+ devid |= (reg & 0xF0) >> 4;
+
+ if (devid != CS35L35_CHIP_ID) {
+ dev_err(dev, "CS35L35 Device ID (%X). Expected ID %X\n",
+ devid, CS35L35_CHIP_ID);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = regmap_read(cs35l35->regmap, CS35L35_REV_ID, &reg);
+ if (ret < 0) {
+ dev_err(dev, "Get Revision ID failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_register_patch(cs35l35->regmap, cs35l35_errata_patch,
+ ARRAY_SIZE(cs35l35_errata_patch));
+ if (ret < 0) {
+ dev_err(dev, "Failed to apply errata patch: %d\n", ret);
+ goto err;
+ }
+
+ dev_info(dev, "Cirrus Logic CS35L35 (%x), Revision: %02X\n",
+ devid, reg & 0xFF);
+
+ /* Set the INT Masks for critical errors */
+ regmap_write(cs35l35->regmap, CS35L35_INT_MASK_1,
+ CS35L35_INT1_CRIT_MASK);
+ regmap_write(cs35l35->regmap, CS35L35_INT_MASK_2,
+ CS35L35_INT2_CRIT_MASK);
+ regmap_write(cs35l35->regmap, CS35L35_INT_MASK_3,
+ CS35L35_INT3_CRIT_MASK);
+ regmap_write(cs35l35->regmap, CS35L35_INT_MASK_4,
+ CS35L35_INT4_CRIT_MASK);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PWR2_PDN_MASK,
+ CS35L35_PWR2_PDN_MASK);
+
+ if (cs35l35->pdata.bst_pdn_fet_on)
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_BST_MASK,
+ 1 << CS35L35_PDN_BST_FETON_SHIFT);
+ else
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
+ CS35L35_PDN_BST_MASK,
+ 1 << CS35L35_PDN_BST_FETOFF_SHIFT);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL3,
+ CS35L35_PWR3_PDN_MASK,
+ CS35L35_PWR3_PDN_MASK);
+
+ regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
+ CS35L35_AMP_MUTE_MASK, 1 << CS35L35_AMP_MUTE_SHIFT);
+
+ ret = snd_soc_register_codec(dev, &soc_codec_dev_cs35l35, cs35l35_dai,
+ ARRAY_SIZE(cs35l35_dai));
+ if (ret < 0) {
+ dev_err(dev, "Failed to register codec: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ regulator_bulk_disable(cs35l35->num_supplies,
+ cs35l35->supplies);
+ gpiod_set_value_cansleep(cs35l35->reset_gpio, 0);
+
+ return ret;
+}
+
+static int cs35l35_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct of_device_id cs35l35_of_match[] = {
+ {.compatible = "cirrus,cs35l35"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, cs35l35_of_match);
+
+static const struct i2c_device_id cs35l35_id[] = {
+ {"cs35l35", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cs35l35_id);
+
+static struct i2c_driver cs35l35_i2c_driver = {
+ .driver = {
+ .name = "cs35l35",
+ .of_match_table = cs35l35_of_match,
+ },
+ .id_table = cs35l35_id,
+ .probe = cs35l35_i2c_probe,
+ .remove = cs35l35_i2c_remove,
+};
+
+module_i2c_driver(cs35l35_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS35L35 driver");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h
new file mode 100644
index 000000000000..5a6e43a87c4d
--- /dev/null
+++ b/sound/soc/codecs/cs35l35.h
@@ -0,0 +1,294 @@
+/*
+ * cs35l35.h -- CS35L35 ALSA SoC audio driver
+ *
+ * Copyright 2016 Cirrus Logic, Inc.
+ *
+ * Author: Brian Austin <brian.austin@cirrus.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __CS35L35_H__
+#define __CS35L35_H__
+
+#define CS35L35_FIRSTREG 0x01
+#define CS35L35_LASTREG 0x7E
+#define CS35L35_CHIP_ID 0x00035A35
+#define CS35L35_DEVID_AB 0x01 /* Device ID A & B [RO] */
+#define CS35L35_DEVID_CD 0x02 /* Device ID C & D [RO] */
+#define CS35L35_DEVID_E 0x03 /* Device ID E [RO] */
+#define CS35L35_FAB_ID 0x04 /* Fab ID [RO] */
+#define CS35L35_REV_ID 0x05 /* Revision ID [RO] */
+#define CS35L35_PWRCTL1 0x06 /* Power Ctl 1 */
+#define CS35L35_PWRCTL2 0x07 /* Power Ctl 2 */
+#define CS35L35_PWRCTL3 0x08 /* Power Ctl 3 */
+#define CS35L35_CLK_CTL1 0x0A /* Clocking Ctl 1 */
+#define CS35L35_CLK_CTL2 0x0B /* Clocking Ctl 2 */
+#define CS35L35_CLK_CTL3 0x0C /* Clocking Ctl 3 */
+#define CS35L35_SP_FMT_CTL1 0x0D /* Serial Port Format CTL1 */
+#define CS35L35_SP_FMT_CTL2 0x0E /* Serial Port Format CTL2 */
+#define CS35L35_SP_FMT_CTL3 0x0F /* Serial Port Format CTL3 */
+#define CS35L35_MAG_COMP_CTL 0x13 /* Magnitude Comp CTL */
+#define CS35L35_AMP_INP_DRV_CTL 0x14 /* Amp Input Drive Ctl */
+#define CS35L35_AMP_DIG_VOL_CTL 0x15 /* Amplifier Dig Volume Ctl */
+#define CS35L35_AMP_DIG_VOL 0x16 /* Amplifier Dig Volume */
+#define CS35L35_ADV_DIG_VOL 0x17 /* Advisory Digital Volume */
+#define CS35L35_PROTECT_CTL 0x18 /* Amp Gain - Prot Ctl Param */
+#define CS35L35_AMP_GAIN_AUD_CTL 0x19 /* Amp Serial Port Gain Ctl */
+#define CS35L35_AMP_GAIN_PDM_CTL 0x1A /* Amplifier Gain PDM Ctl */
+#define CS35L35_AMP_GAIN_ADV_CTL 0x1B /* Amplifier Gain Ctl */
+#define CS35L35_GPI_CTL 0x1C /* GPI Ctl */
+#define CS35L35_BST_CVTR_V_CTL 0x1D /* Boost Conv Voltage Ctl */
+#define CS35L35_BST_PEAK_I 0x1E /* Boost Conv Peak Current */
+#define CS35L35_BST_RAMP_CTL 0x20 /* Boost Conv Soft Ramp Ctl */
+#define CS35L35_BST_CONV_COEF_1 0x21 /* Boost Conv Coefficients 1 */
+#define CS35L35_BST_CONV_COEF_2 0x22 /* Boost Conv Coefficients 2 */
+#define CS35L35_BST_CONV_SLOPE_COMP 0x23 /* Boost Conv Slope Comp */
+#define CS35L35_BST_CONV_SW_FREQ 0x24 /* Boost Conv L BST SW Freq */
+#define CS35L35_CLASS_H_CTL 0x30 /* CLS H Control */
+#define CS35L35_CLASS_H_HEADRM_CTL 0x31 /* CLS H Headroom Ctl */
+#define CS35L35_CLASS_H_RELEASE_RATE 0x32 /* CLS H Release Rate */
+#define CS35L35_CLASS_H_FET_DRIVE_CTL 0x33 /* CLS H Weak FET Drive Ctl */
+#define CS35L35_CLASS_H_VP_CTL 0x34 /* CLS H VP Ctl */
+#define CS35L35_CLASS_H_STATUS 0x38 /* CLS H Status */
+#define CS35L35_VPBR_CTL 0x3A /* VPBR Ctl */
+#define CS35L35_VPBR_VOL_CTL 0x3B /* VPBR Volume Ctl */
+#define CS35L35_VPBR_TIMING_CTL 0x3C /* VPBR Timing Ctl */
+#define CS35L35_VPBR_MODE_VOL_CTL 0x3D /* VPBR Mode/Attack Vol Ctl */
+#define CS35L35_VPBR_ATTEN_STATUS 0x4B /* VPBR Attenuation Status */
+#define CS35L35_SPKR_MON_CTL 0x4E /* Speaker Monitoring Ctl */
+#define CS35L35_IMON_SCALE_CTL 0x51 /* IMON Scale Ctl */
+#define CS35L35_AUDIN_RXLOC_CTL 0x52 /* Audio Input RX Loc Ctl */
+#define CS35L35_ADVIN_RXLOC_CTL 0x53 /* Advisory Input RX Loc Ctl */
+#define CS35L35_VMON_TXLOC_CTL 0x54 /* VMON TX Loc Ctl */
+#define CS35L35_IMON_TXLOC_CTL 0x55 /* IMON TX Loc Ctl */
+#define CS35L35_VPMON_TXLOC_CTL 0x56 /* VPMON TX Loc Ctl */
+#define CS35L35_VBSTMON_TXLOC_CTL 0x57 /* VBSTMON TX Loc Ctl */
+#define CS35L35_VPBR_STATUS_TXLOC_CTL 0x58 /* VPBR Status TX Loc Ctl */
+#define CS35L35_ZERO_FILL_LOC_CTL 0x59 /* Zero Fill Loc Ctl */
+#define CS35L35_AUDIN_DEPTH_CTL 0x5A /* Audio Input Depth Ctl */
+#define CS35L35_SPKMON_DEPTH_CTL 0x5B /* SPK Mon Output Depth Ctl */
+#define CS35L35_SUPMON_DEPTH_CTL 0x5C /* Supply Mon Out Depth Ctl */
+#define CS35L35_ZEROFILL_DEPTH_CTL 0x5D /* Zero Fill Mon Output Ctl */
+#define CS35L35_MULT_DEV_SYNCH1 0x62 /* Multidevice Synch */
+#define CS35L35_MULT_DEV_SYNCH2 0x63 /* Multidevice Synch 2 */
+#define CS35L35_PROT_RELEASE_CTL 0x64 /* Protection Release Ctl */
+#define CS35L35_DIAG_MODE_REG_LOCK 0x68 /* Diagnostic Mode Reg Lock */
+#define CS35L35_DIAG_MODE_CTL_1 0x69 /* Diagnostic Mode Ctl 1 */
+#define CS35L35_DIAG_MODE_CTL_2 0x6A /* Diagnostic Mode Ctl 2 */
+#define CS35L35_INT_MASK_1 0x70 /* Interrupt Mask 1 */
+#define CS35L35_INT_MASK_2 0x71 /* Interrupt Mask 2 */
+#define CS35L35_INT_MASK_3 0x72 /* Interrupt Mask 3 */
+#define CS35L35_INT_MASK_4 0x73 /* Interrupt Mask 4 */
+#define CS35L35_INT_STATUS_1 0x74 /* Interrupt Status 1 */
+#define CS35L35_INT_STATUS_2 0x75 /* Interrupt Status 2 */
+#define CS35L35_INT_STATUS_3 0x76 /* Interrupt Status 3 */
+#define CS35L35_INT_STATUS_4 0x77 /* Interrupt Status 4 */
+#define CS35L35_PLL_STATUS 0x78 /* PLL Status */
+#define CS35L35_OTP_TRIM_STATUS 0x7E /* OTP Trim Status */
+
+#define CS35L35_MAX_REGISTER 0x7F
+
+/* CS35L35_PWRCTL1 */
+#define CS35L35_SFT_RST 0x80
+#define CS35L35_DISCHG_FLT 0x02
+#define CS35L35_PDN_ALL 0x01
+
+/* CS35L35_PWRCTL2 */
+#define CS35L35_PDN_VMON 0x80
+#define CS35L35_PDN_IMON 0x40
+#define CS35L35_PDN_CLASSH 0x20
+#define CS35L35_PDN_VPBR 0x10
+#define CS35L35_PDN_BST 0x04
+#define CS35L35_PDN_AMP 0x01
+
+/* CS35L35_PWRCTL3 */
+#define CS35L35_PDN_VBSTMON_OUT 0x10
+#define CS35L35_PDN_VMON_OUT 0x08
+
+#define CS35L35_AUDIN_DEPTH_MASK 0x03
+#define CS35L35_AUDIN_DEPTH_SHIFT 0
+#define CS35L35_ADVIN_DEPTH_MASK 0x0C
+#define CS35L35_ADVIN_DEPTH_SHIFT 2
+#define CS35L35_SDIN_DEPTH_8 0x01
+#define CS35L35_SDIN_DEPTH_16 0x02
+#define CS35L35_SDIN_DEPTH_24 0x03
+
+#define CS35L35_SDOUT_DEPTH_8 0x01
+#define CS35L35_SDOUT_DEPTH_12 0x02
+#define CS35L35_SDOUT_DEPTH_16 0x03
+
+#define CS35L35_AUD_IN_LR_MASK 0x80
+#define CS35L35_AUD_IN_LR_SHIFT 7
+#define CS35L35_ADV_IN_LR_MASK 0x80
+#define CS35L35_ADV_IN_LR_SHIFT 7
+#define CS35L35_AUD_IN_LOC_MASK 0x0F
+#define CS35L35_AUD_IN_LOC_SHIFT 0
+#define CS35L35_ADV_IN_LOC_MASK 0x0F
+#define CS35L35_ADV_IN_LOC_SHIFT 0
+
+#define CS35L35_IMON_DEPTH_MASK 0x03
+#define CS35L35_IMON_DEPTH_SHIFT 0
+#define CS35L35_VMON_DEPTH_MASK 0x0C
+#define CS35L35_VMON_DEPTH_SHIFT 2
+#define CS35L35_VBSTMON_DEPTH_MASK 0x03
+#define CS35L35_VBSTMON_DEPTH_SHIFT 0
+#define CS35L35_VPMON_DEPTH_MASK 0x0C
+#define CS35L35_VPMON_DEPTH_SHIFT 2
+#define CS35L35_VPBRSTAT_DEPTH_MASK 0x30
+#define CS35L35_VPBRSTAT_DEPTH_SHIFT 4
+#define CS35L35_ZEROFILL_DEPTH_MASK 0x03
+#define CS35L35_ZEROFILL_DEPTH_SHIFT 0x00
+
+#define CS35L35_MON_TXLOC_MASK 0x3F
+#define CS35L35_MON_TXLOC_SHIFT 0
+#define CS35L35_MON_FRM_MASK 0x80
+#define CS35L35_MON_FRM_SHIFT 7
+
+#define CS35L35_IMON_SCALE_MASK 0xF8
+#define CS35L35_IMON_SCALE_SHIFT 3
+
+#define CS35L35_MS_MASK 0x80
+#define CS35L35_MS_SHIFT 7
+#define CS35L35_SPMODE_MASK 0x40
+#define CS35L35_SP_DRV_MASK 0x10
+#define CS35L35_SP_DRV_SHIFT 4
+#define CS35L35_CLK_CTL2_MASK 0xFF
+#define CS35L35_PDM_MODE_MASK 0x40
+#define CS35L35_PDM_MODE_SHIFT 6
+#define CS35L35_CLK_SOURCE_MASK 0x03
+#define CS35L35_CLK_SOURCE_SHIFT 0
+#define CS35L35_CLK_SOURCE_MCLK 0
+#define CS35L35_CLK_SOURCE_SCLK 1
+#define CS35L35_CLK_SOURCE_PDM 2
+
+#define CS35L35_SP_SCLKS_MASK 0x0F
+#define CS35L35_SP_SCLKS_SHIFT 0x00
+#define CS35L35_SP_SCLKS_16FS 0x03
+#define CS35L35_SP_SCLKS_32FS 0x07
+#define CS35L35_SP_SCLKS_48FS 0x0B
+#define CS35L35_SP_SCLKS_64FS 0x0F
+#define CS35L35_SP_RATE_MASK 0xC0
+
+#define CS35L35_PDN_BST_MASK 0x06
+#define CS35L35_PDN_BST_FETON_SHIFT 1
+#define CS35L35_PDN_BST_FETOFF_SHIFT 2
+#define CS35L35_PWR2_PDN_MASK 0xE0
+#define CS35L35_PWR3_PDN_MASK 0x1E
+#define CS35L35_PDN_ALL_MASK 0x01
+#define CS35L35_DISCHG_FILT_MASK 0x02
+#define CS35L35_DISCHG_FILT_SHIFT 1
+#define CS35L35_MCLK_DIS_MASK 0x04
+#define CS35L35_MCLK_DIS_SHIFT 2
+
+#define CS35L35_BST_CTL_MASK 0x7F
+#define CS35L35_BST_CTL_SHIFT 0
+#define CS35L35_BST_IPK_MASK 0x1F
+#define CS35L35_BST_IPK_SHIFT 0
+#define CS35L35_AMP_MUTE_MASK 0x20
+#define CS35L35_AMP_MUTE_SHIFT 5
+#define CS35L35_AMP_GAIN_ZC_MASK 0x10
+#define CS35L35_AMP_GAIN_ZC_SHIFT 4
+
+#define CS35L35_AMP_DIGSFT_MASK 0x02
+#define CS35L35_AMP_DIGSFT_SHIFT 1
+
+/* CS35L35_SP_FMT_CTL3 */
+#define CS35L35_SP_I2S_DRV_MASK 0x03
+#define CS35L35_SP_I2S_DRV_SHIFT 0
+
+/* Class H Algorithm Control */
+#define CS35L35_CH_STEREO_MASK 0x40
+#define CS35L35_CH_STEREO_SHIFT 6
+#define CS35L35_CH_BST_OVR_MASK 0x04
+#define CS35L35_CH_BST_OVR_SHIFT 2
+#define CS35L35_CH_BST_LIM_MASK 0x08
+#define CS35L35_CH_BST_LIM_SHIFT 3
+#define CS35L35_CH_MEM_DEPTH_MASK 0x01
+#define CS35L35_CH_MEM_DEPTH_SHIFT 0
+#define CS35L35_CH_HDRM_CTL_MASK 0x3F
+#define CS35L35_CH_HDRM_CTL_SHIFT 0
+#define CS35L35_CH_REL_RATE_MASK 0xFF
+#define CS35L35_CH_REL_RATE_SHIFT 0
+#define CS35L35_CH_WKFET_DIS_MASK 0x80
+#define CS35L35_CH_WKFET_DIS_SHIFT 7
+#define CS35L35_CH_WKFET_DEL_MASK 0x70
+#define CS35L35_CH_WKFET_DEL_SHIFT 4
+#define CS35L35_CH_WKFET_THLD_MASK 0x0F
+#define CS35L35_CH_WKFET_THLD_SHIFT 0
+#define CS35L35_CH_VP_AUTO_MASK 0x80
+#define CS35L35_CH_VP_AUTO_SHIFT 7
+#define CS35L35_CH_VP_RATE_MASK 0x60
+#define CS35L35_CH_VP_RATE_SHIFT 5
+#define CS35L35_CH_VP_MAN_MASK 0x1F
+#define CS35L35_CH_VP_MAN_SHIFT 0
+
+/* CS35L35_PROT_RELEASE_CTL */
+#define CS35L35_CAL_ERR_RLS 0x80
+#define CS35L35_SHORT_RLS 0x04
+#define CS35L35_OTW_RLS 0x02
+#define CS35L35_OTE_RLS 0x01
+
+/* INT Mask Registers */
+#define CS35L35_INT1_CRIT_MASK 0x38
+#define CS35L35_INT2_CRIT_MASK 0xEF
+#define CS35L35_INT3_CRIT_MASK 0xEE
+#define CS35L35_INT4_CRIT_MASK 0xFF
+
+/* PDN DONE Masks */
+#define CS35L35_M_PDN_DONE_SHIFT 4
+#define CS35L35_M_PDN_DONE_MASK 0x10
+
+/* CS35L35_INT_1 */
+#define CS35L35_CAL_ERR 0x80
+#define CS35L35_OTP_ERR 0x40
+#define CS35L35_LRCLK_ERR 0x20
+#define CS35L35_SPCLK_ERR 0x10
+#define CS35L35_MCLK_ERR 0x08
+#define CS35L35_AMP_SHORT 0x04
+#define CS35L35_OTW 0x02
+#define CS35L35_OTE 0x01
+
+/* CS35L35_INT_2 */
+#define CS35L35_PDN_DONE 0x10
+#define CS35L35_VPBR_ERR 0x02
+#define CS35L35_VPBR_CLR 0x01
+
+/* CS35L35_INT_3 */
+#define CS35L35_BST_HIGH 0x10
+#define CS35L35_BST_HIGH_FLAG 0x08
+#define CS35L35_BST_IPK_FLAG 0x04
+#define CS35L35_LBST_SHORT 0x01
+
+/* CS35L35_INT_4 */
+#define CS35L35_VMON_OVFL 0x08
+#define CS35L35_IMON_OVFL 0x04
+
+#define CS35L35_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+struct cs35l35_private {
+ struct device *dev;
+ struct cs35l35_platform_data pdata;
+ struct regmap *regmap;
+ struct regulator_bulk_data supplies[2];
+ int num_supplies;
+ int sysclk;
+ int sclk;
+ bool pdm_mode;
+ bool i2s_mode;
+ bool slave_mode;
+ /* GPIO for /RST */
+ struct gpio_desc *reset_gpio;
+ struct completion pdn_done;
+};
+
+static const char * const cs35l35_supplies[] = {
+ "VA",
+ "VP",
+};
+
+#endif
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 8c0f3b89b5bc..e78b5f055f25 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -498,7 +498,7 @@ static int cs4271_reset(struct snd_soc_codec *codec)
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
if (gpio_is_valid(cs4271->gpio_nreset)) {
- gpio_set_value(cs4271->gpio_nreset, 0);
+ gpio_direction_output(cs4271->gpio_nreset, 0);
mdelay(1);
gpio_set_value(cs4271->gpio_nreset, 1);
mdelay(1);
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 73559ae864b6..47e6fddef92b 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -173,6 +173,9 @@ SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]),
SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]),
SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1),
+WM_ADSP2_PRELOAD_SWITCH("DSP2", 2),
+WM_ADSP2_PRELOAD_SWITCH("DSP3", 3),
+
ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
@@ -1121,7 +1124,10 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
priv->core.arizona->dapm = dapm;
- arizona_init_spk(codec);
+ ret = arizona_init_spk(codec);
+ if (ret < 0)
+ return ret;
+
arizona_init_gpio(codec);
arizona_init_mono(codec);
arizona_init_notifiers(codec);
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index cb47fb595ff4..1e0d5973b758 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -1130,6 +1130,7 @@ MODULE_DEVICE_TABLE(i2c, cs53l30_id);
static struct i2c_driver cs53l30_i2c_driver = {
.driver = {
.name = "cs53l30",
+ .of_match_table = cs53l30_of_match,
.pm = &cs53l30_runtime_pm,
},
.id_table = cs53l30_id,
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 12da55882c06..6dd7578f0bb8 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -12,6 +12,7 @@
* option) any later version.
*/
+#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -1528,12 +1529,23 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
+#if defined(CONFIG_OF)
/* DT */
static const struct of_device_id da7213_of_match[] = {
{ .compatible = "dlg,da7213", },
{ }
};
MODULE_DEVICE_TABLE(of, da7213_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id da7213_acpi_match[] = {
+ { "DLGS7212", 0},
+ { "DLGS7213", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, da7213_acpi_match);
+#endif
static enum da7213_micbias_voltage
da7213_of_micbias_lvl(struct snd_soc_codec *codec, u32 val)
@@ -1844,6 +1856,7 @@ static struct i2c_driver da7213_i2c_driver = {
.driver = {
.name = "da7213",
.of_match_table = of_match_ptr(da7213_of_match),
+ .acpi_match_table = ACPI_PTR(da7213_acpi_match),
},
.probe = da7213_i2c_probe,
.remove = da7213_remove,
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index c69e97654fc6..d256ebf9e309 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -1634,7 +1634,8 @@ static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* DAI */
- SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, DA7218_DAI_TDM_CTRL,
+ DA7218_DAI_OE_SHIFT, DA7218_NO_INVERT),
SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0),
/* Output Mixers */
diff --git a/sound/soc/codecs/dio2125.c b/sound/soc/codecs/dio2125.c
new file mode 100644
index 000000000000..09451cd44f9b
--- /dev/null
+++ b/sound/soc/codecs/dio2125.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "dio2125"
+
+struct dio2125 {
+ struct gpio_desc *gpiod_enable;
+};
+
+static int drv_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control, int event)
+{
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct dio2125 *priv = snd_soc_component_get_drvdata(c);
+ int val;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ val = 1;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ val = 0;
+ break;
+ default:
+ WARN(1, "Unexpected event");
+ return -EINVAL;
+ }
+
+ gpiod_set_value_cansleep(priv->gpiod_enable, val);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("INL"),
+ SND_SOC_DAPM_INPUT("INR"),
+ SND_SOC_DAPM_OUT_DRV_E("DRV", SND_SOC_NOPM, 0, 0, NULL, 0, drv_event,
+ (SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)),
+ SND_SOC_DAPM_OUTPUT("OUTL"),
+ SND_SOC_DAPM_OUTPUT("OUTR"),
+};
+
+static const struct snd_soc_dapm_route dio2125_dapm_routes[] = {
+ { "DRV", NULL, "INL" },
+ { "DRV", NULL, "INR" },
+ { "OUTL", NULL, "DRV" },
+ { "OUTR", NULL, "DRV" },
+};
+
+static const struct snd_soc_component_driver dio2125_component_driver = {
+ .dapm_widgets = dio2125_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(dio2125_dapm_widgets),
+ .dapm_routes = dio2125_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(dio2125_dapm_routes),
+};
+
+static int dio2125_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct dio2125 *priv;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
+ priv->gpiod_enable = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->gpiod_enable)) {
+ err = PTR_ERR(priv->gpiod_enable);
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get 'enable' gpio: %d", err);
+ return err;
+ }
+
+ return devm_snd_soc_register_component(dev, &dio2125_component_driver,
+ NULL, 0);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dio2125_ids[] = {
+ { .compatible = "dioo,dio2125", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, dio2125_ids);
+#endif
+
+static struct platform_driver dio2125_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(dio2125_ids),
+ },
+ .probe = dio2125_probe,
+};
+
+module_platform_driver(dio2125_driver);
+
+MODULE_DESCRIPTION("ASoC DIO2125 output driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
new file mode 100644
index 000000000000..25ede825d349
--- /dev/null
+++ b/sound/soc/codecs/es7134.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+/*
+ * The everest 7134 is a very simple DA converter with no register
+ */
+
+static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ fmt &= (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK |
+ SND_SOC_DAIFMT_MASTER_MASK);
+
+ if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS)) {
+ dev_err(codec_dai->dev, "Invalid DAI format\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops es7134_dai_ops = {
+ .set_fmt = es7134_set_fmt,
+};
+
+static struct snd_soc_dai_driver es7134_dai = {
+ .name = "es7134-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S18_3LE |
+ SNDRV_PCM_FMTBIT_S20_3LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ },
+ .ops = &es7134_dai_ops,
+};
+
+static const struct snd_soc_dapm_widget es7134_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("AOUTL"),
+ SND_SOC_DAPM_OUTPUT("AOUTR"),
+ SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
+ { "AOUTL", NULL, "DAC" },
+ { "AOUTR", NULL, "DAC" },
+};
+
+static struct snd_soc_codec_driver es7134_codec_driver = {
+ .component_driver = {
+ .dapm_widgets = es7134_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets),
+ .dapm_routes = es7134_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es7134_dapm_routes),
+ },
+};
+
+static int es7134_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev,
+ &es7134_codec_driver,
+ &es7134_dai, 1);
+}
+
+static int es7134_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es7134_ids[] = {
+ { .compatible = "everest,es7134", },
+ { .compatible = "everest,es7144", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, es7134_ids);
+#endif
+
+static struct platform_driver es7134_driver = {
+ .driver = {
+ .name = "es7134",
+ .of_match_table = of_match_ptr(es7134_ids),
+ },
+ .probe = es7134_probe,
+ .remove = es7134_remove,
+};
+
+module_platform_driver(es7134_driver);
+
+MODULE_DESCRIPTION("ASoC ES7134 audio codec driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c
index 2d05b5d3a6ce..318ab28c5351 100644
--- a/sound/soc/codecs/es8328-i2c.c
+++ b/sound/soc/codecs/es8328-i2c.c
@@ -20,12 +20,14 @@
static const struct i2c_device_id es8328_id[] = {
{ "es8328", 0 },
+ { "es8388", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8328_id);
static const struct of_device_id es8328_of_match[] = {
{ .compatible = "everest,es8328", },
+ { .compatible = "everest,es8388", },
{ }
};
MODULE_DEVICE_TABLE(of, es8328_of_match);
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 37722194b107..ed7cc42d1ee2 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -69,14 +69,10 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = {
"HPVDD",
};
-#define ES8328_RATES (SNDRV_PCM_RATE_96000 | \
- SNDRV_PCM_RATE_48000 | \
- SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_32000 | \
- SNDRV_PCM_RATE_22050 | \
- SNDRV_PCM_RATE_16000 | \
- SNDRV_PCM_RATE_11025 | \
- SNDRV_PCM_RATE_8000)
+#define ES8328_RATES (SNDRV_PCM_RATE_192000 | \
+ SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_8000_48000)
#define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -91,6 +87,7 @@ struct es8328_priv {
int mclkdiv2;
const struct snd_pcm_hw_constraint_list *sysclk_constraints;
const int *mclk_ratios;
+ bool master;
struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM];
};
@@ -469,7 +466,7 @@ static int es8328_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
- if (es8328->sysclk_constraints)
+ if (es8328->master && es8328->sysclk_constraints)
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
es8328->sysclk_constraints);
@@ -488,27 +485,34 @@ static int es8328_hw_params(struct snd_pcm_substream *substream,
int wl;
int ratio;
- if (!es8328->sysclk_constraints) {
- dev_err(codec->dev, "No MCLK configured\n");
- return -EINVAL;
- }
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
reg = ES8328_DACCONTROL2;
else
reg = ES8328_ADCCONTROL5;
- for (i = 0; i < es8328->sysclk_constraints->count; i++)
- if (es8328->sysclk_constraints->list[i] == params_rate(params))
- break;
+ if (es8328->master) {
+ if (!es8328->sysclk_constraints) {
+ dev_err(codec->dev, "No MCLK configured\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < es8328->sysclk_constraints->count; i++)
+ if (es8328->sysclk_constraints->list[i] ==
+ params_rate(params))
+ break;
- if (i == es8328->sysclk_constraints->count) {
- dev_err(codec->dev, "LRCLK %d unsupported with current clock\n",
- params_rate(params));
- return -EINVAL;
+ if (i == es8328->sysclk_constraints->count) {
+ dev_err(codec->dev,
+ "LRCLK %d unsupported with current clock\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+ ratio = es8328->mclk_ratios[i];
+ } else {
+ ratio = 0;
+ es8328->mclkdiv2 = 0;
}
- ratio = es8328->mclk_ratios[i];
snd_soc_update_bits(codec, ES8328_MASTERMODE,
ES8328_MASTERMODE_MCLKDIV2,
es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0);
@@ -586,12 +590,27 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec);
u8 dac_mode = 0;
u8 adc_mode = 0;
- /* set master/slave audio interface */
- if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM)
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Master serial port mode, with BCLK generated automatically */
+ snd_soc_update_bits(codec, ES8328_MASTERMODE,
+ ES8328_MASTERMODE_MSC,
+ ES8328_MASTERMODE_MSC);
+ es8328->master = true;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* Slave serial port mode */
+ snd_soc_update_bits(codec, ES8328_MASTERMODE,
+ ES8328_MASTERMODE_MSC, 0);
+ es8328->master = false;
+ break;
+ default:
return -EINVAL;
+ }
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -620,10 +639,6 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai,
snd_soc_update_bits(codec, ES8328_ADCCONTROL4,
ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode);
- /* Master serial port mode, with BCLK generated automatically */
- snd_soc_update_bits(codec, ES8328_MASTERMODE,
- ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC);
-
return 0;
}
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index c602c4960924..bc2e74ff3b2d 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -42,10 +42,15 @@
#define HDA_MAX_CONNECTIONS 32
#define HDA_MAX_CVTS 3
+#define HDA_MAX_PORTS 3
#define ELD_MAX_SIZE 256
#define ELD_FIXED_BYTES 20
+#define ELD_VER_CEA_861D 2
+#define ELD_VER_PARTIAL 31
+#define ELD_MAX_MNL 16
+
struct hdac_hdmi_cvt_params {
unsigned int channels_min;
unsigned int channels_max;
@@ -77,43 +82,180 @@ struct hdac_hdmi_eld {
struct hdac_hdmi_pin {
struct list_head head;
hda_nid_t nid;
+ bool mst_capable;
+ struct hdac_hdmi_port *ports;
+ int num_ports;
+ struct hdac_ext_device *edev;
+};
+
+struct hdac_hdmi_port {
+ struct list_head head;
+ int id;
+ struct hdac_hdmi_pin *pin;
int num_mux_nids;
hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
struct hdac_hdmi_eld eld;
- struct hdac_ext_device *edev;
- int repoll_count;
- struct delayed_work work;
- struct mutex lock;
- bool chmap_set;
- unsigned char chmap[8]; /* ALSA API channel-map */
- int channels; /* current number of channels */
+ const char *jack_pin;
+ struct snd_soc_dapm_context *dapm;
+ const char *output_pin;
};
struct hdac_hdmi_pcm {
struct list_head head;
int pcm_id;
- struct hdac_hdmi_pin *pin;
+ struct list_head port_list;
struct hdac_hdmi_cvt *cvt;
- struct snd_jack *jack;
+ struct snd_soc_jack *jack;
+ int stream_tag;
+ int channels;
+ int format;
+ bool chmap_set;
+ unsigned char chmap[8]; /* ALSA API channel-map */
+ struct mutex lock;
+ int jack_event;
};
-struct hdac_hdmi_dai_pin_map {
+struct hdac_hdmi_dai_port_map {
int dai_id;
- struct hdac_hdmi_pin *pin;
+ struct hdac_hdmi_port *port;
struct hdac_hdmi_cvt *cvt;
};
struct hdac_hdmi_priv {
- struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS];
+ struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
struct list_head pin_list;
struct list_head cvt_list;
struct list_head pcm_list;
int num_pin;
int num_cvt;
+ int num_ports;
struct mutex pin_mutex;
struct hdac_chmap chmap;
};
+static struct hdac_hdmi_pcm *
+hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
+ struct hdac_hdmi_cvt *cvt)
+{
+ struct hdac_hdmi_pcm *pcm = NULL;
+
+ list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+ if (pcm->cvt == cvt)
+ break;
+ }
+
+ return pcm;
+}
+
+static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
+ struct hdac_hdmi_port *port, bool is_connect)
+{
+ struct hdac_ext_device *edev = port->pin->edev;
+
+ if (is_connect)
+ snd_soc_dapm_enable_pin(port->dapm, port->jack_pin);
+ else
+ snd_soc_dapm_disable_pin(port->dapm, port->jack_pin);
+
+ if (is_connect) {
+ /*
+ * Report Jack connect event when a device is connected
+ * for the first time where same PCM is attached to multiple
+ * ports.
+ */
+ if (pcm->jack_event == 0) {
+ dev_dbg(&edev->hdac.dev,
+ "jack report for pcm=%d\n",
+ pcm->pcm_id);
+ snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT,
+ SND_JACK_AVOUT);
+ }
+ pcm->jack_event++;
+ } else {
+ /*
+ * Report Jack disconnect event when a device is disconnected
+ * is the only last connected device when same PCM is attached
+ * to multiple ports.
+ */
+ if (pcm->jack_event == 1)
+ snd_soc_jack_report(pcm->jack, 0, SND_JACK_AVOUT);
+ if (pcm->jack_event > 0)
+ pcm->jack_event--;
+ }
+
+ snd_soc_dapm_sync(port->dapm);
+}
+
+/* MST supported verbs */
+/*
+ * Get the no devices that can be connected to a port on the Pin widget.
+ */
+static int hdac_hdmi_get_port_len(struct hdac_ext_device *hdac, hda_nid_t nid)
+{
+ unsigned int caps;
+ unsigned int type, param;
+
+ caps = get_wcaps(&hdac->hdac, nid);
+ type = get_wcaps_type(caps);
+
+ if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
+ return 0;
+
+ param = snd_hdac_read_parm_uncached(&hdac->hdac, nid,
+ AC_PAR_DEVLIST_LEN);
+ if (param == -1)
+ return param;
+
+ return param & AC_DEV_LIST_LEN_MASK;
+}
+
+/*
+ * Get the port entry select on the pin. Return the port entry
+ * id selected on the pin. Return 0 means the first port entry
+ * is selected or MST is not supported.
+ */
+static int hdac_hdmi_port_select_get(struct hdac_ext_device *hdac,
+ struct hdac_hdmi_port *port)
+{
+ return snd_hdac_codec_read(&hdac->hdac, port->pin->nid,
+ 0, AC_VERB_GET_DEVICE_SEL, 0);
+}
+
+/*
+ * Sets the selected port entry for the configuring Pin widget verb.
+ * returns error if port set is not equal to port get otherwise success
+ */
+static int hdac_hdmi_port_select_set(struct hdac_ext_device *hdac,
+ struct hdac_hdmi_port *port)
+{
+ int num_ports;
+
+ if (!port->pin->mst_capable)
+ return 0;
+
+ /* AC_PAR_DEVLIST_LEN is 0 based. */
+ num_ports = hdac_hdmi_get_port_len(hdac, port->pin->nid);
+
+ if (num_ports < 0)
+ return -EIO;
+ /*
+ * Device List Length is a 0 based integer value indicating the
+ * number of sink device that a MST Pin Widget can support.
+ */
+ if (num_ports + 1 < port->id)
+ return 0;
+
+ snd_hdac_codec_write(&hdac->hdac, port->pin->nid, 0,
+ AC_VERB_SET_DEVICE_SEL, port->id);
+
+ if (port->id != hdac_hdmi_port_select_get(hdac, port))
+ return -EIO;
+
+ dev_dbg(&hdac->hdac.dev, "Selected the port=%d\n", port->id);
+
+ return 0;
+}
+
static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
int pcm_idx)
{
@@ -173,99 +315,6 @@ format_constraint:
}
- /* HDMI ELD routines */
-static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec,
- hda_nid_t nid, int byte_index)
-{
- unsigned int val;
-
- val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD,
- byte_index);
-
- dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n",
- byte_index, val);
-
- return val;
-}
-
-static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid)
-{
- return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
- AC_DIPSIZE_ELD_BUF);
-}
-
-/*
- * This function queries the ELD size and ELD data and fills in the buffer
- * passed by user
- */
-static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid,
- unsigned char *buf, int *eld_size)
-{
- int i, size, ret = 0;
-
- /*
- * ELD size is initialized to zero in caller function. If no errors and
- * ELD is valid, actual eld_size is assigned.
- */
-
- size = hdac_hdmi_get_eld_size(codec, nid);
- if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
- dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size);
- return -ERANGE;
- }
-
- /* set ELD buffer */
- for (i = 0; i < size; i++) {
- unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i);
- /*
- * Graphics driver might be writing to ELD buffer right now.
- * Just abort. The caller will repoll after a while.
- */
- if (!(val & AC_ELDD_ELD_VALID)) {
- dev_err(&codec->dev,
- "HDMI: invalid ELD data byte %d\n", i);
- ret = -EINVAL;
- goto error;
- }
- val &= AC_ELDD_ELD_DATA;
- /*
- * The first byte cannot be zero. This can happen on some DVI
- * connections. Some Intel chips may also need some 250ms delay
- * to return non-zero ELD data, even when the graphics driver
- * correctly writes ELD content before setting ELD_valid bit.
- */
- if (!val && !i) {
- dev_err(&codec->dev, "HDMI: 0 ELD data\n");
- ret = -EINVAL;
- goto error;
- }
- buf[i] = val;
- }
-
- *eld_size = size;
-error:
- return ret;
-}
-
-static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac,
- hda_nid_t cvt_nid, hda_nid_t pin_nid,
- u32 stream_tag, int format)
-{
- unsigned int val;
-
- dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n",
- cvt_nid, pin_nid, stream_tag, format);
-
- val = (stream_tag << 4);
-
- snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
- AC_VERB_SET_CHANNEL_STREAMID, val);
- snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0,
- AC_VERB_SET_STREAM_FORMAT, format);
-
- return 0;
-}
-
static void
hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid,
int packet_index, int byte_index)
@@ -291,13 +340,14 @@ struct dp_audio_infoframe {
};
static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
- hda_nid_t cvt_nid, hda_nid_t pin_nid)
+ struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_port *port)
{
uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE];
struct hdmi_audio_infoframe frame;
+ struct hdac_hdmi_pin *pin = port->pin;
struct dp_audio_infoframe dp_ai;
struct hdac_hdmi_priv *hdmi = hdac->private_data;
- struct hdac_hdmi_pin *pin;
+ struct hdac_hdmi_cvt *cvt = pcm->cvt;
u8 *dip;
int ret;
int i;
@@ -305,21 +355,16 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
u8 conn_type;
int channels, ca;
- list_for_each_entry(pin, &hdmi->pin_list, head) {
- if (pin->nid == pin_nid)
- break;
- }
-
- ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc,
- pin->channels, pin->chmap_set, true, pin->chmap);
+ ca = snd_hdac_channel_allocation(&hdac->hdac, port->eld.info.spk_alloc,
+ pcm->channels, pcm->chmap_set, true, pcm->chmap);
channels = snd_hdac_get_active_channels(ca);
- hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels);
+ hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels);
snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
- pin->channels, pin->chmap, pin->chmap_set);
+ pcm->channels, pcm->chmap, pcm->chmap_set);
- eld_buf = pin->eld.eld_buffer;
+ eld_buf = port->eld.eld_buffer;
conn_type = drm_eld_get_conn_type(eld_buf);
switch (conn_type) {
@@ -353,75 +398,50 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac,
}
/* stop infoframe transmission */
- hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
- snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0);
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
/* Fill infoframe. Index auto-incremented */
- hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
+ hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0);
if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
for (i = 0; i < sizeof(buffer); i++)
- snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, buffer[i]);
} else {
for (i = 0; i < sizeof(dp_ai); i++)
- snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
}
/* Start infoframe */
- hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0);
- snd_hdac_codec_write(&hdac->hdac, pin_nid, 0,
+ hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0);
+ snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
return 0;
}
-static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
- struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state)
+static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
{
- /* Power up pin widget */
- if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid,
- pwr_state))
- snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0,
- AC_VERB_SET_POWER_STATE, pwr_state);
-
- /* Power up converter */
- if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid,
- pwr_state))
- snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_POWER_STATE, pwr_state);
-}
+ struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_dai_port_map *dai_map;
+ struct hdac_hdmi_pcm *pcm;
-static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdac->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map;
- struct hdac_hdmi_pin *pin;
- struct hdac_ext_dma_params *dd;
- int ret;
+ dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask);
dai_map = &hdmi->dai_map[dai->id];
- pin = dai_map->pin;
- dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
- dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n",
- dd->stream_tag, dd->format);
+ pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
- mutex_lock(&pin->lock);
- pin->channels = substream->runtime->channels;
-
- ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid,
- dai_map->pin->nid);
- mutex_unlock(&pin->lock);
- if (ret < 0)
- return ret;
+ if (pcm)
+ pcm->stream_tag = (tx_mask << 4);
- return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid,
- dai_map->pin->nid, dd->stream_tag, dd->format);
+ return 0;
}
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
@@ -429,101 +449,41 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
{
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map;
- struct hdac_hdmi_pin *pin;
- struct hdac_ext_dma_params *dd;
+ struct hdac_hdmi_dai_port_map *dai_map;
+ struct hdac_hdmi_port *port;
+ struct hdac_hdmi_pcm *pcm;
+ int format;
dai_map = &hdmi->dai_map[dai->id];
- pin = dai_map->pin;
+ port = dai_map->port;
- if (!pin)
+ if (!port)
return -ENODEV;
- if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) {
- dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n",
- pin->nid);
+ if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
+ dev_err(&hdac->hdac.dev,
+ "device is not configured for this pin:port%d:%d\n",
+ port->pin->nid, port->id);
return -ENODEV;
}
- dd = snd_soc_dai_get_dma_data(dai, substream);
- if (!dd) {
- dd = kzalloc(sizeof(*dd), GFP_KERNEL);
- if (!dd)
- return -ENOMEM;
- }
-
- dd->format = snd_hdac_calc_stream_format(params_rate(hparams),
+ format = snd_hdac_calc_stream_format(params_rate(hparams),
params_channels(hparams), params_format(hparams),
- 24, 0);
-
- snd_soc_dai_set_dma_data(dai, substream, (void *)dd);
-
- return 0;
-}
-
-static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
- struct hdac_ext_dma_params *dd;
- struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map;
-
- dai_map = &hdmi->dai_map[dai->id];
+ dai->driver->playback.sig_bits, 0);
- dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream);
-
- if (dd) {
- snd_soc_dai_set_dma_data(dai, substream, NULL);
- kfree(dd);
- }
-
- return 0;
-}
-
-static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev,
- struct hdac_hdmi_dai_pin_map *dai_map)
-{
- /* Enable transmission */
- snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_DIGI_CONVERT_1, 1);
-
- /* Category Code (CC) to zero */
- snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_DIGI_CONVERT_2, 0);
-}
-
-static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac,
- struct hdac_hdmi_dai_pin_map *dai_map)
-{
- int mux_idx;
- struct hdac_hdmi_pin *pin = dai_map->pin;
-
- for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) {
- if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) {
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
- AC_VERB_SET_CONNECT_SEL, mux_idx);
- break;
- }
- }
-
- if (mux_idx == pin->num_mux_nids)
+ pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
+ if (!pcm)
return -EIO;
- /* Enable out path for this pin widget */
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-
- hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0);
-
- snd_hdac_codec_write(&hdac->hdac, pin->nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ pcm->format = format;
+ pcm->channels = params_channels(hparams);
return 0;
}
-static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
- struct hdac_hdmi_pin *pin)
+static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *hdac,
+ struct hdac_hdmi_pin *pin,
+ struct hdac_hdmi_port *port)
{
if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) {
dev_warn(&hdac->hdac.dev,
@@ -532,51 +492,60 @@ static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac,
return -EINVAL;
}
- pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
- pin->mux_nids, HDA_MAX_CONNECTIONS);
- if (pin->num_mux_nids == 0)
- dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n",
- pin->nid);
+ if (hdac_hdmi_port_select_set(hdac, port) < 0)
+ return -EIO;
- dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n",
- pin->num_mux_nids, pin->nid);
+ port->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid,
+ port->mux_nids, HDA_MAX_CONNECTIONS);
+ if (port->num_mux_nids == 0)
+ dev_warn(&hdac->hdac.dev,
+ "No connections found for pin:port %d:%d\n",
+ pin->nid, port->id);
- return pin->num_mux_nids;
+ dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin:port %d:%d\n",
+ port->num_mux_nids, pin->nid, port->id);
+
+ return port->num_mux_nids;
}
/*
- * Query pcm list and return pin widget to which stream is routed.
+ * Query pcm list and return port to which stream is routed.
*
- * Also query connection list of the pin, to validate the cvt to pin map.
+ * Also query connection list of the pin, to validate the cvt to port map.
*
- * Same stream rendering to multiple pins simultaneously can be done
- * possibly, but not supported for now in driver. So return the first pin
+ * Same stream rendering to multiple ports simultaneously can be done
+ * possibly, but not supported for now in driver. So return the first port
* connected.
*/
-static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt(
+static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
struct hdac_ext_device *edev,
struct hdac_hdmi_priv *hdmi,
struct hdac_hdmi_cvt *cvt)
{
struct hdac_hdmi_pcm *pcm;
- struct hdac_hdmi_pin *pin = NULL;
+ struct hdac_hdmi_port *port = NULL;
int ret, i;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
if (pcm->cvt == cvt) {
- pin = pcm->pin;
- break;
- }
- }
-
- if (pin) {
- ret = hdac_hdmi_query_pin_connlist(edev, pin);
- if (ret < 0)
- return NULL;
-
- for (i = 0; i < pin->num_mux_nids; i++) {
- if (pin->mux_nids[i] == cvt->nid)
- return pin;
+ if (list_empty(&pcm->port_list))
+ continue;
+
+ list_for_each_entry(port, &pcm->port_list, head) {
+ mutex_lock(&pcm->lock);
+ ret = hdac_hdmi_query_port_connlist(edev,
+ port->pin, port);
+ mutex_unlock(&pcm->lock);
+ if (ret < 0)
+ continue;
+
+ for (i = 0; i < port->num_mux_nids; i++) {
+ if (port->mux_nids[i] == cvt->nid &&
+ port->eld.monitor_present &&
+ port->eld.eld_valid)
+ return port;
+ }
+ }
}
}
@@ -593,67 +562,42 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
{
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_cvt *cvt;
- struct hdac_hdmi_pin *pin;
+ struct hdac_hdmi_port *port;
int ret;
dai_map = &hdmi->dai_map[dai->id];
cvt = dai_map->cvt;
- pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt);
+ port = hdac_hdmi_get_port_from_cvt(hdac, hdmi, cvt);
/*
* To make PA and other userland happy.
* userland scans devices so returning error does not help.
*/
- if (!pin)
+ if (!port)
return 0;
-
- if ((!pin->eld.monitor_present) ||
- (!pin->eld.eld_valid)) {
+ if ((!port->eld.monitor_present) ||
+ (!port->eld.eld_valid)) {
dev_warn(&hdac->hdac.dev,
- "Failed: monitor present? %d ELD valid?: %d for pin: %d\n",
- pin->eld.monitor_present, pin->eld.eld_valid, pin->nid);
+ "Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n",
+ port->eld.monitor_present, port->eld.eld_valid,
+ port->pin->nid, port->id);
return 0;
}
- dai_map->pin = pin;
-
- hdac_hdmi_enable_cvt(hdac, dai_map);
- ret = hdac_hdmi_enable_pin(hdac, dai_map);
- if (ret < 0)
- return ret;
+ dai_map->port = port;
ret = hdac_hdmi_eld_limit_formats(substream->runtime,
- pin->eld.eld_buffer);
+ port->eld.eld_buffer);
if (ret < 0)
return ret;
return snd_pcm_hw_constraint_eld(substream->runtime,
- pin->eld.eld_buffer);
-}
-
-static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct hdac_hdmi_dai_pin_map *dai_map;
- struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdac->private_data;
- int ret;
-
- dai_map = &hdmi->dai_map[dai->id];
- if (cmd == SNDRV_PCM_TRIGGER_RESUME) {
- ret = hdac_hdmi_enable_pin(hdac, dai_map);
- if (ret < 0)
- return ret;
-
- return hdac_hdmi_playback_prepare(substream, dai);
- }
-
- return 0;
+ port->eld.eld_buffer);
}
static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
@@ -661,29 +605,23 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
{
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_hdmi_dai_port_map *dai_map;
+ struct hdac_hdmi_pcm *pcm;
dai_map = &hdmi->dai_map[dai->id];
- if (dai_map->pin) {
- snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_CHANNEL_STREAMID, 0);
- snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0,
- AC_VERB_SET_STREAM_FORMAT, 0);
-
- hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3);
-
- snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
- mutex_lock(&dai_map->pin->lock);
- dai_map->pin->chmap_set = false;
- memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap));
- dai_map->pin->channels = 0;
- mutex_unlock(&dai_map->pin->lock);
-
- dai_map->pin = NULL;
+ if (pcm) {
+ mutex_lock(&pcm->lock);
+ pcm->chmap_set = false;
+ memset(pcm->chmap, 0, sizeof(pcm->chmap));
+ pcm->channels = 0;
+ mutex_unlock(&pcm->lock);
}
+
+ if (dai_map->port)
+ dai_map->port = NULL;
}
static int
@@ -716,10 +654,11 @@ hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt)
}
static int hdac_hdmi_fill_widget_info(struct device *dev,
- struct snd_soc_dapm_widget *w,
- enum snd_soc_dapm_type id, void *priv,
- const char *wname, const char *stream,
- struct snd_kcontrol_new *wc, int numkc)
+ struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id,
+ void *priv, const char *wname, const char *stream,
+ struct snd_kcontrol_new *wc, int numkc,
+ int (*event)(struct snd_soc_dapm_widget *,
+ struct snd_kcontrol *, int), unsigned short event_flags)
{
w->id = id;
w->name = devm_kstrdup(dev, wname, GFP_KERNEL);
@@ -732,6 +671,8 @@ static int hdac_hdmi_fill_widget_info(struct device *dev,
w->kcontrol_news = wc;
w->num_kcontrols = numkc;
w->priv = priv;
+ w->event = event;
+ w->event_flags = event_flags;
return 0;
}
@@ -748,30 +689,175 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
}
static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
- struct hdac_hdmi_pin *pin)
+ struct hdac_hdmi_port *port)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = NULL;
+ struct hdac_hdmi_port *p;
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
- if (pcm->pin == pin)
- return pcm;
+ if (list_empty(&pcm->port_list))
+ continue;
+
+ list_for_each_entry(p, &pcm->port_list, head) {
+ if (p->id == port->id && port->pin == p->pin)
+ return pcm;
+ }
}
return NULL;
}
+static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
+ hda_nid_t nid, unsigned int pwr_state)
+{
+ if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) {
+ if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state))
+ snd_hdac_codec_write(&edev->hdac, nid, 0,
+ AC_VERB_SET_POWER_STATE, pwr_state);
+ }
+}
+
+static void hdac_hdmi_set_amp(struct hdac_ext_device *edev,
+ hda_nid_t nid, int val)
+{
+ if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP)
+ snd_hdac_codec_write(&edev->hdac, nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, val);
+}
+
+
+static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct hdac_hdmi_port *port = w->priv;
+ struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+ struct hdac_hdmi_pcm *pcm;
+
+ dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n",
+ __func__, w->name, event);
+
+ pcm = hdac_hdmi_get_pcm(edev, port);
+ if (!pcm)
+ return -EIO;
+
+ /* set the device if pin is mst_capable */
+ if (hdac_hdmi_port_select_set(edev, port) < 0)
+ return -EIO;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0);
+
+ /* Enable out path for this pin widget */
+ snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+ hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE);
+
+ return hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
+
+ case SND_SOC_DAPM_POST_PMD:
+ hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE);
+
+ /* Disable out path for this pin widget */
+ snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+
+ hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3);
+ break;
+
+ }
+
+ return 0;
+}
+
+static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct hdac_hdmi_cvt *cvt = w->priv;
+ struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm;
+
+ dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n",
+ __func__, w->name, event);
+
+ pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt);
+ if (!pcm)
+ return -EIO;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0);
+
+ /* Enable transmission */
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_DIGI_CONVERT_1, 1);
+
+ /* Category Code (CC) to zero */
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_DIGI_CONVERT_2, 0);
+
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_STREAM_FORMAT, pcm->format);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_CHANNEL_STREAMID, 0);
+ snd_hdac_codec_write(&edev->hdac, cvt->nid, 0,
+ AC_VERB_SET_STREAM_FORMAT, 0);
+
+ hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3);
+ break;
+
+ }
+
+ return 0;
+}
+
+static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kc, int event)
+{
+ struct hdac_hdmi_port *port = w->priv;
+ struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev);
+ int mux_idx;
+
+ dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n",
+ __func__, w->name, event);
+
+ if (!kc)
+ kc = w->kcontrols[0];
+
+ mux_idx = dapm_kcontrol_get_value(kc);
+
+ /* set the device if pin is mst_capable */
+ if (hdac_hdmi_port_select_set(edev, port) < 0)
+ return -EIO;
+
+ if (mux_idx > 0) {
+ snd_hdac_codec_write(&edev->hdac, port->pin->nid, 0,
+ AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
+ }
+
+ return 0;
+}
+
/*
* Based on user selection, map the PINs with the PCMs.
*/
-static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
+static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int ret;
+ struct hdac_hdmi_port *p, *p_next;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_context *dapm = w->dapm;
- struct hdac_hdmi_pin *pin = w->priv;
+ struct hdac_hdmi_port *port = w->priv;
struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = NULL;
@@ -781,26 +867,35 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
if (ret < 0)
return ret;
+ if (port == NULL)
+ return -EINVAL;
+
mutex_lock(&hdmi->pin_mutex);
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
- if (pcm->pin == pin)
- pcm->pin = NULL;
+ if (list_empty(&pcm->port_list))
+ continue;
- /*
- * Jack status is not reported during device probe as the
- * PCMs are not registered by then. So report it here.
- */
- if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) {
- pcm->pin = pin;
- if (pin->eld.monitor_present && pin->eld.eld_valid) {
- dev_dbg(&edev->hdac.dev,
- "jack report for pcm=%d\n",
- pcm->pcm_id);
+ list_for_each_entry_safe(p, p_next, &pcm->port_list, head) {
+ if (p == port && p->id == port->id &&
+ p->pin == port->pin) {
+ hdac_hdmi_jack_report(pcm, port, false);
+ list_del(&p->head);
+ }
+ }
+ }
- snd_jack_report(pcm->jack, SND_JACK_AVOUT);
+ /*
+ * Jack status is not reported during device probe as the
+ * PCMs are not registered by then. So report it here.
+ */
+ list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+ if (!strcmp(cvt_name, pcm->cvt->name)) {
+ list_add_tail(&port->head, &pcm->port_list);
+ if (port->eld.monitor_present && port->eld.eld_valid) {
+ hdac_hdmi_jack_report(pcm, port, true);
+ mutex_unlock(&hdmi->pin_mutex);
+ return ret;
}
- mutex_unlock(&hdmi->pin_mutex);
- return ret;
}
}
mutex_unlock(&hdmi->pin_mutex);
@@ -817,12 +912,13 @@ static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol,
* care of selecting the right one and leaving all other inputs selected to
* "NONE"
*/
-static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
- struct hdac_hdmi_pin *pin,
+static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
+ struct hdac_hdmi_port *port,
struct snd_soc_dapm_widget *widget,
const char *widget_name)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pin *pin = port->pin;
struct snd_kcontrol_new *kc;
struct hdac_hdmi_cvt *cvt;
struct soc_enum *se;
@@ -841,7 +937,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
if (!se)
return -ENOMEM;
- sprintf(kc_name, "Pin %d Input", pin->nid);
+ sprintf(kc_name, "Pin %d port %d Input", pin->nid, port->id);
kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL);
if (!kc->name)
return -ENOMEM;
@@ -850,7 +946,7 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
kc->access = 0;
kc->info = snd_soc_info_enum_double;
- kc->put = hdac_hdmi_set_pin_mux;
+ kc->put = hdac_hdmi_set_pin_port_mux;
kc->get = snd_soc_dapm_get_enum_double;
se->reg = SND_SOC_NOPM;
@@ -878,7 +974,9 @@ static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev,
return -ENOMEM;
return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget,
- snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1);
+ snd_soc_dapm_mux, port, widget_name, NULL, kc, 1,
+ hdac_hdmi_pin_mux_widget_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG);
}
/* Add cvt <- input <- mux route map */
@@ -889,10 +987,10 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
struct hdac_hdmi_priv *hdmi = edev->private_data;
const struct snd_kcontrol_new *kc;
struct soc_enum *se;
- int mux_index = hdmi->num_cvt + hdmi->num_pin;
+ int mux_index = hdmi->num_cvt + hdmi->num_ports;
int i, j;
- for (i = 0; i < hdmi->num_pin; i++) {
+ for (i = 0; i < hdmi->num_ports; i++) {
kc = widgets[mux_index].kcontrol_news;
se = (struct soc_enum *)kc->private_value;
for (j = 0; j < hdmi->num_cvt; j++) {
@@ -911,17 +1009,18 @@ static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
/*
* Widgets are added in the below sequence
* Converter widgets for num converters enumerated
- * Pin widgets for num pins enumerated
- * Pin mux widgets to represent connenction list of pin widget
+ * Pin-port widgets for num ports for Pins enumerated
+ * Pin-port mux widgets to represent connenction list of pin widget
*
- * Total widgets elements = num_cvt + num_pin + num_pin;
+ * For each port, one Mux and One output widget is added
+ * Total widgets elements = num_cvt + (num_ports * 2);
*
* Routes are added as below:
- * pin mux -> pin (based on num_pins)
- * cvt -> "Input sel control" -> pin_mux
+ * pin-port mux -> pin (based on num_ports)
+ * cvt -> "Input sel control" -> pin-port_mux
*
* Total route elements:
- * num_pins + (pin_muxes * num_cvt)
+ * num_ports + (pin_muxes * num_cvt)
*/
static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
{
@@ -933,14 +1032,14 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
char widget_name[NAME_SIZE];
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_pin *pin;
- int ret, i = 0, num_routes = 0;
+ int ret, i = 0, num_routes = 0, j;
if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list))
return -EINVAL;
- widgets = devm_kzalloc(dapm->dev,
- (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)),
- GFP_KERNEL);
+ widgets = devm_kzalloc(dapm->dev, (sizeof(*widgets) *
+ ((2 * hdmi->num_ports) + hdmi->num_cvt)),
+ GFP_KERNEL);
if (!widgets)
return -ENOMEM;
@@ -949,37 +1048,50 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
sprintf(widget_name, "Converter %d", cvt->nid);
ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
- snd_soc_dapm_aif_in, &cvt->nid,
- widget_name, dai_drv[i].playback.stream_name, NULL, 0);
+ snd_soc_dapm_aif_in, cvt,
+ widget_name, dai_drv[i].playback.stream_name, NULL, 0,
+ hdac_hdmi_cvt_output_widget_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
if (ret < 0)
return ret;
i++;
}
list_for_each_entry(pin, &hdmi->pin_list, head) {
- sprintf(widget_name, "hif%d Output", pin->nid);
- ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
- snd_soc_dapm_output, &pin->nid,
- widget_name, NULL, NULL, 0);
- if (ret < 0)
- return ret;
- i++;
+ for (j = 0; j < pin->num_ports; j++) {
+ sprintf(widget_name, "hif%d-%d Output",
+ pin->nid, pin->ports[j].id);
+ ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+ snd_soc_dapm_output, &pin->ports[j],
+ widget_name, NULL, NULL, 0,
+ hdac_hdmi_pin_output_widget_event,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD);
+ if (ret < 0)
+ return ret;
+ pin->ports[j].output_pin = widgets[i].name;
+ i++;
+ }
}
/* DAPM widgets to represent the connection list to pin widget */
list_for_each_entry(pin, &hdmi->pin_list, head) {
- sprintf(widget_name, "Pin %d Mux", pin->nid);
- ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i],
- widget_name);
- if (ret < 0)
- return ret;
- i++;
+ for (j = 0; j < pin->num_ports; j++) {
+ sprintf(widget_name, "Pin%d-Port%d Mux",
+ pin->nid, pin->ports[j].id);
+ ret = hdac_hdmi_create_pin_port_muxs(edev,
+ &pin->ports[j], &widgets[i],
+ widget_name);
+ if (ret < 0)
+ return ret;
+ i++;
- /* For cvt to pin_mux mapping */
- num_routes += hdmi->num_cvt;
+ /* For cvt to pin_mux mapping */
+ num_routes += hdmi->num_cvt;
- /* For pin_mux to pin mapping */
- num_routes++;
+ /* For pin_mux to pin mapping */
+ num_routes++;
+ }
}
route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes),
@@ -990,20 +1102,22 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
i = 0;
/* Add pin <- NULL <- mux route map */
list_for_each_entry(pin, &hdmi->pin_list, head) {
- int sink_index = i + hdmi->num_cvt;
- int src_index = sink_index + hdmi->num_pin;
+ for (j = 0; j < pin->num_ports; j++) {
+ int sink_index = i + hdmi->num_cvt;
+ int src_index = sink_index + pin->num_ports *
+ hdmi->num_pin;
- hdac_hdmi_fill_route(&route[i],
+ hdac_hdmi_fill_route(&route[i],
widgets[sink_index].name, NULL,
widgets[src_index].name, NULL);
- i++;
-
+ i++;
+ }
}
hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
snd_soc_dapm_new_controls(dapm, widgets,
- ((2 * hdmi->num_pin) + hdmi->num_cvt));
+ ((2 * hdmi->num_ports) + hdmi->num_cvt));
snd_soc_dapm_add_routes(dapm, route, num_routes);
snd_soc_dapm_new_widgets(dapm->card);
@@ -1015,7 +1129,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct hdac_hdmi_dai_pin_map *dai_map;
+ struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_cvt *cvt;
int dai_id = 0;
@@ -1059,132 +1173,149 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
return hdac_hdmi_query_cvt_params(&edev->hdac, cvt);
}
-static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
- struct hdac_hdmi_pin *pin)
+static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
+ struct hdac_hdmi_port *port)
{
- pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER];
+ unsigned int ver, mnl;
+
+ ver = (port->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK)
+ >> DRM_ELD_VER_SHIFT;
+
+ if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
+ dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver);
+ return -EINVAL;
+ }
+
+ mnl = (port->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] &
+ DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
+
+ if (mnl > ELD_MAX_MNL) {
+ dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl);
+ return -EINVAL;
+ }
+
+ port->eld.info.spk_alloc = port->eld.eld_buffer[DRM_ELD_SPEAKER];
+
+ return 0;
}
-static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll)
+static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
+ struct hdac_hdmi_port *port)
{
struct hdac_ext_device *edev = pin->edev;
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm;
- int val;
+ int size = 0;
+ int port_id = -1;
- pin->repoll_count = repoll;
+ if (!hdmi)
+ return;
- pm_runtime_get_sync(&edev->hdac.dev);
- val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0,
- AC_VERB_GET_PIN_SENSE, 0);
+ /*
+ * In case of non MST pin, get_eld info API expectes port
+ * to be -1.
+ */
+ mutex_lock(&hdmi->pin_mutex);
+ port->eld.monitor_present = false;
- dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n",
- val, pin->nid);
+ if (pin->mst_capable)
+ port_id = port->id;
+ size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, port_id,
+ &port->eld.monitor_present,
+ port->eld.eld_buffer,
+ ELD_MAX_SIZE);
- mutex_lock(&hdmi->pin_mutex);
- pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE);
- pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV);
+ if (size > 0) {
+ size = min(size, ELD_MAX_SIZE);
+ if (hdac_hdmi_parse_eld(edev, port) < 0)
+ size = -EINVAL;
+ }
- pcm = hdac_hdmi_get_pcm(edev, pin);
+ if (size > 0) {
+ port->eld.eld_valid = true;
+ port->eld.eld_size = size;
+ } else {
+ port->eld.eld_valid = false;
+ port->eld.eld_size = 0;
+ }
- if (!pin->eld.monitor_present || !pin->eld.eld_valid) {
+ pcm = hdac_hdmi_get_pcm(edev, port);
- dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n",
- __func__, pin->nid);
+ if (!port->eld.monitor_present || !port->eld.eld_valid) {
+
+ dev_err(&edev->hdac.dev, "%s: disconnect for pin:port %d:%d\n",
+ __func__, pin->nid, port->id);
/*
* PCMs are not registered during device probe, so don't
* report jack here. It will be done in usermode mux
* control select.
*/
- if (pcm) {
- dev_dbg(&edev->hdac.dev,
- "jack report for pcm=%d\n", pcm->pcm_id);
-
- snd_jack_report(pcm->jack, 0);
- }
+ if (pcm)
+ hdac_hdmi_jack_report(pcm, port, false);
mutex_unlock(&hdmi->pin_mutex);
- goto put_hdac_device;
+ return;
}
- if (pin->eld.monitor_present && pin->eld.eld_valid) {
- /* TODO: use i915 component for reading ELD later */
- if (hdac_hdmi_get_eld(&edev->hdac, pin->nid,
- pin->eld.eld_buffer,
- &pin->eld.eld_size) == 0) {
-
- if (pcm) {
- dev_dbg(&edev->hdac.dev,
- "jack report for pcm=%d\n",
- pcm->pcm_id);
-
- snd_jack_report(pcm->jack, SND_JACK_AVOUT);
- }
- hdac_hdmi_parse_eld(edev, pin);
-
- print_hex_dump_debug("ELD: ",
- DUMP_PREFIX_OFFSET, 16, 1,
- pin->eld.eld_buffer, pin->eld.eld_size,
- true);
- } else {
- pin->eld.monitor_present = false;
- pin->eld.eld_valid = false;
+ if (port->eld.monitor_present && port->eld.eld_valid) {
+ if (pcm)
+ hdac_hdmi_jack_report(pcm, port, true);
- if (pcm) {
- dev_dbg(&edev->hdac.dev,
- "jack report for pcm=%d\n",
- pcm->pcm_id);
+ print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
+ port->eld.eld_buffer, port->eld.eld_size, false);
- snd_jack_report(pcm->jack, 0);
- }
- }
}
-
mutex_unlock(&hdmi->pin_mutex);
-
- /*
- * Sometimes the pin_sense may present invalid monitor
- * present and eld_valid. If ELD data is not valid, loop few
- * more times to get correct pin sense and valid ELD.
- */
- if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll)
- schedule_delayed_work(&pin->work, msecs_to_jiffies(300));
-
-put_hdac_device:
- pm_runtime_put_sync(&edev->hdac.dev);
}
-static void hdac_hdmi_repoll_eld(struct work_struct *work)
+static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi,
+ struct hdac_hdmi_pin *pin)
{
- struct hdac_hdmi_pin *pin =
- container_of(to_delayed_work(work), struct hdac_hdmi_pin, work);
+ struct hdac_hdmi_port *ports;
+ int max_ports = HDA_MAX_PORTS;
+ int i;
+
+ /*
+ * FIXME: max_port may vary for each platform, so pass this as
+ * as driver data or query from i915 interface when this API is
+ * implemented.
+ */
- /* picked from legacy HDA driver */
- if (pin->repoll_count++ > 6)
- pin->repoll_count = 0;
+ ports = kcalloc(max_ports, sizeof(*ports), GFP_KERNEL);
+ if (!ports)
+ return -ENOMEM;
- hdac_hdmi_present_sense(pin, pin->repoll_count);
+ for (i = 0; i < max_ports; i++) {
+ ports[i].id = i;
+ ports[i].pin = pin;
+ }
+ pin->ports = ports;
+ pin->num_ports = max_ports;
+ return 0;
}
static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
{
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pin *pin;
+ int ret;
pin = kzalloc(sizeof(*pin), GFP_KERNEL);
if (!pin)
return -ENOMEM;
pin->nid = nid;
+ pin->mst_capable = false;
+ pin->edev = edev;
+ ret = hdac_hdmi_add_ports(hdmi, pin);
+ if (ret < 0)
+ return ret;
list_add_tail(&pin->head, &hdmi->pin_list);
hdmi->num_pin++;
-
- pin->edev = edev;
- mutex_init(&pin->lock);
- INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld);
+ hdmi->num_ports += pin->num_ports;
return 0;
}
@@ -1233,9 +1364,7 @@ static struct snd_soc_dai_ops hdmi_dai_ops = {
.startup = hdac_hdmi_pcm_open,
.shutdown = hdac_hdmi_pcm_close,
.hw_params = hdac_hdmi_set_hw_params,
- .prepare = hdac_hdmi_playback_prepare,
- .trigger = hdac_hdmi_trigger,
- .hw_free = hdac_hdmi_playback_cleanup,
+ .set_tdm_slot = hdac_hdmi_set_tdm_slot,
};
/*
@@ -1290,8 +1419,8 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdac,
hdmi_dais[i].playback.rate_min = rate_min;
hdmi_dais[i].playback.channels_min = 2;
hdmi_dais[i].playback.channels_max = 2;
+ hdmi_dais[i].playback.sig_bits = bps;
hdmi_dais[i].ops = &hdmi_dai_ops;
-
i++;
}
@@ -1368,17 +1497,20 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
return hdac_hdmi_init_dai_map(edev);
}
-static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
+static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{
struct hdac_ext_device *edev = aptr;
struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct hdac_hdmi_pin *pin;
+ struct hdac_hdmi_pin *pin = NULL;
+ struct hdac_hdmi_port *hport = NULL;
struct snd_soc_codec *codec = edev->scodec;
+ int i;
/* Don't know how this mapping is derived */
hda_nid_t pin_nid = port + 0x04;
- dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid);
+ dev_dbg(&edev->hdac.dev, "%s: for pin:%d port=%d\n", __func__,
+ pin_nid, pipe);
/*
* skip notification during system suspend (but not in runtime PM);
@@ -1394,9 +1526,28 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
return;
list_for_each_entry(pin, &hdmi->pin_list, head) {
- if (pin->nid == pin_nid)
- hdac_hdmi_present_sense(pin, 1);
+ if (pin->nid != pin_nid)
+ continue;
+
+ /* In case of non MST pin, pipe is -1 */
+ if (pipe == -1) {
+ pin->mst_capable = false;
+ /* if not MST, default is port[0] */
+ hport = &pin->ports[0];
+ } else {
+ for (i = 0; i < pin->num_ports; i++) {
+ pin->mst_capable = true;
+ if (pin->ports[i].id == pipe) {
+ hport = &pin->ports[i];
+ break;
+ }
+ }
+ }
+
+ if (hport)
+ hdac_hdmi_present_sense(pin, hport);
}
+
}
static struct i915_audio_component_audio_ops aops = {
@@ -1416,13 +1567,130 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
return NULL;
}
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
+/* create jack pin kcontrols */
+static int create_fill_jack_kcontrols(struct snd_soc_card *card,
+ struct hdac_ext_device *edev)
+{
+ struct hdac_hdmi_pin *pin;
+ struct snd_kcontrol_new *kc;
+ char kc_name[NAME_SIZE], xname[NAME_SIZE];
+ char *name;
+ int i = 0, j;
+ struct snd_soc_codec *codec = edev->scodec;
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+
+ kc = devm_kcalloc(codec->dev, hdmi->num_ports,
+ sizeof(*kc), GFP_KERNEL);
+
+ if (!kc)
+ return -ENOMEM;
+
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ for (j = 0; j < pin->num_ports; j++) {
+ snprintf(xname, sizeof(xname), "hif%d-%d Jack",
+ pin->nid, pin->ports[j].id);
+ name = devm_kstrdup(codec->dev, xname, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+ snprintf(kc_name, sizeof(kc_name), "%s Switch", xname);
+ kc[i].name = devm_kstrdup(codec->dev, kc_name,
+ GFP_KERNEL);
+ if (!kc[i].name)
+ return -ENOMEM;
+
+ kc[i].private_value = (unsigned long)name;
+ kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ kc[i].access = 0;
+ kc[i].info = snd_soc_dapm_info_pin_switch;
+ kc[i].put = snd_soc_dapm_put_pin_switch;
+ kc[i].get = snd_soc_dapm_get_pin_switch;
+ i++;
+ }
+ }
+
+ return snd_soc_add_card_controls(card, kc, i);
+}
+
+int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_context *dapm)
+{
+ struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pin *pin;
+ struct snd_soc_dapm_widget *widgets;
+ struct snd_soc_dapm_route *route;
+ char w_name[NAME_SIZE];
+ int i = 0, j, ret;
+
+ widgets = devm_kcalloc(dapm->dev, hdmi->num_ports,
+ sizeof(*widgets), GFP_KERNEL);
+
+ if (!widgets)
+ return -ENOMEM;
+
+ route = devm_kcalloc(dapm->dev, hdmi->num_ports,
+ sizeof(*route), GFP_KERNEL);
+ if (!route)
+ return -ENOMEM;
+
+ /* create Jack DAPM widget */
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ for (j = 0; j < pin->num_ports; j++) {
+ snprintf(w_name, sizeof(w_name), "hif%d-%d Jack",
+ pin->nid, pin->ports[j].id);
+
+ ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i],
+ snd_soc_dapm_spk, NULL,
+ w_name, NULL, NULL, 0, NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ pin->ports[j].jack_pin = widgets[i].name;
+ pin->ports[j].dapm = dapm;
+
+ /* add to route from Jack widget to output */
+ hdac_hdmi_fill_route(&route[i], pin->ports[j].jack_pin,
+ NULL, pin->ports[j].output_pin, NULL);
+
+ i++;
+ }
+ }
+
+ /* Add Route from Jack widget to the output widget */
+ ret = snd_soc_dapm_new_controls(dapm, widgets, hdmi->num_ports);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, route, hdmi->num_ports);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dapm_new_widgets(dapm->card);
+ if (ret < 0)
+ return ret;
+
+ /* Add Jack Pin switch Kcontrol */
+ ret = create_fill_jack_kcontrols(dapm->card, edev);
+
+ if (ret < 0)
+ return ret;
+
+ /* default set the Jack Pin switch to OFF */
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ for (j = 0; j < pin->num_ports; j++)
+ snd_soc_dapm_disable_pin(pin->ports[j].dapm,
+ pin->ports[j].jack_pin);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hdac_hdmi_jack_port_init);
+
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
+ struct snd_soc_jack *jack)
{
- char jack_name[NAME_SIZE];
struct snd_soc_codec *codec = dai->codec;
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm =
- snd_soc_component_get_dapm(&codec->component);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm;
struct snd_pcm *snd_pcm;
@@ -1437,7 +1705,10 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
return -ENOMEM;
pcm->pcm_id = device;
pcm->cvt = hdmi->dai_map[dai->id].cvt;
-
+ pcm->jack_event = 0;
+ pcm->jack = jack;
+ mutex_init(&pcm->lock);
+ INIT_LIST_HEAD(&pcm->port_list);
snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
if (snd_pcm) {
err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
@@ -1452,20 +1723,40 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
list_add_tail(&pcm->head, &hdmi->pcm_list);
- sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device);
-
- return snd_jack_new(dapm->card->snd_card, jack_name,
- SND_JACK_AVOUT, &pcm->jack, true, false);
+ return 0;
}
EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
+static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
+ struct hdac_hdmi_priv *hdmi, bool detect_pin_caps)
+{
+ int i;
+ struct hdac_hdmi_pin *pin;
+
+ list_for_each_entry(pin, &hdmi->pin_list, head) {
+ if (detect_pin_caps) {
+
+ if (hdac_hdmi_get_port_len(edev, pin->nid) == 0)
+ pin->mst_capable = false;
+ else
+ pin->mst_capable = true;
+ }
+
+ for (i = 0; i < pin->num_ports; i++) {
+ if (!pin->mst_capable && i > 0)
+ continue;
+
+ hdac_hdmi_present_sense(pin, &pin->ports[i]);
+ }
+ }
+}
+
static int hdmi_codec_probe(struct snd_soc_codec *codec)
{
struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(&codec->component);
- struct hdac_hdmi_pin *pin;
struct hdac_ext_link *hlink = NULL;
int ret;
@@ -1495,9 +1786,7 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec)
return ret;
}
- list_for_each_entry(pin, &hdmi->pin_list, head)
- hdac_hdmi_present_sense(pin, 1);
-
+ hdac_hdmi_present_sense_all_pins(edev, hdmi, true);
/* Imp: Store the card pointer in hda_codec */
edev->card = dapm->card->snd_card;
@@ -1545,7 +1834,6 @@ static void hdmi_codec_complete(struct device *dev)
{
struct hdac_ext_device *edev = to_hda_ext_device(dev);
struct hdac_hdmi_priv *hdmi = edev->private_data;
- struct hdac_hdmi_pin *pin;
struct hdac_device *hdac = &edev->hdac;
/* Power up afg */
@@ -1558,10 +1846,10 @@ static void hdmi_codec_complete(struct device *dev)
/*
* As the ELD notify callback request is not entertained while the
* device is in suspend state. Need to manually check detection of
- * all pins here.
+ * all pins here. pin capablity change is not support, so use the
+ * already set pin caps.
*/
- list_for_each_entry(pin, &hdmi->pin_list, head)
- hdac_hdmi_present_sense(pin, 1);
+ hdac_hdmi_present_sense_all_pins(edev, hdmi, false);
pm_runtime_put_sync(&edev->hdac.dev);
}
@@ -1582,13 +1870,8 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
- struct hdac_hdmi_pin *pin = pcm->pin;
-
- /* chmap is already set to 0 in caller */
- if (!pin)
- return;
- memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap));
+ memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap));
}
static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
@@ -1597,14 +1880,18 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
- struct hdac_hdmi_pin *pin = pcm->pin;
-
- mutex_lock(&pin->lock);
- pin->chmap_set = true;
- memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap));
- if (prepared)
- hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid);
- mutex_unlock(&pin->lock);
+ struct hdac_hdmi_port *port;
+
+ if (list_empty(&pcm->port_list))
+ return;
+
+ mutex_lock(&pcm->lock);
+ pcm->chmap_set = true;
+ memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap));
+ list_for_each_entry(port, &pcm->port_list, head)
+ if (prepared)
+ hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
+ mutex_unlock(&pcm->lock);
}
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
@@ -1612,9 +1899,11 @@ static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
- struct hdac_hdmi_pin *pin = pcm->pin;
- return pin ? true:false;
+ if (list_empty(&pcm->port_list))
+ return false;
+
+ return true;
}
static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
@@ -1622,12 +1911,20 @@ static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
struct hdac_ext_device *edev = to_ehdac_device(hdac);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
- struct hdac_hdmi_pin *pin = pcm->pin;
+ struct hdac_hdmi_port *port;
- if (!pin || !pin->eld.eld_valid)
+ if (list_empty(&pcm->port_list))
return 0;
- return pin->eld.info.spk_alloc;
+ port = list_first_entry(&pcm->port_list, struct hdac_hdmi_port, head);
+
+ if (!port)
+ return 0;
+
+ if (!port || !port->eld.eld_valid)
+ return 0;
+
+ return port->eld.info.spk_alloc;
}
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
@@ -1700,12 +1997,20 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
struct hdac_hdmi_pcm *pcm, *pcm_next;
+ struct hdac_hdmi_port *port, *port_next;
+ int i;
snd_soc_unregister_codec(&edev->hdac.dev);
list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) {
pcm->cvt = NULL;
- pcm->pin = NULL;
+ if (list_empty(&pcm->port_list))
+ continue;
+
+ list_for_each_entry_safe(port, port_next,
+ &pcm->port_list, head)
+ list_del(&port->head);
+
list_del(&pcm->head);
kfree(pcm);
}
@@ -1717,6 +2022,9 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
}
list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) {
+ for (i = 0; i < pin->num_ports; i++)
+ pin->ports[i].pin = NULL;
+ kfree(pin->ports);
list_del(&pin->head);
kfree(pin);
}
@@ -1819,6 +2127,7 @@ static const struct hda_device_id hdmi_list[] = {
HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0),
HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0),
+ HDA_CODEC_EXT_ENTRY(0x8086280d, 0x100000, "Geminilake HDMI", 0),
{}
};
diff --git a/sound/soc/codecs/hdac_hdmi.h b/sound/soc/codecs/hdac_hdmi.h
index 8dfd1e0b57b3..dfc3a9cf7199 100644
--- a/sound/soc/codecs/hdac_hdmi.h
+++ b/sound/soc/codecs/hdac_hdmi.h
@@ -1,6 +1,9 @@
#ifndef __HDAC_HDMI_H__
#define __HDAC_HDMI_H__
-int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm);
+int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int pcm,
+ struct snd_soc_jack *jack);
+int hdac_hdmi_jack_port_init(struct snd_soc_codec *codec,
+ struct snd_soc_dapm_context *dapm);
#endif /* __HDAC_HDMI_H__ */
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 90b5948e0ff3..8c5ae1fc23a9 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -18,6 +18,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/tlv.h>
#include <sound/pcm_drm_eld.h>
#include <sound/hdmi-codec.h>
#include <sound/pcm_iec958.h>
@@ -31,8 +32,261 @@ struct hdmi_device {
};
#define pos_to_hdmi_device(pos) container_of((pos), struct hdmi_device, list)
LIST_HEAD(hdmi_device_list);
+static DEFINE_MUTEX(hdmi_mutex);
#define DAI_NAME_SIZE 16
+
+#define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1
+
+struct hdmi_codec_channel_map_table {
+ unsigned char map; /* ALSA API channel map position */
+ unsigned long spk_mask; /* speaker position bit mask */
+};
+
+/*
+ * CEA speaker placement for HDMI 1.4:
+ *
+ * FL FLC FC FRC FR FRW
+ *
+ * LFE
+ *
+ * RL RLC RC RRC RR
+ *
+ * Speaker placement has to be extended to support HDMI 2.0
+ */
+enum hdmi_codec_cea_spk_placement {
+ FL = BIT(0), /* Front Left */
+ FC = BIT(1), /* Front Center */
+ FR = BIT(2), /* Front Right */
+ FLC = BIT(3), /* Front Left Center */
+ FRC = BIT(4), /* Front Right Center */
+ RL = BIT(5), /* Rear Left */
+ RC = BIT(6), /* Rear Center */
+ RR = BIT(7), /* Rear Right */
+ RLC = BIT(8), /* Rear Left Center */
+ RRC = BIT(9), /* Rear Right Center */
+ LFE = BIT(10), /* Low Frequency Effect */
+};
+
+/*
+ * cea Speaker allocation structure
+ */
+struct hdmi_codec_cea_spk_alloc {
+ const int ca_id;
+ unsigned int n_ch;
+ unsigned long mask;
+};
+
+/* Channel maps stereo HDMI */
+const struct snd_pcm_chmap_elem hdmi_codec_stereo_chmaps[] = {
+ { .channels = 2,
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { }
+};
+
+/* Channel maps for multi-channel playbacks, up to 8 n_ch */
+const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = {
+ { .channels = 2, /* CA_ID 0x00 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+ { .channels = 4, /* CA_ID 0x01 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA } },
+ { .channels = 4, /* CA_ID 0x02 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC } },
+ { .channels = 4, /* CA_ID 0x03 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC } },
+ { .channels = 6, /* CA_ID 0x04 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 6, /* CA_ID 0x05 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 6, /* CA_ID 0x06 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 6, /* CA_ID 0x07 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 6, /* CA_ID 0x08 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6, /* CA_ID 0x09 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6, /* CA_ID 0x0A */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 6, /* CA_ID 0x0B */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+ { .channels = 8, /* CA_ID 0x0C */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 8, /* CA_ID 0x0D */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 8, /* CA_ID 0x0E */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 8, /* CA_ID 0x0F */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RC, SNDRV_CHMAP_NA } },
+ { .channels = 8, /* CA_ID 0x10 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+ { .channels = 8, /* CA_ID 0x11 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+ { .channels = 8, /* CA_ID 0x12 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+ { .channels = 8, /* CA_ID 0x13 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
+ SNDRV_CHMAP_RLC, SNDRV_CHMAP_RRC } },
+ { .channels = 8, /* CA_ID 0x14 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x15 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x16 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x17 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x18 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x19 */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x1A */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x1B */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x1C */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x1D */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_NA, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x1E */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { .channels = 8, /* CA_ID 0x1F */
+ .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, SNDRV_CHMAP_LFE,
+ SNDRV_CHMAP_FC, SNDRV_CHMAP_NA, SNDRV_CHMAP_NA,
+ SNDRV_CHMAP_FLC, SNDRV_CHMAP_FRC } },
+ { }
+};
+
+/*
+ * hdmi_codec_channel_alloc: speaker configuration available for CEA
+ *
+ * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct
+ * The preceding ones have better chances to be selected by
+ * hdmi_codec_get_ch_alloc_table_idx().
+ */
+static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
+ { .ca_id = 0x00, .n_ch = 2,
+ .mask = FL | FR},
+ /* 2.1 */
+ { .ca_id = 0x01, .n_ch = 4,
+ .mask = FL | FR | LFE},
+ /* Dolby Surround */
+ { .ca_id = 0x02, .n_ch = 4,
+ .mask = FL | FR | FC },
+ /* surround51 */
+ { .ca_id = 0x0b, .n_ch = 6,
+ .mask = FL | FR | LFE | FC | RL | RR},
+ /* surround40 */
+ { .ca_id = 0x08, .n_ch = 6,
+ .mask = FL | FR | RL | RR },
+ /* surround41 */
+ { .ca_id = 0x09, .n_ch = 6,
+ .mask = FL | FR | LFE | RL | RR },
+ /* surround50 */
+ { .ca_id = 0x0a, .n_ch = 6,
+ .mask = FL | FR | FC | RL | RR },
+ /* 6.1 */
+ { .ca_id = 0x0f, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | RC },
+ /* surround71 */
+ { .ca_id = 0x13, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
+ /* others */
+ { .ca_id = 0x03, .n_ch = 8,
+ .mask = FL | FR | LFE | FC },
+ { .ca_id = 0x04, .n_ch = 8,
+ .mask = FL | FR | RC},
+ { .ca_id = 0x05, .n_ch = 8,
+ .mask = FL | FR | LFE | RC },
+ { .ca_id = 0x06, .n_ch = 8,
+ .mask = FL | FR | FC | RC },
+ { .ca_id = 0x07, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RC },
+ { .ca_id = 0x0c, .n_ch = 8,
+ .mask = FL | FR | RC | RL | RR },
+ { .ca_id = 0x0d, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | RC },
+ { .ca_id = 0x0e, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR | RC },
+ { .ca_id = 0x10, .n_ch = 8,
+ .mask = FL | FR | RL | RR | RLC | RRC },
+ { .ca_id = 0x11, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | RLC | RRC },
+ { .ca_id = 0x12, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR | RLC | RRC },
+ { .ca_id = 0x14, .n_ch = 8,
+ .mask = FL | FR | FLC | FRC },
+ { .ca_id = 0x15, .n_ch = 8,
+ .mask = FL | FR | LFE | FLC | FRC },
+ { .ca_id = 0x16, .n_ch = 8,
+ .mask = FL | FR | FC | FLC | FRC },
+ { .ca_id = 0x17, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | FLC | FRC },
+ { .ca_id = 0x18, .n_ch = 8,
+ .mask = FL | FR | RC | FLC | FRC },
+ { .ca_id = 0x19, .n_ch = 8,
+ .mask = FL | FR | LFE | RC | FLC | FRC },
+ { .ca_id = 0x1a, .n_ch = 8,
+ .mask = FL | FR | RC | FC | FLC | FRC },
+ { .ca_id = 0x1b, .n_ch = 8,
+ .mask = FL | FR | LFE | RC | FC | FLC | FRC },
+ { .ca_id = 0x1c, .n_ch = 8,
+ .mask = FL | FR | RL | RR | FLC | FRC },
+ { .ca_id = 0x1d, .n_ch = 8,
+ .mask = FL | FR | LFE | RL | RR | FLC | FRC },
+ { .ca_id = 0x1e, .n_ch = 8,
+ .mask = FL | FR | FC | RL | RR | FLC | FRC },
+ { .ca_id = 0x1f, .n_ch = 8,
+ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
+};
+
struct hdmi_codec_priv {
struct hdmi_codec_pdata hcd;
struct snd_soc_dai_driver *daidrv;
@@ -41,6 +295,8 @@ struct hdmi_codec_priv {
struct snd_pcm_substream *current_stream;
struct snd_pcm_hw_constraint_list ratec;
uint8_t eld[MAX_ELD_BYTES];
+ struct snd_pcm_chmap *chmap_info;
+ unsigned int chmap_idx;
};
static const struct snd_soc_dapm_widget hdmi_widgets[] = {
@@ -79,6 +335,83 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
return 0;
}
+static unsigned long hdmi_codec_spk_mask_from_alloc(int spk_alloc)
+{
+ int i;
+ const unsigned long hdmi_codec_eld_spk_alloc_bits[] = {
+ [0] = FL | FR, [1] = LFE, [2] = FC, [3] = RL | RR,
+ [4] = RC, [5] = FLC | FRC, [6] = RLC | RRC,
+ };
+ unsigned long spk_mask = 0;
+
+ for (i = 0; i < ARRAY_SIZE(hdmi_codec_eld_spk_alloc_bits); i++) {
+ if (spk_alloc & (1 << i))
+ spk_mask |= hdmi_codec_eld_spk_alloc_bits[i];
+ }
+
+ return spk_mask;
+}
+
+void hdmi_codec_eld_chmap(struct hdmi_codec_priv *hcp)
+{
+ u8 spk_alloc;
+ unsigned long spk_mask;
+
+ spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
+ spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
+
+ /* Detect if only stereo supported, else return 8 channels mappings */
+ if ((spk_mask & ~(FL | FR)) && hcp->chmap_info->max_channels > 2)
+ hcp->chmap_info->chmap = hdmi_codec_8ch_chmaps;
+ else
+ hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
+}
+
+static int hdmi_codec_get_ch_alloc_table_idx(struct hdmi_codec_priv *hcp,
+ unsigned char channels)
+{
+ int i;
+ u8 spk_alloc;
+ unsigned long spk_mask;
+ const struct hdmi_codec_cea_spk_alloc *cap = hdmi_codec_channel_alloc;
+
+ spk_alloc = drm_eld_get_spk_alloc(hcp->eld);
+ spk_mask = hdmi_codec_spk_mask_from_alloc(spk_alloc);
+
+ for (i = 0; i < ARRAY_SIZE(hdmi_codec_channel_alloc); i++, cap++) {
+ /* If spk_alloc == 0, HDMI is unplugged return stereo config*/
+ if (!spk_alloc && cap->ca_id == 0)
+ return i;
+ if (cap->n_ch != channels)
+ continue;
+ if (!(cap->mask == (spk_mask & cap->mask)))
+ continue;
+ return i;
+ }
+
+ return -EINVAL;
+}
+static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned const char *map;
+ unsigned int i;
+ struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+ struct hdmi_codec_priv *hcp = info->private_data;
+
+ map = info->chmap[hcp->chmap_idx].map;
+
+ for (i = 0; i < info->max_channels; i++) {
+ if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN)
+ ucontrol->value.integer.value[i] = 0;
+ else
+ ucontrol->value.integer.value[i] = map[i];
+ }
+
+ return 0;
+}
+
+
static const struct snd_kcontrol_new hdmi_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READ |
@@ -140,6 +473,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (ret)
return ret;
}
+ /* Select chmap supported */
+ hdmi_codec_eld_chmap(hcp);
}
return 0;
}
@@ -153,6 +488,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
WARN_ON(hcp->current_stream != substream);
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
mutex_lock(&hcp->current_stream_lock);
@@ -173,7 +509,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
.dig_subframe = { 0 },
}
};
- int ret;
+ int ret, idx;
dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__,
params_width(params), params_rate(params),
@@ -200,6 +536,17 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream,
hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM;
hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM;
+ /* Select a channel allocation that matches with ELD and pcm channels */
+ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels);
+ if (idx < 0) {
+ dev_err(dai->dev, "Not able to map channels to speakers (%d)\n",
+ idx);
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+ return idx;
+ }
+ hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id;
+ hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id;
+
hp.sample_width = params_width(params);
hp.sample_rate = params_rate(params);
hp.channels = params_channels(params);
@@ -328,6 +675,32 @@ static const struct snd_soc_dai_ops hdmi_dai_ops = {
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE)
+static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_dai_driver *drv = dai->driver;
+ struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ dev_dbg(dai->dev, "%s()\n", __func__);
+
+ ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, drv->playback.channels_max, 0,
+ &hcp->chmap_info);
+ if (ret < 0)
+ return ret;
+
+ /* override handlers */
+ hcp->chmap_info->private_data = hcp;
+ hcp->chmap_info->kctl->get = hdmi_codec_chmap_ctl_get;
+
+ /* default chmap supported is stereo */
+ hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps;
+ hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
+
+ return 0;
+}
+
static struct snd_soc_dai_driver hdmi_i2s_dai = {
.id = DAI_ID_I2S,
.playback = {
@@ -339,6 +712,7 @@ static struct snd_soc_dai_driver hdmi_i2s_dai = {
.sig_bits = 24,
},
.ops = &hdmi_dai_ops,
+ .pcm_new = hdmi_codec_pcm_new,
};
static const struct snd_soc_dai_driver hdmi_spdif_dai = {
@@ -351,6 +725,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.formats = SPDIF_FORMATS,
},
.ops = &hdmi_dai_ops,
+ .pcm_new = hdmi_codec_pcm_new,
};
static char hdmi_dai_name[][DAI_NAME_SIZE] = {
@@ -420,6 +795,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
return -ENOMEM;
hd = NULL;
+ mutex_lock(&hdmi_mutex);
list_for_each(pos, &hdmi_device_list) {
struct hdmi_device *tmp = pos_to_hdmi_device(pos);
@@ -431,13 +807,16 @@ static int hdmi_codec_probe(struct platform_device *pdev)
if (!hd) {
hd = devm_kzalloc(dev, sizeof(*hd), GFP_KERNEL);
- if (!hd)
+ if (!hd) {
+ mutex_unlock(&hdmi_mutex);
return -ENOMEM;
+ }
hd->dev = dev->parent;
list_add_tail(&hd->list, &hdmi_device_list);
}
+ mutex_unlock(&hdmi_mutex);
if (hd->cnt >= ARRAY_SIZE(hdmi_dai_name)) {
dev_err(dev, "too many hdmi codec are deteced\n");
@@ -479,7 +858,25 @@ static int hdmi_codec_probe(struct platform_device *pdev)
static int hdmi_codec_remove(struct platform_device *pdev)
{
- snd_soc_unregister_codec(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct list_head *pos;
+ struct hdmi_codec_priv *hcp;
+
+ mutex_lock(&hdmi_mutex);
+ list_for_each(pos, &hdmi_device_list) {
+ struct hdmi_device *tmp = pos_to_hdmi_device(pos);
+
+ if (tmp->dev == dev->parent) {
+ list_del(pos);
+ break;
+ }
+ }
+ mutex_unlock(&hdmi_mutex);
+
+ hcp = dev_get_drvdata(dev);
+ kfree(hcp->chmap_info);
+ snd_soc_unregister_codec(dev);
+
return 0;
}
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 584aab83e478..66828480d484 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2456,7 +2456,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
if (err) {
micbias = M98090_MBVSEL_2V8;
dev_info(codec->dev, "use default 2.8v micbias\n");
- } else if (micbias < M98090_MBVSEL_2V2 || micbias > M98090_MBVSEL_2V8) {
+ } else if (micbias > M98090_MBVSEL_2V8) {
dev_err(codec->dev, "micbias out of range 0x%x\n", micbias);
micbias = M98090_MBVSEL_2V8;
}
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c
index 42e2e407e287..0247edc9c84e 100644
--- a/sound/soc/codecs/max9867.c
+++ b/sound/soc/codecs/max9867.c
@@ -309,7 +309,6 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec;
struct max9867_priv *max9867 = snd_soc_codec_get_drvdata(codec);
u8 iface1A = 0, iface1B = 0;
- int ret;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
@@ -346,8 +345,8 @@ static int max9867_dai_set_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
- ret = regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
- ret = regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
+ regmap_write(max9867->regmap, MAX9867_IFC1A, iface1A);
+ regmap_write(max9867->regmap, MAX9867_IFC1B, iface1B);
return 0;
}
@@ -517,13 +516,13 @@ static const struct i2c_device_id max9867_i2c_id[] = {
{ "max9867", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, max9867_i2c_id);
static const struct of_device_id max9867_of_match[] = {
{ .compatible = "maxim,max9867", },
{ }
};
-
-MODULE_DEVICE_TABLE(i2c, max9867_i2c_id);
+MODULE_DEVICE_TABLE(of, max9867_of_match);
static const struct dev_pm_ops max9867_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max9867_suspend, max9867_resume)
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
new file mode 100644
index 000000000000..b5ee29499e16
--- /dev/null
+++ b/sound/soc/codecs/max98927.c
@@ -0,0 +1,841 @@
+/*
+ * max98927.c -- MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2016 Maxim Integrated Products
+ * Author: Ryan Lee <ryans.lee@maximintegrated.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/cdev.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/tlv.h>
+#include "max98927.h"
+
+static struct reg_default max98927_reg[] = {
+ {MAX98927_R0001_INT_RAW1, 0x00},
+ {MAX98927_R0002_INT_RAW2, 0x00},
+ {MAX98927_R0003_INT_RAW3, 0x00},
+ {MAX98927_R0004_INT_STATE1, 0x00},
+ {MAX98927_R0005_INT_STATE2, 0x00},
+ {MAX98927_R0006_INT_STATE3, 0x00},
+ {MAX98927_R0007_INT_FLAG1, 0x00},
+ {MAX98927_R0008_INT_FLAG2, 0x00},
+ {MAX98927_R0009_INT_FLAG3, 0x00},
+ {MAX98927_R000A_INT_EN1, 0x00},
+ {MAX98927_R000B_INT_EN2, 0x00},
+ {MAX98927_R000C_INT_EN3, 0x00},
+ {MAX98927_R000D_INT_FLAG_CLR1, 0x00},
+ {MAX98927_R000E_INT_FLAG_CLR2, 0x00},
+ {MAX98927_R000F_INT_FLAG_CLR3, 0x00},
+ {MAX98927_R0010_IRQ_CTRL, 0x00},
+ {MAX98927_R0011_CLK_MON, 0x00},
+ {MAX98927_R0012_WDOG_CTRL, 0x00},
+ {MAX98927_R0013_WDOG_RST, 0x00},
+ {MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH, 0x00},
+ {MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH, 0x00},
+ {MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS, 0x00},
+ {MAX98927_R0017_PIN_CFG, 0x55},
+ {MAX98927_R0018_PCM_RX_EN_A, 0x00},
+ {MAX98927_R0019_PCM_RX_EN_B, 0x00},
+ {MAX98927_R001A_PCM_TX_EN_A, 0x00},
+ {MAX98927_R001B_PCM_TX_EN_B, 0x00},
+ {MAX98927_R001C_PCM_TX_HIZ_CTRL_A, 0x00},
+ {MAX98927_R001D_PCM_TX_HIZ_CTRL_B, 0x00},
+ {MAX98927_R001E_PCM_TX_CH_SRC_A, 0x00},
+ {MAX98927_R001F_PCM_TX_CH_SRC_B, 0x00},
+ {MAX98927_R0020_PCM_MODE_CFG, 0x40},
+ {MAX98927_R0021_PCM_MASTER_MODE, 0x00},
+ {MAX98927_R0022_PCM_CLK_SETUP, 0x22},
+ {MAX98927_R0023_PCM_SR_SETUP1, 0x00},
+ {MAX98927_R0024_PCM_SR_SETUP2, 0x00},
+ {MAX98927_R0025_PCM_TO_SPK_MONOMIX_A, 0x00},
+ {MAX98927_R0026_PCM_TO_SPK_MONOMIX_B, 0x00},
+ {MAX98927_R0027_ICC_RX_EN_A, 0x00},
+ {MAX98927_R0028_ICC_RX_EN_B, 0x00},
+ {MAX98927_R002B_ICC_TX_EN_A, 0x00},
+ {MAX98927_R002C_ICC_TX_EN_B, 0x00},
+ {MAX98927_R002E_ICC_HIZ_MANUAL_MODE, 0x00},
+ {MAX98927_R002F_ICC_TX_HIZ_EN_A, 0x00},
+ {MAX98927_R0030_ICC_TX_HIZ_EN_B, 0x00},
+ {MAX98927_R0031_ICC_LNK_EN, 0x00},
+ {MAX98927_R0032_PDM_TX_EN, 0x00},
+ {MAX98927_R0033_PDM_TX_HIZ_CTRL, 0x00},
+ {MAX98927_R0034_PDM_TX_CTRL, 0x00},
+ {MAX98927_R0035_PDM_RX_CTRL, 0x00},
+ {MAX98927_R0036_AMP_VOL_CTRL, 0x00},
+ {MAX98927_R0037_AMP_DSP_CFG, 0x02},
+ {MAX98927_R0038_TONE_GEN_DC_CFG, 0x00},
+ {MAX98927_R0039_DRE_CTRL, 0x01},
+ {MAX98927_R003A_AMP_EN, 0x00},
+ {MAX98927_R003B_SPK_SRC_SEL, 0x00},
+ {MAX98927_R003C_SPK_GAIN, 0x00},
+ {MAX98927_R003D_SSM_CFG, 0x01},
+ {MAX98927_R003E_MEAS_EN, 0x00},
+ {MAX98927_R003F_MEAS_DSP_CFG, 0x04},
+ {MAX98927_R0040_BOOST_CTRL0, 0x00},
+ {MAX98927_R0041_BOOST_CTRL3, 0x00},
+ {MAX98927_R0042_BOOST_CTRL1, 0x00},
+ {MAX98927_R0043_MEAS_ADC_CFG, 0x00},
+ {MAX98927_R0044_MEAS_ADC_BASE_MSB, 0x00},
+ {MAX98927_R0045_MEAS_ADC_BASE_LSB, 0x00},
+ {MAX98927_R0046_ADC_CH0_DIVIDE, 0x00},
+ {MAX98927_R0047_ADC_CH1_DIVIDE, 0x00},
+ {MAX98927_R0048_ADC_CH2_DIVIDE, 0x00},
+ {MAX98927_R0049_ADC_CH0_FILT_CFG, 0x00},
+ {MAX98927_R004A_ADC_CH1_FILT_CFG, 0x00},
+ {MAX98927_R004B_ADC_CH2_FILT_CFG, 0x00},
+ {MAX98927_R004C_MEAS_ADC_CH0_READ, 0x00},
+ {MAX98927_R004D_MEAS_ADC_CH1_READ, 0x00},
+ {MAX98927_R004E_MEAS_ADC_CH2_READ, 0x00},
+ {MAX98927_R0051_BROWNOUT_STATUS, 0x00},
+ {MAX98927_R0052_BROWNOUT_EN, 0x00},
+ {MAX98927_R0053_BROWNOUT_INFINITE_HOLD, 0x00},
+ {MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR, 0x00},
+ {MAX98927_R0055_BROWNOUT_LVL_HOLD, 0x00},
+ {MAX98927_R005A_BROWNOUT_LVL1_THRESH, 0x00},
+ {MAX98927_R005B_BROWNOUT_LVL2_THRESH, 0x00},
+ {MAX98927_R005C_BROWNOUT_LVL3_THRESH, 0x00},
+ {MAX98927_R005D_BROWNOUT_LVL4_THRESH, 0x00},
+ {MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS, 0x00},
+ {MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL, 0x00},
+ {MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL, 0x00},
+ {MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE, 0x00},
+ {MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT, 0x00},
+ {MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1, 0x00},
+ {MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2, 0x00},
+ {MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3, 0x00},
+ {MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT, 0x00},
+ {MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1, 0x00},
+ {MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2, 0x00},
+ {MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3, 0x00},
+ {MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT, 0x00},
+ {MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1, 0x00},
+ {MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2, 0x00},
+ {MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3, 0x00},
+ {MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT, 0x00},
+ {MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1, 0x00},
+ {MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2, 0x00},
+ {MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3, 0x00},
+ {MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM, 0x00},
+ {MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY, 0x00},
+ {MAX98927_R0084_ENV_TRACK_REL_RATE, 0x00},
+ {MAX98927_R0085_ENV_TRACK_HOLD_RATE, 0x00},
+ {MAX98927_R0086_ENV_TRACK_CTRL, 0x00},
+ {MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ, 0x00},
+ {MAX98927_R00FF_GLOBAL_SHDN, 0x00},
+ {MAX98927_R0100_SOFT_RESET, 0x00},
+ {MAX98927_R01FF_REV_ID, 0x40},
+};
+
+static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+ unsigned int mode = 0;
+ unsigned int format = 0;
+ unsigned int invert = 0;
+
+ dev_dbg(codec->dev, "%s: fmt 0x%08X\n", __func__, fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ mode = MAX98927_PCM_MASTER_MODE_SLAVE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ max98927->master = true;
+ mode = MAX98927_PCM_MASTER_MODE_MASTER;
+ break;
+ default:
+ dev_err(codec->dev, "DAI clock mode unsupported");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MASK,
+ mode);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ invert = MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE;
+ break;
+ default:
+ dev_err(codec->dev, "DAI invert mode unsupported");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE,
+ invert);
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ max98927->iface |= SND_SOC_DAIFMT_I2S;
+ format = MAX98927_PCM_FORMAT_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ max98927->iface |= SND_SOC_DAIFMT_LEFT_J;
+ format = MAX98927_PCM_FORMAT_LJ;
+ break;
+ case SND_SOC_DAIFMT_PDM:
+ max98927->iface |= SND_SOC_DAIFMT_PDM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* pcm channel configuration */
+ if (max98927->iface & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN);
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_FORMAT_MASK,
+ format << MAX98927_PCM_MODE_CFG_FORMAT_SHIFT);
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 0);
+
+ } else
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0018_PCM_RX_EN_A,
+ MAX98927_PCM_RX_CH0_EN | MAX98927_PCM_RX_CH1_EN, 0);
+
+ /* pdm channel configuration */
+ if (max98927->iface & SND_SOC_DAIFMT_PDM) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 1);
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003B_SPK_SRC_SEL,
+ MAX98927_SPK_SRC_MASK, 3);
+ } else
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0035_PDM_RX_CTRL,
+ MAX98927_PDM_RX_EN_MASK, 0);
+ return 0;
+}
+
+/* codec MCLK rate in master mode */
+static const int rate_table[] = {
+ 5644800, 6000000, 6144000, 6500000,
+ 9600000, 11289600, 12000000, 12288000,
+ 13000000, 19200000,
+};
+
+static int max98927_set_clock(struct max98927_priv *max98927,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_codec *codec = max98927->codec;
+ /* BCLK/LRCLK ratio calculation */
+ int blr_clk_ratio = params_channels(params) * max98927->ch_size;
+ int value;
+
+ if (max98927->master) {
+ int i;
+ /* match rate to closest value */
+ for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+ if (rate_table[i] >= max98927->sysclk)
+ break;
+ }
+ if (i == ARRAY_SIZE(rate_table)) {
+ dev_err(codec->dev, "failed to find proper clock rate.\n");
+ return -EINVAL;
+ }
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0021_PCM_MASTER_MODE,
+ MAX98927_PCM_MASTER_MODE_MCLK_MASK,
+ i << MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT);
+ }
+
+ switch (blr_clk_ratio) {
+ case 32:
+ value = 2;
+ break;
+ case 48:
+ value = 3;
+ break;
+ case 64:
+ value = 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0022_PCM_CLK_SETUP,
+ MAX98927_PCM_CLK_SETUP_BSEL_MASK,
+ value);
+ return 0;
+}
+
+static int max98927_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+ unsigned int sampling_rate = 0;
+ unsigned int chan_sz = 0;
+
+ /* pcm mode configuration */
+ switch (snd_pcm_format_width(params_format(params))) {
+ case 16:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_16;
+ break;
+ case 24:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_24;
+ break;
+ case 32:
+ chan_sz = MAX98927_PCM_MODE_CFG_CHANSZ_32;
+ break;
+ default:
+ dev_err(codec->dev, "format unsupported %d",
+ params_format(params));
+ goto err;
+ }
+
+ max98927->ch_size = snd_pcm_format_width(params_format(params));
+
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0020_PCM_MODE_CFG,
+ MAX98927_PCM_MODE_CFG_CHANSZ_MASK, chan_sz);
+
+ dev_dbg(codec->dev, "format supported %d",
+ params_format(params));
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 8000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_8000;
+ break;
+ case 11025:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_11025;
+ break;
+ case 12000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_12000;
+ break;
+ case 16000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_16000;
+ break;
+ case 22050:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_22050;
+ break;
+ case 24000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_24000;
+ break;
+ case 32000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_32000;
+ break;
+ case 44100:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_44100;
+ break;
+ case 48000:
+ sampling_rate = MAX98927_PCM_SR_SET1_SR_48000;
+ break;
+ default:
+ dev_err(codec->dev, "rate %d not supported\n",
+ params_rate(params));
+ goto err;
+ }
+ /* set DAI_SR to correct LRCLK frequency */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0023_PCM_SR_SETUP1,
+ MAX98927_PCM_SR_SET1_SR_MASK,
+ sampling_rate);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_SR_MASK,
+ sampling_rate << MAX98927_PCM_SR_SET2_SR_SHIFT);
+
+ /* set sampling rate of IV */
+ if (max98927->interleave_mode &&
+ sampling_rate > MAX98927_PCM_SR_SET1_SR_16000)
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate - 3);
+ else
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R0024_PCM_SR_SETUP2,
+ MAX98927_PCM_SR_SET2_IVADC_SR_MASK,
+ sampling_rate);
+ return max98927_set_clock(max98927, params);
+err:
+ return -EINVAL;
+}
+
+#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000
+
+#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int max98927_dai_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+ max98927->sysclk = freq;
+ return 0;
+}
+
+static const struct snd_soc_dai_ops max98927_dai_ops = {
+ .set_sysclk = max98927_dai_set_sysclk,
+ .set_fmt = max98927_dai_set_fmt,
+ .hw_params = max98927_dai_hw_params,
+};
+
+static int max98927_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 1);
+ /* enable VMON and IMON */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003E_MEAS_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R00FF_GLOBAL_SHDN,
+ MAX98927_GLOBAL_EN_MASK, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003A_AMP_EN,
+ MAX98927_AMP_EN_MASK, 0);
+ /* disable VMON and IMON */
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R003E_MEAS_EN,
+ MAX98927_MEAS_V_EN | MAX98927_MEAS_I_EN, 0);
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static const char * const max98927_switch_text[] = {
+ "Left", "Right", "LeftRight"};
+
+static const struct soc_enum dai_sel_enum =
+ SOC_ENUM_SINGLE(MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT,
+ 3, max98927_switch_text);
+
+static const struct snd_kcontrol_new max98927_dai_controls =
+ SOC_DAPM_ENUM("DAI Sel", dai_sel_enum);
+
+static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("DAI_OUT", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC_E("Amp Enable", "HiFi Playback", MAX98927_R003A_AMP_EN,
+ 0, 0, max98927_dac_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("DAI Sel Mux", SND_SOC_NOPM, 0, 0,
+ &max98927_dai_controls),
+ SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0);
+static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0);
+
+static bool max98927_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98927_R0001_INT_RAW1 ... MAX98927_R0028_ICC_RX_EN_B:
+ case MAX98927_R002B_ICC_TX_EN_A ... MAX98927_R002C_ICC_TX_EN_B:
+ case MAX98927_R002E_ICC_HIZ_MANUAL_MODE
+ ... MAX98927_R004E_MEAS_ADC_CH2_READ:
+ case MAX98927_R0051_BROWNOUT_STATUS
+ ... MAX98927_R0055_BROWNOUT_LVL_HOLD:
+ case MAX98927_R005A_BROWNOUT_LVL1_THRESH
+ ... MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE:
+ case MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT
+ ... MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ:
+ case MAX98927_R00FF_GLOBAL_SHDN:
+ case MAX98927_R0100_SOFT_RESET:
+ case MAX98927_R01FF_REV_ID:
+ return true;
+ default:
+ return false;
+ }
+};
+
+static bool max98927_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX98927_R0001_INT_RAW1 ... MAX98927_R0009_INT_FLAG3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char * const max98927_boost_voltage_text[] = {
+ "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V",
+ "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V",
+ "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V",
+ "9.5V", "9.625V", "9.75V", "9.875V", "10V"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_boost_voltage,
+ MAX98927_R0040_BOOST_CTRL0, 0,
+ max98927_boost_voltage_text);
+
+static const char * const max98927_current_limit_text[] = {
+ "1.00A", "1.10A", "1.20A", "1.30A", "1.40A", "1.50A", "1.60A", "1.70A",
+ "1.80A", "1.90A", "2.00A", "2.10A", "2.20A", "2.30A", "2.40A", "2.50A",
+ "2.60A", "2.70A", "2.80A", "2.90A", "3.00A", "3.10A", "3.20A", "3.30A",
+ "3.40A", "3.50A", "3.60A", "3.70A", "3.80A", "3.90A", "4.00A", "4.10A"
+};
+
+static SOC_ENUM_SINGLE_DECL(max98927_current_limit,
+ MAX98927_R0042_BOOST_CTRL1, 1,
+ max98927_current_limit_text);
+
+static const struct snd_kcontrol_new max98927_snd_controls[] = {
+ SOC_SINGLE_TLV("Speaker Volume", MAX98927_R003C_SPK_GAIN,
+ 0, 6, 0,
+ max98927_spk_tlv),
+ SOC_SINGLE_TLV("Digital Volume", MAX98927_R0036_AMP_VOL_CTRL,
+ 0, (1<<MAX98927_AMP_VOL_WIDTH)-1, 0,
+ max98927_digital_tlv),
+ SOC_SINGLE("Amp DSP Switch", MAX98927_R0052_BROWNOUT_EN,
+ MAX98927_BROWNOUT_DSP_SHIFT, 1, 0),
+ SOC_SINGLE("Ramp Switch", MAX98927_R0037_AMP_DSP_CFG,
+ MAX98927_AMP_DSP_CFG_RMP_SHIFT, 1, 0),
+ SOC_SINGLE("DRE Switch", MAX98927_R0039_DRE_CTRL,
+ MAX98927_DRE_EN_SHIFT, 1, 0),
+ SOC_SINGLE("Volume Location Switch", MAX98927_R0036_AMP_VOL_CTRL,
+ MAX98927_AMP_VOL_SEL_SHIFT, 1, 0),
+ SOC_ENUM("Boost Output Voltage", max98927_boost_voltage),
+ SOC_ENUM("Current Limit", max98927_current_limit),
+};
+
+static const struct snd_soc_dapm_route max98927_audio_map[] = {
+ {"Amp Enable", NULL, "DAI_OUT"},
+ {"DAI Sel Mux", "Left", "Amp Enable"},
+ {"DAI Sel Mux", "Right", "Amp Enable"},
+ {"DAI Sel Mux", "LeftRight", "Amp Enable"},
+ {"BE_OUT", NULL, "DAI Sel Mux"},
+};
+
+static struct snd_soc_dai_driver max98927_dai[] = {
+ {
+ .name = "max98927-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98927_RATES,
+ .formats = MAX98927_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MAX98927_RATES,
+ .formats = MAX98927_FORMATS,
+ },
+ .ops = &max98927_dai_ops,
+ }
+};
+
+static int max98927_probe(struct snd_soc_codec *codec)
+{
+ struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec);
+
+ max98927->codec = codec;
+ codec->control_data = max98927->regmap;
+ codec->cache_bypass = 1;
+
+ /* Software Reset */
+ regmap_write(max98927->regmap,
+ MAX98927_R0100_SOFT_RESET, MAX98927_SOFT_RESET);
+
+ /* IV default slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 0xFF);
+ regmap_write(max98927->regmap,
+ MAX98927_R0025_PCM_TO_SPK_MONOMIX_A,
+ 0x80);
+ regmap_write(max98927->regmap,
+ MAX98927_R0026_PCM_TO_SPK_MONOMIX_B,
+ 0x1);
+ /* Set inital volume (+13dB) */
+ regmap_write(max98927->regmap,
+ MAX98927_R0036_AMP_VOL_CTRL,
+ 0x38);
+ regmap_write(max98927->regmap,
+ MAX98927_R003C_SPK_GAIN,
+ 0x05);
+ /* Enable DC blocker */
+ regmap_write(max98927->regmap,
+ MAX98927_R0037_AMP_DSP_CFG,
+ 0x03);
+ /* Enable IMON VMON DC blocker */
+ regmap_write(max98927->regmap,
+ MAX98927_R003F_MEAS_DSP_CFG,
+ 0xF7);
+ /* Boost Output Voltage & Current limit */
+ regmap_write(max98927->regmap,
+ MAX98927_R0040_BOOST_CTRL0,
+ 0x1C);
+ regmap_write(max98927->regmap,
+ MAX98927_R0042_BOOST_CTRL1,
+ 0x3E);
+ /* Measurement ADC config */
+ regmap_write(max98927->regmap,
+ MAX98927_R0043_MEAS_ADC_CFG,
+ 0x04);
+ regmap_write(max98927->regmap,
+ MAX98927_R0044_MEAS_ADC_BASE_MSB,
+ 0x00);
+ regmap_write(max98927->regmap,
+ MAX98927_R0045_MEAS_ADC_BASE_LSB,
+ 0x24);
+ /* Brownout Level */
+ regmap_write(max98927->regmap,
+ MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1,
+ 0x06);
+ /* Envelope Tracking configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM,
+ 0x08);
+ regmap_write(max98927->regmap,
+ MAX98927_R0086_ENV_TRACK_CTRL,
+ 0x01);
+ regmap_write(max98927->regmap,
+ MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ,
+ 0x10);
+
+ /* voltage, current slot configuration */
+ regmap_write(max98927->regmap,
+ MAX98927_R001E_PCM_TX_CH_SRC_A,
+ (max98927->i_l_slot<<MAX98927_PCM_TX_CH_SRC_A_I_SHIFT|
+ max98927->v_l_slot)&0xFF);
+
+ if (max98927->v_l_slot < 8) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->v_l_slot, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->v_l_slot,
+ 1 << max98927->v_l_slot);
+ } else {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->v_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->v_l_slot - 8),
+ 1 << (max98927->v_l_slot - 8));
+ }
+
+ if (max98927->i_l_slot < 8) {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001C_PCM_TX_HIZ_CTRL_A,
+ 1 << max98927->i_l_slot, 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001A_PCM_TX_EN_A,
+ 1 << max98927->i_l_slot,
+ 1 << max98927->i_l_slot);
+ } else {
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001D_PCM_TX_HIZ_CTRL_B,
+ 1 << (max98927->i_l_slot - 8), 0);
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001B_PCM_TX_EN_B,
+ 1 << (max98927->i_l_slot - 8),
+ 1 << (max98927->i_l_slot - 8));
+ }
+
+ /* Set interleave mode */
+ if (max98927->interleave_mode)
+ regmap_update_bits(max98927->regmap,
+ MAX98927_R001F_PCM_TX_CH_SRC_B,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK,
+ MAX98927_PCM_TX_CH_INTERLEAVE_MASK);
+ return 0;
+}
+
+static const struct snd_soc_codec_driver soc_codec_dev_max98927 = {
+ .probe = max98927_probe,
+ .component_driver = {
+ .controls = max98927_snd_controls,
+ .num_controls = ARRAY_SIZE(max98927_snd_controls),
+ .dapm_widgets = max98927_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets),
+ .dapm_routes = max98927_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(max98927_audio_map),
+ },
+};
+
+static const struct regmap_config max98927_regmap = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = MAX98927_R01FF_REV_ID,
+ .reg_defaults = max98927_reg,
+ .num_reg_defaults = ARRAY_SIZE(max98927_reg),
+ .readable_reg = max98927_readable_register,
+ .volatile_reg = max98927_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static void max98927_slot_config(struct i2c_client *i2c,
+ struct max98927_priv *max98927)
+{
+ int value;
+
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "vmon-slot-no", &value))
+ max98927->v_l_slot = value & 0xF;
+ else
+ max98927->v_l_slot = 0;
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "imon-slot-no", &value))
+ max98927->i_l_slot = value & 0xF;
+ else
+ max98927->i_l_slot = 1;
+}
+
+static int max98927_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+
+ int ret = 0, value;
+ int reg = 0;
+ struct max98927_priv *max98927 = NULL;
+
+ max98927 = devm_kzalloc(&i2c->dev,
+ sizeof(*max98927), GFP_KERNEL);
+
+ if (!max98927) {
+ ret = -ENOMEM;
+ return ret;
+ }
+ i2c_set_clientdata(i2c, max98927);
+
+ /* update interleave mode info */
+ if (!of_property_read_u32(i2c->dev.of_node,
+ "interleave_mode", &value)) {
+ if (value > 0)
+ max98927->interleave_mode = 1;
+ else
+ max98927->interleave_mode = 0;
+ } else
+ max98927->interleave_mode = 0;
+
+ /* regmap initialization */
+ max98927->regmap
+ = devm_regmap_init_i2c(i2c, &max98927_regmap);
+ if (IS_ERR(max98927->regmap)) {
+ ret = PTR_ERR(max98927->regmap);
+ dev_err(&i2c->dev,
+ "Failed to allocate regmap: %d\n", ret);
+ return ret;
+ }
+
+ /* Check Revision ID */
+ ret = regmap_read(max98927->regmap,
+ MAX98927_R01FF_REV_ID, &reg);
+ if (ret < 0) {
+ dev_err(&i2c->dev,
+ "Failed to read: 0x%02X\n", MAX98927_R01FF_REV_ID);
+ return ret;
+ }
+ dev_info(&i2c->dev, "MAX98927 revisionID: 0x%02X\n", reg);
+
+ /* voltage/current slot configuration */
+ max98927_slot_config(i2c, max98927);
+
+ /* codec registeration */
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927,
+ max98927_dai, ARRAY_SIZE(max98927_dai));
+ if (ret < 0)
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+
+ return ret;
+}
+
+static int max98927_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id max98927_i2c_id[] = {
+ { "max98927", 0},
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, max98927_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max98927_of_match[] = {
+ { .compatible = "maxim,max98927", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max98927_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id max98927_acpi_match[] = {
+ { "MX98927", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, max98927_acpi_match);
+#endif
+
+static struct i2c_driver max98927_i2c_driver = {
+ .driver = {
+ .name = "max98927",
+ .of_match_table = of_match_ptr(max98927_of_match),
+ .acpi_match_table = ACPI_PTR(max98927_acpi_match),
+ .pm = NULL,
+ },
+ .probe = max98927_i2c_probe,
+ .remove = max98927_i2c_remove,
+ .id_table = max98927_i2c_id,
+};
+
+module_i2c_driver(max98927_i2c_driver)
+
+MODULE_DESCRIPTION("ALSA SoC MAX98927 driver");
+MODULE_AUTHOR("Ryan Lee <ryans.lee@maximintegrated.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/max98927.h b/sound/soc/codecs/max98927.h
new file mode 100644
index 000000000000..ece6a608cbe1
--- /dev/null
+++ b/sound/soc/codecs/max98927.h
@@ -0,0 +1,272 @@
+/*
+ * max98927.h -- MAX98927 ALSA Soc Audio driver
+ *
+ * Copyright 2013-15 Maxim Integrated Products
+ * Author: Ryan Lee <ryans.lee@maximintegrated.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef _MAX98927_H
+#define _MAX98927_H
+
+/* Register Values */
+#define MAX98927_R0001_INT_RAW1 0x0001
+#define MAX98927_R0002_INT_RAW2 0x0002
+#define MAX98927_R0003_INT_RAW3 0x0003
+#define MAX98927_R0004_INT_STATE1 0x0004
+#define MAX98927_R0005_INT_STATE2 0x0005
+#define MAX98927_R0006_INT_STATE3 0x0006
+#define MAX98927_R0007_INT_FLAG1 0x0007
+#define MAX98927_R0008_INT_FLAG2 0x0008
+#define MAX98927_R0009_INT_FLAG3 0x0009
+#define MAX98927_R000A_INT_EN1 0x000A
+#define MAX98927_R000B_INT_EN2 0x000B
+#define MAX98927_R000C_INT_EN3 0x000C
+#define MAX98927_R000D_INT_FLAG_CLR1 0x000D
+#define MAX98927_R000E_INT_FLAG_CLR2 0x000E
+#define MAX98927_R000F_INT_FLAG_CLR3 0x000F
+#define MAX98927_R0010_IRQ_CTRL 0x0010
+#define MAX98927_R0011_CLK_MON 0x0011
+#define MAX98927_R0012_WDOG_CTRL 0x0012
+#define MAX98927_R0013_WDOG_RST 0x0013
+#define MAX98927_R0014_MEAS_ADC_THERM_WARN_THRESH 0x0014
+#define MAX98927_R0015_MEAS_ADC_THERM_SHDN_THRESH 0x0015
+#define MAX98927_R0016_MEAS_ADC_THERM_HYSTERESIS 0x0016
+#define MAX98927_R0017_PIN_CFG 0x0017
+#define MAX98927_R0018_PCM_RX_EN_A 0x0018
+#define MAX98927_R0019_PCM_RX_EN_B 0x0019
+#define MAX98927_R001A_PCM_TX_EN_A 0x001A
+#define MAX98927_R001B_PCM_TX_EN_B 0x001B
+#define MAX98927_R001C_PCM_TX_HIZ_CTRL_A 0x001C
+#define MAX98927_R001D_PCM_TX_HIZ_CTRL_B 0x001D
+#define MAX98927_R001E_PCM_TX_CH_SRC_A 0x001E
+#define MAX98927_R001F_PCM_TX_CH_SRC_B 0x001F
+#define MAX98927_R0020_PCM_MODE_CFG 0x0020
+#define MAX98927_R0021_PCM_MASTER_MODE 0x0021
+#define MAX98927_R0022_PCM_CLK_SETUP 0x0022
+#define MAX98927_R0023_PCM_SR_SETUP1 0x0023
+#define MAX98927_R0024_PCM_SR_SETUP2 0x0024
+#define MAX98927_R0025_PCM_TO_SPK_MONOMIX_A 0x0025
+#define MAX98927_R0026_PCM_TO_SPK_MONOMIX_B 0x0026
+#define MAX98927_R0027_ICC_RX_EN_A 0x0027
+#define MAX98927_R0028_ICC_RX_EN_B 0x0028
+#define MAX98927_R002B_ICC_TX_EN_A 0x002B
+#define MAX98927_R002C_ICC_TX_EN_B 0x002C
+#define MAX98927_R002E_ICC_HIZ_MANUAL_MODE 0x002E
+#define MAX98927_R002F_ICC_TX_HIZ_EN_A 0x002F
+#define MAX98927_R0030_ICC_TX_HIZ_EN_B 0x0030
+#define MAX98927_R0031_ICC_LNK_EN 0x0031
+#define MAX98927_R0032_PDM_TX_EN 0x0032
+#define MAX98927_R0033_PDM_TX_HIZ_CTRL 0x0033
+#define MAX98927_R0034_PDM_TX_CTRL 0x0034
+#define MAX98927_R0035_PDM_RX_CTRL 0x0035
+#define MAX98927_R0036_AMP_VOL_CTRL 0x0036
+#define MAX98927_R0037_AMP_DSP_CFG 0x0037
+#define MAX98927_R0038_TONE_GEN_DC_CFG 0x0038
+#define MAX98927_R0039_DRE_CTRL 0x0039
+#define MAX98927_R003A_AMP_EN 0x003A
+#define MAX98927_R003B_SPK_SRC_SEL 0x003B
+#define MAX98927_R003C_SPK_GAIN 0x003C
+#define MAX98927_R003D_SSM_CFG 0x003D
+#define MAX98927_R003E_MEAS_EN 0x003E
+#define MAX98927_R003F_MEAS_DSP_CFG 0x003F
+#define MAX98927_R0040_BOOST_CTRL0 0x0040
+#define MAX98927_R0041_BOOST_CTRL3 0x0041
+#define MAX98927_R0042_BOOST_CTRL1 0x0042
+#define MAX98927_R0043_MEAS_ADC_CFG 0x0043
+#define MAX98927_R0044_MEAS_ADC_BASE_MSB 0x0044
+#define MAX98927_R0045_MEAS_ADC_BASE_LSB 0x0045
+#define MAX98927_R0046_ADC_CH0_DIVIDE 0x0046
+#define MAX98927_R0047_ADC_CH1_DIVIDE 0x0047
+#define MAX98927_R0048_ADC_CH2_DIVIDE 0x0048
+#define MAX98927_R0049_ADC_CH0_FILT_CFG 0x0049
+#define MAX98927_R004A_ADC_CH1_FILT_CFG 0x004A
+#define MAX98927_R004B_ADC_CH2_FILT_CFG 0x004B
+#define MAX98927_R004C_MEAS_ADC_CH0_READ 0x004C
+#define MAX98927_R004D_MEAS_ADC_CH1_READ 0x004D
+#define MAX98927_R004E_MEAS_ADC_CH2_READ 0x004E
+#define MAX98927_R0051_BROWNOUT_STATUS 0x0051
+#define MAX98927_R0052_BROWNOUT_EN 0x0052
+#define MAX98927_R0053_BROWNOUT_INFINITE_HOLD 0x0053
+#define MAX98927_R0054_BROWNOUT_INFINITE_HOLD_CLR 0x0054
+#define MAX98927_R0055_BROWNOUT_LVL_HOLD 0x0055
+#define MAX98927_R005A_BROWNOUT_LVL1_THRESH 0x005A
+#define MAX98927_R005B_BROWNOUT_LVL2_THRESH 0x005B
+#define MAX98927_R005C_BROWNOUT_LVL3_THRESH 0x005C
+#define MAX98927_R005D_BROWNOUT_LVL4_THRESH 0x005D
+#define MAX98927_R005E_BROWNOUT_THRESH_HYSTERYSIS 0x005E
+#define MAX98927_R005F_BROWNOUT_AMP_LIMITER_ATK_REL 0x005F
+#define MAX98927_R0060_BROWNOUT_AMP_GAIN_ATK_REL 0x0060
+#define MAX98927_R0061_BROWNOUT_AMP1_CLIP_MODE 0x0061
+#define MAX98927_R0072_BROWNOUT_LVL1_CUR_LIMIT 0x0072
+#define MAX98927_R0073_BROWNOUT_LVL1_AMP1_CTRL1 0x0073
+#define MAX98927_R0074_BROWNOUT_LVL1_AMP1_CTRL2 0x0074
+#define MAX98927_R0075_BROWNOUT_LVL1_AMP1_CTRL3 0x0075
+#define MAX98927_R0076_BROWNOUT_LVL2_CUR_LIMIT 0x0076
+#define MAX98927_R0077_BROWNOUT_LVL2_AMP1_CTRL1 0x0077
+#define MAX98927_R0078_BROWNOUT_LVL2_AMP1_CTRL2 0x0078
+#define MAX98927_R0079_BROWNOUT_LVL2_AMP1_CTRL3 0x0079
+#define MAX98927_R007A_BROWNOUT_LVL3_CUR_LIMIT 0x007A
+#define MAX98927_R007B_BROWNOUT_LVL3_AMP1_CTRL1 0x007B
+#define MAX98927_R007C_BROWNOUT_LVL3_AMP1_CTRL2 0x007C
+#define MAX98927_R007D_BROWNOUT_LVL3_AMP1_CTRL3 0x007D
+#define MAX98927_R007E_BROWNOUT_LVL4_CUR_LIMIT 0x007E
+#define MAX98927_R007F_BROWNOUT_LVL4_AMP1_CTRL1 0x007F
+#define MAX98927_R0080_BROWNOUT_LVL4_AMP1_CTRL2 0x0080
+#define MAX98927_R0081_BROWNOUT_LVL4_AMP1_CTRL3 0x0081
+#define MAX98927_R0082_ENV_TRACK_VOUT_HEADROOM 0x0082
+#define MAX98927_R0083_ENV_TRACK_BOOST_VOUT_DELAY 0x0083
+#define MAX98927_R0084_ENV_TRACK_REL_RATE 0x0084
+#define MAX98927_R0085_ENV_TRACK_HOLD_RATE 0x0085
+#define MAX98927_R0086_ENV_TRACK_CTRL 0x0086
+#define MAX98927_R0087_ENV_TRACK_BOOST_VOUT_READ 0x0087
+#define MAX98927_R00FF_GLOBAL_SHDN 0x00FF
+#define MAX98927_R0100_SOFT_RESET 0x0100
+#define MAX98927_R01FF_REV_ID 0x01FF
+
+/* MAX98927_R0018_PCM_RX_EN_A */
+#define MAX98927_PCM_RX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_RX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_RX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_RX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_RX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_RX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_RX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_RX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001A_PCM_TX_EN_A */
+#define MAX98927_PCM_TX_CH0_EN (0x1 << 0)
+#define MAX98927_PCM_TX_CH1_EN (0x1 << 1)
+#define MAX98927_PCM_TX_CH2_EN (0x1 << 2)
+#define MAX98927_PCM_TX_CH3_EN (0x1 << 3)
+#define MAX98927_PCM_TX_CH4_EN (0x1 << 4)
+#define MAX98927_PCM_TX_CH5_EN (0x1 << 5)
+#define MAX98927_PCM_TX_CH6_EN (0x1 << 6)
+#define MAX98927_PCM_TX_CH7_EN (0x1 << 7)
+
+/* MAX98927_R001E_PCM_TX_CH_SRC_A */
+#define MAX98927_PCM_TX_CH_SRC_A_V_SHIFT (0)
+#define MAX98927_PCM_TX_CH_SRC_A_I_SHIFT (4)
+
+/* MAX98927_R001F_PCM_TX_CH_SRC_B */
+#define MAX98927_PCM_TX_CH_INTERLEAVE_MASK (0x1 << 5)
+
+/* MAX98927_R0020_PCM_MODE_CFG */
+#define MAX98927_PCM_MODE_CFG_PCM_BCLKEDGE (0x1 << 2)
+#define MAX98927_PCM_MODE_CFG_FORMAT_MASK (0x7 << 3)
+#define MAX98927_PCM_MODE_CFG_FORMAT_SHIFT (3)
+#define MAX98927_PCM_FORMAT_I2S (0x0 << 0)
+#define MAX98927_PCM_FORMAT_LJ (0x1 << 0)
+
+#define MAX98927_PCM_MODE_CFG_CHANSZ_MASK (0x3 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_16 (0x1 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_24 (0x2 << 6)
+#define MAX98927_PCM_MODE_CFG_CHANSZ_32 (0x3 << 6)
+
+/* MAX98927_R0021_PCM_MASTER_MODE */
+#define MAX98927_PCM_MASTER_MODE_MASK (0x3 << 0)
+#define MAX98927_PCM_MASTER_MODE_SLAVE (0x0 << 0)
+#define MAX98927_PCM_MASTER_MODE_MASTER (0x3 << 0)
+
+#define MAX98927_PCM_MASTER_MODE_MCLK_MASK (0xF << 2)
+#define MAX98927_PCM_MASTER_MODE_MCLK_RATE_SHIFT (2)
+
+/* MAX98927_R0022_PCM_CLK_SETUP */
+#define MAX98927_PCM_CLK_SETUP_BSEL_MASK (0xF << 0)
+
+/* MAX98927_R0023_PCM_SR_SETUP1 */
+#define MAX98927_PCM_SR_SET1_SR_MASK (0xF << 0)
+
+#define MAX98927_PCM_SR_SET1_SR_8000 (0x0 << 0)
+#define MAX98927_PCM_SR_SET1_SR_11025 (0x1 << 0)
+#define MAX98927_PCM_SR_SET1_SR_12000 (0x2 << 0)
+#define MAX98927_PCM_SR_SET1_SR_16000 (0x3 << 0)
+#define MAX98927_PCM_SR_SET1_SR_22050 (0x4 << 0)
+#define MAX98927_PCM_SR_SET1_SR_24000 (0x5 << 0)
+#define MAX98927_PCM_SR_SET1_SR_32000 (0x6 << 0)
+#define MAX98927_PCM_SR_SET1_SR_44100 (0x7 << 0)
+#define MAX98927_PCM_SR_SET1_SR_48000 (0x8 << 0)
+
+/* MAX98927_R0024_PCM_SR_SETUP2 */
+#define MAX98927_PCM_SR_SET2_SR_MASK (0xF << 4)
+#define MAX98927_PCM_SR_SET2_SR_SHIFT (4)
+#define MAX98927_PCM_SR_SET2_IVADC_SR_MASK (0xf << 0)
+
+/* MAX98927_R0025_PCM_TO_SPK_MONOMIX_A */
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_MASK (0x3 << 6)
+#define MAX98927_PCM_TO_SPK_MONOMIX_CFG_SHIFT (6)
+
+/* MAX98927_R0035_PDM_RX_CTRL */
+#define MAX98927_PDM_RX_EN_MASK (0x1 << 0)
+
+/* MAX98927_R0036_AMP_VOL_CTRL */
+#define MAX98927_AMP_VOL_SEL (0x1 << 7)
+#define MAX98927_AMP_VOL_SEL_WIDTH (1)
+#define MAX98927_AMP_VOL_SEL_SHIFT (7)
+#define MAX98927_AMP_VOL_MASK (0x7f << 0)
+#define MAX98927_AMP_VOL_WIDTH (7)
+#define MAX98927_AMP_VOL_SHIFT (0)
+
+/* MAX98927_R0037_AMP_DSP_CFG */
+#define MAX98927_AMP_DSP_CFG_DCBLK_EN (0x1 << 0)
+#define MAX98927_AMP_DSP_CFG_DITH_EN (0x1 << 1)
+#define MAX98927_AMP_DSP_CFG_RMP_BYPASS (0x1 << 4)
+#define MAX98927_AMP_DSP_CFG_DAC_INV (0x1 << 5)
+#define MAX98927_AMP_DSP_CFG_RMP_SHIFT (4)
+
+/* MAX98927_R0039_DRE_CTRL */
+#define MAX98927_DRE_CTRL_DRE_EN (0x1 << 0)
+#define MAX98927_DRE_EN_SHIFT 0x1
+
+/* MAX98927_R003A_AMP_EN */
+#define MAX98927_AMP_EN_MASK (0x1 << 0)
+
+/* MAX98927_R003B_SPK_SRC_SEL */
+#define MAX98927_SPK_SRC_MASK (0x3 << 0)
+
+/* MAX98927_R003C_SPK_GAIN */
+#define MAX98927_SPK_PCM_GAIN_MASK (0x7 << 0)
+#define MAX98927_SPK_PDM_GAIN_MASK (0x7 << 4)
+#define MAX98927_SPK_GAIN_WIDTH (3)
+
+/* MAX98927_R003E_MEAS_EN */
+#define MAX98927_MEAS_V_EN (0x1 << 0)
+#define MAX98927_MEAS_I_EN (0x1 << 1)
+
+/* MAX98927_R0040_BOOST_CTRL0 */
+#define MAX98927_BOOST_CTRL0_VOUT_MASK (0x1f << 0)
+#define MAX98927_BOOST_CTRL0_PVDD_MASK (0x1 << 7)
+#define MAX98927_BOOST_CTRL0_PVDD_EN_SHIFT (7)
+
+/* MAX98927_R0052_BROWNOUT_EN */
+#define MAX98927_BROWNOUT_BDE_EN (0x1 << 0)
+#define MAX98927_BROWNOUT_AMP_EN (0x1 << 1)
+#define MAX98927_BROWNOUT_DSP_EN (0x1 << 2)
+#define MAX98927_BROWNOUT_DSP_SHIFT (2)
+
+/* MAX98927_R0100_SOFT_RESET */
+#define MAX98927_SOFT_RESET (0x1 << 0)
+
+/* MAX98927_R00FF_GLOBAL_SHDN */
+#define MAX98927_GLOBAL_EN_MASK (0x1 << 0)
+
+struct max98927_priv {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct max98927_pdata *pdata;
+ unsigned int spk_gain;
+ unsigned int sysclk;
+ unsigned int v_l_slot;
+ unsigned int i_l_slot;
+ bool interleave_mode;
+ unsigned int ch_size;
+ unsigned int rate;
+ unsigned int iface;
+ unsigned int master;
+ unsigned int digital_gain;
+};
+#endif
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
new file mode 100644
index 000000000000..c8bcb1db966d
--- /dev/null
+++ b/sound/soc/codecs/nau8540.c
@@ -0,0 +1,835 @@
+/*
+ * NAU85L40 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include "nau8540.h"
+
+
+#define NAU_FREF_MAX 13500000
+#define NAU_FVCO_MAX 100000000
+#define NAU_FVCO_MIN 90000000
+
+/* the maximum frequency of CLK_ADC */
+#define CLK_ADC_MAX 6144000
+
+/* scaling for mclk from sysclk_src output */
+static const struct nau8540_fll_attr mclk_src_scaling[] = {
+ { 1, 0x0 },
+ { 2, 0x2 },
+ { 4, 0x3 },
+ { 8, 0x4 },
+ { 16, 0x5 },
+ { 32, 0x6 },
+ { 3, 0x7 },
+ { 6, 0xa },
+ { 12, 0xb },
+ { 24, 0xc },
+};
+
+/* ratio for input clk freq */
+static const struct nau8540_fll_attr fll_ratio[] = {
+ { 512000, 0x01 },
+ { 256000, 0x02 },
+ { 128000, 0x04 },
+ { 64000, 0x08 },
+ { 32000, 0x10 },
+ { 8000, 0x20 },
+ { 4000, 0x40 },
+};
+
+static const struct nau8540_fll_attr fll_pre_scalar[] = {
+ { 1, 0x0 },
+ { 2, 0x1 },
+ { 4, 0x2 },
+ { 8, 0x3 },
+};
+
+/* over sampling rate */
+static const struct nau8540_osr_attr osr_adc_sel[] = {
+ { 32, 3 }, /* OSR 32, SRC 1/8 */
+ { 64, 2 }, /* OSR 64, SRC 1/4 */
+ { 128, 1 }, /* OSR 128, SRC 1/2 */
+ { 256, 0 }, /* OSR 256, SRC 1 */
+};
+
+static const struct reg_default nau8540_reg_defaults[] = {
+ {NAU8540_REG_POWER_MANAGEMENT, 0x0000},
+ {NAU8540_REG_CLOCK_CTRL, 0x0000},
+ {NAU8540_REG_CLOCK_SRC, 0x0000},
+ {NAU8540_REG_FLL1, 0x0001},
+ {NAU8540_REG_FLL2, 0x3126},
+ {NAU8540_REG_FLL3, 0x0008},
+ {NAU8540_REG_FLL4, 0x0010},
+ {NAU8540_REG_FLL5, 0xC000},
+ {NAU8540_REG_FLL6, 0x6000},
+ {NAU8540_REG_FLL_VCO_RSV, 0xF13C},
+ {NAU8540_REG_PCM_CTRL0, 0x000B},
+ {NAU8540_REG_PCM_CTRL1, 0x3010},
+ {NAU8540_REG_PCM_CTRL2, 0x0800},
+ {NAU8540_REG_PCM_CTRL3, 0x0000},
+ {NAU8540_REG_PCM_CTRL4, 0x000F},
+ {NAU8540_REG_ALC_CONTROL_1, 0x0000},
+ {NAU8540_REG_ALC_CONTROL_2, 0x700B},
+ {NAU8540_REG_ALC_CONTROL_3, 0x0022},
+ {NAU8540_REG_ALC_CONTROL_4, 0x1010},
+ {NAU8540_REG_ALC_CONTROL_5, 0x1010},
+ {NAU8540_REG_NOTCH_FIL1_CH1, 0x0000},
+ {NAU8540_REG_NOTCH_FIL2_CH1, 0x0000},
+ {NAU8540_REG_NOTCH_FIL1_CH2, 0x0000},
+ {NAU8540_REG_NOTCH_FIL2_CH2, 0x0000},
+ {NAU8540_REG_NOTCH_FIL1_CH3, 0x0000},
+ {NAU8540_REG_NOTCH_FIL2_CH3, 0x0000},
+ {NAU8540_REG_NOTCH_FIL1_CH4, 0x0000},
+ {NAU8540_REG_NOTCH_FIL2_CH4, 0x0000},
+ {NAU8540_REG_HPF_FILTER_CH12, 0x0000},
+ {NAU8540_REG_HPF_FILTER_CH34, 0x0000},
+ {NAU8540_REG_ADC_SAMPLE_RATE, 0x0002},
+ {NAU8540_REG_DIGITAL_GAIN_CH1, 0x0400},
+ {NAU8540_REG_DIGITAL_GAIN_CH2, 0x0400},
+ {NAU8540_REG_DIGITAL_GAIN_CH3, 0x0400},
+ {NAU8540_REG_DIGITAL_GAIN_CH4, 0x0400},
+ {NAU8540_REG_DIGITAL_MUX, 0x00E4},
+ {NAU8540_REG_GPIO_CTRL, 0x0000},
+ {NAU8540_REG_MISC_CTRL, 0x0000},
+ {NAU8540_REG_I2C_CTRL, 0xEFFF},
+ {NAU8540_REG_VMID_CTRL, 0x0000},
+ {NAU8540_REG_MUTE, 0x0000},
+ {NAU8540_REG_ANALOG_ADC1, 0x0011},
+ {NAU8540_REG_ANALOG_ADC2, 0x0020},
+ {NAU8540_REG_ANALOG_PWR, 0x0000},
+ {NAU8540_REG_MIC_BIAS, 0x0004},
+ {NAU8540_REG_REFERENCE, 0x0000},
+ {NAU8540_REG_FEPGA1, 0x0000},
+ {NAU8540_REG_FEPGA2, 0x0000},
+ {NAU8540_REG_FEPGA3, 0x0101},
+ {NAU8540_REG_FEPGA4, 0x0101},
+ {NAU8540_REG_PWR, 0x0000},
+};
+
+static bool nau8540_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8540_REG_POWER_MANAGEMENT ... NAU8540_REG_FLL_VCO_RSV:
+ case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4:
+ case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5:
+ case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ADC_SAMPLE_RATE:
+ case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX:
+ case NAU8540_REG_P2P_CH1 ... NAU8540_REG_I2C_CTRL:
+ case NAU8540_REG_I2C_DEVICE_ID:
+ case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE:
+ case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR:
+ return true;
+ default:
+ return false;
+ }
+
+}
+
+static bool nau8540_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8540_REG_SW_RESET ... NAU8540_REG_FLL_VCO_RSV:
+ case NAU8540_REG_PCM_CTRL0 ... NAU8540_REG_PCM_CTRL4:
+ case NAU8540_REG_ALC_CONTROL_1 ... NAU8540_REG_ALC_CONTROL_5:
+ case NAU8540_REG_NOTCH_FIL1_CH1 ... NAU8540_REG_ADC_SAMPLE_RATE:
+ case NAU8540_REG_DIGITAL_GAIN_CH1 ... NAU8540_REG_DIGITAL_MUX:
+ case NAU8540_REG_GPIO_CTRL ... NAU8540_REG_I2C_CTRL:
+ case NAU8540_REG_RST:
+ case NAU8540_REG_VMID_CTRL ... NAU8540_REG_MUTE:
+ case NAU8540_REG_ANALOG_ADC1 ... NAU8540_REG_PWR:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool nau8540_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8540_REG_SW_RESET:
+ case NAU8540_REG_ALC_GAIN_CH12 ... NAU8540_REG_ALC_STATUS:
+ case NAU8540_REG_P2P_CH1 ... NAU8540_REG_PEAK_CH4:
+ case NAU8540_REG_I2C_DEVICE_ID:
+ case NAU8540_REG_RST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -12800, 3600);
+static const DECLARE_TLV_DB_MINMAX(fepga_gain_tlv, -100, 3600);
+
+static const struct snd_kcontrol_new nau8540_snd_controls[] = {
+ SOC_SINGLE_TLV("Mic1 Volume", NAU8540_REG_DIGITAL_GAIN_CH1,
+ 0, 0x520, 0, adc_vol_tlv),
+ SOC_SINGLE_TLV("Mic2 Volume", NAU8540_REG_DIGITAL_GAIN_CH2,
+ 0, 0x520, 0, adc_vol_tlv),
+ SOC_SINGLE_TLV("Mic3 Volume", NAU8540_REG_DIGITAL_GAIN_CH3,
+ 0, 0x520, 0, adc_vol_tlv),
+ SOC_SINGLE_TLV("Mic4 Volume", NAU8540_REG_DIGITAL_GAIN_CH4,
+ 0, 0x520, 0, adc_vol_tlv),
+
+ SOC_SINGLE_TLV("Frontend PGA1 Volume", NAU8540_REG_FEPGA3,
+ 0, 0x25, 0, fepga_gain_tlv),
+ SOC_SINGLE_TLV("Frontend PGA2 Volume", NAU8540_REG_FEPGA3,
+ 8, 0x25, 0, fepga_gain_tlv),
+ SOC_SINGLE_TLV("Frontend PGA3 Volume", NAU8540_REG_FEPGA4,
+ 0, 0x25, 0, fepga_gain_tlv),
+ SOC_SINGLE_TLV("Frontend PGA4 Volume", NAU8540_REG_FEPGA4,
+ 8, 0x25, 0, fepga_gain_tlv),
+};
+
+static const char * const adc_channel[] = {
+ "ADC channel 1", "ADC channel 2", "ADC channel 3", "ADC channel 4"
+};
+static SOC_ENUM_SINGLE_DECL(
+ digital_ch4_enum, NAU8540_REG_DIGITAL_MUX, 6, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch4_mux =
+ SOC_DAPM_ENUM("Digital CH4 Select", digital_ch4_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ digital_ch3_enum, NAU8540_REG_DIGITAL_MUX, 4, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch3_mux =
+ SOC_DAPM_ENUM("Digital CH3 Select", digital_ch3_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ digital_ch2_enum, NAU8540_REG_DIGITAL_MUX, 2, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch2_mux =
+ SOC_DAPM_ENUM("Digital CH2 Select", digital_ch2_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ digital_ch1_enum, NAU8540_REG_DIGITAL_MUX, 0, adc_channel);
+
+static const struct snd_kcontrol_new digital_ch1_mux =
+ SOC_DAPM_ENUM("Digital CH1 Select", digital_ch1_enum);
+
+static const struct snd_soc_dapm_widget nau8540_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", NAU8540_REG_MIC_BIAS, 11, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", NAU8540_REG_MIC_BIAS, 10, 0, NULL, 0),
+
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("MIC3"),
+ SND_SOC_DAPM_INPUT("MIC4"),
+
+ SND_SOC_DAPM_PGA("Frontend PGA1", NAU8540_REG_PWR, 12, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Frontend PGA2", NAU8540_REG_PWR, 13, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Frontend PGA3", NAU8540_REG_PWR, 14, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Frontend PGA4", NAU8540_REG_PWR, 15, 0, NULL, 0),
+
+ SND_SOC_DAPM_ADC("ADC1", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 0, 0),
+ SND_SOC_DAPM_ADC("ADC2", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 1, 0),
+ SND_SOC_DAPM_ADC("ADC3", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 2, 0),
+ SND_SOC_DAPM_ADC("ADC4", NULL,
+ NAU8540_REG_POWER_MANAGEMENT, 3, 0),
+
+ SND_SOC_DAPM_PGA("ADC CH1", NAU8540_REG_ANALOG_PWR, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC CH2", NAU8540_REG_ANALOG_PWR, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC CH3", NAU8540_REG_ANALOG_PWR, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ADC CH4", NAU8540_REG_ANALOG_PWR, 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("Digital CH4 Mux",
+ SND_SOC_NOPM, 0, 0, &digital_ch4_mux),
+ SND_SOC_DAPM_MUX("Digital CH3 Mux",
+ SND_SOC_NOPM, 0, 0, &digital_ch3_mux),
+ SND_SOC_DAPM_MUX("Digital CH2 Mux",
+ SND_SOC_NOPM, 0, 0, &digital_ch2_mux),
+ SND_SOC_DAPM_MUX("Digital CH1 Mux",
+ SND_SOC_NOPM, 0, 0, &digital_ch1_mux),
+
+ SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
+ {"Frontend PGA1", NULL, "MIC1"},
+ {"Frontend PGA2", NULL, "MIC2"},
+ {"Frontend PGA3", NULL, "MIC3"},
+ {"Frontend PGA4", NULL, "MIC4"},
+
+ {"ADC1", NULL, "Frontend PGA1"},
+ {"ADC2", NULL, "Frontend PGA2"},
+ {"ADC3", NULL, "Frontend PGA3"},
+ {"ADC4", NULL, "Frontend PGA4"},
+
+ {"ADC CH1", NULL, "ADC1"},
+ {"ADC CH2", NULL, "ADC2"},
+ {"ADC CH3", NULL, "ADC3"},
+ {"ADC CH4", NULL, "ADC4"},
+
+ {"ADC1", NULL, "MICBIAS1"},
+ {"ADC2", NULL, "MICBIAS1"},
+ {"ADC3", NULL, "MICBIAS2"},
+ {"ADC4", NULL, "MICBIAS2"},
+
+ {"Digital CH1 Mux", "ADC channel 1", "ADC CH1"},
+ {"Digital CH1 Mux", "ADC channel 2", "ADC CH2"},
+ {"Digital CH1 Mux", "ADC channel 3", "ADC CH3"},
+ {"Digital CH1 Mux", "ADC channel 4", "ADC CH4"},
+
+ {"Digital CH2 Mux", "ADC channel 1", "ADC CH1"},
+ {"Digital CH2 Mux", "ADC channel 2", "ADC CH2"},
+ {"Digital CH2 Mux", "ADC channel 3", "ADC CH3"},
+ {"Digital CH2 Mux", "ADC channel 4", "ADC CH4"},
+
+ {"Digital CH3 Mux", "ADC channel 1", "ADC CH1"},
+ {"Digital CH3 Mux", "ADC channel 2", "ADC CH2"},
+ {"Digital CH3 Mux", "ADC channel 3", "ADC CH3"},
+ {"Digital CH3 Mux", "ADC channel 4", "ADC CH4"},
+
+ {"Digital CH4 Mux", "ADC channel 1", "ADC CH1"},
+ {"Digital CH4 Mux", "ADC channel 2", "ADC CH2"},
+ {"Digital CH4 Mux", "ADC channel 3", "ADC CH3"},
+ {"Digital CH4 Mux", "ADC channel 4", "ADC CH4"},
+
+ {"AIFTX", NULL, "Digital CH1 Mux"},
+ {"AIFTX", NULL, "Digital CH2 Mux"},
+ {"AIFTX", NULL, "Digital CH3 Mux"},
+ {"AIFTX", NULL, "Digital CH4 Mux"},
+};
+
+static int nau8540_clock_check(struct nau8540 *nau8540, int rate, int osr)
+{
+ int osrate;
+
+ if (osr >= ARRAY_SIZE(osr_adc_sel))
+ return -EINVAL;
+ osrate = osr_adc_sel[osr].osr;
+
+ if (rate * osr > CLK_ADC_MAX) {
+ dev_err(nau8540->dev, "exceed the maximum frequency of CLK_ADC\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nau8540_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val_len = 0, osr;
+
+ /* CLK_ADC = OSR * FS
+ * ADC clock frequency is defined as Over Sampling Rate (OSR)
+ * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+ * values must be selected such that the maximum frequency is less
+ * than 6.144 MHz.
+ */
+ regmap_read(nau8540->regmap, NAU8540_REG_ADC_SAMPLE_RATE, &osr);
+ osr &= NAU8540_ADC_OSR_MASK;
+ if (nau8540_clock_check(nau8540, params_rate(params), osr))
+ return -EINVAL;
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+ NAU8540_CLK_ADC_SRC_MASK,
+ osr_adc_sel[osr].clk_src << NAU8540_CLK_ADC_SRC_SFT);
+
+ switch (params_width(params)) {
+ case 16:
+ val_len |= NAU8540_I2S_DL_16;
+ break;
+ case 20:
+ val_len |= NAU8540_I2S_DL_20;
+ break;
+ case 24:
+ val_len |= NAU8540_I2S_DL_24;
+ break;
+ case 32:
+ val_len |= NAU8540_I2S_DL_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0,
+ NAU8540_I2S_DL_MASK, val_len);
+
+ return 0;
+}
+
+static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+ unsigned int ctrl1_val = 0, ctrl2_val = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ctrl2_val |= NAU8540_I2S_MS_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl1_val |= NAU8540_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl1_val |= NAU8540_I2S_DF_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl1_val |= NAU8540_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl1_val |= NAU8540_I2S_DF_RIGTH;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ctrl1_val |= NAU8540_I2S_DF_PCM_AB;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl1_val |= NAU8540_I2S_DF_PCM_AB;
+ ctrl1_val |= NAU8540_I2S_PCMB_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL0,
+ NAU8540_I2S_DL_MASK | NAU8540_I2S_DF_MASK |
+ NAU8540_I2S_BP_INV | NAU8540_I2S_PCMB_EN, ctrl1_val);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+ NAU8540_I2S_MS_MASK | NAU8540_I2S_DO12_OE, ctrl2_val);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+ NAU8540_I2S_DO34_OE, 0);
+
+ return 0;
+}
+
+/**
+ * nau8540_set_tdm_slot - configure DAI TX TDM.
+ * @dai: DAI
+ * @tx_mask: bitmask representing active TX slots. Ex.
+ * 0xf for normal 4 channel TDM.
+ * 0xf0 for shifted 4 channel TDM
+ * @rx_mask: no used.
+ * @slots: Number of slots in use.
+ * @slot_width: Width in bits for each slot.
+ *
+ * Configures a DAI for TDM operation. Only support 4 slots TDM.
+ */
+static int nau8540_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+ unsigned int ctrl2_val = 0, ctrl4_val = 0;
+
+ if (slots > 4 || ((tx_mask & 0xf0) && (tx_mask & 0xf)))
+ return -EINVAL;
+
+ ctrl4_val |= (NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN);
+ if (tx_mask & 0xf0) {
+ ctrl2_val = 4 * slot_width;
+ ctrl4_val |= (tx_mask >> 4);
+ } else {
+ ctrl4_val |= tx_mask;
+ }
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL4,
+ NAU8540_TDM_MODE | NAU8540_TDM_OFFSET_EN |
+ NAU8540_TDM_TX_MASK, ctrl4_val);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL1,
+ NAU8540_I2S_DO12_OE, NAU8540_I2S_DO12_OE);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_PCM_CTRL2,
+ NAU8540_I2S_DO34_OE | NAU8540_I2S_TSLOT_L_MASK,
+ NAU8540_I2S_DO34_OE | ctrl2_val);
+
+ return 0;
+}
+
+
+static const struct snd_soc_dai_ops nau8540_dai_ops = {
+ .hw_params = nau8540_hw_params,
+ .set_fmt = nau8540_set_fmt,
+ .set_tdm_slot = nau8540_set_tdm_slot,
+};
+
+#define NAU8540_RATES SNDRV_PCM_RATE_8000_48000
+#define NAU8540_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8540_dai = {
+ .name = "nau8540-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = NAU8540_RATES,
+ .formats = NAU8540_FORMATS,
+ },
+ .ops = &nau8540_dai_ops,
+};
+
+/**
+ * nau8540_calc_fll_param - Calculate FLL parameters.
+ * @fll_in: external clock provided to codec.
+ * @fs: sampling rate.
+ * @fll_param: Pointer to structure of FLL parameters.
+ *
+ * Calculate FLL parameters to configure codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int nau8540_calc_fll_param(unsigned int fll_in,
+ unsigned int fs, struct nau8540_fll *fll_param)
+{
+ u64 fvco, fvco_max;
+ unsigned int fref, i, fvco_sel;
+
+ /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
+ * freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
+ * FREF = freq_in / NAU8540_FLL_REF_DIV_MASK
+ */
+ for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
+ fref = fll_in / fll_pre_scalar[i].param;
+ if (fref <= NAU_FREF_MAX)
+ break;
+ }
+ if (i == ARRAY_SIZE(fll_pre_scalar))
+ return -EINVAL;
+ fll_param->clk_ref_div = fll_pre_scalar[i].val;
+
+ /* Choose the FLL ratio based on FREF */
+ for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
+ if (fref >= fll_ratio[i].param)
+ break;
+ }
+ if (i == ARRAY_SIZE(fll_ratio))
+ return -EINVAL;
+ fll_param->ratio = fll_ratio[i].val;
+
+ /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
+ * FDCO must be within the 90MHz - 124MHz or the FFL cannot be
+ * guaranteed across the full range of operation.
+ * FDCO = freq_out * 2 * mclk_src_scaling
+ */
+ fvco_max = 0;
+ fvco_sel = ARRAY_SIZE(mclk_src_scaling);
+ for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
+ fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+ if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
+ fvco_max < fvco) {
+ fvco_max = fvco;
+ fvco_sel = i;
+ }
+ }
+ if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel)
+ return -EINVAL;
+ fll_param->mclk_src = mclk_src_scaling[fvco_sel].val;
+
+ /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
+ * input based on FDCO, FREF and FLL ratio.
+ */
+ fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
+ fll_param->fll_int = (fvco >> 16) & 0x3FF;
+ fll_param->fll_frac = fvco & 0xFFFF;
+ return 0;
+}
+
+static void nau8540_fll_apply(struct regmap *regmap,
+ struct nau8540_fll *fll_param)
+{
+ regmap_update_bits(regmap, NAU8540_REG_CLOCK_SRC,
+ NAU8540_CLK_SRC_MASK | NAU8540_CLK_MCLK_SRC_MASK,
+ NAU8540_CLK_SRC_MCLK | fll_param->mclk_src);
+ regmap_update_bits(regmap, NAU8540_REG_FLL1,
+ NAU8540_FLL_RATIO_MASK, fll_param->ratio);
+ /* FLL 16-bit fractional input */
+ regmap_write(regmap, NAU8540_REG_FLL2, fll_param->fll_frac);
+ /* FLL 10-bit integer input */
+ regmap_update_bits(regmap, NAU8540_REG_FLL3,
+ NAU8540_FLL_INTEGER_MASK, fll_param->fll_int);
+ /* FLL pre-scaler */
+ regmap_update_bits(regmap, NAU8540_REG_FLL4,
+ NAU8540_FLL_REF_DIV_MASK,
+ fll_param->clk_ref_div << NAU8540_FLL_REF_DIV_SFT);
+ regmap_update_bits(regmap, NAU8540_REG_FLL5,
+ NAU8540_FLL_CLK_SW_MASK, NAU8540_FLL_CLK_SW_REF);
+ regmap_update_bits(regmap,
+ NAU8540_REG_FLL6, NAU8540_DCO_EN, 0);
+ if (fll_param->fll_frac) {
+ regmap_update_bits(regmap, NAU8540_REG_FLL5,
+ NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
+ NAU8540_FLL_FTR_SW_MASK,
+ NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
+ NAU8540_FLL_FTR_SW_FILTER);
+ regmap_update_bits(regmap, NAU8540_REG_FLL6,
+ NAU8540_SDM_EN, NAU8540_SDM_EN);
+ } else {
+ regmap_update_bits(regmap, NAU8540_REG_FLL5,
+ NAU8540_FLL_PDB_DAC_EN | NAU8540_FLL_LOOP_FTR_EN |
+ NAU8540_FLL_FTR_SW_MASK, NAU8540_FLL_FTR_SW_ACCU);
+ regmap_update_bits(regmap,
+ NAU8540_REG_FLL6, NAU8540_SDM_EN, 0);
+ }
+}
+
+/* freq_out must be 256*Fs in order to achieve the best performance */
+static int nau8540_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+ struct nau8540_fll fll_param;
+ int ret, fs;
+
+ switch (pll_id) {
+ case NAU8540_CLK_FLL_MCLK:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+ NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_MCLK);
+ break;
+
+ case NAU8540_CLK_FLL_BLK:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+ NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_BLK);
+ break;
+
+ case NAU8540_CLK_FLL_FS:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL3,
+ NAU8540_FLL_CLK_SRC_MASK, NAU8540_FLL_CLK_SRC_FS);
+ break;
+
+ default:
+ dev_err(nau8540->dev, "Invalid clock id (%d)\n", pll_id);
+ return -EINVAL;
+ }
+ dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n",
+ freq_out, pll_id);
+
+ fs = freq_out / 256;
+ ret = nau8540_calc_fll_param(freq_in, fs, &fll_param);
+ if (ret < 0) {
+ dev_err(nau8540->dev, "Unsupported input clock %d\n", freq_in);
+ return ret;
+ }
+ dev_dbg(nau8540->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+ fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
+ fll_param.fll_int, fll_param.clk_ref_div);
+
+ nau8540_fll_apply(nau8540->regmap, &fll_param);
+ mdelay(2);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+ NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO);
+
+ return 0;
+}
+
+static int nau8540_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case NAU8540_CLK_DIS:
+ case NAU8540_CLK_MCLK:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+ NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_MCLK);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6,
+ NAU8540_DCO_EN, 0);
+ break;
+
+ case NAU8540_CLK_INTERNAL:
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_FLL6,
+ NAU8540_DCO_EN, NAU8540_DCO_EN);
+ regmap_update_bits(nau8540->regmap, NAU8540_REG_CLOCK_SRC,
+ NAU8540_CLK_SRC_MASK, NAU8540_CLK_SRC_VCO);
+ break;
+
+ default:
+ dev_err(nau8540->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ dev_dbg(nau8540->dev, "Sysclk is %dHz and clock id is %d\n",
+ freq, clk_id);
+
+ return 0;
+}
+
+static void nau8540_reset_chip(struct regmap *regmap)
+{
+ regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00);
+ regmap_write(regmap, NAU8540_REG_SW_RESET, 0x00);
+}
+
+static void nau8540_init_regs(struct nau8540 *nau8540)
+{
+ struct regmap *regmap = nau8540->regmap;
+
+ /* Enable Bias/VMID/VMID Tieoff */
+ regmap_update_bits(regmap, NAU8540_REG_VMID_CTRL,
+ NAU8540_VMID_EN | NAU8540_VMID_SEL_MASK,
+ NAU8540_VMID_EN | (0x2 << NAU8540_VMID_SEL_SFT));
+ regmap_update_bits(regmap, NAU8540_REG_REFERENCE,
+ NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN,
+ NAU8540_PRECHARGE_DIS | NAU8540_GLOBAL_BIAS_EN);
+ mdelay(2);
+ regmap_update_bits(regmap, NAU8540_REG_MIC_BIAS,
+ NAU8540_PU_PRE, NAU8540_PU_PRE);
+ regmap_update_bits(regmap, NAU8540_REG_CLOCK_CTRL,
+ NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN,
+ NAU8540_CLK_ADC_EN | NAU8540_CLK_I2S_EN);
+ /* ADC OSR selection, CLK_ADC = Fs * OSR */
+ regmap_update_bits(regmap, NAU8540_REG_ADC_SAMPLE_RATE,
+ NAU8540_ADC_OSR_MASK, NAU8540_ADC_OSR_64);
+}
+
+static int __maybe_unused nau8540_suspend(struct snd_soc_codec *codec)
+{
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(nau8540->regmap, true);
+ regcache_mark_dirty(nau8540->regmap);
+
+ return 0;
+}
+
+static int __maybe_unused nau8540_resume(struct snd_soc_codec *codec)
+{
+ struct nau8540 *nau8540 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(nau8540->regmap, false);
+ regcache_sync(nau8540->regmap);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver nau8540_codec_driver = {
+ .set_sysclk = nau8540_set_sysclk,
+ .set_pll = nau8540_set_pll,
+ .suspend = nau8540_suspend,
+ .resume = nau8540_resume,
+ .suspend_bias_off = true,
+
+ .component_driver = {
+ .controls = nau8540_snd_controls,
+ .num_controls = ARRAY_SIZE(nau8540_snd_controls),
+ .dapm_widgets = nau8540_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(nau8540_dapm_widgets),
+ .dapm_routes = nau8540_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(nau8540_dapm_routes),
+ },
+};
+
+static const struct regmap_config nau8540_regmap_config = {
+ .val_bits = 16,
+ .reg_bits = 16,
+
+ .max_register = NAU8540_REG_MAX,
+ .readable_reg = nau8540_readable_reg,
+ .writeable_reg = nau8540_writeable_reg,
+ .volatile_reg = nau8540_volatile_reg,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = nau8540_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(nau8540_reg_defaults),
+};
+
+static int nau8540_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c->dev;
+ struct nau8540 *nau8540 = dev_get_platdata(dev);
+ int ret, value;
+
+ if (!nau8540) {
+ nau8540 = devm_kzalloc(dev, sizeof(*nau8540), GFP_KERNEL);
+ if (!nau8540)
+ return -ENOMEM;
+ }
+ i2c_set_clientdata(i2c, nau8540);
+
+ nau8540->regmap = devm_regmap_init_i2c(i2c, &nau8540_regmap_config);
+ if (IS_ERR(nau8540->regmap))
+ return PTR_ERR(nau8540->regmap);
+ ret = regmap_read(nau8540->regmap, NAU8540_REG_I2C_DEVICE_ID, &value);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read device id from the NAU85L40: %d\n",
+ ret);
+ return ret;
+ }
+
+ nau8540->dev = dev;
+ nau8540_reset_chip(nau8540->regmap);
+ nau8540_init_regs(nau8540);
+
+ return snd_soc_register_codec(dev,
+ &nau8540_codec_driver, &nau8540_dai, 1);
+}
+
+static int nau8540_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+
+static const struct i2c_device_id nau8540_i2c_ids[] = {
+ { "nau8540", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nau8540_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8540_of_ids[] = {
+ { .compatible = "nuvoton,nau8540", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, nau8540_of_ids);
+#endif
+
+static struct i2c_driver nau8540_i2c_driver = {
+ .driver = {
+ .name = "nau8540",
+ .of_match_table = of_match_ptr(nau8540_of_ids),
+ },
+ .probe = nau8540_i2c_probe,
+ .remove = nau8540_i2c_remove,
+ .id_table = nau8540_i2c_ids,
+};
+module_i2c_driver(nau8540_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NAU85L40 driver");
+MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8540.h b/sound/soc/codecs/nau8540.h
new file mode 100644
index 000000000000..5db5b224944d
--- /dev/null
+++ b/sound/soc/codecs/nau8540.h
@@ -0,0 +1,222 @@
+/*
+ * NAU85L40 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __NAU8540_H__
+#define __NAU8540_H__
+
+#define NAU8540_REG_SW_RESET 0x00
+#define NAU8540_REG_POWER_MANAGEMENT 0x01
+#define NAU8540_REG_CLOCK_CTRL 0x02
+#define NAU8540_REG_CLOCK_SRC 0x03
+#define NAU8540_REG_FLL1 0x04
+#define NAU8540_REG_FLL2 0x05
+#define NAU8540_REG_FLL3 0x06
+#define NAU8540_REG_FLL4 0x07
+#define NAU8540_REG_FLL5 0x08
+#define NAU8540_REG_FLL6 0x09
+#define NAU8540_REG_FLL_VCO_RSV 0x0A
+#define NAU8540_REG_PCM_CTRL0 0x10
+#define NAU8540_REG_PCM_CTRL1 0x11
+#define NAU8540_REG_PCM_CTRL2 0x12
+#define NAU8540_REG_PCM_CTRL3 0x13
+#define NAU8540_REG_PCM_CTRL4 0x14
+#define NAU8540_REG_ALC_CONTROL_1 0x20
+#define NAU8540_REG_ALC_CONTROL_2 0x21
+#define NAU8540_REG_ALC_CONTROL_3 0x22
+#define NAU8540_REG_ALC_CONTROL_4 0x23
+#define NAU8540_REG_ALC_CONTROL_5 0x24
+#define NAU8540_REG_ALC_GAIN_CH12 0x2D
+#define NAU8540_REG_ALC_GAIN_CH34 0x2E
+#define NAU8540_REG_ALC_STATUS 0x2F
+#define NAU8540_REG_NOTCH_FIL1_CH1 0x30
+#define NAU8540_REG_NOTCH_FIL2_CH1 0x31
+#define NAU8540_REG_NOTCH_FIL1_CH2 0x32
+#define NAU8540_REG_NOTCH_FIL2_CH2 0x33
+#define NAU8540_REG_NOTCH_FIL1_CH3 0x34
+#define NAU8540_REG_NOTCH_FIL2_CH3 0x35
+#define NAU8540_REG_NOTCH_FIL1_CH4 0x36
+#define NAU8540_REG_NOTCH_FIL2_CH4 0x37
+#define NAU8540_REG_HPF_FILTER_CH12 0x38
+#define NAU8540_REG_HPF_FILTER_CH34 0x39
+#define NAU8540_REG_ADC_SAMPLE_RATE 0x3A
+#define NAU8540_REG_DIGITAL_GAIN_CH1 0x40
+#define NAU8540_REG_DIGITAL_GAIN_CH2 0x41
+#define NAU8540_REG_DIGITAL_GAIN_CH3 0x42
+#define NAU8540_REG_DIGITAL_GAIN_CH4 0x43
+#define NAU8540_REG_DIGITAL_MUX 0x44
+#define NAU8540_REG_P2P_CH1 0x48
+#define NAU8540_REG_P2P_CH2 0x49
+#define NAU8540_REG_P2P_CH3 0x4A
+#define NAU8540_REG_P2P_CH4 0x4B
+#define NAU8540_REG_PEAK_CH1 0x4C
+#define NAU8540_REG_PEAK_CH2 0x4D
+#define NAU8540_REG_PEAK_CH3 0x4E
+#define NAU8540_REG_PEAK_CH4 0x4F
+#define NAU8540_REG_GPIO_CTRL 0x50
+#define NAU8540_REG_MISC_CTRL 0x51
+#define NAU8540_REG_I2C_CTRL 0x52
+#define NAU8540_REG_I2C_DEVICE_ID 0x58
+#define NAU8540_REG_RST 0x5A
+#define NAU8540_REG_VMID_CTRL 0x60
+#define NAU8540_REG_MUTE 0x61
+#define NAU8540_REG_ANALOG_ADC1 0x64
+#define NAU8540_REG_ANALOG_ADC2 0x65
+#define NAU8540_REG_ANALOG_PWR 0x66
+#define NAU8540_REG_MIC_BIAS 0x67
+#define NAU8540_REG_REFERENCE 0x68
+#define NAU8540_REG_FEPGA1 0x69
+#define NAU8540_REG_FEPGA2 0x6A
+#define NAU8540_REG_FEPGA3 0x6B
+#define NAU8540_REG_FEPGA4 0x6C
+#define NAU8540_REG_PWR 0x6D
+#define NAU8540_REG_MAX NAU8540_REG_PWR
+
+
+/* POWER_MANAGEMENT (0x01) */
+#define NAU8540_ADC4_EN (0x1 << 3)
+#define NAU8540_ADC3_EN (0x1 << 2)
+#define NAU8540_ADC2_EN (0x1 << 1)
+#define NAU8540_ADC1_EN 0x1
+
+/* CLOCK_CTRL (0x02) */
+#define NAU8540_CLK_ADC_EN (0x1 << 15)
+#define NAU8540_CLK_I2S_EN (0x1 << 1)
+
+/* CLOCK_SRC (0x03) */
+#define NAU8540_CLK_SRC_SFT 15
+#define NAU8540_CLK_SRC_MASK (1 << NAU8540_CLK_SRC_SFT)
+#define NAU8540_CLK_SRC_VCO (1 << NAU8540_CLK_SRC_SFT)
+#define NAU8540_CLK_SRC_MCLK (0 << NAU8540_CLK_SRC_SFT)
+#define NAU8540_CLK_ADC_SRC_SFT 6
+#define NAU8540_CLK_ADC_SRC_MASK (0x3 << NAU8540_CLK_ADC_SRC_SFT)
+#define NAU8540_CLK_MCLK_SRC_MASK 0xf
+
+/* FLL1 (0x04) */
+#define NAU8540_FLL_RATIO_MASK 0x7f
+
+/* FLL3 (0x06) */
+#define NAU8540_FLL_CLK_SRC_SFT 10
+#define NAU8540_FLL_CLK_SRC_MASK (0x3 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_CLK_SRC_MCLK (0 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_CLK_SRC_BLK (0x2 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_CLK_SRC_FS (0x3 << NAU8540_FLL_CLK_SRC_SFT)
+#define NAU8540_FLL_INTEGER_MASK 0x3ff
+
+/* FLL4 (0x07) */
+#define NAU8540_FLL_REF_DIV_SFT 10
+#define NAU8540_FLL_REF_DIV_MASK (0x3 << NAU8540_FLL_REF_DIV_SFT)
+
+/* FLL5 (0x08) */
+#define NAU8540_FLL_PDB_DAC_EN (0x1 << 15)
+#define NAU8540_FLL_LOOP_FTR_EN (0x1 << 14)
+#define NAU8540_FLL_CLK_SW_MASK (0x1 << 13)
+#define NAU8540_FLL_CLK_SW_N2 (0x1 << 13)
+#define NAU8540_FLL_CLK_SW_REF (0x0 << 13)
+#define NAU8540_FLL_FTR_SW_MASK (0x1 << 12)
+#define NAU8540_FLL_FTR_SW_ACCU (0x1 << 12)
+#define NAU8540_FLL_FTR_SW_FILTER (0x0 << 12)
+
+/* FLL6 (0x9) */
+#define NAU8540_DCO_EN (0x1 << 15)
+#define NAU8540_SDM_EN (0x1 << 14)
+
+/* PCM_CTRL0 (0x10) */
+#define NAU8540_I2S_BP_SFT 7
+#define NAU8540_I2S_BP_INV (0x1 << NAU8540_I2S_BP_SFT)
+#define NAU8540_I2S_PCMB_SFT 6
+#define NAU8540_I2S_PCMB_EN (0x1 << NAU8540_I2S_PCMB_SFT)
+#define NAU8540_I2S_DL_SFT 2
+#define NAU8540_I2S_DL_MASK (0x3 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_16 (0 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_20 (0x1 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_24 (0x2 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DL_32 (0x3 << NAU8540_I2S_DL_SFT)
+#define NAU8540_I2S_DF_MASK 0x3
+#define NAU8540_I2S_DF_RIGTH 0
+#define NAU8540_I2S_DF_LEFT 0x1
+#define NAU8540_I2S_DF_I2S 0x2
+#define NAU8540_I2S_DF_PCM_AB 0x3
+
+/* PCM_CTRL1 (0x11) */
+#define NAU8540_I2S_LRC_DIV_SFT 12
+#define NAU8540_I2S_LRC_DIV_MASK (0x3 << NAU8540_I2S_LRC_DIV_SFT)
+#define NAU8540_I2S_DO12_OE (0x1 << 4)
+#define NAU8540_I2S_MS_SFT 3
+#define NAU8540_I2S_MS_MASK (0x1 << NAU8540_I2S_MS_SFT)
+#define NAU8540_I2S_MS_MASTER (0x1 << NAU8540_I2S_MS_SFT)
+#define NAU8540_I2S_MS_SLAVE (0x0 << NAU8540_I2S_MS_SFT)
+#define NAU8540_I2S_BLK_DIV_MASK 0x7
+
+/* PCM_CTRL1 (0x12) */
+#define NAU8540_I2S_DO34_OE (0x1 << 11)
+#define NAU8540_I2S_TSLOT_L_MASK 0x3ff
+
+/* PCM_CTRL4 (0x14) */
+#define NAU8540_TDM_MODE (0x1 << 15)
+#define NAU8540_TDM_OFFSET_EN (0x1 << 14)
+#define NAU8540_TDM_TX_MASK 0xf
+
+/* ADC_SAMPLE_RATE (0x3A) */
+#define NAU8540_ADC_OSR_MASK 0x3
+#define NAU8540_ADC_OSR_256 0x3
+#define NAU8540_ADC_OSR_128 0x2
+#define NAU8540_ADC_OSR_64 0x1
+#define NAU8540_ADC_OSR_32 0x0
+
+/* VMID_CTRL (0x60) */
+#define NAU8540_VMID_EN (1 << 6)
+#define NAU8540_VMID_SEL_SFT 4
+#define NAU8540_VMID_SEL_MASK (0x3 << NAU8540_VMID_SEL_SFT)
+
+/* MIC_BIAS (0x67) */
+#define NAU8540_PU_PRE (0x1 << 8)
+
+/* REFERENCE (0x68) */
+#define NAU8540_PRECHARGE_DIS (0x1 << 13)
+#define NAU8540_GLOBAL_BIAS_EN (0x1 << 12)
+
+
+/* System Clock Source */
+enum {
+ NAU8540_CLK_DIS,
+ NAU8540_CLK_MCLK,
+ NAU8540_CLK_INTERNAL,
+ NAU8540_CLK_FLL_MCLK,
+ NAU8540_CLK_FLL_BLK,
+ NAU8540_CLK_FLL_FS,
+};
+
+struct nau8540 {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+struct nau8540_fll {
+ int mclk_src;
+ int ratio;
+ int fll_frac;
+ int fll_int;
+ int clk_ref_div;
+};
+
+struct nau8540_fll_attr {
+ unsigned int param;
+ unsigned int val;
+};
+
+/* over sampling rate */
+struct nau8540_osr_attr {
+ unsigned int osr;
+ unsigned int clk_src;
+};
+
+
+#endif /* __NAU8540_H__ */
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
new file mode 100644
index 000000000000..cca974d26136
--- /dev/null
+++ b/sound/soc/codecs/nau8824.c
@@ -0,0 +1,1831 @@
+/*
+ * NAU88L24 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/acpi.h>
+#include <linux/math64.h>
+#include <linux/semaphore.h>
+
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "nau8824.h"
+
+
+static int nau8824_config_sysclk(struct nau8824 *nau8824,
+ int clk_id, unsigned int freq);
+static bool nau8824_is_jack_inserted(struct nau8824 *nau8824);
+
+/* the ADC threshold of headset */
+#define DMIC_CLK 3072000
+
+/* the ADC threshold of headset */
+#define HEADSET_SARADC_THD 0x80
+
+/* the parameter threshold of FLL */
+#define NAU_FREF_MAX 13500000
+#define NAU_FVCO_MAX 124000000
+#define NAU_FVCO_MIN 90000000
+
+/* scaling for mclk from sysclk_src output */
+static const struct nau8824_fll_attr mclk_src_scaling[] = {
+ { 1, 0x0 },
+ { 2, 0x2 },
+ { 4, 0x3 },
+ { 8, 0x4 },
+ { 16, 0x5 },
+ { 32, 0x6 },
+ { 3, 0x7 },
+ { 6, 0xa },
+ { 12, 0xb },
+ { 24, 0xc },
+};
+
+/* ratio for input clk freq */
+static const struct nau8824_fll_attr fll_ratio[] = {
+ { 512000, 0x01 },
+ { 256000, 0x02 },
+ { 128000, 0x04 },
+ { 64000, 0x08 },
+ { 32000, 0x10 },
+ { 8000, 0x20 },
+ { 4000, 0x40 },
+};
+
+static const struct nau8824_fll_attr fll_pre_scalar[] = {
+ { 1, 0x0 },
+ { 2, 0x1 },
+ { 4, 0x2 },
+ { 8, 0x3 },
+};
+
+/* the maximum frequency of CLK_ADC and CLK_DAC */
+#define CLK_DA_AD_MAX 6144000
+
+/* over sampling rate */
+static const struct nau8824_osr_attr osr_dac_sel[] = {
+ { 64, 2 }, /* OSR 64, SRC 1/4 */
+ { 256, 0 }, /* OSR 256, SRC 1 */
+ { 128, 1 }, /* OSR 128, SRC 1/2 */
+ { 0, 0 },
+ { 32, 3 }, /* OSR 32, SRC 1/8 */
+};
+
+static const struct nau8824_osr_attr osr_adc_sel[] = {
+ { 32, 3 }, /* OSR 32, SRC 1/8 */
+ { 64, 2 }, /* OSR 64, SRC 1/4 */
+ { 128, 1 }, /* OSR 128, SRC 1/2 */
+ { 256, 0 }, /* OSR 256, SRC 1 */
+};
+
+static const struct reg_default nau8824_reg_defaults[] = {
+ { NAU8824_REG_ENA_CTRL, 0x0000 },
+ { NAU8824_REG_CLK_GATING_ENA, 0x0000 },
+ { NAU8824_REG_CLK_DIVIDER, 0x0000 },
+ { NAU8824_REG_FLL1, 0x0000 },
+ { NAU8824_REG_FLL2, 0x3126 },
+ { NAU8824_REG_FLL3, 0x0008 },
+ { NAU8824_REG_FLL4, 0x0010 },
+ { NAU8824_REG_FLL5, 0xC000 },
+ { NAU8824_REG_FLL6, 0x6000 },
+ { NAU8824_REG_FLL_VCO_RSV, 0xF13C },
+ { NAU8824_REG_JACK_DET_CTRL, 0x0000 },
+ { NAU8824_REG_INTERRUPT_SETTING_1, 0x0000 },
+ { NAU8824_REG_IRQ, 0x0000 },
+ { NAU8824_REG_CLEAR_INT_REG, 0x0000 },
+ { NAU8824_REG_INTERRUPT_SETTING, 0x1000 },
+ { NAU8824_REG_SAR_ADC, 0x0015 },
+ { NAU8824_REG_VDET_COEFFICIENT, 0x0110 },
+ { NAU8824_REG_VDET_THRESHOLD_1, 0x0000 },
+ { NAU8824_REG_VDET_THRESHOLD_2, 0x0000 },
+ { NAU8824_REG_VDET_THRESHOLD_3, 0x0000 },
+ { NAU8824_REG_VDET_THRESHOLD_4, 0x0000 },
+ { NAU8824_REG_GPIO_SEL, 0x0000 },
+ { NAU8824_REG_PORT0_I2S_PCM_CTRL_1, 0x000B },
+ { NAU8824_REG_PORT0_I2S_PCM_CTRL_2, 0x0010 },
+ { NAU8824_REG_PORT0_LEFT_TIME_SLOT, 0x0000 },
+ { NAU8824_REG_PORT0_RIGHT_TIME_SLOT, 0x0000 },
+ { NAU8824_REG_TDM_CTRL, 0x0000 },
+ { NAU8824_REG_ADC_HPF_FILTER, 0x0000 },
+ { NAU8824_REG_ADC_FILTER_CTRL, 0x0002 },
+ { NAU8824_REG_DAC_FILTER_CTRL_1, 0x0000 },
+ { NAU8824_REG_DAC_FILTER_CTRL_2, 0x0000 },
+ { NAU8824_REG_NOTCH_FILTER_1, 0x0000 },
+ { NAU8824_REG_NOTCH_FILTER_2, 0x0000 },
+ { NAU8824_REG_EQ1_LOW, 0x112C },
+ { NAU8824_REG_EQ2_EQ3, 0x2C2C },
+ { NAU8824_REG_EQ4_EQ5, 0x2C2C },
+ { NAU8824_REG_ADC_CH0_DGAIN_CTRL, 0x0100 },
+ { NAU8824_REG_ADC_CH1_DGAIN_CTRL, 0x0100 },
+ { NAU8824_REG_ADC_CH2_DGAIN_CTRL, 0x0100 },
+ { NAU8824_REG_ADC_CH3_DGAIN_CTRL, 0x0100 },
+ { NAU8824_REG_DAC_MUTE_CTRL, 0x0000 },
+ { NAU8824_REG_DAC_CH0_DGAIN_CTRL, 0x0100 },
+ { NAU8824_REG_DAC_CH1_DGAIN_CTRL, 0x0100 },
+ { NAU8824_REG_ADC_TO_DAC_ST, 0x0000 },
+ { NAU8824_REG_DRC_KNEE_IP12_ADC_CH01, 0x1486 },
+ { NAU8824_REG_DRC_KNEE_IP34_ADC_CH01, 0x0F12 },
+ { NAU8824_REG_DRC_SLOPE_ADC_CH01, 0x25FF },
+ { NAU8824_REG_DRC_ATKDCY_ADC_CH01, 0x3457 },
+ { NAU8824_REG_DRC_KNEE_IP12_ADC_CH23, 0x1486 },
+ { NAU8824_REG_DRC_KNEE_IP34_ADC_CH23, 0x0F12 },
+ { NAU8824_REG_DRC_SLOPE_ADC_CH23, 0x25FF },
+ { NAU8824_REG_DRC_ATKDCY_ADC_CH23, 0x3457 },
+ { NAU8824_REG_DRC_GAINL_ADC0, 0x0200 },
+ { NAU8824_REG_DRC_GAINL_ADC1, 0x0200 },
+ { NAU8824_REG_DRC_GAINL_ADC2, 0x0200 },
+ { NAU8824_REG_DRC_GAINL_ADC3, 0x0200 },
+ { NAU8824_REG_DRC_KNEE_IP12_DAC, 0x1486 },
+ { NAU8824_REG_DRC_KNEE_IP34_DAC, 0x0F12 },
+ { NAU8824_REG_DRC_SLOPE_DAC, 0x25F9 },
+ { NAU8824_REG_DRC_ATKDCY_DAC, 0x3457 },
+ { NAU8824_REG_DRC_GAIN_DAC_CH0, 0x0200 },
+ { NAU8824_REG_DRC_GAIN_DAC_CH1, 0x0200 },
+ { NAU8824_REG_MODE, 0x0000 },
+ { NAU8824_REG_MODE1, 0x0000 },
+ { NAU8824_REG_MODE2, 0x0000 },
+ { NAU8824_REG_CLASSG, 0x0000 },
+ { NAU8824_REG_OTP_EFUSE, 0x0000 },
+ { NAU8824_REG_OTPDOUT_1, 0x0000 },
+ { NAU8824_REG_OTPDOUT_2, 0x0000 },
+ { NAU8824_REG_MISC_CTRL, 0x0000 },
+ { NAU8824_REG_I2C_TIMEOUT, 0xEFFF },
+ { NAU8824_REG_TEST_MODE, 0x0000 },
+ { NAU8824_REG_I2C_DEVICE_ID, 0x1AF1 },
+ { NAU8824_REG_SAR_ADC_DATA_OUT, 0x00FF },
+ { NAU8824_REG_BIAS_ADJ, 0x0000 },
+ { NAU8824_REG_PGA_GAIN, 0x0000 },
+ { NAU8824_REG_TRIM_SETTINGS, 0x0000 },
+ { NAU8824_REG_ANALOG_CONTROL_1, 0x0000 },
+ { NAU8824_REG_ANALOG_CONTROL_2, 0x0000 },
+ { NAU8824_REG_ENABLE_LO, 0x0000 },
+ { NAU8824_REG_GAIN_LO, 0x0000 },
+ { NAU8824_REG_CLASSD_GAIN_1, 0x0000 },
+ { NAU8824_REG_CLASSD_GAIN_2, 0x0000 },
+ { NAU8824_REG_ANALOG_ADC_1, 0x0011 },
+ { NAU8824_REG_ANALOG_ADC_2, 0x0020 },
+ { NAU8824_REG_RDAC, 0x0008 },
+ { NAU8824_REG_MIC_BIAS, 0x0006 },
+ { NAU8824_REG_HS_VOLUME_CONTROL, 0x0000 },
+ { NAU8824_REG_BOOST, 0x0000 },
+ { NAU8824_REG_FEPGA, 0x0000 },
+ { NAU8824_REG_FEPGA_II, 0x0000 },
+ { NAU8824_REG_FEPGA_SE, 0x0000 },
+ { NAU8824_REG_FEPGA_ATTENUATION, 0x0000 },
+ { NAU8824_REG_ATT_PORT0, 0x0000 },
+ { NAU8824_REG_ATT_PORT1, 0x0000 },
+ { NAU8824_REG_POWER_UP_CONTROL, 0x0000 },
+ { NAU8824_REG_CHARGE_PUMP_CONTROL, 0x0300 },
+ { NAU8824_REG_CHARGE_PUMP_INPUT, 0x0013 },
+};
+
+static int nau8824_sema_acquire(struct nau8824 *nau8824, long timeout)
+{
+ int ret;
+
+ if (timeout) {
+ ret = down_timeout(&nau8824->jd_sem, timeout);
+ if (ret < 0)
+ dev_warn(nau8824->dev, "Acquire semaphone timeout\n");
+ } else {
+ ret = down_interruptible(&nau8824->jd_sem);
+ if (ret < 0)
+ dev_warn(nau8824->dev, "Acquire semaphone fail\n");
+ }
+
+ return ret;
+}
+
+static inline void nau8824_sema_release(struct nau8824 *nau8824)
+{
+ up(&nau8824->jd_sem);
+}
+
+static bool nau8824_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8824_REG_ENA_CTRL ... NAU8824_REG_FLL_VCO_RSV:
+ case NAU8824_REG_JACK_DET_CTRL:
+ case NAU8824_REG_INTERRUPT_SETTING_1:
+ case NAU8824_REG_IRQ:
+ case NAU8824_REG_CLEAR_INT_REG ... NAU8824_REG_VDET_THRESHOLD_4:
+ case NAU8824_REG_GPIO_SEL:
+ case NAU8824_REG_PORT0_I2S_PCM_CTRL_1 ... NAU8824_REG_TDM_CTRL:
+ case NAU8824_REG_ADC_HPF_FILTER ... NAU8824_REG_EQ4_EQ5:
+ case NAU8824_REG_ADC_CH0_DGAIN_CTRL ... NAU8824_REG_ADC_TO_DAC_ST:
+ case NAU8824_REG_DRC_KNEE_IP12_ADC_CH01 ... NAU8824_REG_DRC_GAINL_ADC3:
+ case NAU8824_REG_DRC_KNEE_IP12_DAC ... NAU8824_REG_DRC_GAIN_DAC_CH1:
+ case NAU8824_REG_CLASSG ... NAU8824_REG_OTP_EFUSE:
+ case NAU8824_REG_OTPDOUT_1 ... NAU8824_REG_OTPDOUT_2:
+ case NAU8824_REG_I2C_TIMEOUT:
+ case NAU8824_REG_I2C_DEVICE_ID ... NAU8824_REG_SAR_ADC_DATA_OUT:
+ case NAU8824_REG_BIAS_ADJ ... NAU8824_REG_CLASSD_GAIN_2:
+ case NAU8824_REG_ANALOG_ADC_1 ... NAU8824_REG_ATT_PORT1:
+ case NAU8824_REG_POWER_UP_CONTROL ... NAU8824_REG_CHARGE_PUMP_INPUT:
+ return true;
+ default:
+ return false;
+ }
+
+}
+
+static bool nau8824_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8824_REG_RESET ... NAU8824_REG_FLL_VCO_RSV:
+ case NAU8824_REG_JACK_DET_CTRL:
+ case NAU8824_REG_INTERRUPT_SETTING_1:
+ case NAU8824_REG_CLEAR_INT_REG ... NAU8824_REG_VDET_THRESHOLD_4:
+ case NAU8824_REG_GPIO_SEL:
+ case NAU8824_REG_PORT0_I2S_PCM_CTRL_1 ... NAU8824_REG_TDM_CTRL:
+ case NAU8824_REG_ADC_HPF_FILTER ... NAU8824_REG_EQ4_EQ5:
+ case NAU8824_REG_ADC_CH0_DGAIN_CTRL ... NAU8824_REG_ADC_TO_DAC_ST:
+ case NAU8824_REG_DRC_KNEE_IP12_ADC_CH01:
+ case NAU8824_REG_DRC_KNEE_IP34_ADC_CH01:
+ case NAU8824_REG_DRC_SLOPE_ADC_CH01:
+ case NAU8824_REG_DRC_ATKDCY_ADC_CH01:
+ case NAU8824_REG_DRC_KNEE_IP12_ADC_CH23:
+ case NAU8824_REG_DRC_KNEE_IP34_ADC_CH23:
+ case NAU8824_REG_DRC_SLOPE_ADC_CH23:
+ case NAU8824_REG_DRC_ATKDCY_ADC_CH23:
+ case NAU8824_REG_DRC_KNEE_IP12_DAC ... NAU8824_REG_DRC_ATKDCY_DAC:
+ case NAU8824_REG_CLASSG ... NAU8824_REG_OTP_EFUSE:
+ case NAU8824_REG_I2C_TIMEOUT:
+ case NAU8824_REG_BIAS_ADJ ... NAU8824_REG_CLASSD_GAIN_2:
+ case NAU8824_REG_ANALOG_ADC_1 ... NAU8824_REG_ATT_PORT1:
+ case NAU8824_REG_POWER_UP_CONTROL ... NAU8824_REG_CHARGE_PUMP_CONTROL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool nau8824_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case NAU8824_REG_RESET:
+ case NAU8824_REG_IRQ ... NAU8824_REG_CLEAR_INT_REG:
+ case NAU8824_REG_DRC_GAINL_ADC0 ... NAU8824_REG_DRC_GAINL_ADC3:
+ case NAU8824_REG_DRC_GAIN_DAC_CH0 ... NAU8824_REG_DRC_GAIN_DAC_CH1:
+ case NAU8824_REG_OTPDOUT_1 ... NAU8824_REG_OTPDOUT_2:
+ case NAU8824_REG_I2C_DEVICE_ID ... NAU8824_REG_SAR_ADC_DATA_OUT:
+ case NAU8824_REG_CHARGE_PUMP_INPUT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char * const nau8824_companding[] = {
+ "Off", "NC", "u-law", "A-law" };
+
+static const struct soc_enum nau8824_companding_adc_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_PORT0_I2S_PCM_CTRL_1, 12,
+ ARRAY_SIZE(nau8824_companding), nau8824_companding);
+
+static const struct soc_enum nau8824_companding_dac_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_PORT0_I2S_PCM_CTRL_1, 14,
+ ARRAY_SIZE(nau8824_companding), nau8824_companding);
+
+static const char * const nau8824_adc_decimation[] = {
+ "32", "64", "128", "256" };
+
+static const struct soc_enum nau8824_adc_decimation_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_ADC_FILTER_CTRL, 0,
+ ARRAY_SIZE(nau8824_adc_decimation), nau8824_adc_decimation);
+
+static const char * const nau8824_dac_oversampl[] = {
+ "64", "256", "128", "", "32" };
+
+static const struct soc_enum nau8824_dac_oversampl_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_DAC_FILTER_CTRL_1, 0,
+ ARRAY_SIZE(nau8824_dac_oversampl), nau8824_dac_oversampl);
+
+static const char * const nau8824_input_channel[] = {
+ "Input CH0", "Input CH1", "Input CH2", "Input CH3" };
+
+static const struct soc_enum nau8824_adc_ch0_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH0_DGAIN_CTRL, 9,
+ ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const struct soc_enum nau8824_adc_ch1_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH1_DGAIN_CTRL, 9,
+ ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const struct soc_enum nau8824_adc_ch2_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH2_DGAIN_CTRL, 9,
+ ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const struct soc_enum nau8824_adc_ch3_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_ADC_CH3_DGAIN_CTRL, 9,
+ ARRAY_SIZE(nau8824_input_channel), nau8824_input_channel);
+
+static const char * const nau8824_tdm_slot[] = {
+ "Slot 0", "Slot 1", "Slot 2", "Slot 3" };
+
+static const struct soc_enum nau8824_dac_left_sel_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_TDM_CTRL, 6,
+ ARRAY_SIZE(nau8824_tdm_slot), nau8824_tdm_slot);
+
+static const struct soc_enum nau8824_dac_right_sel_enum =
+ SOC_ENUM_SINGLE(NAU8824_REG_TDM_CTRL, 4,
+ ARRAY_SIZE(nau8824_tdm_slot), nau8824_tdm_slot);
+
+static const DECLARE_TLV_DB_MINMAX_MUTE(spk_vol_tlv, 0, 2400);
+static const DECLARE_TLV_DB_MINMAX(hp_vol_tlv, -3000, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 200, 0);
+static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, -12800, 50, 0);
+
+static const struct snd_kcontrol_new nau8824_snd_controls[] = {
+ SOC_ENUM("ADC Companding", nau8824_companding_adc_enum),
+ SOC_ENUM("DAC Companding", nau8824_companding_dac_enum),
+
+ SOC_ENUM("ADC Decimation Rate", nau8824_adc_decimation_enum),
+ SOC_ENUM("DAC Oversampling Rate", nau8824_dac_oversampl_enum),
+
+ SOC_SINGLE_TLV("Speaker Right DACR Volume",
+ NAU8824_REG_CLASSD_GAIN_1, 8, 0x1f, 0, spk_vol_tlv),
+ SOC_SINGLE_TLV("Speaker Left DACL Volume",
+ NAU8824_REG_CLASSD_GAIN_2, 0, 0x1f, 0, spk_vol_tlv),
+ SOC_SINGLE_TLV("Speaker Left DACR Volume",
+ NAU8824_REG_CLASSD_GAIN_1, 0, 0x1f, 0, spk_vol_tlv),
+ SOC_SINGLE_TLV("Speaker Right DACL Volume",
+ NAU8824_REG_CLASSD_GAIN_2, 8, 0x1f, 0, spk_vol_tlv),
+
+ SOC_SINGLE_TLV("Headphone Right DACR Volume",
+ NAU8824_REG_ATT_PORT0, 8, 0x1f, 0, hp_vol_tlv),
+ SOC_SINGLE_TLV("Headphone Left DACL Volume",
+ NAU8824_REG_ATT_PORT0, 0, 0x1f, 0, hp_vol_tlv),
+ SOC_SINGLE_TLV("Headphone Right DACL Volume",
+ NAU8824_REG_ATT_PORT1, 8, 0x1f, 0, hp_vol_tlv),
+ SOC_SINGLE_TLV("Headphone Left DACR Volume",
+ NAU8824_REG_ATT_PORT1, 0, 0x1f, 0, hp_vol_tlv),
+
+ SOC_SINGLE_TLV("MIC1 Volume", NAU8824_REG_FEPGA_II,
+ NAU8824_FEPGA_GAINL_SFT, 0x12, 0, mic_vol_tlv),
+ SOC_SINGLE_TLV("MIC2 Volume", NAU8824_REG_FEPGA_II,
+ NAU8824_FEPGA_GAINR_SFT, 0x12, 0, mic_vol_tlv),
+
+ SOC_SINGLE_TLV("DMIC1 Volume", NAU8824_REG_ADC_CH0_DGAIN_CTRL,
+ 0, 0x164, 0, dmic_vol_tlv),
+ SOC_SINGLE_TLV("DMIC2 Volume", NAU8824_REG_ADC_CH1_DGAIN_CTRL,
+ 0, 0x164, 0, dmic_vol_tlv),
+ SOC_SINGLE_TLV("DMIC3 Volume", NAU8824_REG_ADC_CH2_DGAIN_CTRL,
+ 0, 0x164, 0, dmic_vol_tlv),
+ SOC_SINGLE_TLV("DMIC4 Volume", NAU8824_REG_ADC_CH3_DGAIN_CTRL,
+ 0, 0x164, 0, dmic_vol_tlv),
+
+ SOC_ENUM("ADC CH0 Select", nau8824_adc_ch0_enum),
+ SOC_ENUM("ADC CH1 Select", nau8824_adc_ch1_enum),
+ SOC_ENUM("ADC CH2 Select", nau8824_adc_ch2_enum),
+ SOC_ENUM("ADC CH3 Select", nau8824_adc_ch3_enum),
+
+ SOC_SINGLE("ADC CH0 TX Switch", NAU8824_REG_TDM_CTRL, 0, 1, 0),
+ SOC_SINGLE("ADC CH1 TX Switch", NAU8824_REG_TDM_CTRL, 1, 1, 0),
+ SOC_SINGLE("ADC CH2 TX Switch", NAU8824_REG_TDM_CTRL, 2, 1, 0),
+ SOC_SINGLE("ADC CH3 TX Switch", NAU8824_REG_TDM_CTRL, 3, 1, 0),
+
+ SOC_ENUM("DACL Channel Source", nau8824_dac_left_sel_enum),
+ SOC_ENUM("DACR Channel Source", nau8824_dac_right_sel_enum),
+
+ SOC_SINGLE("DACL LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 0, 1, 0),
+ SOC_SINGLE("DACR LR Mix", NAU8824_REG_DAC_MUTE_CTRL, 1, 1, 0),
+};
+
+static int nau8824_output_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Disables the TESTDAC to let DAC signal pass through. */
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_ENABLE_LO,
+ NAU8824_TEST_DAC_EN, 0);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_ENABLE_LO,
+ NAU8824_TEST_DAC_EN, NAU8824_TEST_DAC_EN);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nau8824_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_ANALOG_CONTROL_2,
+ NAU8824_CLASSD_CLAMP_DIS, NAU8824_CLASSD_CLAMP_DIS);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_ANALOG_CONTROL_2,
+ NAU8824_CLASSD_CLAMP_DIS, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nau8824_pump_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* Prevent startup click by letting charge pump to ramp up */
+ msleep(10);
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_CHARGE_PUMP_CONTROL,
+ NAU8824_JAMNODCLOW, NAU8824_JAMNODCLOW);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_CHARGE_PUMP_CONTROL,
+ NAU8824_JAMNODCLOW, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int system_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ /* Set clock source to disable or internal clock before the
+ * playback or capture end. Codec needs clock for Jack
+ * detection and button press if jack inserted; otherwise,
+ * the clock should be closed.
+ */
+ if (nau8824_is_jack_inserted(nau8824)) {
+ nau8824_config_sysclk(nau8824,
+ NAU8824_CLK_INTERNAL, 0);
+ } else {
+ nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+ }
+ }
+ return 0;
+}
+
+static int dmic_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+ int src;
+
+ /* The DMIC clock is gotten from system clock (256fs) divided by
+ * DMIC_SRC (1, 2, 4, 8, 16, 32). The clock has to be equal or
+ * less than 3.072 MHz.
+ */
+ for (src = 0; src < 5; src++) {
+ if ((0x1 << (8 - src)) * nau8824->fs <= DMIC_CLK)
+ break;
+ }
+ dev_dbg(nau8824->dev, "dmic src %d for mclk %d\n", src, nau8824->fs * 256);
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_DMIC_SRC_MASK, (src << NAU8824_CLK_DMIC_SRC_SFT));
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new nau8824_adc_ch0_dmic =
+ SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+ NAU8824_ADC_CH0_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_ch1_dmic =
+ SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+ NAU8824_ADC_CH1_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_ch2_dmic =
+ SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+ NAU8824_ADC_CH2_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_ch3_dmic =
+ SOC_DAPM_SINGLE("Switch", NAU8824_REG_ENA_CTRL,
+ NAU8824_ADC_CH3_DMIC_SFT, 1, 0);
+
+static const struct snd_kcontrol_new nau8824_adc_left_mixer[] = {
+ SOC_DAPM_SINGLE("MIC Switch", NAU8824_REG_FEPGA,
+ NAU8824_FEPGA_MODEL_MIC1_SFT, 1, 0),
+ SOC_DAPM_SINGLE("HSMIC Switch", NAU8824_REG_FEPGA,
+ NAU8824_FEPGA_MODEL_HSMIC_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_adc_right_mixer[] = {
+ SOC_DAPM_SINGLE("MIC Switch", NAU8824_REG_FEPGA,
+ NAU8824_FEPGA_MODER_MIC2_SFT, 1, 0),
+ SOC_DAPM_SINGLE("HSMIC Switch", NAU8824_REG_FEPGA,
+ NAU8824_FEPGA_MODER_HSMIC_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_hp_left_mixer[] = {
+ SOC_DAPM_SINGLE("DAC Right Switch", NAU8824_REG_ENABLE_LO,
+ NAU8824_DACR_HPL_EN_SFT, 1, 0),
+ SOC_DAPM_SINGLE("DAC Left Switch", NAU8824_REG_ENABLE_LO,
+ NAU8824_DACL_HPL_EN_SFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new nau8824_hp_right_mixer[] = {
+ SOC_DAPM_SINGLE("DAC Left Switch", NAU8824_REG_ENABLE_LO,
+ NAU8824_DACL_HPR_EN_SFT, 1, 0),
+ SOC_DAPM_SINGLE("DAC Right Switch", NAU8824_REG_ENABLE_LO,
+ NAU8824_DACR_HPR_EN_SFT, 1, 0),
+};
+
+static const char * const nau8824_dac_src[] = { "DACL", "DACR" };
+
+static SOC_ENUM_SINGLE_DECL(
+ nau8824_dacl_enum, NAU8824_REG_DAC_CH0_DGAIN_CTRL,
+ NAU8824_DAC_CH0_SEL_SFT, nau8824_dac_src);
+
+static SOC_ENUM_SINGLE_DECL(
+ nau8824_dacr_enum, NAU8824_REG_DAC_CH1_DGAIN_CTRL,
+ NAU8824_DAC_CH1_SEL_SFT, nau8824_dac_src);
+
+static const struct snd_kcontrol_new nau8824_dacl_mux =
+ SOC_DAPM_ENUM("DACL Source", nau8824_dacl_enum);
+
+static const struct snd_kcontrol_new nau8824_dacr_mux =
+ SOC_DAPM_ENUM("DACR Source", nau8824_dacr_enum);
+
+
+static const struct snd_soc_dapm_widget nau8824_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("System Clock", SND_SOC_NOPM, 0, 0,
+ system_clock_control, SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("HSMIC1"),
+ SND_SOC_DAPM_INPUT("HSMIC2"),
+ SND_SOC_DAPM_INPUT("MIC1"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+ SND_SOC_DAPM_INPUT("DMIC3"),
+ SND_SOC_DAPM_INPUT("DMIC4"),
+
+ SND_SOC_DAPM_SUPPLY("SAR", NAU8824_REG_SAR_ADC,
+ NAU8824_SAR_ADC_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS", NAU8824_REG_MIC_BIAS,
+ NAU8824_MICBIAS_POWERUP_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC12 Power", NAU8824_REG_BIAS_ADJ,
+ NAU8824_DMIC1_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC34 Power", NAU8824_REG_BIAS_ADJ,
+ NAU8824_DMIC2_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DMIC Clock", SND_SOC_NOPM, 0, 0,
+ dmic_clock_control, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SWITCH("DMIC1 Enable", SND_SOC_NOPM,
+ 0, 0, &nau8824_adc_ch0_dmic),
+ SND_SOC_DAPM_SWITCH("DMIC2 Enable", SND_SOC_NOPM,
+ 0, 0, &nau8824_adc_ch1_dmic),
+ SND_SOC_DAPM_SWITCH("DMIC3 Enable", SND_SOC_NOPM,
+ 0, 0, &nau8824_adc_ch2_dmic),
+ SND_SOC_DAPM_SWITCH("DMIC4 Enable", SND_SOC_NOPM,
+ 0, 0, &nau8824_adc_ch3_dmic),
+
+ SND_SOC_DAPM_MIXER("Left ADC", NAU8824_REG_POWER_UP_CONTROL,
+ 12, 0, nau8824_adc_left_mixer,
+ ARRAY_SIZE(nau8824_adc_left_mixer)),
+ SND_SOC_DAPM_MIXER("Right ADC", NAU8824_REG_POWER_UP_CONTROL,
+ 13, 0, nau8824_adc_right_mixer,
+ ARRAY_SIZE(nau8824_adc_right_mixer)),
+
+ SND_SOC_DAPM_ADC("ADCL", NULL, NAU8824_REG_ANALOG_ADC_2,
+ NAU8824_ADCL_EN_SFT, 0),
+ SND_SOC_DAPM_ADC("ADCR", NULL, NAU8824_REG_ANALOG_ADC_2,
+ NAU8824_ADCR_EN_SFT, 0),
+
+ SND_SOC_DAPM_AIF_OUT("AIFTX", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIFRX", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_DAC("DACL", NULL, NAU8824_REG_RDAC,
+ NAU8824_DACL_EN_SFT, 0),
+ SND_SOC_DAPM_SUPPLY("DACL Clock", NAU8824_REG_RDAC,
+ NAU8824_DACL_CLK_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_DAC("DACR", NULL, NAU8824_REG_RDAC,
+ NAU8824_DACR_EN_SFT, 0),
+ SND_SOC_DAPM_SUPPLY("DACR Clock", NAU8824_REG_RDAC,
+ NAU8824_DACR_CLK_SFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8824_dacl_mux),
+ SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8824_dacr_mux),
+
+ SND_SOC_DAPM_PGA_S("Output DACL", 0, NAU8824_REG_CHARGE_PUMP_CONTROL,
+ 8, 1, nau8824_output_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_S("Output DACR", 0, NAU8824_REG_CHARGE_PUMP_CONTROL,
+ 9, 1, nau8824_output_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_PGA_S("ClassD", 0, NAU8824_REG_CLASSD_GAIN_1,
+ NAU8824_CLASSD_EN_SFT, 0, nau8824_spk_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("Left Headphone", NAU8824_REG_CLASSG,
+ NAU8824_CLASSG_LDAC_EN_SFT, 0, nau8824_hp_left_mixer,
+ ARRAY_SIZE(nau8824_hp_left_mixer)),
+ SND_SOC_DAPM_MIXER("Right Headphone", NAU8824_REG_CLASSG,
+ NAU8824_CLASSG_RDAC_EN_SFT, 0, nau8824_hp_right_mixer,
+ ARRAY_SIZE(nau8824_hp_right_mixer)),
+ SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8824_REG_CHARGE_PUMP_CONTROL,
+ NAU8824_CHARGE_PUMP_EN_SFT, 0, nau8824_pump_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_PGA("Output Driver L",
+ NAU8824_REG_POWER_UP_CONTROL, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Output Driver R",
+ NAU8824_REG_POWER_UP_CONTROL, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Main Driver L",
+ NAU8824_REG_POWER_UP_CONTROL, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Main Driver R",
+ NAU8824_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("HP Boost Driver", NAU8824_REG_BOOST,
+ NAU8824_HP_BOOST_DIS_SFT, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Class G", NAU8824_REG_CLASSG,
+ NAU8824_CLASSG_EN_SFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+ SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+};
+
+static const struct snd_soc_dapm_route nau8824_dapm_routes[] = {
+ {"DMIC1 Enable", "Switch", "DMIC1"},
+ {"DMIC2 Enable", "Switch", "DMIC2"},
+ {"DMIC3 Enable", "Switch", "DMIC3"},
+ {"DMIC4 Enable", "Switch", "DMIC4"},
+
+ {"DMIC1", NULL, "DMIC12 Power"},
+ {"DMIC2", NULL, "DMIC12 Power"},
+ {"DMIC3", NULL, "DMIC34 Power"},
+ {"DMIC4", NULL, "DMIC34 Power"},
+ {"DMIC12 Power", NULL, "DMIC Clock"},
+ {"DMIC34 Power", NULL, "DMIC Clock"},
+
+ {"Left ADC", "MIC Switch", "MIC1"},
+ {"Left ADC", "HSMIC Switch", "HSMIC1"},
+ {"Right ADC", "MIC Switch", "MIC2"},
+ {"Right ADC", "HSMIC Switch", "HSMIC2"},
+
+ {"ADCL", NULL, "Left ADC"},
+ {"ADCR", NULL, "Right ADC"},
+
+ {"AIFTX", NULL, "MICBIAS"},
+ {"AIFTX", NULL, "ADCL"},
+ {"AIFTX", NULL, "ADCR"},
+ {"AIFTX", NULL, "DMIC1 Enable"},
+ {"AIFTX", NULL, "DMIC2 Enable"},
+ {"AIFTX", NULL, "DMIC3 Enable"},
+ {"AIFTX", NULL, "DMIC4 Enable"},
+
+ {"AIFTX", NULL, "System Clock"},
+ {"AIFRX", NULL, "System Clock"},
+
+ {"DACL", NULL, "AIFRX"},
+ {"DACL", NULL, "DACL Clock"},
+ {"DACR", NULL, "AIFRX"},
+ {"DACR", NULL, "DACR Clock"},
+
+ {"DACL Mux", "DACL", "DACL"},
+ {"DACL Mux", "DACR", "DACR"},
+ {"DACR Mux", "DACL", "DACL"},
+ {"DACR Mux", "DACR", "DACR"},
+
+ {"Output DACL", NULL, "DACL Mux"},
+ {"Output DACR", NULL, "DACR Mux"},
+
+ {"ClassD", NULL, "Output DACL"},
+ {"ClassD", NULL, "Output DACR"},
+
+ {"Left Headphone", "DAC Left Switch", "Output DACL"},
+ {"Left Headphone", "DAC Right Switch", "Output DACR"},
+ {"Right Headphone", "DAC Left Switch", "Output DACL"},
+ {"Right Headphone", "DAC Right Switch", "Output DACR"},
+
+ {"Charge Pump", NULL, "Left Headphone"},
+ {"Charge Pump", NULL, "Right Headphone"},
+ {"Output Driver L", NULL, "Charge Pump"},
+ {"Output Driver R", NULL, "Charge Pump"},
+ {"Main Driver L", NULL, "Output Driver L"},
+ {"Main Driver R", NULL, "Output Driver R"},
+ {"Class G", NULL, "Main Driver L"},
+ {"Class G", NULL, "Main Driver R"},
+ {"HP Boost Driver", NULL, "Class G"},
+
+ {"SPKOUTL", NULL, "ClassD"},
+ {"SPKOUTR", NULL, "ClassD"},
+ {"HPOL", NULL, "HP Boost Driver"},
+ {"HPOR", NULL, "HP Boost Driver"},
+};
+
+static bool nau8824_is_jack_inserted(struct nau8824 *nau8824)
+{
+ struct snd_soc_jack *jack = nau8824->jack;
+ bool insert = FALSE;
+
+ if (nau8824->irq && jack)
+ insert = jack->status & SND_JACK_HEADPHONE;
+
+ return insert;
+}
+
+static void nau8824_int_status_clear_all(struct regmap *regmap)
+{
+ int active_irq, clear_irq, i;
+
+ /* Reset the intrruption status from rightmost bit if the corres-
+ * ponding irq event occurs.
+ */
+ regmap_read(regmap, NAU8824_REG_IRQ, &active_irq);
+ for (i = 0; i < NAU8824_REG_DATA_LEN; i++) {
+ clear_irq = (0x1 << i);
+ if (active_irq & clear_irq)
+ regmap_write(regmap,
+ NAU8824_REG_CLEAR_INT_REG, clear_irq);
+ }
+}
+
+static void nau8824_eject_jack(struct nau8824 *nau8824)
+{
+ struct snd_soc_dapm_context *dapm = nau8824->dapm;
+ struct regmap *regmap = nau8824->regmap;
+
+ /* Clear all interruption status */
+ nau8824_int_status_clear_all(regmap);
+
+ snd_soc_dapm_disable_pin(dapm, "SAR");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_sync(dapm);
+
+ /* Enable the insertion interruption, disable the ejection
+ * interruption, and then bypass de-bounce circuit.
+ */
+ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+ NAU8824_IRQ_KEY_RELEASE_DIS | NAU8824_IRQ_KEY_SHORT_PRESS_DIS |
+ NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_INSERT_DIS,
+ NAU8824_IRQ_KEY_RELEASE_DIS | NAU8824_IRQ_KEY_SHORT_PRESS_DIS |
+ NAU8824_IRQ_EJECT_DIS);
+ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1,
+ NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN,
+ NAU8824_IRQ_INSERT_EN);
+ regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
+ NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
+
+ /* Close clock for jack type detection at manual mode */
+ nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+}
+
+static void nau8824_jdet_work(struct work_struct *work)
+{
+ struct nau8824 *nau8824 = container_of(
+ work, struct nau8824, jdet_work);
+ struct snd_soc_dapm_context *dapm = nau8824->dapm;
+ struct regmap *regmap = nau8824->regmap;
+ int adc_value, event = 0, event_mask = 0;
+
+ snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_force_enable_pin(dapm, "SAR");
+ snd_soc_dapm_sync(dapm);
+
+ msleep(100);
+
+ regmap_read(regmap, NAU8824_REG_SAR_ADC_DATA_OUT, &adc_value);
+ adc_value = adc_value & NAU8824_SAR_ADC_DATA_MASK;
+ dev_dbg(nau8824->dev, "SAR ADC data 0x%02x\n", adc_value);
+ if (adc_value < HEADSET_SARADC_THD) {
+ event |= SND_JACK_HEADPHONE;
+
+ snd_soc_dapm_disable_pin(dapm, "SAR");
+ snd_soc_dapm_disable_pin(dapm, "MICBIAS");
+ snd_soc_dapm_sync(dapm);
+ } else {
+ event |= SND_JACK_HEADSET;
+ }
+ event_mask |= SND_JACK_HEADSET;
+ snd_soc_jack_report(nau8824->jack, event, event_mask);
+
+ nau8824_sema_release(nau8824);
+}
+
+static void nau8824_setup_auto_irq(struct nau8824 *nau8824)
+{
+ struct regmap *regmap = nau8824->regmap;
+
+ /* Enable jack ejection, short key press and release interruption. */
+ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING_1,
+ NAU8824_IRQ_INSERT_EN | NAU8824_IRQ_EJECT_EN,
+ NAU8824_IRQ_EJECT_EN);
+ regmap_update_bits(regmap, NAU8824_REG_INTERRUPT_SETTING,
+ NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_KEY_RELEASE_DIS |
+ NAU8824_IRQ_KEY_SHORT_PRESS_DIS, 0);
+ /* Enable internal VCO needed for interruptions */
+ nau8824_config_sysclk(nau8824, NAU8824_CLK_INTERNAL, 0);
+ regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
+ NAU8824_JD_SLEEP_MODE, 0);
+}
+
+static int nau8824_button_decode(int value)
+{
+ int buttons = 0;
+
+ /* The chip supports up to 8 buttons, but ALSA defines
+ * only 6 buttons.
+ */
+ if (value & BIT(0))
+ buttons |= SND_JACK_BTN_0;
+ if (value & BIT(1))
+ buttons |= SND_JACK_BTN_1;
+ if (value & BIT(2))
+ buttons |= SND_JACK_BTN_2;
+ if (value & BIT(3))
+ buttons |= SND_JACK_BTN_3;
+ if (value & BIT(4))
+ buttons |= SND_JACK_BTN_4;
+ if (value & BIT(5))
+ buttons |= SND_JACK_BTN_5;
+
+ return buttons;
+}
+
+#define NAU8824_BUTTONS (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+ SND_JACK_BTN_2 | SND_JACK_BTN_3)
+
+static irqreturn_t nau8824_interrupt(int irq, void *data)
+{
+ struct nau8824 *nau8824 = (struct nau8824 *)data;
+ struct regmap *regmap = nau8824->regmap;
+ int active_irq, clear_irq = 0, event = 0, event_mask = 0;
+
+ if (regmap_read(regmap, NAU8824_REG_IRQ, &active_irq)) {
+ dev_err(nau8824->dev, "failed to read irq status\n");
+ return IRQ_NONE;
+ }
+ dev_dbg(nau8824->dev, "IRQ %x\n", active_irq);
+
+ if (active_irq & NAU8824_JACK_EJECTION_DETECTED) {
+ nau8824_eject_jack(nau8824);
+ event_mask |= SND_JACK_HEADSET;
+ clear_irq = NAU8824_JACK_EJECTION_DETECTED;
+ /* release semaphore held after resume,
+ * and cancel jack detection
+ */
+ nau8824_sema_release(nau8824);
+ cancel_work_sync(&nau8824->jdet_work);
+ } else if (active_irq & NAU8824_KEY_SHORT_PRESS_IRQ) {
+ int key_status, button_pressed;
+
+ regmap_read(regmap, NAU8824_REG_CLEAR_INT_REG,
+ &key_status);
+
+ /* lower 8 bits of the register are for pressed keys */
+ button_pressed = nau8824_button_decode(key_status);
+
+ event |= button_pressed;
+ dev_dbg(nau8824->dev, "button %x pressed\n", event);
+ event_mask |= NAU8824_BUTTONS;
+ clear_irq = NAU8824_KEY_SHORT_PRESS_IRQ;
+ } else if (active_irq & NAU8824_KEY_RELEASE_IRQ) {
+ event_mask = NAU8824_BUTTONS;
+ clear_irq = NAU8824_KEY_RELEASE_IRQ;
+ } else if (active_irq & NAU8824_JACK_INSERTION_DETECTED) {
+ /* Turn off insertion interruption at manual mode */
+ regmap_update_bits(regmap,
+ NAU8824_REG_INTERRUPT_SETTING,
+ NAU8824_IRQ_INSERT_DIS,
+ NAU8824_IRQ_INSERT_DIS);
+ regmap_update_bits(regmap,
+ NAU8824_REG_INTERRUPT_SETTING_1,
+ NAU8824_IRQ_INSERT_EN, 0);
+ /* detect microphone and jack type */
+ cancel_work_sync(&nau8824->jdet_work);
+ schedule_work(&nau8824->jdet_work);
+
+ /* Enable interruption for jack type detection at audo
+ * mode which can detect microphone and jack type.
+ */
+ nau8824_setup_auto_irq(nau8824);
+ }
+
+ if (!clear_irq)
+ clear_irq = active_irq;
+ /* clears the rightmost interruption */
+ regmap_write(regmap, NAU8824_REG_CLEAR_INT_REG, clear_irq);
+
+ if (event_mask)
+ snd_soc_jack_report(nau8824->jack, event, event_mask);
+
+ return IRQ_HANDLED;
+}
+
+static int nau8824_clock_check(struct nau8824 *nau8824,
+ int stream, int rate, int osr)
+{
+ int osrate;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (osr >= ARRAY_SIZE(osr_dac_sel))
+ return -EINVAL;
+ osrate = osr_dac_sel[osr].osr;
+ } else {
+ if (osr >= ARRAY_SIZE(osr_adc_sel))
+ return -EINVAL;
+ osrate = osr_adc_sel[osr].osr;
+ }
+
+ if (!osrate || rate * osr > CLK_DA_AD_MAX) {
+ dev_err(nau8824->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int nau8824_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div;
+
+ nau8824_sema_acquire(nau8824, HZ);
+
+ /* CLK_DAC or CLK_ADC = OSR * FS
+ * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR)
+ * multiplied by the audio sample rate (Fs). Note that the OSR and Fs
+ * values must be selected such that the maximum frequency is less
+ * than 6.144 MHz.
+ */
+ nau8824->fs = params_rate(params);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_read(nau8824->regmap,
+ NAU8824_REG_DAC_FILTER_CTRL_1, &osr);
+ osr &= NAU8824_DAC_OVERSAMPLE_MASK;
+ if (nau8824_clock_check(nau8824, substream->stream,
+ nau8824->fs, osr))
+ return -EINVAL;
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_DAC_SRC_MASK,
+ osr_dac_sel[osr].clk_src << NAU8824_CLK_DAC_SRC_SFT);
+ } else {
+ regmap_read(nau8824->regmap,
+ NAU8824_REG_ADC_FILTER_CTRL, &osr);
+ osr &= NAU8824_ADC_SYNC_DOWN_MASK;
+ if (nau8824_clock_check(nau8824, substream->stream,
+ nau8824->fs, osr))
+ return -EINVAL;
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_ADC_SRC_MASK,
+ osr_adc_sel[osr].clk_src << NAU8824_CLK_ADC_SRC_SFT);
+ }
+
+ /* make BCLK and LRC divde configuration if the codec as master. */
+ regmap_read(nau8824->regmap,
+ NAU8824_REG_PORT0_I2S_PCM_CTRL_2, &ctrl_val);
+ if (ctrl_val & NAU8824_I2S_MS_MASTER) {
+ /* get the bclk and fs ratio */
+ bclk_fs = snd_soc_params_to_bclk(params) / nau8824->fs;
+ if (bclk_fs <= 32)
+ bclk_div = 0x3;
+ else if (bclk_fs <= 64)
+ bclk_div = 0x2;
+ else if (bclk_fs <= 128)
+ bclk_div = 0x1;
+ else if (bclk_fs <= 256)
+ bclk_div = 0;
+ else
+ return -EINVAL;
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_PORT0_I2S_PCM_CTRL_2,
+ NAU8824_I2S_LRC_DIV_MASK | NAU8824_I2S_BLK_DIV_MASK,
+ (bclk_div << NAU8824_I2S_LRC_DIV_SFT) | bclk_div);
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ val_len |= NAU8824_I2S_DL_16;
+ break;
+ case 20:
+ val_len |= NAU8824_I2S_DL_20;
+ break;
+ case 24:
+ val_len |= NAU8824_I2S_DL_24;
+ break;
+ case 32:
+ val_len |= NAU8824_I2S_DL_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1,
+ NAU8824_I2S_DL_MASK, val_len);
+
+ nau8824_sema_release(nau8824);
+
+ return 0;
+}
+
+static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+ unsigned int ctrl1_val = 0, ctrl2_val = 0;
+
+ nau8824_sema_acquire(nau8824, HZ);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ ctrl2_val |= NAU8824_I2S_MS_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl1_val |= NAU8824_I2S_BP_INV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ ctrl1_val |= NAU8824_I2S_DF_I2S;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl1_val |= NAU8824_I2S_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ctrl1_val |= NAU8824_I2S_DF_RIGTH;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ctrl1_val |= NAU8824_I2S_DF_PCM_AB;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl1_val |= NAU8824_I2S_DF_PCM_AB;
+ ctrl1_val |= NAU8824_I2S_PCMB_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_1,
+ NAU8824_I2S_DF_MASK | NAU8824_I2S_BP_MASK |
+ NAU8824_I2S_PCMB_EN, ctrl1_val);
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_PORT0_I2S_PCM_CTRL_2,
+ NAU8824_I2S_MS_MASK, ctrl2_val);
+
+ nau8824_sema_release(nau8824);
+
+ return 0;
+}
+
+/**
+ * nau8824_calc_fll_param - Calculate FLL parameters.
+ * @fll_in: external clock provided to codec.
+ * @fs: sampling rate.
+ * @fll_param: Pointer to structure of FLL parameters.
+ *
+ * Calculate FLL parameters to configure codec.
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int nau8824_calc_fll_param(unsigned int fll_in,
+ unsigned int fs, struct nau8824_fll *fll_param)
+{
+ u64 fvco, fvco_max;
+ unsigned int fref, i, fvco_sel;
+
+ /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing
+ * freq_in by 1, 2, 4, or 8 using FLL pre-scalar.
+ * FREF = freq_in / NAU8824_FLL_REF_DIV_MASK
+ */
+ for (i = 0; i < ARRAY_SIZE(fll_pre_scalar); i++) {
+ fref = fll_in / fll_pre_scalar[i].param;
+ if (fref <= NAU_FREF_MAX)
+ break;
+ }
+ if (i == ARRAY_SIZE(fll_pre_scalar))
+ return -EINVAL;
+ fll_param->clk_ref_div = fll_pre_scalar[i].val;
+
+ /* Choose the FLL ratio based on FREF */
+ for (i = 0; i < ARRAY_SIZE(fll_ratio); i++) {
+ if (fref >= fll_ratio[i].param)
+ break;
+ }
+ if (i == ARRAY_SIZE(fll_ratio))
+ return -EINVAL;
+ fll_param->ratio = fll_ratio[i].val;
+
+ /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs.
+ * FDCO must be within the 90MHz - 124MHz or the FFL cannot be
+ * guaranteed across the full range of operation.
+ * FDCO = freq_out * 2 * mclk_src_scaling
+ */
+ fvco_max = 0;
+ fvco_sel = ARRAY_SIZE(mclk_src_scaling);
+ for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) {
+ fvco = 256 * fs * 2 * mclk_src_scaling[i].param;
+ if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
+ fvco_max < fvco) {
+ fvco_max = fvco;
+ fvco_sel = i;
+ }
+ }
+ if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel)
+ return -EINVAL;
+ fll_param->mclk_src = mclk_src_scaling[fvco_sel].val;
+
+ /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional
+ * input based on FDCO, FREF and FLL ratio.
+ */
+ fvco = div_u64(fvco_max << 16, fref * fll_param->ratio);
+ fll_param->fll_int = (fvco >> 16) & 0x3FF;
+ fll_param->fll_frac = fvco & 0xFFFF;
+ return 0;
+}
+
+static void nau8824_fll_apply(struct regmap *regmap,
+ struct nau8824_fll *fll_param)
+{
+ regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_SRC_MASK | NAU8824_CLK_MCLK_SRC_MASK,
+ NAU8824_CLK_SRC_MCLK | fll_param->mclk_src);
+ regmap_update_bits(regmap, NAU8824_REG_FLL1,
+ NAU8824_FLL_RATIO_MASK, fll_param->ratio);
+ /* FLL 16-bit fractional input */
+ regmap_write(regmap, NAU8824_REG_FLL2, fll_param->fll_frac);
+ /* FLL 10-bit integer input */
+ regmap_update_bits(regmap, NAU8824_REG_FLL3,
+ NAU8824_FLL_INTEGER_MASK, fll_param->fll_int);
+ /* FLL pre-scaler */
+ regmap_update_bits(regmap, NAU8824_REG_FLL4,
+ NAU8824_FLL_REF_DIV_MASK,
+ fll_param->clk_ref_div << NAU8824_FLL_REF_DIV_SFT);
+ /* select divided VCO input */
+ regmap_update_bits(regmap, NAU8824_REG_FLL5,
+ NAU8824_FLL_CLK_SW_MASK, NAU8824_FLL_CLK_SW_REF);
+ /* Disable free-running mode */
+ regmap_update_bits(regmap,
+ NAU8824_REG_FLL6, NAU8824_DCO_EN, 0);
+ if (fll_param->fll_frac) {
+ regmap_update_bits(regmap, NAU8824_REG_FLL5,
+ NAU8824_FLL_PDB_DAC_EN | NAU8824_FLL_LOOP_FTR_EN |
+ NAU8824_FLL_FTR_SW_MASK,
+ NAU8824_FLL_PDB_DAC_EN | NAU8824_FLL_LOOP_FTR_EN |
+ NAU8824_FLL_FTR_SW_FILTER);
+ regmap_update_bits(regmap, NAU8824_REG_FLL6,
+ NAU8824_SDM_EN, NAU8824_SDM_EN);
+ } else {
+ regmap_update_bits(regmap, NAU8824_REG_FLL5,
+ NAU8824_FLL_PDB_DAC_EN | NAU8824_FLL_LOOP_FTR_EN |
+ NAU8824_FLL_FTR_SW_MASK, NAU8824_FLL_FTR_SW_ACCU);
+ regmap_update_bits(regmap,
+ NAU8824_REG_FLL6, NAU8824_SDM_EN, 0);
+ }
+}
+
+/* freq_out must be 256*Fs in order to achieve the best performance */
+static int nau8824_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
+ unsigned int freq_in, unsigned int freq_out)
+{
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+ struct nau8824_fll fll_param;
+ int ret, fs;
+
+ fs = freq_out / 256;
+ ret = nau8824_calc_fll_param(freq_in, fs, &fll_param);
+ if (ret < 0) {
+ dev_err(nau8824->dev, "Unsupported input clock %d\n", freq_in);
+ return ret;
+ }
+ dev_dbg(nau8824->dev, "mclk_src=%x ratio=%x fll_frac=%x fll_int=%x clk_ref_div=%x\n",
+ fll_param.mclk_src, fll_param.ratio, fll_param.fll_frac,
+ fll_param.fll_int, fll_param.clk_ref_div);
+
+ nau8824_fll_apply(nau8824->regmap, &fll_param);
+ mdelay(2);
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_VCO);
+
+ return 0;
+}
+
+static int nau8824_config_sysclk(struct nau8824 *nau8824,
+ int clk_id, unsigned int freq)
+{
+ struct regmap *regmap = nau8824->regmap;
+
+ switch (clk_id) {
+ case NAU8824_CLK_DIS:
+ regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_MCLK);
+ regmap_update_bits(regmap, NAU8824_REG_FLL6,
+ NAU8824_DCO_EN, 0);
+ break;
+
+ case NAU8824_CLK_MCLK:
+ nau8824_sema_acquire(nau8824, HZ);
+ regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_MCLK);
+ regmap_update_bits(regmap, NAU8824_REG_FLL6,
+ NAU8824_DCO_EN, 0);
+ nau8824_sema_release(nau8824);
+ break;
+
+ case NAU8824_CLK_INTERNAL:
+ regmap_update_bits(regmap, NAU8824_REG_FLL6,
+ NAU8824_DCO_EN, NAU8824_DCO_EN);
+ regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_SRC_MASK, NAU8824_CLK_SRC_VCO);
+ break;
+
+ case NAU8824_CLK_FLL_MCLK:
+ nau8824_sema_acquire(nau8824, HZ);
+ regmap_update_bits(regmap, NAU8824_REG_FLL3,
+ NAU8824_FLL_CLK_SRC_MASK, NAU8824_FLL_CLK_SRC_MCLK);
+ nau8824_sema_release(nau8824);
+ break;
+
+ case NAU8824_CLK_FLL_BLK:
+ nau8824_sema_acquire(nau8824, HZ);
+ regmap_update_bits(regmap, NAU8824_REG_FLL3,
+ NAU8824_FLL_CLK_SRC_MASK, NAU8824_FLL_CLK_SRC_BLK);
+ nau8824_sema_release(nau8824);
+ break;
+
+ case NAU8824_CLK_FLL_FS:
+ nau8824_sema_acquire(nau8824, HZ);
+ regmap_update_bits(regmap, NAU8824_REG_FLL3,
+ NAU8824_FLL_CLK_SRC_MASK, NAU8824_FLL_CLK_SRC_FS);
+ nau8824_sema_release(nau8824);
+ break;
+
+ default:
+ dev_err(nau8824->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+
+ dev_dbg(nau8824->dev, "Sysclk is %dHz and clock id is %d\n", freq,
+ clk_id);
+
+ return 0;
+}
+
+static int nau8824_set_sysclk(struct snd_soc_codec *codec,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ return nau8824_config_sysclk(nau8824, clk_id, freq);
+}
+
+static void nau8824_resume_setup(struct nau8824 *nau8824)
+{
+ nau8824_config_sysclk(nau8824, NAU8824_CLK_DIS, 0);
+ if (nau8824->irq) {
+ /* Clear all interruption status */
+ nau8824_int_status_clear_all(nau8824->regmap);
+ /* Enable jack detection at sleep mode, insertion detection,
+ * and ejection detection.
+ */
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_ENA_CTRL,
+ NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_INTERRUPT_SETTING_1,
+ NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN,
+ NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN);
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_INTERRUPT_SETTING,
+ NAU8824_IRQ_EJECT_DIS | NAU8824_IRQ_INSERT_DIS, 0);
+ }
+}
+
+static int nau8824_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct nau8824 *nau8824 = 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 (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
+ /* Setup codec configuration after resume */
+ nau8824_resume_setup(nau8824);
+ }
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_INTERRUPT_SETTING, 0x3ff, 0x3ff);
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_INTERRUPT_SETTING_1,
+ NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static int nau8824_codec_probe(struct snd_soc_codec *codec)
+{
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+ nau8824->dapm = dapm;
+
+ return 0;
+}
+
+static int __maybe_unused nau8824_suspend(struct snd_soc_codec *codec)
+{
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ if (nau8824->irq) {
+ disable_irq(nau8824->irq);
+ snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
+ }
+ regcache_cache_only(nau8824->regmap, true);
+ regcache_mark_dirty(nau8824->regmap);
+
+ return 0;
+}
+
+static int __maybe_unused nau8824_resume(struct snd_soc_codec *codec)
+{
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+
+ regcache_cache_only(nau8824->regmap, false);
+ regcache_sync(nau8824->regmap);
+ if (nau8824->irq) {
+ /* Hold semaphore to postpone playback happening
+ * until jack detection done.
+ */
+ nau8824_sema_acquire(nau8824, 0);
+ enable_irq(nau8824->irq);
+ }
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver nau8824_codec_driver = {
+ .probe = nau8824_codec_probe,
+ .set_sysclk = nau8824_set_sysclk,
+ .set_pll = nau8824_set_pll,
+ .set_bias_level = nau8824_set_bias_level,
+ .suspend = nau8824_suspend,
+ .resume = nau8824_resume,
+ .suspend_bias_off = true,
+
+ .component_driver = {
+ .controls = nau8824_snd_controls,
+ .num_controls = ARRAY_SIZE(nau8824_snd_controls),
+ .dapm_widgets = nau8824_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(nau8824_dapm_widgets),
+ .dapm_routes = nau8824_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(nau8824_dapm_routes),
+ },
+};
+
+static const struct snd_soc_dai_ops nau8824_dai_ops = {
+ .hw_params = nau8824_hw_params,
+ .set_fmt = nau8824_set_fmt,
+};
+
+#define NAU8824_RATES SNDRV_PCM_RATE_8000_192000
+#define NAU8824_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+ | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver nau8824_dai = {
+ .name = NAU8824_CODEC_DAI,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = NAU8824_RATES,
+ .formats = NAU8824_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = NAU8824_RATES,
+ .formats = NAU8824_FORMATS,
+ },
+ .ops = &nau8824_dai_ops,
+};
+
+static const struct regmap_config nau8824_regmap_config = {
+ .val_bits = NAU8824_REG_ADDR_LEN,
+ .reg_bits = NAU8824_REG_DATA_LEN,
+
+ .max_register = NAU8824_REG_MAX,
+ .readable_reg = nau8824_readable_reg,
+ .writeable_reg = nau8824_writeable_reg,
+ .volatile_reg = nau8824_volatile_reg,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = nau8824_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(nau8824_reg_defaults),
+};
+
+/**
+ * nau8824_enable_jack_detect - Specify a jack for event reporting
+ *
+ * @component: component to register the jack with
+ * @jack: jack to use to report headset and button events on
+ *
+ * After this function has been called the headset insert/remove and button
+ * events will be routed to the given jack. Jack can be null to stop
+ * reporting.
+ */
+int nau8824_enable_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack)
+{
+ struct nau8824 *nau8824 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ nau8824->jack = jack;
+ /* Initiate jack detection work queue */
+ INIT_WORK(&nau8824->jdet_work, nau8824_jdet_work);
+ ret = devm_request_threaded_irq(nau8824->dev, nau8824->irq, NULL,
+ nau8824_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "nau8824", nau8824);
+ if (ret) {
+ dev_err(nau8824->dev, "Cannot request irq %d (%d)\n",
+ nau8824->irq, ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nau8824_enable_jack_detect);
+
+static void nau8824_reset_chip(struct regmap *regmap)
+{
+ regmap_write(regmap, NAU8824_REG_RESET, 0x00);
+ regmap_write(regmap, NAU8824_REG_RESET, 0x00);
+}
+
+static void nau8824_setup_buttons(struct nau8824 *nau8824)
+{
+ struct regmap *regmap = nau8824->regmap;
+
+ regmap_update_bits(regmap, NAU8824_REG_SAR_ADC,
+ NAU8824_SAR_TRACKING_GAIN_MASK,
+ nau8824->sar_voltage << NAU8824_SAR_TRACKING_GAIN_SFT);
+ regmap_update_bits(regmap, NAU8824_REG_SAR_ADC,
+ NAU8824_SAR_COMPARE_TIME_MASK,
+ nau8824->sar_compare_time << NAU8824_SAR_COMPARE_TIME_SFT);
+ regmap_update_bits(regmap, NAU8824_REG_SAR_ADC,
+ NAU8824_SAR_SAMPLING_TIME_MASK,
+ nau8824->sar_sampling_time << NAU8824_SAR_SAMPLING_TIME_SFT);
+
+ regmap_update_bits(regmap, NAU8824_REG_VDET_COEFFICIENT,
+ NAU8824_LEVELS_NR_MASK,
+ (nau8824->sar_threshold_num - 1) << NAU8824_LEVELS_NR_SFT);
+ regmap_update_bits(regmap, NAU8824_REG_VDET_COEFFICIENT,
+ NAU8824_HYSTERESIS_MASK,
+ nau8824->sar_hysteresis << NAU8824_HYSTERESIS_SFT);
+ regmap_update_bits(regmap, NAU8824_REG_VDET_COEFFICIENT,
+ NAU8824_SHORTKEY_DEBOUNCE_MASK,
+ nau8824->key_debounce << NAU8824_SHORTKEY_DEBOUNCE_SFT);
+
+ regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_1,
+ (nau8824->sar_threshold[0] << 8) | nau8824->sar_threshold[1]);
+ regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_2,
+ (nau8824->sar_threshold[2] << 8) | nau8824->sar_threshold[3]);
+ regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_3,
+ (nau8824->sar_threshold[4] << 8) | nau8824->sar_threshold[5]);
+ regmap_write(regmap, NAU8824_REG_VDET_THRESHOLD_4,
+ (nau8824->sar_threshold[6] << 8) | nau8824->sar_threshold[7]);
+}
+
+static void nau8824_init_regs(struct nau8824 *nau8824)
+{
+ struct regmap *regmap = nau8824->regmap;
+
+ /* Enable Bias/VMID/VMID Tieoff */
+ regmap_update_bits(regmap, NAU8824_REG_BIAS_ADJ,
+ NAU8824_VMID | NAU8824_VMID_SEL_MASK, NAU8824_VMID |
+ (nau8824->vref_impedance << NAU8824_VMID_SEL_SFT));
+ regmap_update_bits(regmap, NAU8824_REG_BOOST,
+ NAU8824_GLOBAL_BIAS_EN, NAU8824_GLOBAL_BIAS_EN);
+ mdelay(2);
+ regmap_update_bits(regmap, NAU8824_REG_MIC_BIAS,
+ NAU8824_MICBIAS_VOLTAGE_MASK, nau8824->micbias_voltage);
+ /* Disable Boost Driver, Automatic Short circuit protection enable */
+ regmap_update_bits(regmap, NAU8824_REG_BOOST,
+ NAU8824_PRECHARGE_DIS | NAU8824_HP_BOOST_DIS |
+ NAU8824_HP_BOOST_G_DIS | NAU8824_SHORT_SHUTDOWN_EN,
+ NAU8824_PRECHARGE_DIS | NAU8824_HP_BOOST_DIS |
+ NAU8824_HP_BOOST_G_DIS | NAU8824_SHORT_SHUTDOWN_EN);
+ /* Scaling for ADC and DAC clock */
+ regmap_update_bits(regmap, NAU8824_REG_CLK_DIVIDER,
+ NAU8824_CLK_ADC_SRC_MASK | NAU8824_CLK_DAC_SRC_MASK,
+ (0x1 << NAU8824_CLK_ADC_SRC_SFT) |
+ (0x1 << NAU8824_CLK_DAC_SRC_SFT));
+ regmap_update_bits(regmap, NAU8824_REG_DAC_MUTE_CTRL,
+ NAU8824_DAC_ZC_EN, NAU8824_DAC_ZC_EN);
+ regmap_update_bits(regmap, NAU8824_REG_ENA_CTRL,
+ NAU8824_DAC_CH1_EN | NAU8824_DAC_CH0_EN |
+ NAU8824_ADC_CH0_EN | NAU8824_ADC_CH1_EN |
+ NAU8824_ADC_CH2_EN | NAU8824_ADC_CH3_EN,
+ NAU8824_DAC_CH1_EN | NAU8824_DAC_CH0_EN |
+ NAU8824_ADC_CH0_EN | NAU8824_ADC_CH1_EN |
+ NAU8824_ADC_CH2_EN | NAU8824_ADC_CH3_EN);
+ regmap_update_bits(regmap, NAU8824_REG_CLK_GATING_ENA,
+ NAU8824_CLK_ADC_CH23_EN | NAU8824_CLK_ADC_CH01_EN |
+ NAU8824_CLK_DAC_CH1_EN | NAU8824_CLK_DAC_CH0_EN |
+ NAU8824_CLK_I2S_EN | NAU8824_CLK_GAIN_EN |
+ NAU8824_CLK_SAR_EN | NAU8824_CLK_DMIC_CH23_EN,
+ NAU8824_CLK_ADC_CH23_EN | NAU8824_CLK_ADC_CH01_EN |
+ NAU8824_CLK_DAC_CH1_EN | NAU8824_CLK_DAC_CH0_EN |
+ NAU8824_CLK_I2S_EN | NAU8824_CLK_GAIN_EN |
+ NAU8824_CLK_SAR_EN | NAU8824_CLK_DMIC_CH23_EN);
+ /* Class G timer 64ms */
+ regmap_update_bits(regmap, NAU8824_REG_CLASSG,
+ NAU8824_CLASSG_TIMER_MASK,
+ 0x20 << NAU8824_CLASSG_TIMER_SFT);
+ regmap_update_bits(regmap, NAU8824_REG_TRIM_SETTINGS,
+ NAU8824_DRV_CURR_INC, NAU8824_DRV_CURR_INC);
+ /* Disable DACR/L power */
+ regmap_update_bits(regmap, NAU8824_REG_CHARGE_PUMP_CONTROL,
+ NAU8824_SPKR_PULL_DOWN | NAU8824_SPKL_PULL_DOWN |
+ NAU8824_POWER_DOWN_DACR | NAU8824_POWER_DOWN_DACL,
+ NAU8824_SPKR_PULL_DOWN | NAU8824_SPKL_PULL_DOWN |
+ NAU8824_POWER_DOWN_DACR | NAU8824_POWER_DOWN_DACL);
+ /* Enable TESTDAC. This sets the analog DAC inputs to a '0' input
+ * signal to avoid any glitches due to power up transients in both
+ * the analog and digital DAC circuit.
+ */
+ regmap_update_bits(regmap, NAU8824_REG_ENABLE_LO,
+ NAU8824_TEST_DAC_EN, NAU8824_TEST_DAC_EN);
+ /* Config L/R channel */
+ regmap_update_bits(regmap, NAU8824_REG_DAC_CH0_DGAIN_CTRL,
+ NAU8824_DAC_CH0_SEL_MASK, NAU8824_DAC_CH0_SEL_I2S0);
+ regmap_update_bits(regmap, NAU8824_REG_DAC_CH1_DGAIN_CTRL,
+ NAU8824_DAC_CH1_SEL_MASK, NAU8824_DAC_CH1_SEL_I2S1);
+ regmap_update_bits(regmap, NAU8824_REG_ENABLE_LO,
+ NAU8824_DACR_HPR_EN | NAU8824_DACL_HPL_EN,
+ NAU8824_DACR_HPR_EN | NAU8824_DACL_HPL_EN);
+ /* Default oversampling/decimations settings are unusable
+ * (audible hiss). Set it to something better.
+ */
+ regmap_update_bits(regmap, NAU8824_REG_ADC_FILTER_CTRL,
+ NAU8824_ADC_SYNC_DOWN_MASK, NAU8824_ADC_SYNC_DOWN_64);
+ regmap_update_bits(regmap, NAU8824_REG_DAC_FILTER_CTRL_1,
+ NAU8824_DAC_CICCLP_OFF | NAU8824_DAC_OVERSAMPLE_MASK,
+ NAU8824_DAC_CICCLP_OFF | NAU8824_DAC_OVERSAMPLE_64);
+ /* DAC clock delay 2ns, VREF */
+ regmap_update_bits(regmap, NAU8824_REG_RDAC,
+ NAU8824_RDAC_CLK_DELAY_MASK | NAU8824_RDAC_VREF_MASK,
+ (0x2 << NAU8824_RDAC_CLK_DELAY_SFT) |
+ (0x3 << NAU8824_RDAC_VREF_SFT));
+ /* PGA input mode selection */
+ regmap_update_bits(regmap, NAU8824_REG_FEPGA,
+ NAU8824_FEPGA_MODEL_SHORT_EN | NAU8824_FEPGA_MODER_SHORT_EN,
+ NAU8824_FEPGA_MODEL_SHORT_EN | NAU8824_FEPGA_MODER_SHORT_EN);
+ /* Digital microphone control */
+ regmap_update_bits(regmap, NAU8824_REG_ANALOG_CONTROL_1,
+ NAU8824_DMIC_CLK_DRV_STRG | NAU8824_DMIC_CLK_SLEW_FAST,
+ NAU8824_DMIC_CLK_DRV_STRG | NAU8824_DMIC_CLK_SLEW_FAST);
+ regmap_update_bits(regmap, NAU8824_REG_JACK_DET_CTRL,
+ NAU8824_JACK_LOGIC,
+ /* jkdet_polarity - 1 is for active-low */
+ nau8824->jkdet_polarity ? 0 : NAU8824_JACK_LOGIC);
+ regmap_update_bits(regmap,
+ NAU8824_REG_JACK_DET_CTRL, NAU8824_JACK_EJECT_DT_MASK,
+ (nau8824->jack_eject_debounce << NAU8824_JACK_EJECT_DT_SFT));
+ if (nau8824->sar_threshold_num)
+ nau8824_setup_buttons(nau8824);
+}
+
+static int nau8824_setup_irq(struct nau8824 *nau8824)
+{
+ /* Disable interruption before codec initiation done */
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_ENA_CTRL,
+ NAU8824_JD_SLEEP_MODE, NAU8824_JD_SLEEP_MODE);
+ regmap_update_bits(nau8824->regmap,
+ NAU8824_REG_INTERRUPT_SETTING, 0x3ff, 0x3ff);
+ regmap_update_bits(nau8824->regmap, NAU8824_REG_INTERRUPT_SETTING_1,
+ NAU8824_IRQ_EJECT_EN | NAU8824_IRQ_INSERT_EN, 0);
+
+ return 0;
+}
+
+static void nau8824_print_device_properties(struct nau8824 *nau8824)
+{
+ struct device *dev = nau8824->dev;
+ int i;
+
+ dev_dbg(dev, "jkdet-polarity: %d\n", nau8824->jkdet_polarity);
+ dev_dbg(dev, "micbias-voltage: %d\n", nau8824->micbias_voltage);
+ dev_dbg(dev, "vref-impedance: %d\n", nau8824->vref_impedance);
+
+ dev_dbg(dev, "sar-threshold-num: %d\n", nau8824->sar_threshold_num);
+ for (i = 0; i < nau8824->sar_threshold_num; i++)
+ dev_dbg(dev, "sar-threshold[%d]=%x\n", i,
+ nau8824->sar_threshold[i]);
+
+ dev_dbg(dev, "sar-hysteresis: %d\n", nau8824->sar_hysteresis);
+ dev_dbg(dev, "sar-voltage: %d\n", nau8824->sar_voltage);
+ dev_dbg(dev, "sar-compare-time: %d\n", nau8824->sar_compare_time);
+ dev_dbg(dev, "sar-sampling-time: %d\n", nau8824->sar_sampling_time);
+ dev_dbg(dev, "short-key-debounce: %d\n", nau8824->key_debounce);
+ dev_dbg(dev, "jack-eject-debounce: %d\n",
+ nau8824->jack_eject_debounce);
+}
+
+static int nau8824_read_device_properties(struct device *dev,
+ struct nau8824 *nau8824) {
+ int ret;
+
+ ret = device_property_read_u32(dev, "nuvoton,jkdet-polarity",
+ &nau8824->jkdet_polarity);
+ if (ret)
+ nau8824->jkdet_polarity = 1;
+ ret = device_property_read_u32(dev, "nuvoton,micbias-voltage",
+ &nau8824->micbias_voltage);
+ if (ret)
+ nau8824->micbias_voltage = 6;
+ ret = device_property_read_u32(dev, "nuvoton,vref-impedance",
+ &nau8824->vref_impedance);
+ if (ret)
+ nau8824->vref_impedance = 2;
+ ret = device_property_read_u32(dev, "nuvoton,sar-threshold-num",
+ &nau8824->sar_threshold_num);
+ if (ret)
+ nau8824->sar_threshold_num = 4;
+ ret = device_property_read_u32_array(dev, "nuvoton,sar-threshold",
+ nau8824->sar_threshold, nau8824->sar_threshold_num);
+ if (ret) {
+ nau8824->sar_threshold[0] = 0x0a;
+ nau8824->sar_threshold[1] = 0x14;
+ nau8824->sar_threshold[2] = 0x26;
+ nau8824->sar_threshold[3] = 0x73;
+ }
+ ret = device_property_read_u32(dev, "nuvoton,sar-hysteresis",
+ &nau8824->sar_hysteresis);
+ if (ret)
+ nau8824->sar_hysteresis = 0;
+ ret = device_property_read_u32(dev, "nuvoton,sar-voltage",
+ &nau8824->sar_voltage);
+ if (ret)
+ nau8824->sar_voltage = 6;
+ ret = device_property_read_u32(dev, "nuvoton,sar-compare-time",
+ &nau8824->sar_compare_time);
+ if (ret)
+ nau8824->sar_compare_time = 1;
+ ret = device_property_read_u32(dev, "nuvoton,sar-sampling-time",
+ &nau8824->sar_sampling_time);
+ if (ret)
+ nau8824->sar_sampling_time = 1;
+ ret = device_property_read_u32(dev, "nuvoton,short-key-debounce",
+ &nau8824->key_debounce);
+ if (ret)
+ nau8824->key_debounce = 0;
+ ret = device_property_read_u32(dev, "nuvoton,jack-eject-debounce",
+ &nau8824->jack_eject_debounce);
+ if (ret)
+ nau8824->jack_eject_debounce = 1;
+
+ return 0;
+}
+
+static int nau8824_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c->dev;
+ struct nau8824 *nau8824 = dev_get_platdata(dev);
+ int ret, value;
+
+ if (!nau8824) {
+ nau8824 = devm_kzalloc(dev, sizeof(*nau8824), GFP_KERNEL);
+ if (!nau8824)
+ return -ENOMEM;
+ ret = nau8824_read_device_properties(dev, nau8824);
+ if (ret)
+ return ret;
+ }
+ i2c_set_clientdata(i2c, nau8824);
+
+ nau8824->regmap = devm_regmap_init_i2c(i2c, &nau8824_regmap_config);
+ if (IS_ERR(nau8824->regmap))
+ return PTR_ERR(nau8824->regmap);
+ nau8824->dev = dev;
+ nau8824->irq = i2c->irq;
+ sema_init(&nau8824->jd_sem, 1);
+
+ nau8824_print_device_properties(nau8824);
+
+ ret = regmap_read(nau8824->regmap, NAU8824_REG_I2C_DEVICE_ID, &value);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read device id from the NAU8824: %d\n",
+ ret);
+ return ret;
+ }
+ nau8824_reset_chip(nau8824->regmap);
+ nau8824_init_regs(nau8824);
+
+ if (i2c->irq)
+ nau8824_setup_irq(nau8824);
+
+ return snd_soc_register_codec(dev,
+ &nau8824_codec_driver, &nau8824_dai, 1);
+}
+
+
+static int nau8824_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id nau8824_i2c_ids[] = {
+ { "nau8824", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nau8824_i2c_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id nau8824_of_ids[] = {
+ { .compatible = "nuvoton,nau8824", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, nau8824_of_ids);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id nau8824_acpi_match[] = {
+ { "10508824", 0 },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, nau8824_acpi_match);
+#endif
+
+static struct i2c_driver nau8824_i2c_driver = {
+ .driver = {
+ .name = "nau8824",
+ .of_match_table = of_match_ptr(nau8824_of_ids),
+ .acpi_match_table = ACPI_PTR(nau8824_acpi_match),
+ },
+ .probe = nau8824_i2c_probe,
+ .remove = nau8824_i2c_remove,
+ .id_table = nau8824_i2c_ids,
+};
+module_i2c_driver(nau8824_i2c_driver);
+
+
+MODULE_DESCRIPTION("ASoC NAU88L24 driver");
+MODULE_AUTHOR("John Hsu <KCHSU0@nuvoton.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/nau8824.h b/sound/soc/codecs/nau8824.h
new file mode 100644
index 000000000000..87ac9a382aed
--- /dev/null
+++ b/sound/soc/codecs/nau8824.h
@@ -0,0 +1,466 @@
+/*
+ * NAU88L24 ALSA SoC audio driver
+ *
+ * Copyright 2016 Nuvoton Technology Corp.
+ * Author: John Hsu <KCHSU0@nuvoton.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __NAU8824_H__
+#define __NAU8824_H__
+
+#define NAU8824_REG_RESET 0x00
+#define NAU8824_REG_ENA_CTRL 0x01
+#define NAU8824_REG_CLK_GATING_ENA 0x02
+#define NAU8824_REG_CLK_DIVIDER 0x03
+#define NAU8824_REG_FLL1 0x04
+#define NAU8824_REG_FLL2 0x05
+#define NAU8824_REG_FLL3 0x06
+#define NAU8824_REG_FLL4 0x07
+#define NAU8824_REG_FLL5 0x08
+#define NAU8824_REG_FLL6 0x09
+#define NAU8824_REG_FLL_VCO_RSV 0x0A
+#define NAU8824_REG_JACK_DET_CTRL 0x0D
+#define NAU8824_REG_INTERRUPT_SETTING_1 0x0F
+#define NAU8824_REG_IRQ 0x10
+#define NAU8824_REG_CLEAR_INT_REG 0x11
+#define NAU8824_REG_INTERRUPT_SETTING 0x12
+#define NAU8824_REG_SAR_ADC 0x13
+#define NAU8824_REG_VDET_COEFFICIENT 0x14
+#define NAU8824_REG_VDET_THRESHOLD_1 0x15
+#define NAU8824_REG_VDET_THRESHOLD_2 0x16
+#define NAU8824_REG_VDET_THRESHOLD_3 0x17
+#define NAU8824_REG_VDET_THRESHOLD_4 0x18
+#define NAU8824_REG_GPIO_SEL 0x1A
+#define NAU8824_REG_PORT0_I2S_PCM_CTRL_1 0x1C
+#define NAU8824_REG_PORT0_I2S_PCM_CTRL_2 0x1D
+#define NAU8824_REG_PORT0_LEFT_TIME_SLOT 0x1E
+#define NAU8824_REG_PORT0_RIGHT_TIME_SLOT 0x1F
+#define NAU8824_REG_TDM_CTRL 0x20
+#define NAU8824_REG_ADC_HPF_FILTER 0x23
+#define NAU8824_REG_ADC_FILTER_CTRL 0x24
+#define NAU8824_REG_DAC_FILTER_CTRL_1 0x25
+#define NAU8824_REG_DAC_FILTER_CTRL_2 0x26
+#define NAU8824_REG_NOTCH_FILTER_1 0x27
+#define NAU8824_REG_NOTCH_FILTER_2 0x28
+#define NAU8824_REG_EQ1_LOW 0x29
+#define NAU8824_REG_EQ2_EQ3 0x2A
+#define NAU8824_REG_EQ4_EQ5 0x2B
+#define NAU8824_REG_ADC_CH0_DGAIN_CTRL 0x2D
+#define NAU8824_REG_ADC_CH1_DGAIN_CTRL 0x2E
+#define NAU8824_REG_ADC_CH2_DGAIN_CTRL 0x2F
+#define NAU8824_REG_ADC_CH3_DGAIN_CTRL 0x30
+#define NAU8824_REG_DAC_MUTE_CTRL 0x31
+#define NAU8824_REG_DAC_CH0_DGAIN_CTRL 0x32
+#define NAU8824_REG_DAC_CH1_DGAIN_CTRL 0x33
+#define NAU8824_REG_ADC_TO_DAC_ST 0x34
+#define NAU8824_REG_DRC_KNEE_IP12_ADC_CH01 0x38
+#define NAU8824_REG_DRC_KNEE_IP34_ADC_CH01 0x39
+#define NAU8824_REG_DRC_SLOPE_ADC_CH01 0x3A
+#define NAU8824_REG_DRC_ATKDCY_ADC_CH01 0x3B
+#define NAU8824_REG_DRC_KNEE_IP12_ADC_CH23 0x3C
+#define NAU8824_REG_DRC_KNEE_IP34_ADC_CH23 0x3D
+#define NAU8824_REG_DRC_SLOPE_ADC_CH23 0x3E
+#define NAU8824_REG_DRC_ATKDCY_ADC_CH23 0x3F
+#define NAU8824_REG_DRC_GAINL_ADC0 0x40
+#define NAU8824_REG_DRC_GAINL_ADC1 0x41
+#define NAU8824_REG_DRC_GAINL_ADC2 0x42
+#define NAU8824_REG_DRC_GAINL_ADC3 0x43
+#define NAU8824_REG_DRC_KNEE_IP12_DAC 0x45
+#define NAU8824_REG_DRC_KNEE_IP34_DAC 0x46
+#define NAU8824_REG_DRC_SLOPE_DAC 0x47
+#define NAU8824_REG_DRC_ATKDCY_DAC 0x48
+#define NAU8824_REG_DRC_GAIN_DAC_CH0 0x49
+#define NAU8824_REG_DRC_GAIN_DAC_CH1 0x4A
+#define NAU8824_REG_MODE 0x4C
+#define NAU8824_REG_MODE1 0x4D
+#define NAU8824_REG_MODE2 0x4E
+#define NAU8824_REG_CLASSG 0x50
+#define NAU8824_REG_OTP_EFUSE 0x51
+#define NAU8824_REG_OTPDOUT_1 0x53
+#define NAU8824_REG_OTPDOUT_2 0x54
+#define NAU8824_REG_MISC_CTRL 0x55
+#define NAU8824_REG_I2C_TIMEOUT 0x56
+#define NAU8824_REG_TEST_MODE 0x57
+#define NAU8824_REG_I2C_DEVICE_ID 0x58
+#define NAU8824_REG_SAR_ADC_DATA_OUT 0x59
+#define NAU8824_REG_BIAS_ADJ 0x66
+#define NAU8824_REG_PGA_GAIN 0x67
+#define NAU8824_REG_TRIM_SETTINGS 0x68
+#define NAU8824_REG_ANALOG_CONTROL_1 0x69
+#define NAU8824_REG_ANALOG_CONTROL_2 0x6A
+#define NAU8824_REG_ENABLE_LO 0x6B
+#define NAU8824_REG_GAIN_LO 0x6C
+#define NAU8824_REG_CLASSD_GAIN_1 0x6D
+#define NAU8824_REG_CLASSD_GAIN_2 0x6E
+#define NAU8824_REG_ANALOG_ADC_1 0x71
+#define NAU8824_REG_ANALOG_ADC_2 0x72
+#define NAU8824_REG_RDAC 0x73
+#define NAU8824_REG_MIC_BIAS 0x74
+#define NAU8824_REG_HS_VOLUME_CONTROL 0x75
+#define NAU8824_REG_BOOST 0x76
+#define NAU8824_REG_FEPGA 0x77
+#define NAU8824_REG_FEPGA_II 0x78
+#define NAU8824_REG_FEPGA_SE 0x79
+#define NAU8824_REG_FEPGA_ATTENUATION 0x7A
+#define NAU8824_REG_ATT_PORT0 0x7B
+#define NAU8824_REG_ATT_PORT1 0x7C
+#define NAU8824_REG_POWER_UP_CONTROL 0x7F
+#define NAU8824_REG_CHARGE_PUMP_CONTROL 0x80
+#define NAU8824_REG_CHARGE_PUMP_INPUT 0x81
+#define NAU8824_REG_MAX NAU8824_REG_CHARGE_PUMP_INPUT
+/* 16-bit control register address, and 16-bits control register data */
+#define NAU8824_REG_ADDR_LEN 16
+#define NAU8824_REG_DATA_LEN 16
+
+
+/* ENA_CTRL (0x1) */
+#define NAU8824_DMIC_LCH_EDGE_CH23 (0x1 << 12)
+#define NAU8824_DMIC_LCH_EDGE_CH01 (0x1 << 11)
+#define NAU8824_JD_SLEEP_MODE (0x1 << 10)
+#define NAU8824_ADC_CH3_DMIC_SFT 9
+#define NAU8824_ADC_CH3_DMIC_EN (0x1 << NAU8824_ADC_CH3_DMIC_SFT)
+#define NAU8824_ADC_CH2_DMIC_SFT 8
+#define NAU8824_ADC_CH2_DMIC_EN (0x1 << NAU8824_ADC_CH2_DMIC_SFT)
+#define NAU8824_ADC_CH1_DMIC_SFT 7
+#define NAU8824_ADC_CH1_DMIC_EN (0x1 << NAU8824_ADC_CH1_DMIC_SFT)
+#define NAU8824_ADC_CH0_DMIC_SFT 6
+#define NAU8824_ADC_CH0_DMIC_EN (0x1 << NAU8824_ADC_CH0_DMIC_SFT)
+#define NAU8824_DAC_CH1_EN (0x1 << 5)
+#define NAU8824_DAC_CH0_EN (0x1 << 4)
+#define NAU8824_ADC_CH3_EN (0x1 << 3)
+#define NAU8824_ADC_CH2_EN (0x1 << 2)
+#define NAU8824_ADC_CH1_EN (0x1 << 1)
+#define NAU8824_ADC_CH0_EN 0x1
+
+/* CLK_GATING_ENA (0x02) */
+#define NAU8824_CLK_ADC_CH23_EN (0x1 << 15)
+#define NAU8824_CLK_ADC_CH01_EN (0x1 << 14)
+#define NAU8824_CLK_DAC_CH1_EN (0x1 << 13)
+#define NAU8824_CLK_DAC_CH0_EN (0x1 << 12)
+#define NAU8824_CLK_I2S_EN (0x1 << 7)
+#define NAU8824_CLK_GAIN_EN (0x1 << 5)
+#define NAU8824_CLK_SAR_EN (0x1 << 3)
+#define NAU8824_CLK_DMIC_CH23_EN (0x1 << 1)
+
+/* CLK_DIVIDER (0x3) */
+#define NAU8824_CLK_SRC_SFT 15
+#define NAU8824_CLK_SRC_MASK (1 << NAU8824_CLK_SRC_SFT)
+#define NAU8824_CLK_SRC_VCO (1 << NAU8824_CLK_SRC_SFT)
+#define NAU8824_CLK_SRC_MCLK (0 << NAU8824_CLK_SRC_SFT)
+#define NAU8824_CLK_MCLK_SRC_MASK (0xf << 0)
+#define NAU8824_CLK_DMIC_SRC_SFT 10
+#define NAU8824_CLK_DMIC_SRC_MASK (0x7 << NAU8824_CLK_DMIC_SRC_SFT)
+#define NAU8824_CLK_ADC_SRC_SFT 6
+#define NAU8824_CLK_ADC_SRC_MASK (0x3 << NAU8824_CLK_ADC_SRC_SFT)
+#define NAU8824_CLK_DAC_SRC_SFT 4
+#define NAU8824_CLK_DAC_SRC_MASK (0x3 << NAU8824_CLK_DAC_SRC_SFT)
+
+/* FLL1 (0x04) */
+#define NAU8824_FLL_RATIO_MASK (0x7f << 0)
+
+/* FLL3 (0x06) */
+#define NAU8824_FLL_INTEGER_MASK (0x3ff << 0)
+#define NAU8824_FLL_CLK_SRC_SFT 10
+#define NAU8824_FLL_CLK_SRC_MASK (0x3 << NAU8824_FLL_CLK_SRC_SFT)
+#define NAU8824_FLL_CLK_SRC_MCLK (0 << NAU8824_FLL_CLK_SRC_SFT)
+#define NAU8824_FLL_CLK_SRC_BLK (0x2 << NAU8824_FLL_CLK_SRC_SFT)
+#define NAU8824_FLL_CLK_SRC_FS (0x3 << NAU8824_FLL_CLK_SRC_SFT)
+
+/* FLL4 (0x07) */
+#define NAU8824_FLL_REF_DIV_SFT 10
+#define NAU8824_FLL_REF_DIV_MASK (0x3 << NAU8824_FLL_REF_DIV_SFT)
+
+/* FLL5 (0x08) */
+#define NAU8824_FLL_PDB_DAC_EN (0x1 << 15)
+#define NAU8824_FLL_LOOP_FTR_EN (0x1 << 14)
+#define NAU8824_FLL_CLK_SW_MASK (0x1 << 13)
+#define NAU8824_FLL_CLK_SW_N2 (0x1 << 13)
+#define NAU8824_FLL_CLK_SW_REF (0x0 << 13)
+#define NAU8824_FLL_FTR_SW_MASK (0x1 << 12)
+#define NAU8824_FLL_FTR_SW_ACCU (0x1 << 12)
+#define NAU8824_FLL_FTR_SW_FILTER (0x0 << 12)
+
+/* FLL6 (0x9) */
+#define NAU8824_DCO_EN (0x1 << 15)
+#define NAU8824_SDM_EN (0x1 << 14)
+
+/* IRQ (0x10) */
+#define NAU8824_SHORT_CIRCUIT_IRQ (0x1 << 7)
+#define NAU8824_IMPEDANCE_MEAS_IRQ (0x1 << 6)
+#define NAU8824_KEY_RELEASE_IRQ (0x1 << 5)
+#define NAU8824_KEY_LONG_PRESS_IRQ (0x1 << 4)
+#define NAU8824_KEY_SHORT_PRESS_IRQ (0x1 << 3)
+#define NAU8824_JACK_EJECTION_DETECTED (0x1 << 1)
+#define NAU8824_JACK_INSERTION_DETECTED 0x1
+
+/* JACK_DET_CTRL (0x0D) */
+#define NAU8824_JACK_EJECT_DT_SFT 2
+#define NAU8824_JACK_EJECT_DT_MASK (0x3 << NAU8824_JACK_EJECT_DT_SFT)
+#define NAU8824_JACK_LOGIC 0x1
+
+
+/* INTERRUPT_SETTING_1 (0x0F) */
+#define NAU8824_IRQ_EJECT_EN (0x1 << 9)
+#define NAU8824_IRQ_INSERT_EN (0x1 << 8)
+
+/* INTERRUPT_SETTING (0x12) */
+#define NAU8824_IRQ_KEY_RELEASE_DIS (0x1 << 5)
+#define NAU8824_IRQ_KEY_SHORT_PRESS_DIS (0x1 << 3)
+#define NAU8824_IRQ_EJECT_DIS (0x1 << 1)
+#define NAU8824_IRQ_INSERT_DIS 0x1
+
+/* SAR_ADC (0x13) */
+#define NAU8824_SAR_ADC_EN_SFT 12
+#define NAU8824_SAR_TRACKING_GAIN_SFT 8
+#define NAU8824_SAR_TRACKING_GAIN_MASK (0x7 << NAU8824_SAR_TRACKING_GAIN_SFT)
+#define NAU8824_SAR_COMPARE_TIME_SFT 2
+#define NAU8824_SAR_COMPARE_TIME_MASK (3 << 2)
+#define NAU8824_SAR_SAMPLING_TIME_SFT 0
+#define NAU8824_SAR_SAMPLING_TIME_MASK (3 << 0)
+
+/* VDET_COEFFICIENT (0x14) */
+#define NAU8824_SHORTKEY_DEBOUNCE_SFT 12
+#define NAU8824_SHORTKEY_DEBOUNCE_MASK (0x3 << NAU8824_SHORTKEY_DEBOUNCE_SFT)
+#define NAU8824_LEVELS_NR_SFT 8
+#define NAU8824_LEVELS_NR_MASK (0x7 << 8)
+#define NAU8824_HYSTERESIS_SFT 0
+#define NAU8824_HYSTERESIS_MASK 0xf
+
+/* PORT0_I2S_PCM_CTRL_1 (0x1C) */
+#define NAU8824_I2S_BP_SFT 7
+#define NAU8824_I2S_BP_MASK (1 << NAU8824_I2S_BP_SFT)
+#define NAU8824_I2S_BP_INV (1 << NAU8824_I2S_BP_SFT)
+#define NAU8824_I2S_PCMB_SFT 6
+#define NAU8824_I2S_PCMB_EN (1 << NAU8824_I2S_PCMB_SFT)
+#define NAU8824_I2S_DL_SFT 2
+#define NAU8824_I2S_DL_MASK (0x3 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_16 (0 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_20 (1 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_24 (2 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DL_32 (3 << NAU8824_I2S_DL_SFT)
+#define NAU8824_I2S_DF_MASK 0x3
+#define NAU8824_I2S_DF_RIGTH 0
+#define NAU8824_I2S_DF_LEFT 1
+#define NAU8824_I2S_DF_I2S 2
+#define NAU8824_I2S_DF_PCM_AB 3
+
+
+/* PORT0_I2S_PCM_CTRL_2 (0x1D) */
+#define NAU8824_I2S_LRC_DIV_SFT 12
+#define NAU8824_I2S_LRC_DIV_MASK (0x3 << NAU8824_I2S_LRC_DIV_SFT)
+#define NAU8824_I2S_MS_SFT 3
+#define NAU8824_I2S_MS_MASK (1 << NAU8824_I2S_MS_SFT)
+#define NAU8824_I2S_MS_MASTER (1 << NAU8824_I2S_MS_SFT)
+#define NAU8824_I2S_MS_SLAVE (0 << NAU8824_I2S_MS_SFT)
+#define NAU8824_I2S_BLK_DIV_MASK 0x7
+
+/* ADC_FILTER_CTRL (0x24) */
+#define NAU8824_ADC_SYNC_DOWN_MASK 0x3
+#define NAU8824_ADC_SYNC_DOWN_32 0
+#define NAU8824_ADC_SYNC_DOWN_64 1
+#define NAU8824_ADC_SYNC_DOWN_128 2
+#define NAU8824_ADC_SYNC_DOWN_256 3
+
+/* DAC_FILTER_CTRL_1 (0x25) */
+#define NAU8824_DAC_CICCLP_OFF (0x1 << 7)
+#define NAU8824_DAC_OVERSAMPLE_MASK 0x7
+#define NAU8824_DAC_OVERSAMPLE_64 0
+#define NAU8824_DAC_OVERSAMPLE_256 1
+#define NAU8824_DAC_OVERSAMPLE_128 2
+#define NAU8824_DAC_OVERSAMPLE_32 4
+
+/* DAC_MUTE_CTRL (0x31) */
+#define NAU8824_DAC_CH01_MIX 0x3
+#define NAU8824_DAC_ZC_EN (0x1 << 11)
+
+/* DAC_CH0_DGAIN_CTRL (0x32) */
+#define NAU8824_DAC_CH0_SEL_SFT 9
+#define NAU8824_DAC_CH0_SEL_MASK (0x1 << NAU8824_DAC_CH0_SEL_SFT)
+#define NAU8824_DAC_CH0_SEL_I2S0 (0x0 << NAU8824_DAC_CH0_SEL_SFT)
+#define NAU8824_DAC_CH0_SEL_I2S1 (0x1 << NAU8824_DAC_CH0_SEL_SFT)
+#define NAU8824_DAC_CH0_VOL_MASK 0x1ff
+
+/* DAC_CH1_DGAIN_CTRL (0x33) */
+#define NAU8824_DAC_CH1_SEL_SFT 9
+#define NAU8824_DAC_CH1_SEL_MASK (0x1 << NAU8824_DAC_CH1_SEL_SFT)
+#define NAU8824_DAC_CH1_SEL_I2S0 (0x0 << NAU8824_DAC_CH1_SEL_SFT)
+#define NAU8824_DAC_CH1_SEL_I2S1 (0x1 << NAU8824_DAC_CH1_SEL_SFT)
+#define NAU8824_DAC_CH1_VOL_MASK 0x1ff
+
+/* CLASSG (0x50) */
+#define NAU8824_CLASSG_TIMER_SFT 8
+#define NAU8824_CLASSG_TIMER_MASK (0x3f << NAU8824_CLASSG_TIMER_SFT)
+#define NAU8824_CLASSG_LDAC_EN_SFT 2
+#define NAU8824_CLASSG_RDAC_EN_SFT 1
+#define NAU8824_CLASSG_EN_SFT 0
+
+/* SAR_ADC_DATA_OUT (0x59) */
+#define NAU8824_SAR_ADC_DATA_MASK 0xff
+
+/* BIAS_ADJ (0x66) */
+#define NAU8824_VMID (1 << 6)
+#define NAU8824_VMID_SEL_SFT 4
+#define NAU8824_VMID_SEL_MASK (3 << NAU8824_VMID_SEL_SFT)
+#define NAU8824_DMIC2_EN_SFT 3
+#define NAU8824_DMIC1_EN_SFT 2
+
+/* TRIM_SETTINGS (0x68) */
+#define NAU8824_DRV_CURR_INC (1 << 15)
+
+/* ANALOG_CONTROL_1 (0x69) */
+#define NAU8824_DMIC_CLK_DRV_STRG (1 << 3)
+#define NAU8824_DMIC_CLK_SLEW_FAST (0x7)
+
+/* ANALOG_CONTROL_2 (0x6A) */
+#define NAU8824_CLASSD_CLAMP_DIS_SFT 3
+#define NAU8824_CLASSD_CLAMP_DIS (0x1 << NAU8824_CLASSD_CLAMP_DIS_SFT)
+
+/* ENABLE_LO (0x6B) */
+#define NAU8824_TEST_DAC_SFT 14
+#define NAU8824_TEST_DAC_EN (0x3 << NAU8824_TEST_DAC_SFT)
+#define NAU8824_DACL_HPR_EN_SFT 3
+#define NAU8824_DACL_HPR_EN (0x1 << NAU8824_DACL_HPR_EN_SFT)
+#define NAU8824_DACR_HPR_EN_SFT 2
+#define NAU8824_DACR_HPR_EN (0x1 << NAU8824_DACR_HPR_EN_SFT)
+#define NAU8824_DACR_HPL_EN_SFT 1
+#define NAU8824_DACR_HPL_EN (0x1 << NAU8824_DACR_HPL_EN_SFT)
+#define NAU8824_DACL_HPL_EN_SFT 0
+#define NAU8824_DACL_HPL_EN 0x1
+
+/* CLASSD_GAIN_1 (0x6D) */
+#define NAU8824_CLASSD_GAIN_1R_SFT 8
+#define NAU8824_CLASSD_GAIN_1R_MASK (0x1f << NAU8824_CLASSD_GAIN_1R_SFT)
+#define NAU8824_CLASSD_EN_SFT 7
+#define NAU8824_CLASSD_EN (0x1 << NAU8824_CLASSD_EN_SFT)
+#define NAU8824_CLASSD_GAIN_1L_MASK 0x1f
+
+/* CLASSD_GAIN_2 (0x6E) */
+#define NAU8824_CLASSD_GAIN_2R_SFT 8
+#define NAU8824_CLASSD_GAIN_2R_MASK (0x1f << NAU8824_CLASSD_GAIN_1R_SFT)
+#define NAU8824_CLASSD_EN_SFT 7
+#define NAU8824_CLASSD_EN (0x1 << NAU8824_CLASSD_EN_SFT)
+#define NAU8824_CLASSD_GAIN_2L_MASK 0x1f
+
+/* ANALOG_ADC_2 (0x72) */
+#define NAU8824_ADCR_EN_SFT 7
+#define NAU8824_ADCL_EN_SFT 6
+
+/* RDAC (0x73) */
+#define NAU8824_DACR_EN_SFT 13
+#define NAU8824_DACL_EN_SFT 12
+#define NAU8824_DACR_CLK_SFT 9
+#define NAU8824_DACL_CLK_SFT 8
+#define NAU8824_RDAC_CLK_DELAY_SFT 4
+#define NAU8824_RDAC_CLK_DELAY_MASK (0x7 << NAU8824_RDAC_CLK_DELAY_SFT)
+#define NAU8824_RDAC_VREF_SFT 2
+#define NAU8824_RDAC_VREF_MASK (0x3 << NAU8824_RDAC_VREF_SFT)
+
+/* MIC_BIAS (0x74) */