aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/ac97/bus.c26
-rw-r--r--sound/aoa/core/gpio-feature.c4
-rw-r--r--sound/arm/Kconfig5
-rw-r--r--sound/arm/Makefile3
-rw-r--r--sound/arm/pxa2xx-ac97-lib.c12
-rw-r--r--sound/arm/pxa2xx-ac97.c124
-rw-r--r--sound/arm/pxa2xx-pcm-lib.c75
-rw-r--r--sound/arm/pxa2xx-pcm.c129
-rw-r--r--sound/arm/pxa2xx-pcm.h27
-rw-r--r--sound/core/compress_offload.c12
-rw-r--r--sound/core/memalloc.c8
-rw-r--r--sound/core/oss/pcm_oss.c2
-rw-r--r--sound/core/oss/pcm_plugin.c9
-rw-r--r--sound/core/pcm.c7
-rw-r--r--sound/core/pcm_lib.c38
-rw-r--r--sound/core/pcm_local.h2
-rw-r--r--sound/core/pcm_native.c10
-rw-r--r--sound/core/rawmidi.c249
-rw-r--r--sound/core/seq/oss/seq_oss.c2
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c2
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c2
-rw-r--r--sound/core/seq/seq.c33
-rw-r--r--sound/core/seq/seq_clientmgr.c33
-rw-r--r--sound/core/seq/seq_info.c10
-rw-r--r--sound/core/seq/seq_info.h6
-rw-r--r--sound/core/seq/seq_memory.c12
-rw-r--r--sound/core/seq/seq_memory.h6
-rw-r--r--sound/core/seq/seq_midi.c24
-rw-r--r--sound/core/seq/seq_midi_emul.c14
-rw-r--r--sound/core/seq/seq_midi_event.c87
-rw-r--r--sound/core/seq/seq_queue.c12
-rw-r--r--sound/core/seq/seq_queue.h27
-rw-r--r--sound/core/seq/seq_virmidi.c133
-rw-r--r--sound/core/timer.c7
-rw-r--r--sound/drivers/aloop.c1
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c16
-rw-r--r--sound/drivers/opl3/opl3_drums.c2
-rw-r--r--sound/drivers/opl3/opl3_lib.c19
-rw-r--r--sound/drivers/opl3/opl3_midi.c17
-rw-r--r--sound/drivers/opl3/opl3_oss.c8
-rw-r--r--sound/drivers/opl3/opl3_synth.c1
-rw-r--r--sound/drivers/opl3/opl3_voice.h4
-rw-r--r--sound/drivers/opl4/opl4_lib.c12
-rw-r--r--sound/drivers/vx/vx_core.c15
-rw-r--r--sound/drivers/vx/vx_pcm.c2
-rw-r--r--sound/firewire/bebob/bebob_pcm.c1
-rw-r--r--sound/firewire/dice/dice-alesis.c2
-rw-r--r--sound/firewire/dice/dice-pcm.c2
-rw-r--r--sound/firewire/digi00x/digi00x-pcm.c1
-rw-r--r--sound/firewire/fireface/ff-pcm.c1
-rw-r--r--sound/firewire/fireworks/fireworks_pcm.c1
-rw-r--r--sound/firewire/isight.c1
-rw-r--r--sound/firewire/motu/motu-pcm.c2
-rw-r--r--sound/firewire/motu/motu-protocol-v2.c64
-rw-r--r--sound/firewire/motu/motu-protocol-v3.c19
-rw-r--r--sound/firewire/motu/motu.c19
-rw-r--r--sound/firewire/motu/motu.h5
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c2
-rw-r--r--sound/firewire/tascam/tascam-pcm.c1
-rw-r--r--sound/hda/Kconfig7
-rw-r--r--sound/hda/Makefile1
-rw-r--r--sound/hda/ext/hdac_ext_bus.c80
-rw-r--r--sound/hda/ext/hdac_ext_controller.c64
-rw-r--r--sound/hda/ext/hdac_ext_stream.c104
-rw-r--r--sound/hda/hdac_component.c335
-rw-r--r--sound/hda/hdac_device.c2
-rw-r--r--sound/hda/hdac_i915.c353
-rw-r--r--sound/hda/hdac_stream.c4
-rw-r--r--sound/i2c/cs8427.c12
-rw-r--r--sound/i2c/i2c.c13
-rw-r--r--sound/i2c/other/ak4xxx-adda.c12
-rw-r--r--sound/i2c/tea6330t.c16
-rw-r--r--sound/isa/Kconfig2
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c3
-rw-r--r--sound/isa/es1688/es1688.c2
-rw-r--r--sound/isa/es1688/es1688_lib.c16
-rw-r--r--sound/isa/es18xx.c1
-rw-r--r--sound/isa/galaxy/galaxy.c3
-rw-r--r--sound/isa/gus/gus_io.c2
-rw-r--r--sound/isa/gus/gus_main.c16
-rw-r--r--sound/isa/gus/gus_reset.c2
-rw-r--r--sound/isa/msnd/msnd.c18
-rw-r--r--sound/isa/msnd/msnd.h2
-rw-r--r--sound/isa/msnd/msnd_midi.c2
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c8
-rw-r--r--sound/isa/opti9xx/miro.c5
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c3
-rw-r--r--sound/isa/sb/emu8000_patch.c7
-rw-r--r--sound/isa/sb/emu8000_pcm.c2
-rw-r--r--sound/isa/sb/sb16_csp.c52
-rw-r--r--sound/isa/sb/sb16_main.c25
-rw-r--r--sound/isa/sb/sb8_main.c19
-rw-r--r--sound/isa/sb/sb_common.c16
-rw-r--r--sound/isa/wss/wss_lib.c18
-rw-r--r--sound/mips/sgio2audio.c3
-rw-r--r--sound/pci/ac97/ac97_codec.c16
-rw-r--r--sound/pci/ali5451/ali5451.c5
-rw-r--r--sound/pci/asihpi/asihpi.c24
-rw-r--r--sound/pci/asihpi/hpi6205.c5
-rw-r--r--sound/pci/atiixp.c4
-rw-r--r--sound/pci/atiixp_modem.c4
-rw-r--r--sound/pci/au88x0/au88x0.h2
-rw-r--r--sound/pci/au88x0/au88x0_core.c2
-rw-r--r--sound/pci/bt87x.c4
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c3
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c7
-rw-r--r--sound/pci/cs5535audio/cs5535audio.h6
-rw-r--r--sound/pci/cs5535audio/cs5535audio_pcm.c4
-rw-r--r--sound/pci/ctxfi/cthw20k1.c6
-rw-r--r--sound/pci/ctxfi/cthw20k2.c12
-rw-r--r--sound/pci/ctxfi/ctmixer.c15
-rw-r--r--sound/pci/echoaudio/echoaudio.c2
-rw-r--r--sound/pci/echoaudio/echoaudio.h2
-rw-r--r--sound/pci/echoaudio/echoaudio_3g.c14
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c6
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.h50
-rw-r--r--sound/pci/echoaudio/echoaudio_gml.c8
-rw-r--r--sound/pci/emu10k1/emu10k1_patch.c7
-rw-r--r--sound/pci/emu10k1/emufx.c24
-rw-r--r--sound/pci/emu10k1/emupcm.c7
-rw-r--r--sound/pci/ens1370.c3
-rw-r--r--sound/pci/hda/dell_wmi_helper.c116
-rw-r--r--sound/pci/hda/hda_codec.c102
-rw-r--r--sound/pci/hda/hda_codec.h7
-rw-r--r--sound/pci/hda/hda_generic.c144
-rw-r--r--sound/pci/hda/hda_generic.h16
-rw-r--r--sound/pci/hda/hda_intel.c18
-rw-r--r--sound/pci/hda/patch_analog.c4
-rw-r--r--sound/pci/hda/patch_ca0132.c346
-rw-r--r--sound/pci/hda/patch_cirrus.c29
-rw-r--r--sound/pci/hda/patch_conexant.c105
-rw-r--r--sound/pci/hda/patch_hdmi.c152
-rw-r--r--sound/pci/hda/patch_realtek.c879
-rw-r--r--sound/pci/hda/patch_sigmatel.c31
-rw-r--r--sound/pci/hda/patch_via.c294
-rw-r--r--sound/pci/hda/thinkpad_helper.c27
-rw-r--r--sound/pci/ice1712/ak4xxx.c12
-rw-r--r--sound/pci/ice1712/prodigy_hifi.c21
-rw-r--r--sound/pci/intel8x0.c6
-rw-r--r--sound/pci/intel8x0m.c6
-rw-r--r--sound/pci/korg1212/korg1212.c4
-rw-r--r--sound/pci/lola/lola.c4
-rw-r--r--sound/pci/lola/lola.h4
-rw-r--r--sound/pci/lola/lola_pcm.c8
-rw-r--r--sound/pci/lx6464es/lx6464es.c1
-rw-r--r--sound/pci/maestro3.c6
-rw-r--r--sound/pci/mixart/mixart.c1
-rw-r--r--sound/pci/mixart/mixart_core.c6
-rw-r--r--sound/pci/mixart/mixart_hwdep.c42
-rw-r--r--sound/pci/mixart/mixart_hwdep.h8
-rw-r--r--sound/pci/riptide/riptide.c10
-rw-r--r--sound/pci/sonicvibes.c2
-rw-r--r--sound/pci/trident/trident.c2
-rw-r--r--sound/pci/trident/trident.h2
-rw-r--r--sound/pci/trident/trident_main.c2
-rw-r--r--sound/pci/vx222/vx222_ops.c8
-rw-r--r--sound/pci/ymfpci/ymfpci.h78
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c6
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c1
-rw-r--r--sound/pcmcia/vx/vxp_ops.c10
-rw-r--r--sound/ppc/snd_ps3.c5
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/amd/Kconfig1
-rw-r--r--sound/soc/amd/acp-da7219-max98357a.c109
-rw-r--r--sound/soc/amd/acp-pcm-dma.c214
-rw-r--r--sound/soc/amd/acp.h13
-rw-r--r--sound/soc/atmel/atmel-i2s.c46
-rw-r--r--sound/soc/codecs/Kconfig25
-rw-r--r--sound/soc/codecs/Makefile8
-rw-r--r--sound/soc/codecs/adau17x1.c1
-rw-r--r--sound/soc/codecs/adav80x.c1
-rw-r--r--sound/soc/codecs/ak4458.c2
-rw-r--r--sound/soc/codecs/ak4554.c17
-rw-r--r--sound/soc/codecs/ak4613.c26
-rw-r--r--sound/soc/codecs/ak4642.c26
-rw-r--r--sound/soc/codecs/ak5558.c4
-rw-r--r--sound/soc/codecs/cs4270.c2
-rw-r--r--sound/soc/codecs/cs47l24.c11
-rw-r--r--sound/soc/codecs/cx20442.c23
-rw-r--r--sound/soc/codecs/da7210.c27
-rw-r--r--sound/soc/codecs/da7213.c4
-rw-r--r--sound/soc/codecs/da7219-aad.c5
-rw-r--r--sound/soc/codecs/da7219.c48
-rw-r--r--sound/soc/codecs/da7219.h8
-rw-r--r--sound/soc/codecs/da9055.c4
-rw-r--r--sound/soc/codecs/es7134.c227
-rw-r--r--sound/soc/codecs/es7241.c322
-rw-r--r--sound/soc/codecs/hdac_hdmi.c495
-rw-r--r--sound/soc/codecs/hdmi-codec.c21
-rw-r--r--sound/soc/codecs/max98373.c1
-rw-r--r--sound/soc/codecs/max9850.c4
-rw-r--r--sound/soc/codecs/nau8540.c3
-rw-r--r--sound/soc/codecs/nau8824.c2
-rw-r--r--sound/soc/codecs/nau8825.c2
-rw-r--r--sound/soc/codecs/pcm1789.c3
-rw-r--r--sound/soc/codecs/pcm186x.c2
-rw-r--r--sound/soc/codecs/rt1305.c15
-rw-r--r--sound/soc/codecs/rt5514-spi.c1
-rw-r--r--sound/soc/codecs/rt5514.c8
-rw-r--r--sound/soc/codecs/rt5631.c12
-rw-r--r--sound/soc/codecs/rt5640.c2
-rw-r--r--sound/soc/codecs/rt5651.c235
-rw-r--r--sound/soc/codecs/rt5651.h8
-rw-r--r--sound/soc/codecs/rt5677.c3
-rw-r--r--sound/soc/codecs/rt5682.c2681
-rw-r--r--sound/soc/codecs/rt5682.h1324
-rw-r--r--sound/soc/codecs/simple-amplifier.c (renamed from sound/soc/codecs/dio2125.c)42
-rw-r--r--sound/soc/codecs/tas571x.c110
-rw-r--r--sound/soc/codecs/tas571x.h16
-rw-r--r--sound/soc/codecs/tda7419.c4
-rw-r--r--sound/soc/codecs/tscs42xx.c37
-rw-r--r--sound/soc/codecs/tscs42xx.h8
-rw-r--r--sound/soc/codecs/twl6040.c2
-rw-r--r--sound/soc/codecs/wm2200.c10
-rw-r--r--sound/soc/codecs/wm5100-tables.c12
-rw-r--r--sound/soc/codecs/wm5102.c10
-rw-r--r--sound/soc/codecs/wm5110.c13
-rw-r--r--sound/soc/codecs/wm8903.c4
-rw-r--r--sound/soc/codecs/wm8904.c1
-rw-r--r--sound/soc/codecs/wm8955.c1
-rw-r--r--sound/soc/codecs/wm8960.c1
-rw-r--r--sound/soc/codecs/wm8961.c1
-rw-r--r--sound/soc/codecs/wm8962.c1
-rw-r--r--sound/soc/codecs/wm8988.c4
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8994.c1
-rw-r--r--sound/soc/codecs/wm8995.c1
-rw-r--r--sound/soc/codecs/wm8996.c9
-rw-r--r--sound/soc/codecs/wm9081.c1
-rw-r--r--sound/soc/codecs/wm_adsp.c216
-rw-r--r--sound/soc/codecs/wm_adsp.h12
-rw-r--r--sound/soc/codecs/wmfw.h1
-rw-r--r--sound/soc/davinci/davinci-i2s.c1
-rw-r--r--sound/soc/davinci/davinci-mcasp.c16
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c20
-rw-r--r--sound/soc/fsl/fsl_asrc.c18
-rw-r--r--sound/soc/fsl/fsl_asrc.h5
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c18
-rw-r--r--sound/soc/fsl/fsl_esai.c1
-rw-r--r--sound/soc/fsl/fsl_spdif.c2
-rw-r--r--sound/soc/fsl/fsl_utils.c18
-rw-r--r--sound/soc/fsl/fsl_utils.h7
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c15
-rw-r--r--sound/soc/generic/audio-graph-card.c41
-rw-r--r--sound/soc/generic/audio-graph-scu-card.c25
-rw-r--r--sound/soc/generic/simple-card-utils.c74
-rw-r--r--sound/soc/generic/simple-card.c106
-rw-r--r--sound/soc/generic/simple-scu-card.c21
-rw-r--r--sound/soc/intel/atom/sst/sst_drv_interface.c29
-rw-r--r--sound/soc/intel/atom/sst/sst_loader.c6
-rw-r--r--sound/soc/intel/boards/Kconfig14
-rw-r--r--sound/soc/intel/boards/Makefile2
-rw-r--r--sound/soc/intel/boards/bdw-rt5677.c4
-rw-r--r--sound/soc/intel/boards/bxt_da7219_max98357a.c20
-rw-r--r--sound/soc/intel/boards/bxt_rt298.c2
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c55
-rw-r--r--sound/soc/intel/boards/bytcr_rt5651.c364
-rw-r--r--sound/soc/intel/boards/glk_rt5682_max98357a.c643
-rw-r--r--sound/soc/intel/boards/kbl_da7219_max98357a.c3
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_max98927.c4
-rw-r--r--sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c4
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_max98357a.c2
-rw-r--r--sound/soc/intel/boards/skl_nau88l25_ssm4567.c2
-rw-r--r--sound/soc/intel/boards/skl_rt286.c2
-rw-r--r--sound/soc/intel/common/Makefile6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-bxt-match.c59
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-byt-match.c40
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cht-match.c56
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-cnl-match.c32
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-glk-match.c41
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c16
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-kbl-match.c91
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-skl-match.c47
-rw-r--r--sound/soc/intel/common/sst-firmware.c6
-rw-r--r--sound/soc/intel/haswell/sst-haswell-dsp.c53
-rw-r--r--sound/soc/intel/skylake/skl-messages.c50
-rw-r--r--sound/soc/intel/skylake/skl-nhlt.c8
-rw-r--r--sound/soc/intel/skylake/skl-pcm.c119
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.c8
-rw-r--r--sound/soc/intel/skylake/skl-sst-cldma.h2
-rw-r--r--sound/soc/intel/skylake/skl-topology.c28
-rw-r--r--sound/soc/intel/skylake/skl-topology.h11
-rw-r--r--sound/soc/intel/skylake/skl.c360
-rw-r--r--sound/soc/intel/skylake/skl.h7
-rw-r--r--sound/soc/mediatek/common/mtk-afe-platform-driver.c64
-rw-r--r--sound/soc/mediatek/common/mtk-base-afe.h6
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-common.h1
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c65
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-adda.c20
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-hostless.c16
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-dai-pcm.c19
-rw-r--r--sound/soc/meson/Kconfig65
-rw-r--r--sound/soc/meson/Makefile21
-rw-r--r--sound/soc/meson/axg-card.c671
-rw-r--r--sound/soc/meson/axg-fifo.c341
-rw-r--r--sound/soc/meson/axg-fifo.h80
-rw-r--r--sound/soc/meson/axg-frddr.c141
-rw-r--r--sound/soc/meson/axg-spdifout.c456
-rw-r--r--sound/soc/meson/axg-tdm-formatter.c381
-rw-r--r--sound/soc/meson/axg-tdm-formatter.h39
-rw-r--r--sound/soc/meson/axg-tdm-interface.c542
-rw-r--r--sound/soc/meson/axg-tdm.h78
-rw-r--r--sound/soc/meson/axg-tdmin.c229
-rw-r--r--sound/soc/meson/axg-tdmout.c259
-rw-r--r--sound/soc/meson/axg-toddr.c199
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c2
-rw-r--r--sound/soc/omap/omap-dmic.c2
-rw-r--r--sound/soc/omap/omap-mcpdm.c4
-rw-r--r--sound/soc/pxa/Kconfig6
-rw-r--r--sound/soc/pxa/magician.c106
-rw-r--r--sound/soc/pxa/pxa-ssp.c181
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c47
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c9
-rw-r--r--sound/soc/pxa/pxa2xx-pcm.c73
-rw-r--r--sound/soc/pxa/zylonite.c9
-rw-r--r--sound/soc/qcom/Kconfig14
-rw-r--r--sound/soc/qcom/Makefile4
-rw-r--r--sound/soc/qcom/apq8096.c188
-rw-r--r--sound/soc/qcom/common.c112
-rw-r--r--sound/soc/qcom/common.h11
-rw-r--r--sound/soc/qcom/lpass-platform.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6adm.c16
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c225
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c43
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c42
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c17
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c71
-rw-r--r--sound/soc/qcom/sdm845.c285
-rw-r--r--sound/soc/rockchip/Makefile3
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c3
-rw-r--r--sound/soc/rockchip/rockchip_pcm.c45
-rw-r--r--sound/soc/rockchip/rockchip_pcm.h14
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c27
-rw-r--r--sound/soc/samsung/i2s.c1
-rw-r--r--sound/soc/sh/Kconfig1
-rw-r--r--sound/soc/sh/dma-sh7760.c26
-rw-r--r--sound/soc/sh/fsi.c22
-rw-r--r--sound/soc/sh/hac.c20
-rw-r--r--sound/soc/sh/migor.c14
-rw-r--r--sound/soc/sh/rcar/Makefile1
-rw-r--r--sound/soc/sh/rcar/adg.c15
-rw-r--r--sound/soc/sh/rcar/cmd.c19
-rw-r--r--sound/soc/sh/rcar/core.c41
-rw-r--r--sound/soc/sh/rcar/ctu.c15
-rw-r--r--sound/soc/sh/rcar/dma.c17
-rw-r--r--sound/soc/sh/rcar/dvc.c16
-rw-r--r--sound/soc/sh/rcar/gen.c16
-rw-r--r--sound/soc/sh/rcar/mix.c14
-rw-r--r--sound/soc/sh/rcar/rsnd.h17
-rw-r--r--sound/soc/sh/rcar/src.c16
-rw-r--r--sound/soc/sh/rcar/ssi.c59
-rw-r--r--sound/soc/sh/rcar/ssiu.c15
-rw-r--r--sound/soc/sh/sh7760-ac97.c14
-rw-r--r--sound/soc/sh/siu.h26
-rw-r--r--sound/soc/sh/siu_dai.c26
-rw-r--r--sound/soc/sh/siu_pcm.c27
-rw-r--r--sound/soc/sh/ssi.c21
-rw-r--r--sound/soc/sirf/sirf-usp.c7
-rw-r--r--sound/soc/soc-ac97.c29
-rw-r--r--sound/soc/soc-acpi.c20
-rw-r--r--sound/soc/soc-compress.c120
-rw-r--r--sound/soc/soc-core.c200
-rw-r--r--sound/soc/soc-dapm.c51
-rw-r--r--sound/soc/soc-devres.c15
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c30
-rw-r--r--sound/soc/soc-io.c19
-rw-r--r--sound/soc/soc-jack.c19
-rw-r--r--sound/soc/soc-ops.c29
-rw-r--r--sound/soc/soc-pcm.c469
-rw-r--r--sound/soc/soc-topology.c91
-rw-r--r--sound/soc/soc-utils.c24
-rw-r--r--sound/soc/sti/uniperif_player.c6
-rw-r--r--sound/soc/sti/uniperif_reader.c2
-rw-r--r--sound/soc/stm/Kconfig1
-rw-r--r--sound/soc/stm/stm32_adfsdm.c10
-rw-r--r--sound/soc/stm/stm32_sai_sub.c146
-rw-r--r--sound/soc/tegra/tegra20_ac97.c2
-rw-r--r--sound/soc/tegra/tegra30_i2s.h2
-rw-r--r--sound/soc/tegra/tegra_alc5632.c17
-rw-r--r--sound/soc/tegra/tegra_rt5677.c17
-rw-r--r--sound/soc/uniphier/aio-core.c84
-rw-r--r--sound/soc/uniphier/aio-cpu.c5
-rw-r--r--sound/soc/uniphier/aio-ld11.c2
-rw-r--r--sound/soc/uniphier/aio-reg.h1
-rw-r--r--sound/soc/uniphier/aio.h6
-rw-r--r--sound/soc/zte/zx-tdm.c4
-rw-r--r--sound/synth/emux/emux.c17
-rw-r--r--sound/synth/util_mem.c16
-rw-r--r--sound/usb/6fire/pcm.c1
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/caiaq/audio.c6
-rw-r--r--sound/usb/card.c9
-rw-r--r--sound/usb/card.h2
-rw-r--r--sound/usb/clock.c24
-rw-r--r--sound/usb/endpoint.c2
-rw-r--r--sound/usb/hiface/pcm.c1
-rw-r--r--sound/usb/line6/toneport.c5
-rw-r--r--sound/usb/midi.c5
-rw-r--r--sound/usb/misc/ua101.c2
-rw-r--r--sound/usb/mixer.c214
-rw-r--r--sound/usb/mixer.h2
-rw-r--r--sound/usb/mixer_quirks.c2
-rw-r--r--sound/usb/pcm.c71
-rw-r--r--sound/usb/pcm.h2
-rw-r--r--sound/usb/power.c104
-rw-r--r--sound/usb/power.h19
-rw-r--r--sound/usb/quirks-table.h3
-rw-r--r--sound/usb/quirks.c16
-rw-r--r--sound/usb/stream.c70
-rw-r--r--sound/x86/intel_hdmi_audio.c4
-rw-r--r--sound/xen/xen_snd_front_alsa.c4
412 files changed, 16382 insertions, 5832 deletions
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
index 31f858eceffc..7a0dfca03a57 100644
--- a/sound/ac97/bus.c
+++ b/sound/ac97/bus.c
@@ -13,6 +13,7 @@
#include <linux/idr.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
@@ -68,6 +69,27 @@ ac97_codec_find(struct ac97_controller *ac97_ctrl, unsigned int codec_num)
return ac97_ctrl->codecs[codec_num];
}
+static struct device_node *
+ac97_of_get_child_device(struct ac97_controller *ac97_ctrl, int idx,
+ unsigned int vendor_id)
+{
+ struct device_node *node;
+ u32 reg;
+ char compat[] = "ac97,0000,0000";
+
+ snprintf(compat, sizeof(compat), "ac97,%04x,%04x",
+ vendor_id >> 16, vendor_id & 0xffff);
+
+ for_each_child_of_node(ac97_ctrl->parent->of_node, node) {
+ if ((idx != of_property_read_u32(node, "reg", &reg)) ||
+ !of_device_is_compatible(node, compat))
+ continue;
+ return of_node_get(node);
+ }
+
+ return NULL;
+}
+
static void ac97_codec_release(struct device *dev)
{
struct ac97_codec_device *adev;
@@ -76,6 +98,7 @@ static void ac97_codec_release(struct device *dev)
adev = to_ac97_device(dev);
ac97_ctrl = adev->ac97_ctrl;
ac97_ctrl->codecs[adev->num] = NULL;
+ of_node_put(dev->of_node);
kfree(adev);
}
@@ -98,6 +121,8 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
device_initialize(&codec->dev);
dev_set_name(&codec->dev, "%s:%u", dev_name(ac97_ctrl->parent), idx);
+ codec->dev.of_node = ac97_of_get_child_device(ac97_ctrl, idx,
+ vendor_id);
ret = device_add(&codec->dev);
if (ret)
@@ -105,6 +130,7 @@ static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
return 0;
err_free_codec:
+ of_node_put(codec->dev.of_node);
put_device(&codec->dev);
kfree(codec);
ac97_ctrl->codecs[idx] = NULL;
diff --git a/sound/aoa/core/gpio-feature.c b/sound/aoa/core/gpio-feature.c
index 71960089e207..65557421fe0b 100644
--- a/sound/aoa/core/gpio-feature.c
+++ b/sound/aoa/core/gpio-feature.c
@@ -88,8 +88,10 @@ static struct device_node *get_gpio(char *name,
}
reg = of_get_property(np, "reg", NULL);
- if (!reg)
+ if (!reg) {
+ of_node_put(np);
return NULL;
+ }
*gpioptr = *reg;
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 65171f6657a2..5fbd47a9177e 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -17,14 +17,9 @@ config SND_ARMAACI
select SND_PCM
select SND_AC97_CODEC
-config SND_PXA2XX_PCM
- tristate
- select SND_PCM
-
config SND_PXA2XX_AC97
tristate "AC97 driver for the Intel PXA2xx chip"
depends on ARCH_PXA
- select SND_PXA2XX_PCM
select SND_AC97_CODEC
select SND_PXA2XX_LIB
select SND_PXA2XX_LIB_AC97
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index e10d5b169565..34c769489877 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -6,9 +6,6 @@
obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o
snd-aaci-objs := aaci.o
-obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
-snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
-
obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o
snd-pxa2xx-lib-y := pxa2xx-pcm-lib.o
snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c
index 5950a9e218d9..8eafd3d3dff6 100644
--- a/sound/arm/pxa2xx-ac97-lib.c
+++ b/sound/arm/pxa2xx-ac97-lib.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <sound/pxa2xx-lib.h>
@@ -337,6 +338,17 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
dev_err(&dev->dev, "Invalid reset GPIO %d\n",
pdata->reset_gpio);
}
+ } else if (!pdata && dev->dev.of_node) {
+ pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node,
+ "reset-gpios", 0);
+ if (pdata->reset_gpio == -ENOENT)
+ pdata->reset_gpio = -1;
+ else if (pdata->reset_gpio < 0)
+ return pdata->reset_gpio;
+ reset_gpio = pdata->reset_gpio;
} else {
if (cpu_is_pxa27x())
reset_gpio = 113;
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 4bc244c40f80..1f72672262d0 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmaengine.h>
-#include <linux/dma/pxa-dma.h>
+#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -27,8 +27,6 @@
#include <mach/regs-ac97.h>
#include <mach/audio.h>
-#include "pxa2xx-pcm.h"
-
static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
{
if (!pxa2xx_ac97_try_cold_reset())
@@ -63,61 +61,46 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.reset = pxa2xx_ac97_legacy_reset,
};
-static struct pxad_param pxa2xx_ac97_pcm_out_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 12,
-};
-
-static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
- .addr = __PREG(PCDR),
- .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .maxburst = 32,
- .filter_data = &pxa2xx_ac97_pcm_out_req,
-};
-
-static struct pxad_param pxa2xx_ac97_pcm_in_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 11,
-};
-
-static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
- .addr = __PREG(PCDR),
- .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .maxburst = 32,
- .filter_data = &pxa2xx_ac97_pcm_in_req,
-};
-
static struct snd_pcm *pxa2xx_ac97_pcm;
static struct snd_ac97 *pxa2xx_ac97_ac97;
-static int pxa2xx_ac97_pcm_startup(struct snd_pcm_substream *substream)
+static int pxa2xx_ac97_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
pxa2xx_audio_ops_t *platform_ops;
- int r;
+ int ret, i;
+
+ ret = pxa2xx_pcm_open(substream);
+ if (ret)
+ return ret;
runtime->hw.channels_min = 2;
runtime->hw.channels_max = 2;
- r = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
- runtime->hw.rates = pxa2xx_ac97_ac97->rates[r];
+ i = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
+ runtime->hw.rates = pxa2xx_ac97_ac97->rates[i];
snd_pcm_limit_hw_rates(runtime);
- platform_ops = substream->pcm->card->dev->platform_data;
- if (platform_ops && platform_ops->startup)
- return platform_ops->startup(substream, platform_ops->priv);
- else
- return 0;
+ platform_ops = substream->pcm->card->dev->platform_data;
+ if (platform_ops && platform_ops->startup) {
+ ret = platform_ops->startup(substream, platform_ops->priv);
+ if (ret < 0)
+ pxa2xx_pcm_close(substream);
+ }
+
+ return ret;
}
-static void pxa2xx_ac97_pcm_shutdown(struct snd_pcm_substream *substream)
+static int pxa2xx_ac97_pcm_close(struct snd_pcm_substream *substream)
{
pxa2xx_audio_ops_t *platform_ops;
- platform_ops = substream->pcm->card->dev->platform_data;
+ platform_ops = substream->pcm->card->dev->platform_data;
if (platform_ops && platform_ops->shutdown)
platform_ops->shutdown(substream, platform_ops->priv);
+
+ return 0;
}
static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
@@ -125,17 +108,15 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+ int ret;
+
+ ret = pxa2xx_pcm_prepare(substream);
+ if (ret < 0)
+ return ret;
+
return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
}
-static struct pxa2xx_pcm_client pxa2xx_ac97_pcm_client = {
- .playback_params = &pxa2xx_ac97_pcm_out,
- .capture_params = &pxa2xx_ac97_pcm_in,
- .startup = pxa2xx_ac97_pcm_startup,
- .shutdown = pxa2xx_ac97_pcm_shutdown,
- .prepare = pxa2xx_ac97_pcm_prepare,
-};
-
#ifdef CONFIG_PM_SLEEP
static int pxa2xx_ac97_do_suspend(struct snd_card *card)
@@ -193,6 +174,53 @@ static int pxa2xx_ac97_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
#endif
+static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
+ .open = pxa2xx_ac97_pcm_open,
+ .close = pxa2xx_ac97_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pxa2xx_pcm_hw_params,
+ .hw_free = pxa2xx_pcm_hw_free,
+ .prepare = pxa2xx_ac97_pcm_prepare,
+ .trigger = pxa2xx_pcm_trigger,
+ .pointer = pxa2xx_pcm_pointer,
+ .mmap = pxa2xx_pcm_mmap,
+};
+
+
+static int pxa2xx_ac97_pcm_new(struct snd_card *card)
+{
+ struct snd_pcm *pcm;
+ int stream, ret;
+
+ ret = snd_pcm_new(card, "PXA2xx-PCM", 0, 1, 1, &pcm);
+ if (ret)
+ goto out;
+
+ pcm->private_free = pxa2xx_pcm_free_dma_buffers;
+
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ goto out;
+
+ stream = SNDRV_PCM_STREAM_PLAYBACK;
+ snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+ if (ret)
+ goto out;
+
+ stream = SNDRV_PCM_STREAM_CAPTURE;
+ snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+ if (ret)
+ goto out;
+
+ pxa2xx_ac97_pcm = pcm;
+ ret = 0;
+
+ out:
+ return ret;
+}
+
static int pxa2xx_ac97_probe(struct platform_device *dev)
{
struct snd_card *card;
@@ -214,7 +242,7 @@ static int pxa2xx_ac97_probe(struct platform_device *dev)
strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
- ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
+ ret = pxa2xx_ac97_pcm_new(card);
if (ret)
goto err;
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
index e8da3b8ee721..7931789d4a9f 100644
--- a/sound/arm/pxa2xx-pcm-lib.c
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -16,8 +16,6 @@
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>
-#include "pxa2xx-pcm.h"
-
static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -25,8 +23,8 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
- SNDRV_PCM_FMTBIT_S32_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.period_bytes_min = 32,
.period_bytes_max = 8192 - 32,
.periods_min = 1,
@@ -35,8 +33,8 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
.fifo_size = 32,
};
-int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -64,14 +62,14 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
+EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
-int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
-EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
+EXPORT_SYMBOL(pxa2xx_pcm_hw_free);
int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
@@ -86,13 +84,13 @@ pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL(pxa2xx_pcm_pointer);
-int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
{
return 0;
}
-EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
+EXPORT_SYMBOL(pxa2xx_pcm_prepare);
-int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -125,17 +123,17 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
if (ret < 0)
return ret;
- return snd_dmaengine_pcm_open_request_chan(substream,
- pxad_filter_fn,
- dma_params->filter_data);
+ return snd_dmaengine_pcm_open(
+ substream, dma_request_slave_channel(rtd->cpu_dai->dev,
+ dma_params->chan_name));
}
-EXPORT_SYMBOL(__pxa2xx_pcm_open);
+EXPORT_SYMBOL(pxa2xx_pcm_open);
-int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
+int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
{
return snd_dmaengine_pcm_close_release_chan(substream);
}
-EXPORT_SYMBOL(__pxa2xx_pcm_close);
+EXPORT_SYMBOL(pxa2xx_pcm_close);
int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
@@ -181,6 +179,47 @@ void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
+int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_pcm *pcm = rtd->pcm;
+ int ret;
+
+ ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+ out:
+ return ret;
+}
+EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
+
+const struct snd_pcm_ops pxa2xx_pcm_ops = {
+ .open = pxa2xx_pcm_open,
+ .close = pxa2xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pxa2xx_pcm_hw_params,
+ .hw_free = pxa2xx_pcm_hw_free,
+ .prepare = pxa2xx_pcm_prepare,
+ .trigger = pxa2xx_pcm_trigger,
+ .pointer = pxa2xx_pcm_pointer,
+ .mmap = pxa2xx_pcm_mmap,
+};
+EXPORT_SYMBOL(pxa2xx_pcm_ops);
+
MODULE_AUTHOR("Nicolas Pitre");
MODULE_DESCRIPTION("Intel PXA2xx sound library");
MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
deleted file mode 100644
index 1c6f4b436de3..000000000000
--- a/sound/arm/pxa2xx-pcm.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author: Nicolas Pitre
- * Created: Nov 30, 2004
- * Copyright: (C) 2004 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-
-#include <mach/dma.h>
-
-#include <sound/core.h>
-#include <sound/pxa2xx-lib.h>
-#include <sound/dmaengine_pcm.h>
-
-#include "pxa2xx-pcm.h"
-
-static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
-{
- struct pxa2xx_pcm_client *client = substream->private_data;
-
- __pxa2xx_pcm_prepare(substream);
-
- return client->prepare(substream);
-}
-
-static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
-{
- struct pxa2xx_pcm_client *client = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct pxa2xx_runtime_data *rtd;
- int ret;
-
- ret = __pxa2xx_pcm_open(substream);
- if (ret)
- goto out;
-
- rtd = runtime->private_data;
-
- rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- client->playback_params : client->capture_params;
-
- ret = client->startup(substream);
- if (!ret)
- goto err2;
-
- return 0;
-
- err2:
- __pxa2xx_pcm_close(substream);
- out:
- return ret;
-}
-
-static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
-{
- struct pxa2xx_pcm_client *client = substream->private_data;
-
- client->shutdown(substream);
-
- return __pxa2xx_pcm_close(substream);
-}
-
-static const struct snd_pcm_ops pxa2xx_pcm_ops = {
- .open = pxa2xx_pcm_open,
- .close = pxa2xx_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = __pxa2xx_pcm_hw_params,
- .hw_free = __pxa2xx_pcm_hw_free,
- .prepare = pxa2xx_pcm_prepare,
- .trigger = pxa2xx_pcm_trigger,
- .pointer = pxa2xx_pcm_pointer,
- .mmap = pxa2xx_pcm_mmap,
-};
-
-int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client,
- struct snd_pcm **rpcm)
-{
- struct snd_pcm *pcm;
- int play = client->playback_params ? 1 : 0;
- int capt = client->capture_params ? 1 : 0;
- int ret;
-
- ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm);
- if (ret)
- goto out;
-
- pcm->private_data = client;
- pcm->private_free = pxa2xx_pcm_free_dma_buffers;
-
- ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
- if (ret)
- goto out;
-
- if (play) {
- int stream = SNDRV_PCM_STREAM_PLAYBACK;
- snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
- ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
- if (ret)
- goto out;
- }
- if (capt) {
- int stream = SNDRV_PCM_STREAM_CAPTURE;
- snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
- ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
- if (ret)
- goto out;
- }
-
- if (rpcm)
- *rpcm = pcm;
- ret = 0;
-
- out:
- return ret;
-}
-
-EXPORT_SYMBOL(pxa2xx_pcm_new);
-
-MODULE_AUTHOR("Nicolas Pitre");
-MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
-MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
deleted file mode 100644
index 8fa2b7c9e6b8..000000000000
--- a/sound/arm/pxa2xx-pcm.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
- *
- * Author: Nicolas Pitre
- * Created: Nov 30, 2004
- * Copyright: MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-struct pxa2xx_runtime_data {
- int dma_ch;
- struct snd_dmaengine_dai_dma_data *params;
-};
-
-struct pxa2xx_pcm_client {
- struct snd_dmaengine_dai_dma_data *playback_params;
- struct snd_dmaengine_dai_dma_data *capture_params;
- int (*startup)(struct snd_pcm_substream *);
- void (*shutdown)(struct snd_pcm_substream *);
- int (*prepare)(struct snd_pcm_substream *);
-};
-
-extern int pxa2xx_pcm_new(struct snd_card *, struct pxa2xx_pcm_client *, struct snd_pcm **);
-
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 4b01a37c836e..26b5e245b074 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -1160,18 +1160,6 @@ int snd_compress_deregister(struct snd_compr *device)
}
EXPORT_SYMBOL_GPL(snd_compress_deregister);
-static int __init snd_compress_init(void)
-{
- return 0;
-}
-
-static void __exit snd_compress_exit(void)
-{
-}
-
-module_init(snd_compress_init);
-module_exit(snd_compress_exit);
-
MODULE_DESCRIPTION("ALSA Compressed offload framework");
MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 7f89d3c79a4b..753d5fc4b284 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -242,16 +242,12 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
int err;
while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
- size_t aligned_size;
if (err != -ENOMEM)
return err;
if (size <= PAGE_SIZE)
return -ENOMEM;
- aligned_size = PAGE_SIZE << get_order(size);
- if (size != aligned_size)
- size = aligned_size;
- else
- size >>= 1;
+ size >>= 1;
+ size = PAGE_SIZE << get_order(size);
}
if (! dmab->area)
return -ENOMEM;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 905a53c1cde5..f8d4a419f3af 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -1851,7 +1851,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
for (fmt = 0; fmt < 32; ++fmt) {
if (snd_mask_test(format_mask, fmt)) {
- int f = snd_pcm_oss_format_to(fmt);
+ int f = snd_pcm_oss_format_to((__force snd_pcm_format_t)fmt);
if (f >= 0)
formats |= f;
}
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 85a56af104bd..0391cb1a4f19 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -281,10 +281,10 @@ static int snd_pcm_plug_formats(const struct snd_mask *mask,
SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
- if (formats.bits[0] & (u32)linfmts)
- formats.bits[0] |= (u32)linfmts;
- if (formats.bits[1] & (u32)(linfmts >> 32))
- formats.bits[1] |= (u32)(linfmts >> 32);
+ if (formats.bits[0] & lower_32_bits(linfmts))
+ formats.bits[0] |= lower_32_bits(linfmts);
+ if (formats.bits[1] & upper_32_bits(linfmts))
+ formats.bits[1] |= upper_32_bits(linfmts);
return snd_mask_test(&formats, (__force int)format);
}
@@ -353,6 +353,7 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
if (snd_mask_test(format_mask, (__force int)format1))
return format1;
}
+ /* fall through */
default:
return (__force snd_pcm_format_t)-EINVAL;
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index c352bfb973cc..fdb9b92fc8d6 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -492,13 +492,8 @@ static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct snd_pcm_substream *substream = entry->private_data;
- struct snd_pcm_runtime *runtime;
- snd_pcm_stream_lock_irq(substream);
- runtime = substream->runtime;
- if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irq(substream);
+ snd_pcm_stop_xrun(substream);
}
static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 44b5ae833082..4e6110d778bd 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -153,7 +153,8 @@ EXPORT_SYMBOL(snd_pcm_debug_name);
dump_stack(); \
} while (0)
-static void xrun(struct snd_pcm_substream *substream)
+/* call with stream lock held */
+void __snd_pcm_xrun(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -201,7 +202,7 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
}
} else {
if (avail >= runtime->stop_threshold) {
- xrun(substream);
+ __snd_pcm_xrun(substream);
return -EPIPE;
}
}
@@ -297,7 +298,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
if (pos == SNDRV_PCM_POS_XRUN) {
- xrun(substream);
+ __snd_pcm_xrun(substream);
return -EPIPE;
}
if (pos >= runtime->buffer_size) {
@@ -626,27 +627,33 @@ EXPORT_SYMBOL(snd_interval_refine);
static int snd_interval_refine_first(struct snd_interval *i)
{
+ const unsigned int last_max = i->max;
+
if (snd_BUG_ON(snd_interval_empty(i)))
return -EINVAL;
if (snd_interval_single(i))
return 0;
i->max = i->min;
- i->openmax = i->openmin;
- if (i->openmax)
+ if (i->openmin)
i->max++;
+ /* only exclude max value if also excluded before refine */
+ i->openmax = (i->openmax && i->max >= last_max);
return 1;
}
static int snd_interval_refine_last(struct snd_interval *i)
{
+ const unsigned int last_min = i->min;
+
if (snd_BUG_ON(snd_interval_empty(i)))
return -EINVAL;
if (snd_interval_single(i))
return 0;
i->min = i->max;
- i->openmin = i->openmax;
- if (i->openmin)
+ if (i->openmax)
i->min--;
+ /* only exclude min value if also excluded before refine */
+ i->openmin = (i->openmin && i->min <= last_min);
return 1;
}
@@ -1832,12 +1839,19 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
if (runtime->no_period_wakeup)
wait_time = MAX_SCHEDULE_TIMEOUT;
else {
- wait_time = 10;
- if (runtime->rate) {
- long t = runtime->period_size * 2 / runtime->rate;
- wait_time = max(t, wait_time);
+ /* use wait time from substream if available */
+ if (substream->wait_time) {
+ wait_time = substream->wait_time;
+ } else {
+ wait_time = 10;
+
+ if (runtime->rate) {
+ long t = runtime->period_size * 2 /
+ runtime->rate;
+ wait_time = max(t, wait_time);
+ }
+ wait_time = msecs_to_jiffies(wait_time * 1000);
}
- wait_time = msecs_to_jiffies(wait_time * 1000);
}
for (;;) {
diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h
index 7a499d02df6c..c515612969a4 100644
--- a/sound/core/pcm_local.h
+++ b/sound/core/pcm_local.h
@@ -65,4 +65,6 @@ static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {}
static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
#endif
+void __snd_pcm_xrun(struct snd_pcm_substream *substream);
+
#endif /* __SOUND_CORE_PCM_LOCAL_H */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index cecc79772c94..66c90f486af9 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1337,13 +1337,12 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
{
unsigned long flags;
- int ret = 0;
snd_pcm_stream_lock_irqsave(substream, flags);
- if (snd_pcm_running(substream))
- ret = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ if (substream->runtime && snd_pcm_running(substream))
+ __snd_pcm_xrun(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
@@ -1591,7 +1590,8 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)
result = 0; /* already there */
break;
case SNDRV_PCM_STATE_RUNNING:
- result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ __snd_pcm_xrun(substream);
+ result = 0;
break;
default:
result = -EBADFD;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 69616d00481c..69517e18ef07 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -29,6 +29,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/mm.h>
#include <sound/rawmidi.h>
#include <sound/info.h>
#include <sound/control.h>
@@ -88,6 +89,7 @@ static inline unsigned short snd_rawmidi_file_flags(struct file *file)
static inline int snd_rawmidi_ready(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
+
return runtime->avail >= runtime->avail_min;
}
@@ -95,6 +97,7 @@ static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substre
size_t count)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
+
return runtime->avail >= runtime->avail_min &&
(!substream->append || runtime->avail >= count);
}
@@ -103,6 +106,7 @@ static void snd_rawmidi_input_event_work(struct work_struct *work)
{
struct snd_rawmidi_runtime *runtime =
container_of(work, struct snd_rawmidi_runtime, event_work);
+
if (runtime->event)
runtime->event(runtime->substream);
}
@@ -111,7 +115,8 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime;
- if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL)
+ runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+ if (!runtime)
return -ENOMEM;
runtime->substream = substream;
spin_lock_init(&runtime->lock);
@@ -124,7 +129,8 @@ static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream)
runtime->avail = 0;
else
runtime->avail = runtime->buffer_size;
- if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL) {
+ runtime->buffer = kvmalloc(runtime->buffer_size, GFP_KERNEL);
+ if (!runtime->buffer) {
kfree(runtime);
return -ENOMEM;
}
@@ -137,13 +143,13 @@ static int snd_rawmidi_runtime_free(struct snd_rawmidi_substream *substream)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
- kfree(runtime->buffer);
+ kvfree(runtime->buffer);
kfree(runtime);
substream->runtime = NULL;
return 0;
}
-static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream,int up)
+static inline void snd_rawmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
if (!substream->opened)
return;
@@ -159,17 +165,28 @@ static void snd_rawmidi_input_trigger(struct snd_rawmidi_substream *substream, i
cancel_work_sync(&substream->runtime->event_work);
}
-int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
+static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
+ bool is_input)
+{
+ runtime->drain = 0;
+ runtime->appl_ptr = runtime->hw_ptr = 0;
+ runtime->avail = is_input ? 0 : runtime->buffer_size;
+}
+
+static void reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime,
+ bool is_input)
{
unsigned long flags;
- struct snd_rawmidi_runtime *runtime = substream->runtime;
- snd_rawmidi_output_trigger(substream, 0);
- runtime->drain = 0;
spin_lock_irqsave(&runtime->lock, flags);
- runtime->appl_ptr = runtime->hw_ptr = 0;
- runtime->avail = runtime->buffer_size;
+ __reset_runtime_ptrs(runtime, is_input);
spin_unlock_irqrestore(&runtime->lock, flags);
+}
+
+int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream)
+{
+ snd_rawmidi_output_trigger(substream, 0);
+ reset_runtime_ptrs(substream->runtime, false);
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_drop_output);
@@ -208,15 +225,8 @@ EXPORT_SYMBOL(snd_rawmidi_drain_output);
int snd_rawmidi_drain_input(struct snd_rawmidi_substream *substream)
{
- unsigned long flags;
- struct snd_rawmidi_runtime *runtime = substream->runtime;
-
snd_rawmidi_input_trigger(substream, 0);
- runtime->drain = 0;
- spin_lock_irqsave(&runtime->lock, flags);
- runtime->appl_ptr = runtime->hw_ptr = 0;
- runtime->avail = 0;
- spin_unlock_irqrestore(&runtime->lock, flags);
+ reset_runtime_ptrs(substream->runtime, true);
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_drain_input);
@@ -330,25 +340,23 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
/* called from sound/core/seq/seq_midi.c */
int snd_rawmidi_kernel_open(struct snd_card *card, int device, int subdevice,
- int mode, struct snd_rawmidi_file * rfile)
+ int mode, struct snd_rawmidi_file *rfile)
{
struct snd_rawmidi *rmidi;
- int err;
+ int err = 0;
if (snd_BUG_ON(!rfile))
return -EINVAL;
mutex_lock(&register_mutex);
rmidi = snd_rawmidi_search(card, device);
- if (rmidi == NULL) {
- mutex_unlock(&register_mutex);
- return -ENODEV;
- }
- if (!try_module_get(rmidi->card->module)) {
- mutex_unlock(&register_mutex);
- return -ENXIO;
- }
+ if (!rmidi)
+ err = -ENODEV;
+ else if (!try_module_get(rmidi->card->module))
+ err = -ENXIO;
mutex_unlock(&register_mutex);
+ if (err < 0)
+ return err;
mutex_lock(&rmidi->open_mutex);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
@@ -370,7 +378,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
struct snd_rawmidi_file *rawmidi_file = NULL;
wait_queue_entry_t wait;
- if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
+ if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
err = nonseekable_open(inode, file);
@@ -520,7 +528,7 @@ int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile)
if (snd_BUG_ON(!rfile))
return -ENXIO;
-
+
rmidi = rfile->rmidi;
rawmidi_release_priv(rfile);
module_put(rmidi->card->module);
@@ -548,7 +556,7 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_info *info)
{
struct snd_rawmidi *rmidi;
-
+
if (substream == NULL)
return -ENODEV;
rmidi = substream->rmidi;
@@ -568,11 +576,13 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
}
static int snd_rawmidi_info_user(struct snd_rawmidi_substream *substream,
- struct snd_rawmidi_info __user * _info)
+ struct snd_rawmidi_info __user *_info)
{
struct snd_rawmidi_info info;
int err;
- if ((err = snd_rawmidi_info(substream, &info)) < 0)
+
+ err = snd_rawmidi_info(substream, &info);
+ if (err < 0)
return err;
if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))
return -EFAULT;
@@ -619,77 +629,68 @@ static int snd_rawmidi_info_select_user(struct snd_card *card,
{
int err;
struct snd_rawmidi_info info;
+
if (get_user(info.device, &_info->device))
return -EFAULT;
if (get_user(info.stream, &_info->stream))
return -EFAULT;
if (get_user(info.subdevice, &_info->subdevice))
return -EFAULT;
- if ((err = snd_rawmidi_info_select(card, &info)) < 0)
+ err = snd_rawmidi_info_select(card, &info);
+ if (err < 0)
return err;
if (copy_to_user(_info, &info, sizeof(struct snd_rawmidi_info)))
return -EFAULT;
return 0;
}
-int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
- struct snd_rawmidi_params * params)
+static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
+ struct snd_rawmidi_params *params,
+ bool is_input)
{
- char *newbuf;
- struct snd_rawmidi_runtime *runtime = substream->runtime;
-
- if (substream->append && substream->use_count > 1)
- return -EBUSY;
- snd_rawmidi_drain_output(substream);
- if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
+ char *newbuf, *oldbuf;
+
+ if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L)
return -EINVAL;
- }
- if (params->avail_min < 1 || params->avail_min > params->buffer_size) {
+ if (params->avail_min < 1 || params->avail_min > params->buffer_size)
return -EINVAL;
- }
if (params->buffer_size != runtime->buffer_size) {
- newbuf = krealloc(runtime->buffer, params->buffer_size,
- GFP_KERNEL);
+ newbuf = kvmalloc(params->buffer_size, GFP_KERNEL);
if (!newbuf)
return -ENOMEM;
+ spin_lock_irq(&runtime->lock);
+ oldbuf = runtime->buffer;
runtime->buffer = newbuf;
runtime->buffer_size = params->buffer_size;
- runtime->avail = runtime->buffer_size;
+ __reset_runtime_ptrs(runtime, is_input);
+ spin_unlock_irq(&runtime->lock);
+ kvfree(oldbuf);
}
runtime->avail_min = params->avail_min;
- substream->active_sensing = !params->no_active_sensing;
return 0;
}
+
+int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
+ struct snd_rawmidi_params *params)
+{
+ if (substream->append && substream->use_count > 1)
+ return -EBUSY;
+ snd_rawmidi_drain_output(substream);
+ substream->active_sensing = !params->no_active_sensing;
+ return resize_runtime_buffer(substream->runtime, params, false);
+}
EXPORT_SYMBOL(snd_rawmidi_output_params);
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
- struct snd_rawmidi_params * params)
+ struct snd_rawmidi_params *params)
{
- char *newbuf;
- struct snd_rawmidi_runtime *runtime = substream->runtime;
-
snd_rawmidi_drain_input(substream);
- if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
- return -EINVAL;
- }
- if (params->avail_min < 1 || params->avail_min > params->buffer_size) {
- return -EINVAL;
- }
- if (params->buffer_size != runtime->buffer_size) {
- newbuf = krealloc(runtime->buffer, params->buffer_size,
- GFP_KERNEL);
- if (!newbuf)
- return -ENOMEM;
- runtime->buffer = newbuf;
- runtime->buffer_size = params->buffer_size;
- }
- runtime->avail_min = params->avail_min;
- return 0;
+ return resize_runtime_buffer(substream->runtime, params, true);
}
EXPORT_SYMBOL(snd_rawmidi_input_params);
static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
- struct snd_rawmidi_status * status)
+ struct snd_rawmidi_status *status)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
@@ -702,7 +703,7 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
}
static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
- struct snd_rawmidi_status * status)
+ struct snd_rawmidi_status *status)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
@@ -731,6 +732,7 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
{
int stream;
struct snd_rawmidi_info __user *info = argp;
+
if (get_user(stream, &info->stream))
return -EFAULT;
switch (stream) {
@@ -745,6 +747,7 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDRV_RAWMIDI_IOCTL_PARAMS:
{
struct snd_rawmidi_params params;
+
if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
return -EFAULT;
switch (params.stream) {
@@ -764,6 +767,7 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
{
int err = 0;
struct snd_rawmidi_status status;
+
if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
switch (status.stream) {
@@ -789,6 +793,7 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDRV_RAWMIDI_IOCTL_DROP:
{
int val;
+
if (get_user(val, (int __user *) argp))
return -EFAULT;
switch (val) {
@@ -803,6 +808,7 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDRV_RAWMIDI_IOCTL_DRAIN:
{
int val;
+
if (get_user(val, (int __user *) argp))
return -EFAULT;
switch (val) {
@@ -836,7 +842,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
{
int device;
-
+
if (get_user(device, (int __user *)argp))
return -EFAULT;
if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */
@@ -858,7 +864,7 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
{
int val;
-
+
if (get_user(val, (int __user *)argp))
return -EFAULT;
control->preferred_subdevice[SND_CTL_SUBDEV_RAWMIDI] = val;
@@ -1012,6 +1018,7 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
spin_lock_irq(&runtime->lock);
while (!snd_rawmidi_ready(substream)) {
wait_queue_entry_t wait;
+
if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
spin_unlock_irq(&runtime->lock);
return result > 0 ? result : -EAGAIN;
@@ -1064,7 +1071,7 @@ int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream)
spin_lock_irqsave(&runtime->lock, flags);
result = runtime->avail >= runtime->buffer_size;
spin_unlock_irqrestore(&runtime->lock, flags);
- return result;
+ return result;
}
EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
@@ -1202,7 +1209,7 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
* @substream: the rawmidi substream
* @buffer: the buffer pointer
* @count: the data size to transfer
- *
+ *
* Copies data from the buffer to the device and advances the pointer.
*
* Return: The copied size if successful, or a negative error code on failure.
@@ -1316,6 +1323,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
spin_lock_irq(&runtime->lock);
while (!snd_rawmidi_ready_append(substream, count)) {
wait_queue_entry_t wait;
+
if (file->f_flags & O_NONBLOCK) {
spin_unlock_irq(&runtime->lock);
return result > 0 ? result : -EAGAIN;
@@ -1349,6 +1357,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
while (runtime->avail != runtime->buffer_size) {
wait_queue_entry_t wait;
unsigned int last_avail = runtime->avail;
+
init_waitqueue_entry(&wait, current);
add_wait_queue(&runtime->sleep, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -1366,7 +1375,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
return result;
}
-static __poll_t snd_rawmidi_poll(struct file *file, poll_table * wait)
+static __poll_t snd_rawmidi_poll(struct file *file, poll_table *wait)
{
struct snd_rawmidi_file *rfile;
struct snd_rawmidi_runtime *runtime;
@@ -1403,7 +1412,6 @@ static __poll_t snd_rawmidi_poll(struct file *file, poll_table * wait)
#endif
/*
-
*/
static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
@@ -1471,8 +1479,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
* Register functions
*/
-static const struct file_operations snd_rawmidi_f_ops =
-{
+static const struct file_operations snd_rawmidi_f_ops = {
.owner = THIS_MODULE,
.read = snd_rawmidi_read,
.write = snd_rawmidi_write,
@@ -1527,7 +1534,7 @@ static void release_rawmidi_device(struct device *dev)
*/
int snd_rawmidi_new(struct snd_card *card, char *id, int device,
int output_count, int input_count,
- struct snd_rawmidi ** rrawmidi)
+ struct snd_rawmidi **rrawmidi)
{
struct snd_rawmidi *rmidi;
int err;
@@ -1558,27 +1565,29 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
rmidi->dev.release = release_rawmidi_device;
dev_set_name(&rmidi->dev, "midiC%iD%i", card->number, device);
- if ((err = snd_rawmidi_alloc_substreams(rmidi,
- &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
- SNDRV_RAWMIDI_STREAM_INPUT,
- input_count)) < 0) {
- snd_rawmidi_free(rmidi);
- return err;
- }
- if ((err = snd_rawmidi_alloc_substreams(rmidi,
- &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
- SNDRV_RAWMIDI_STREAM_OUTPUT,
- output_count)) < 0) {
- snd_rawmidi_free(rmidi);
- return err;
- }
- if ((err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)) < 0) {
- snd_rawmidi_free(rmidi);
- return err;
- }
+ err = snd_rawmidi_alloc_substreams(rmidi,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT],
+ SNDRV_RAWMIDI_STREAM_INPUT,
+ input_count);
+ if (err < 0)
+ goto error;
+ err = snd_rawmidi_alloc_substreams(rmidi,
+ &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT],
+ SNDRV_RAWMIDI_STREAM_OUTPUT,
+ output_count);
+ if (err < 0)
+ goto error;
+ err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops);
+ if (err < 0)
+ goto error;
+
if (rrawmidi)
*rrawmidi = rmidi;
return 0;
+
+ error:
+ snd_rawmidi_free(rmidi);
+ return err;
}
EXPORT_SYMBOL(snd_rawmidi_new);
@@ -1616,6 +1625,7 @@ static int snd_rawmidi_free(struct snd_rawmidi *rmidi)
static int snd_rawmidi_dev_free(struct snd_device *device)
{
struct snd_rawmidi *rmidi = device->device_data;
+
return snd_rawmidi_free(rmidi);
}
@@ -1623,6 +1633,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device)
static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device)
{
struct snd_rawmidi *rmidi = device->private_data;
+
rmidi->seq_dev = NULL;
}
#endif
@@ -1636,30 +1647,27 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
return -ENOMEM;
+ err = 0;
mutex_lock(&register_mutex);
- if (snd_rawmidi_search(rmidi->card, rmidi->device)) {
- mutex_unlock(&register_mutex);
- return -EBUSY;
- }
- list_add_tail(&rmidi->list, &snd_rawmidi_devices);
+ if (snd_rawmidi_search(rmidi->card, rmidi->device))
+ err = -EBUSY;
+ else
+ list_add_tail(&rmidi->list, &snd_rawmidi_devices);
mutex_unlock(&register_mutex);
+ if (err < 0)
+ return err;
+
err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
rmidi->card, rmidi->device,
&snd_rawmidi_f_ops, rmidi, &rmidi->dev);
if (err < 0) {
rmidi_err(rmidi, "unable to register\n");
- mutex_lock(&register_mutex);
- list_del(&rmidi->list);
- mutex_unlock(&register_mutex);
- return err;
+ goto error;
}
- if (rmidi->ops && rmidi->ops->dev_register &&
- (err = rmidi->ops->dev_register(rmidi)) < 0) {
- snd_unregister_device(&rmidi->dev);
- mutex_lock(&register_mutex);
- list_del(&rmidi->list);
- mutex_unlock(&register_mutex);
- return err;
+ if (rmidi->ops && rmidi->ops->dev_register) {
+ err = rmidi->ops->dev_register(rmidi);
+ if (err < 0)
+ goto error_unregister;
}
#ifdef CONFIG_SND_OSSEMUL
rmidi->ossreg = 0;
@@ -1711,6 +1719,14 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
}
#endif
return 0;
+
+ error_unregister:
+ snd_unregister_device(&rmidi->dev);
+ error:
+ mutex_lock(&register_mutex);
+ list_del(&rmidi->list);
+ mutex_unlock(&register_mutex);
+ return err;
}
static int snd_rawmidi_dev_disconnect(struct snd_device *device)
@@ -1724,6 +1740,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
list_del_init(&rmidi->list);
for (dir = 0; dir < 2; dir++) {
struct snd_rawmidi_substream *s;
+
list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
if (s->runtime)
wake_up(&s->runtime->sleep);
@@ -1761,7 +1778,7 @@ void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
const struct snd_rawmidi_ops *ops)
{
struct snd_rawmidi_substream *substream;
-
+
list_for_each_entry(substream, &rmidi->streams[stream].substreams, list)
substream->ops = ops;
}
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 5f64d0d88320..e1f44fc86885 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -203,7 +203,7 @@ odev_poll(struct file *file, poll_table * wait)
struct seq_oss_devinfo *dp;
dp = file->private_data;
if (snd_BUG_ON(!dp))
- return -ENXIO;
+ return EPOLLERR;
return snd_seq_oss_poll(dp, file, wait);
}
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
index 9debd1b8fd28..0d5f8b16d057 100644
--- a/sound/core/seq/oss/seq_oss_midi.c
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -637,7 +637,7 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
if ((mdev = get_mididev(dp, dev)) == NULL)
return -ENODEV;
- if (snd_midi_event_encode_byte(mdev->coder, c, ev) > 0) {
+ if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
snd_use_lock_free(&mdev->use_lock);
return 0;
diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
index 4f24ea9fad93..ba127c22539a 100644
--- a/sound/core/seq/oss/seq_oss_timer.c
+++ b/sound/core/seq/oss/seq_oss_timer.c
@@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
case TMR_WAIT_REL:
parm += rec->cur_tick;
rec->realtime = 0;
- /* continue to next */
+ /* fall through and continue to next */
case TMR_WAIT_ABS:
if (parm == 0) {
rec->realtime = 1;
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 639544b4fb04..7de98d71f2aa 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -84,30 +84,32 @@ static int __init alsa_seq_init(void)
{
int err;
- if ((err = client_init_data()) < 0)
- goto error;
-
- /* init memory, room for selected events */
- if ((err = snd_sequencer_memory_init()) < 0)
- goto error;
-
- /* init event queues */
- if ((err = snd_seq_queues_init()) < 0)
+ err = client_init_data();
+ if (err < 0)
goto error;
/* register sequencer device */
- if ((err = snd_sequencer_device_init()) < 0)
+ err = snd_sequencer_device_init();
+ if (err < 0)
goto error;
/* register proc interface */
- if ((err = snd_seq_info_init()) < 0)
- goto error;
+ err = snd_seq_info_init();
+ if (err < 0)
+ goto error_device;
/* register our internal client */
- if ((err = snd_seq_system_client_init()) < 0)
- goto error;
+ err = snd_seq_system_client_init();
+ if (err < 0)
+ goto error_info;
snd_seq_autoload_init();
+ return 0;
+
+ error_info:
+ snd_seq_info_done();
+ error_device:
+ snd_sequencer_device_done();
error:
return err;
}
@@ -126,9 +128,6 @@ static void __exit alsa_seq_exit(void)
/* unregister sequencer device */
snd_sequencer_device_done();
- /* release event memory */
- snd_sequencer_memory_done();
-
snd_seq_autoload_exit();
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 61a07fe34cd2..92e6524a3a9d 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -311,10 +311,9 @@ static int snd_seq_open(struct inode *inode, struct file *file)
if (err < 0)
return err;
- if (mutex_lock_interruptible(&register_mutex))
- return -ERESTARTSYS;
+ mutex_lock(&register_mutex);
client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
- if (client == NULL) {
+ if (!client) {
mutex_unlock(&register_mutex);
return -ENOMEM; /* failure code */
}
@@ -1101,7 +1100,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait)
/* check client structures are in place */
if (snd_BUG_ON(!client))
- return -ENXIO;
+ return EPOLLERR;
if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) &&
client->data.user.fifo) {
@@ -1704,10 +1703,7 @@ static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client,
if (queue == NULL)
return -EINVAL;
- if (mutex_lock_interruptible(&queue->timer_mutex)) {
- queuefree(queue);
- return -ERESTARTSYS;
- }
+ mutex_lock(&queue->timer_mutex);
tmr = queue->timer;
memset(timer, 0, sizeof(*timer));
timer->queue = queue->queue;
@@ -1741,10 +1737,7 @@ static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client,
q = queueptr(timer->queue);
if (q == NULL)
return -ENXIO;
- if (mutex_lock_interruptible(&q->timer_mutex)) {
- queuefree(q);
- return -ERESTARTSYS;
- }
+ mutex_lock(&q->timer_mutex);
tmr = q->timer;
snd_seq_queue_timer_close(timer->queue);
tmr->type = timer->type;
@@ -2004,7 +1997,8 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
struct snd_seq_client *cptr = NULL;
/* search for next client */
- info->client++;
+ if (info->client < INT_MAX)
+ info->client++;
if (info->client < 0)
info->client = 0;
for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) {
@@ -2179,8 +2173,7 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)
return -EINVAL;
- if (mutex_lock_interruptible(&register_mutex))
- return -ERESTARTSYS;
+ mutex_lock(&register_mutex);
if (card) {
client_index += SNDRV_SEQ_GLOBAL_CLIENTS
@@ -2521,19 +2514,15 @@ int __init snd_sequencer_device_init(void)
snd_device_initialize(&seq_dev, NULL);
dev_set_name(&seq_dev, "seq");
- if (mutex_lock_interruptible(&register_mutex))
- return -ERESTARTSYS;
-
+ mutex_lock(&register_mutex);
err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
&snd_seq_f_ops, NULL, &seq_dev);
+ mutex_unlock(&register_mutex);
if (err < 0) {
- mutex_unlock(&register_mutex);
put_device(&seq_dev);
return err;
}
- mutex_unlock(&register_mutex);
-
return 0;
}
@@ -2542,7 +2531,7 @@ int __init snd_sequencer_device_init(void)
/*
* unregister sequencer device
*/
-void __exit snd_sequencer_device_done(void)
+void snd_sequencer_device_done(void)
{
snd_unregister_device(&seq_dev);
put_device(&seq_dev);
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
index 97015447b9b3..b27fedd435b6 100644
--- a/sound/core/seq/seq_info.c
+++ b/sound/core/seq/seq_info.c
@@ -50,7 +50,7 @@ create_info_entry(char *name, void (*read)(struct snd_info_entry *,
return entry;
}
-static void free_info_entries(void)
+void snd_seq_info_done(void)
{
snd_info_free_entry(queues_entry);
snd_info_free_entry(clients_entry);
@@ -70,12 +70,6 @@ int __init snd_seq_info_init(void)
return 0;
error:
- free_info_entries();
+ snd_seq_info_done();
return -ENOMEM;
}
-
-int __exit snd_seq_info_done(void)
-{
- free_info_entries();
- return 0;
-}
diff --git a/sound/core/seq/seq_info.h b/sound/core/seq/seq_info.h
index f8549f81a645..2cdf8f6e63f5 100644
--- a/sound/core/seq/seq_info.h
+++ b/sound/core/seq/seq_info.h
@@ -30,11 +30,11 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buff
#ifdef CONFIG_SND_PROC_FS
-int snd_seq_info_init( void );
-int snd_seq_info_done( void );
+int snd_seq_info_init(void);
+void snd_seq_info_done(void);
#else
static inline int snd_seq_info_init(void) { return 0; }
-static inline int snd_seq_info_done(void) { return 0; }
+static inline void snd_seq_info_done(void) {}
#endif
#endif
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index a4c8543176b2..5b0388202bac 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -504,18 +504,6 @@ int snd_seq_pool_delete(struct snd_seq_pool **ppool)
return 0;
}
-/* initialize sequencer memory */
-int __init snd_sequencer_memory_init(void)
-{
- return 0;
-}
-
-/* release sequencer memory */
-void __exit snd_sequencer_memory_done(void)
-{
-}
-
-
/* exported to seq_clientmgr.c */
void snd_seq_info_pool(struct snd_info_buffer *buffer,
struct snd_seq_pool *pool, char *space)
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
index 3abe306c394a..1292fe91f02e 100644
--- a/sound/core/seq/seq_memory.h
+++ b/sound/core/seq/seq_memory.h
@@ -94,12 +94,6 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize);
/* remove pool */
int snd_seq_pool_delete(struct snd_seq_pool **pool);
-/* init memory */
-int snd_sequencer_memory_init(void);
-
-/* release event memory */
-void snd_sequencer_memory_done(void);
-
/* polling */
int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, poll_table *wait);
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 5dd0ee258359..9e0dabd3ce5f 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -78,7 +78,7 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
struct seq_midisynth *msynth;
struct snd_seq_event ev;
char buf[16], *pbuf;
- long res, count;
+ long res;
if (substream == NULL)
return;
@@ -94,19 +94,15 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
if (msynth->parser == NULL)
continue;
pbuf = buf;
- while (res > 0) {
- count = snd_midi_event_encode(msynth->parser, pbuf, res, &ev);
- if (count < 0)
- break;
- pbuf += count;
- res -= count;
- if (ev.type != SNDRV_SEQ_EVENT_NONE) {
- ev.source.port = msynth->seq_port;
- ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
- snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0);
- /* clear event and reset header */
- memset(&ev, 0, sizeof(ev));
- }
+ while (res-- > 0) {
+ if (!snd_midi_event_encode_byte(msynth->parser,
+ *pbuf++, &ev))
+ continue;
+ ev.source.port = msynth->seq_port;
+ ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
+ snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0);
+ /* clear event and reset header */
+ memset(&ev, 0, sizeof(ev));
}
}
}
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
index 288f839a554b..c1975dd31871 100644
--- a/sound/core/seq/seq_midi_emul.c
+++ b/sound/core/seq/seq_midi_emul.c
@@ -318,7 +318,7 @@ do_control(struct snd_midi_op *ops, void *drv, struct snd_midi_channel_set *chse
break;
case MIDI_CTL_MSB_DATA_ENTRY:
chan->control[MIDI_CTL_LSB_DATA_ENTRY] = 0;
- /* go through here */
+ /* fall through */
case MIDI_CTL_LSB_DATA_ENTRY:
if (chan->param_type == SNDRV_MIDI_PARAM_TYPE_REGISTERED)
rpn(ops, drv, chan, chset);
@@ -728,15 +728,3 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset)
kfree(chset);
}
EXPORT_SYMBOL(snd_midi_channel_free_set);
-
-static int __init alsa_seq_midi_emul_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_seq_midi_emul_exit(void)
-{
-}
-
-module_init(alsa_seq_midi_emul_init)
-module_exit(alsa_seq_midi_emul_exit)
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
index 90bbbdbeba03..b11419537062 100644
--- a/sound/core/seq/seq_midi_event.c
+++ b/sound/core/seq/seq_midi_event.c
@@ -175,14 +175,6 @@ void snd_midi_event_reset_decode(struct snd_midi_event *dev)
}
EXPORT_SYMBOL(snd_midi_event_reset_decode);
-#if 0
-void snd_midi_event_init(struct snd_midi_event *dev)
-{
- snd_midi_event_reset_encode(dev);
- snd_midi_event_reset_decode(dev);
-}
-#endif /* 0 */
-
void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
{
dev->nostat = on ? 1 : 0;
@@ -190,69 +182,16 @@ void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
EXPORT_SYMBOL(snd_midi_event_no_status);
/*
- * resize buffer
- */
-#if 0
-int snd_midi_event_resize_buffer(struct snd_midi_event *dev, int bufsize)
-{
- unsigned char *new_buf, *old_buf;
- unsigned long flags;
-
- if (bufsize == dev->bufsize)
- return 0;
- new_buf = kmalloc(bufsize, GFP_KERNEL);
- if (new_buf == NULL)
- return -ENOMEM;
- spin_lock_irqsave(&dev->lock, flags);
- old_buf = dev->buf;
- dev->buf = new_buf;
- dev->bufsize = bufsize;
- reset_encode(dev);
- spin_unlock_irqrestore(&dev->lock, flags);
- kfree(old_buf);
- return 0;
-}
-#endif /* 0 */
-
-/*
- * read bytes and encode to sequencer event if finished
- * return the size of encoded bytes
- */
-long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long count,
- struct snd_seq_event *ev)
-{
- long result = 0;
- int rc;
-
- ev->type = SNDRV_SEQ_EVENT_NONE;
-
- while (count-- > 0) {
- rc = snd_midi_event_encode_byte(dev, *buf++, ev);
- result++;
- if (rc < 0)
- return rc;
- else if (rc > 0)
- return result;
- }
-
- return result;
-}
-EXPORT_SYMBOL(snd_midi_event_encode);
-
-/*
* read one byte and encode to sequencer event:
- * return 1 if MIDI bytes are encoded to an event
- * 0 data is not finished
- * negative for error
+ * return true if MIDI bytes are encoded to an event
+ * false data is not finished
*/
-int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,
- struct snd_seq_event *ev)
+bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c,
+ struct snd_seq_event *ev)
{
- int rc = 0;
+ bool rc = false;
unsigned long flags;
- c &= 0xff;
-
if (c >= MIDI_CMD_COMMON_CLOCK) {
/* real-time event */
ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
@@ -293,7 +232,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,
status_event[dev->type].encode(dev, ev);
if (dev->type >= ST_SPECIAL)
dev->type = ST_INVALID;
- rc = 1;
+ rc = true;
} else if (dev->type == ST_SYSEX) {
if (c == MIDI_CMD_COMMON_SYSEX_END ||
dev->read >= dev->bufsize) {
@@ -306,7 +245,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,
dev->read = 0; /* continue to parse */
else
reset_encode(dev); /* all parsed */
- rc = 1;
+ rc = true;
}
}
@@ -531,15 +470,3 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
}
return idx;
}
-
-static int __init alsa_seq_midi_event_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_seq_midi_event_exit(void)
-{
-}
-
-module_init(alsa_seq_midi_event_init)
-module_exit(alsa_seq_midi_event_exit)
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index b377f5048352..3b3ac96f1f5f 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -159,18 +159,8 @@ static void queue_delete(struct snd_seq_queue *q)
/*----------------------------------------------------------------*/
-/* setup queues */
-int __init snd_seq_queues_init(void)
-{
- /*
- memset(queue_list, 0, sizeof(queue_list));
- num_queues = 0;
- */
- return 0;
-}
-
/* delete all existing queues */
-void __exit snd_seq_queues_delete(void)
+void snd_seq_queues_delete(void)
{
int i;
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 719093489a2c..e006fc8e3a36 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -63,9 +63,6 @@ struct snd_seq_queue {
/* get the number of current queues */
int snd_seq_queue_get_cur_queues(void);
-/* init queues structure */
-int snd_seq_queues_init(void);
-
/* delete queues */
void snd_seq_queues_delete(void);
@@ -112,28 +109,4 @@ int snd_seq_queue_is_used(int queueid, int client);
int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop);
-/*
- * 64bit division - for sync stuff..
- */
-#if defined(i386) || defined(i486)
-
-#define udiv_qrnnd(q, r, n1, n0, d) \
- __asm__ ("divl %4" \
- : "=a" ((u32)(q)), \
- "=d" ((u32)(r)) \
- : "0" ((u32)(n0)), \
- "1" ((u32)(n1)), \
- "rm" ((u32)(d)))
-
-#define u64_div(x,y,q) do {u32 __tmp; udiv_qrnnd(q, __tmp, (x)>>32, x, y);} while (0)
-#define u64_mod(x,y,r) do {u32 __tmp; udiv_qrnnd(__tmp, q, (x)>>32, x, y);} while (0)
-#define u64_divmod(x,y,q,r) udiv_qrnnd(q, r, (x)>>32, x, y)
-
-#else
-#define u64_div(x,y,q) ((q) = (u32)((u64)(x) / (u64)(y)))
-#define u64_mod(x,y,r) ((r) = (u32)((u64)(x) % (u64)(y)))
-#define u64_divmod(x,y,q,r) (u64_div(x,y,q), u64_mod(x,y,r))
-#endif
-
-
#endif
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 289ae6bb81d9..a2f1c6b58693 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -89,7 +89,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
else
down_read(&rdev->filelist_sem);
list_for_each_entry(vmidi, &rdev->filelist, list) {
- if (!vmidi->trigger)
+ if (!READ_ONCE(vmidi->trigger))
continue;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
@@ -110,23 +110,6 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
}
/*
- * receive an event from the remote virmidi port
- *
- * for rawmidi inputs, you can call this function from the event
- * handler of a remote port which is attached to the virmidi via
- * SNDRV_VIRMIDI_SEQ_ATTACH.
- */
-#if 0
-int snd_virmidi_receive(struct snd_rawmidi *rmidi, struct snd_seq_event *ev)
-{
- struct snd_virmidi_dev *rdev;
-
- rdev = rmidi->private_data;
- return snd_virmidi_dev_receive_event(rdev, ev, true);
-}
-#endif /* 0 */
-
-/*
* event handler of virmidi port
*/
static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
@@ -147,68 +130,62 @@ static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, i
{
struct snd_virmidi *vmidi = substream->runtime->private_data;
- if (up) {
- vmidi->trigger = 1;
- } else {
- vmidi->trigger = 0;
- }
+ WRITE_ONCE(vmidi->trigger, !!up);
}
-/*
- * trigger rawmidi stream for output
+/* process rawmidi bytes and send events;
+ * we need no lock here for vmidi->event since it's handled only in this work
*/
-static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
+static void snd_vmidi_output_work(struct work_struct *work)
{
- struct snd_virmidi *vmidi = substream->runtime->private_data;
- int count, res;
- unsigned char buf[32], *pbuf;
- unsigned long flags;
-
- if (up) {
- vmidi->trigger = 1;
- if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
- !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
- while (snd_rawmidi_transmit(substream, buf,
- sizeof(buf)) > 0) {
- /* ignored */
- }
- return;
- }
- spin_lock_irqsave(&substream->runtime->lock, flags);
+ struct snd_virmidi *vmidi;
+ struct snd_rawmidi_substream *substream;
+ unsigned char input;
+ int ret;
+
+ vmidi = container_of(work, struct snd_virmidi, output_work);
+ substream = vmidi->substream;
+
+ /* discard the outputs in dispatch mode unless subscribed */
+ if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
+ !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
+ while (!snd_rawmidi_transmit_empty(substream))
+ snd_rawmidi_transmit_ack(substream, 1);
+ return;
+ }
+
+ while (READ_ONCE(vmidi->trigger)) {
+ if (snd_rawmidi_transmit(substream, &input, 1) != 1)
+ break;
+ if (!snd_midi_event_encode_byte(vmidi->parser, input,
+ &vmidi->event))
+ continue;
if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
- if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
- goto out;
+ ret = snd_seq_kernel_client_dispatch(vmidi->client,
+ &vmidi->event,
+ false, 0);
vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
- }
- while (1) {
- count = __snd_rawmidi_transmit_peek(substream, buf, sizeof(buf));
- if (count <= 0)
+ if (ret < 0)
break;
- pbuf = buf;
- while (count > 0) {
- res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event);
- if (res < 0) {
- snd_midi_event_reset_encode(vmidi->parser);
- continue;
- }
- __snd_rawmidi_transmit_ack(substream, res);
- pbuf += res;
- count -= res;
- if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
- if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
- goto out;
- vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
- }
- }
}
- out:
- spin_unlock_irqrestore(&substream->runtime->lock, flags);
- } else {
- vmidi->trigger = 0;
+ /* rawmidi input might be huge, allow to have a break */
+ cond_resched();
}
}
/*
+ * trigger rawmidi stream for output
+ */
+static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct snd_virmidi *vmidi = substream->runtime->private_data;
+
+ WRITE_ONCE(vmidi->trigger, !!up);
+ if (up)
+ queue_work(system_highpri_wq, &vmidi->output_work);
+}
+
+/*
* open rawmidi handle for input
*/
static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
@@ -260,6 +237,7 @@ static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream)
vmidi->port = rdev->port;
snd_virmidi_init_event(vmidi, &vmidi->event);
vmidi->rdev = rdev;
+ INIT_WORK(&vmidi->output_work, snd_vmidi_output_work);
runtime->private_data = vmidi;
return 0;
}
@@ -289,6 +267,9 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream)
{
struct snd_virmidi *vmidi = substream->runtime->private_data;
+
+ WRITE_ONCE(vmidi->trigger, false); /* to be sure */
+ cancel_work_sync(&vmidi->output_work);
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@@ -546,19 +527,3 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
return 0;
}
EXPORT_SYMBOL(snd_virmidi_new);
-
-/*
- * ENTRY functions
- */
-
-static int __init alsa_virmidi_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_virmidi_exit(void)
-{
-}
-
-module_init(alsa_virmidi_init)
-module_exit(alsa_virmidi_exit)
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 665089c45560..61a0cec6e1f6 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -883,6 +883,11 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
if (snd_BUG_ON(!tid))
return -EINVAL;
+ if (tid->dev_class == SNDRV_TIMER_CLASS_CARD ||
+ tid->dev_class == SNDRV_TIMER_CLASS_PCM) {
+ if (WARN_ON(!card))
+ return -EINVAL;
+ }
if (rtimer)
*rtimer = NULL;
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
@@ -1520,7 +1525,7 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
} else {
if (id.subdevice < 0)
id.subdevice = 0;
- else
+ else if (id.subdevice < INT_MAX)
id.subdevice++;
}
}
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 78a2fdc38531..1e34e6381baa 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -778,7 +778,6 @@ static const struct snd_pcm_ops loopback_pcm_ops = {
.trigger = loopback_trigger,
.pointer = loopback_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static int loopback_pcm_new(struct loopback *loopback,
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 3e745f47dd2f..dae26e856b26 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -617,19 +617,3 @@ free_device:
}
EXPORT_SYMBOL(snd_mpu401_uart_new);
-
-/*
- * INIT part
- */
-
-static int __init alsa_mpu401_uart_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_mpu401_uart_exit(void)
-{
-}
-
-module_init(alsa_mpu401_uart_init)
-module_exit(alsa_mpu401_uart_exit)
diff --git a/sound/drivers/opl3/opl3_drums.c b/sound/drivers/opl3/opl3_drums.c
index 73694380734a..14929822956c 100644
--- a/sound/drivers/opl3/opl3_drums.c
+++ b/sound/drivers/opl3/opl3_drums.c
@@ -21,8 +21,6 @@
#include "opl3_voice.h"
-extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
-
static char snd_opl3_drum_table[47] =
{
OPL3_BASSDRUM_ON, OPL3_BASSDRUM_ON, OPL3_HIHAT_ON, /* 35 - 37 */
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 588963d6be28..cf86c36c7c3b 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -31,13 +31,12 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <sound/minors.h>
+#include "opl3_voice.h"
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Hannu Savolainen 1993-1996, Rob Hooft");
MODULE_DESCRIPTION("Routines for control of AdLib FM cards (OPL2/OPL3/OPL4 chips)");
MODULE_LICENSE("GPL");
-extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
-
static void snd_opl2_command(struct snd_opl3 * opl3, unsigned short cmd, unsigned char val)
{
unsigned long flags;
@@ -539,19 +538,3 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
}
EXPORT_SYMBOL(snd_opl3_hwdep_new);
-
-/*
- * INIT part
- */
-
-static int __init alsa_opl3_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_opl3_exit(void)
-{
-}
-
-module_init(alsa_opl3_init)
-module_exit(alsa_opl3_exit)
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index bb3f3a5a6951..a33cb744e96c 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -25,10 +25,6 @@
#include "opl3_voice.h"
#include <sound/asoundef.h>
-extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
-
-extern bool use_internal_drums;
-
static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
struct snd_midi_channel *chan);
/*
@@ -372,6 +368,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
instr_4op = 1;
break;
}
+ /* fall through */
default:
spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
@@ -721,9 +718,6 @@ void snd_opl3_note_off(void *p, int note, int vel,
*/
void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *chan)
{
- struct snd_opl3 *opl3;
-
- opl3 = p;
#ifdef DEBUG_MIDI
snd_printk(KERN_DEBUG "Key pressure, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
@@ -735,9 +729,6 @@ void snd_opl3_key_press(void *p, int note, int vel, struct snd_midi_channel *cha
*/
void snd_opl3_terminate_note(void *p, int note, struct snd_midi_channel *chan)
{
- struct snd_opl3 *opl3;
-
- opl3 = p;
#ifdef DEBUG_MIDI
snd_printk(KERN_DEBUG "Terminate note, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
@@ -861,9 +852,6 @@ void snd_opl3_control(void *p, int type, struct snd_midi_channel *chan)
void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
struct snd_midi_channel_set *chset)
{
- struct snd_opl3 *opl3;
-
- opl3 = p;
#ifdef DEBUG_MIDI
snd_printk(KERN_DEBUG "NRPN, ch#: %i, inst#: %i\n",
chan->number, chan->midi_program);
@@ -876,9 +864,6 @@ void snd_opl3_nrpn(void *p, struct snd_midi_channel *chan,
void snd_opl3_sysex(void *p, unsigned char *buf, int len,
int parsed, struct snd_midi_channel_set *chset)
{
- struct snd_opl3 *opl3;
-
- opl3 = p;
#ifdef DEBUG_MIDI
snd_printk(KERN_DEBUG "SYSEX\n");
#endif
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 22c3e4bca220..869220ced4ed 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -29,8 +29,6 @@ static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg);
/* operators */
-extern struct snd_midi_op opl3_ops;
-
static struct snd_seq_oss_callback oss_callback = {
.owner = THIS_MODULE,
.open = snd_opl3_open_seq_oss,
@@ -233,11 +231,8 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
unsigned long ioarg)
{
- struct snd_opl3 *opl3;
-
if (snd_BUG_ON(!arg))
return -ENXIO;
- opl3 = arg->private_data;
switch (cmd) {
case SNDCTL_FM_LOAD_INSTR:
snd_printk(KERN_ERR "OPL3: "
@@ -261,11 +256,8 @@ static int snd_opl3_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
/* reset device */
static int snd_opl3_reset_seq_oss(struct snd_seq_oss_arg *arg)
{
- struct snd_opl3 *opl3;
-
if (snd_BUG_ON(!arg))
return -ENXIO;
- opl3 = arg->private_data;
return 0;
}
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 42920a243328..d522925fc5c0 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -24,6 +24,7 @@
#include <linux/nospec.h>
#include <sound/opl3.h>
#include <sound/asound_fm.h>
+#include "opl3_voice.h"
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
#define OPL3_SUPPORT_SYNTH
diff --git a/sound/drivers/opl3/opl3_voice.h b/sound/drivers/opl3/opl3_voice.h
index a2445163008e..5b02bd49fde4 100644
--- a/sound/drivers/opl3/opl3_voice.h
+++ b/sound/drivers/opl3/opl3_voice.h
@@ -52,4 +52,8 @@ void snd_opl3_free_seq_oss(struct snd_opl3 *opl3);
#define snd_opl3_free_seq_oss(opl3) /* NOP */
#endif
+extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
+extern bool use_internal_drums;
+extern struct snd_midi_op opl3_ops;
+
#endif
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c
index db76a5bf2bd2..819d2dce2a19 100644
--- a/sound/drivers/opl4/opl4_lib.c
+++ b/sound/drivers/opl4/opl4_lib.c
@@ -263,15 +263,3 @@ int snd_opl4_create(struct snd_card *card,
}
EXPORT_SYMBOL(snd_opl4_create);
-
-static int __init alsa_opl4_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_opl4_exit(void)
-{
-}
-
-module_init(alsa_opl4_init)
-module_exit(alsa_opl4_exit)
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 121357397a6d..04368dd59a4c 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -815,18 +815,3 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw,
}
EXPORT_SYMBOL(snd_vx_create);
-
-/*
- * module entries
- */
-static int __init alsa_vx_core_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_vx_core_exit(void)
-{
-}
-
-module_init(alsa_vx_core_init)
-module_exit(alsa_vx_core_exit)
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 380a028469c4..ba80f459bdc5 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -883,7 +883,6 @@ static const struct snd_pcm_ops vx_pcm_playback_ops = {
.trigger = vx_pcm_trigger,
.pointer = vx_pcm_playback_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
@@ -1105,7 +1104,6 @@ static const struct snd_pcm_ops vx_pcm_capture_ops = {
.trigger = vx_pcm_trigger,
.pointer = vx_pcm_capture_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index e6adab3ef42e..ea9b86450580 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -373,7 +373,6 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/firewire/dice/dice-alesis.c b/sound/firewire/dice/dice-alesis.c
index b2efb1c71a98..218292bdace6 100644
--- a/sound/firewire/dice/dice-alesis.c
+++ b/sound/firewire/dice/dice-alesis.c
@@ -37,7 +37,7 @@ int snd_dice_detect_alesis_formats(struct snd_dice *dice)
MAX_STREAMS * SND_DICE_RATE_MODE_COUNT *
sizeof(unsigned int));
} else {
- memcpy(dice->rx_pcm_chs, alesis_io26_tx_pcm_chs,
+ memcpy(dice->tx_pcm_chs, alesis_io26_tx_pcm_chs,
MAX_STREAMS * SND_DICE_RATE_MODE_COUNT *
sizeof(unsigned int));
}
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 80351b29fe0d..bb3ef5ff3488 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -412,7 +412,6 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.pointer = capture_pointer,
.ack = capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@@ -425,7 +424,6 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.pointer = playback_pointer,
.ack = playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
unsigned int capture, playback;
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c
index 796f4b4645f5..fdcff0460c53 100644
--- a/sound/firewire/digi00x/digi00x-pcm.c
+++ b/sound/firewire/digi00x/digi00x-pcm.c
@@ -352,7 +352,6 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c
index e3c16308363d..bf47f9ec8703 100644
--- a/sound/firewire/fireface/ff-pcm.c
+++ b/sound/firewire/fireface/ff-pcm.c
@@ -383,7 +383,6 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c
index 40faed5e6968..aed566d82726 100644
--- a/sound/firewire/fireworks/fireworks_pcm.c
+++ b/sound/firewire/fireworks/fireworks_pcm.c
@@ -397,7 +397,6 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index 3919e186a30b..30957477e005 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -454,7 +454,6 @@ static int isight_create_pcm(struct isight *isight)
.trigger = isight_trigger,
.pointer = isight_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c
index 4330220890e8..ab69d7e6ac05 100644
--- a/sound/firewire/motu/motu-pcm.c
+++ b/sound/firewire/motu/motu-pcm.c
@@ -363,7 +363,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
.pointer = capture_pointer,
.ack = capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@@ -376,7 +375,6 @@ int snd_motu_create_pcm_devices(struct snd_motu *motu)
.pointer = playback_pointer,
.ack = playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/firewire/motu/motu-protocol-v2.c b/sound/firewire/motu/motu-protocol-v2.c
index 525b746330be..453fc29fade7 100644
--- a/sound/firewire/motu/motu-protocol-v2.c
+++ b/sound/firewire/motu/motu-protocol-v2.c
@@ -13,6 +13,8 @@
#define V2_CLOCK_RATE_SHIFT 3
#define V2_CLOCK_SRC_MASK 0x00000007
#define V2_CLOCK_SRC_SHIFT 0
+#define V2_CLOCK_TRAVELER_FETCH_DISABLE 0x04000000
+#define V2_CLOCK_TRAVELER_FETCH_ENABLE 0x03000000
#define V2_IN_OUT_CONF_OFFSET 0x0c04
#define V2_OPT_OUT_IFACE_MASK 0x00000c00
@@ -66,6 +68,11 @@ static int v2_set_clock_rate(struct snd_motu *motu, unsigned int rate)
data &= ~V2_CLOCK_RATE_MASK;
data |= i << V2_CLOCK_RATE_SHIFT;
+ if (motu->spec == &snd_motu_spec_traveler) {
+ data &= ~V2_CLOCK_TRAVELER_FETCH_ENABLE;
+ data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
+ }
+
reg = cpu_to_be32(data);
return snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET, &reg,
sizeof(reg));
@@ -121,8 +128,31 @@ static int v2_get_clock_source(struct snd_motu *motu,
static int v2_switch_fetching_mode(struct snd_motu *motu, bool enable)
{
- /* V2 protocol doesn't have this feature. */
- return 0;
+ __be32 reg;
+ u32 data;
+ int err = 0;
+
+ if (motu->spec == &snd_motu_spec_traveler) {
+ err = snd_motu_transaction_read(motu, V2_CLOCK_STATUS_OFFSET,
+ &reg, sizeof(reg));
+ if (err < 0)
+ return err;
+ data = be32_to_cpu(reg);
+
+ data &= ~(V2_CLOCK_TRAVELER_FETCH_DISABLE |
+ V2_CLOCK_TRAVELER_FETCH_ENABLE);
+
+ if (enable)
+ data |= V2_CLOCK_TRAVELER_FETCH_ENABLE;
+ else
+ data |= V2_CLOCK_TRAVELER_FETCH_DISABLE;
+
+ reg = cpu_to_be32(data);
+ err = snd_motu_transaction_write(motu, V2_CLOCK_STATUS_OFFSET,
+ &reg, sizeof(reg));
+ }
+
+ return err;
}
static void calculate_fixed_part(struct snd_motu_packet_format *formats,
@@ -149,11 +179,20 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats,
pcm_chunks[1] += 2;
}
} else {
- /*
- * Packets to v2 units transfer main-out-1/2 and phone-out-1/2.
- */
- pcm_chunks[0] += 4;
- pcm_chunks[1] += 4;
+ if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+
+ // Packets to v2 units include 2 chunks for phone 1/2, except
+ // for 176.4/192.0 kHz.
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+
+ if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
}
/*
@@ -164,19 +203,16 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats,
pcm_chunks[0] += 2;
pcm_chunks[1] += 2;
- /* This part should be multiples of 4. */
- formats->fixed_part_pcm_chunks[0] = round_up(2 + pcm_chunks[0], 4) - 2;
- formats->fixed_part_pcm_chunks[1] = round_up(2 + pcm_chunks[1], 4) - 2;
- if (flags & SND_MOTU_SPEC_SUPPORT_CLOCK_X4)
- formats->fixed_part_pcm_chunks[2] =
- round_up(2 + pcm_chunks[2], 4) - 2;
+ formats->fixed_part_pcm_chunks[0] = pcm_chunks[0];
+ formats->fixed_part_pcm_chunks[1] = pcm_chunks[1];
+ formats->fixed_part_pcm_chunks[2] = pcm_chunks[2];
}
static void calculate_differed_part(struct snd_motu_packet_format *formats,
enum snd_motu_spec_flags flags,
u32 data, u32 mask, u32 shift)
{
- unsigned char pcm_chunks[3] = {0, 0};
+ unsigned char pcm_chunks[2] = {0, 0};
/*
* When optical interfaces are configured for S/PDIF (TOSLINK),
diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c
index c7cd9864dc4d..7cc80a05e91f 100644
--- a/sound/firewire/motu/motu-protocol-v3.c
+++ b/sound/firewire/motu/motu-protocol-v3.c
@@ -188,11 +188,20 @@ static void calculate_fixed_part(struct snd_motu_packet_format *formats,
pcm_chunks[1] += 2;
}
} else {
- /*
- * Packets to v2 units transfer main-out-1/2 and phone-out-1/2.
- */
- pcm_chunks[0] += 4;
- pcm_chunks[1] += 4;
+ if (flags & SND_MOTU_SPEC_RX_SEPARETED_MAIN) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+
+ // Packets to v3 units include 2 chunks for phone 1/2, except
+ // for 176.4/192.0 kHz.
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
+ }
+
+ if (flags & SND_MOTU_SPEC_HAS_AESEBU_IFACE) {
+ pcm_chunks[0] += 2;
+ pcm_chunks[1] += 2;
}
/*
diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c
index 0d6b526105ab..300d31b6f191 100644
--- a/sound/firewire/motu/motu.c
+++ b/sound/firewire/motu/motu.c
@@ -200,6 +200,22 @@ static const struct snd_motu_spec motu_828mk2 = {
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
+ SND_MOTU_SPEC_RX_SEPARETED_MAIN |
+ SND_MOTU_SPEC_HAS_OPT_IFACE_A |
+ SND_MOTU_SPEC_RX_MIDI_2ND_Q |
+ SND_MOTU_SPEC_TX_MIDI_2ND_Q,
+
+ .analog_in_ports = 8,
+ .analog_out_ports = 8,
+};
+
+const struct snd_motu_spec snd_motu_spec_traveler = {
+ .name = "Traveler",
+ .protocol = &snd_motu_protocol_v2,
+ .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
+ SND_MOTU_SPEC_SUPPORT_CLOCK_X4 |
+ SND_MOTU_SPEC_TX_RETURN_CHUNK |
+ SND_MOTU_SPEC_HAS_AESEBU_IFACE |
SND_MOTU_SPEC_HAS_OPT_IFACE_A |
SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_2ND_Q,
@@ -216,6 +232,7 @@ static const struct snd_motu_spec motu_828mk3 = {
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
SND_MOTU_SPEC_TX_REVERB_CHUNK |
+ SND_MOTU_SPEC_RX_SEPARETED_MAIN |
SND_MOTU_SPEC_HAS_OPT_IFACE_A |
SND_MOTU_SPEC_HAS_OPT_IFACE_B |
SND_MOTU_SPEC_RX_MIDI_3RD_Q |
@@ -231,6 +248,7 @@ static const struct snd_motu_spec motu_audio_express = {
.flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 |
SND_MOTU_SPEC_TX_MICINST_CHUNK |
SND_MOTU_SPEC_TX_RETURN_CHUNK |
+ SND_MOTU_SPEC_RX_SEPARETED_MAIN |
SND_MOTU_SPEC_RX_MIDI_2ND_Q |
SND_MOTU_SPEC_TX_MIDI_3RD_Q,
.analog_in_ports = 2,
@@ -250,6 +268,7 @@ static const struct snd_motu_spec motu_audio_express = {
static const struct ieee1394_device_id motu_id_table[] = {
SND_MOTU_DEV_ENTRY(0x101800, &motu_828mk2),
+ SND_MOTU_DEV_ENTRY(0x107800, &snd_motu_spec_traveler),
SND_MOTU_DEV_ENTRY(0x106800, &motu_828mk3), /* FireWire only. */
SND_MOTU_DEV_ENTRY(0x100800, &motu_828mk3), /* Hybrid. */
SND_MOTU_DEV_ENTRY(0x104800, &motu_audio_express),
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h
index 4b23cf337c4b..fd5327d30ab1 100644
--- a/sound/firewire/motu/motu.h
+++ b/sound/firewire/motu/motu.h
@@ -79,13 +79,14 @@ enum snd_motu_spec_flags {
SND_MOTU_SPEC_TX_MICINST_CHUNK = 0x0004,
SND_MOTU_SPEC_TX_RETURN_CHUNK = 0x0008,
SND_MOTU_SPEC_TX_REVERB_CHUNK = 0x0010,
- SND_MOTU_SPEC_TX_AESEBU_CHUNK = 0x0020,
+ SND_MOTU_SPEC_HAS_AESEBU_IFACE = 0x0020,
SND_MOTU_SPEC_HAS_OPT_IFACE_A = 0x0040,
SND_MOTU_SPEC_HAS_OPT_IFACE_B = 0x0080,
SND_MOTU_SPEC_RX_MIDI_2ND_Q = 0x0100,
SND_MOTU_SPEC_RX_MIDI_3RD_Q = 0x0200,
SND_MOTU_SPEC_TX_MIDI_2ND_Q = 0x0400,
SND_MOTU_SPEC_TX_MIDI_3RD_Q = 0x0800,
+ SND_MOTU_SPEC_RX_SEPARETED_MAIN = 0x1000,
};
#define SND_MOTU_CLOCK_RATE_COUNT 6
@@ -128,6 +129,8 @@ struct snd_motu_spec {
extern const struct snd_motu_protocol snd_motu_protocol_v2;
extern const struct snd_motu_protocol snd_motu_protocol_v3;
+extern const struct snd_motu_spec snd_motu_spec_traveler;
+
int amdtp_motu_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir,
const struct snd_motu_protocol *const protocol);
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index 3dd46285c0e2..b3f6503dd34d 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -389,7 +389,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
.pointer = pcm_capture_pointer,
.ack = pcm_capture_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops playback_ops = {
.open = pcm_open,
@@ -402,7 +401,6 @@ int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
unsigned int cap = 0;
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c
index 6ec8ec634d4d..e4cc8990e195 100644
--- a/sound/firewire/tascam/tascam-pcm.c
+++ b/sound/firewire/tascam/tascam-pcm.c
@@ -279,7 +279,6 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
.pointer = pcm_playback_pointer,
.ack = pcm_playback_ack,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
struct snd_pcm *pcm;
int err;
diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig
index 3129546398d0..2d90e11b3eaa 100644
--- a/sound/hda/Kconfig
+++ b/sound/hda/Kconfig
@@ -5,11 +5,12 @@ config SND_HDA_CORE
config SND_HDA_DSP_LOADER
bool
+config SND_HDA_COMPONENT
+ bool
+
config SND_HDA_I915
bool
- default y
- depends on DRM_I915
- depends on SND_HDA_CORE
+ select SND_HDA_COMPONENT
config SND_HDA_EXT_CORE
tristate
diff --git a/sound/hda/Makefile b/sound/hda/Makefile
index e4e726f2ce98..2160202e2dc1 100644
--- a/sound/hda/Makefile
+++ b/sound/hda/Makefile
@@ -6,6 +6,7 @@ snd-hda-core-objs += trace.o
CFLAGS_trace.o := -I$(src)
# for sync with i915 gfx driver
+snd-hda-core-$(CONFIG_SND_HDA_COMPONENT) += hdac_component.o
snd-hda-core-$(CONFIG_SND_HDA_I915) += hdac_i915.o
obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c
index 0daf31383084..9c37d9af3023 100644
--- a/sound/hda/ext/hdac_ext_bus.c
+++ b/sound/hda/ext/hdac_ext_bus.c
@@ -87,9 +87,10 @@ static const struct hdac_io_ops hdac_ext_default_io = {
*
* Returns 0 if successful, or a negative error code.
*/
-int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
+int snd_hdac_ext_bus_init(struct hdac_bus *bus, struct device *dev,
const struct hdac_bus_ops *ops,
- const struct hdac_io_ops *io_ops)
+ const struct hdac_io_ops *io_ops,
+ const struct hdac_ext_bus_ops *ext_ops)
{
int ret;
static int idx;
@@ -98,15 +99,16 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev,
if (io_ops == NULL)
io_ops = &hdac_ext_default_io;
- ret = snd_hdac_bus_init(&ebus->bus, dev, ops, io_ops);
+ ret = snd_hdac_bus_init(bus, dev, ops, io_ops);
if (ret < 0)
return ret;
- INIT_LIST_HEAD(&ebus->hlink_list);
- ebus->idx = idx++;
+ bus->ext_ops = ext_ops;
+ INIT_LIST_HEAD(&bus->hlink_list);
+ bus->idx = idx++;
- mutex_init(&ebus->lock);
- ebus->cmd_dma_state = true;
+ mutex_init(&bus->lock);
+ bus->cmd_dma_state = true;
return 0;
}
@@ -116,10 +118,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init);
* snd_hdac_ext_bus_exit - clean up a HD-audio extended bus
* @ebus: the pointer to extended bus object
*/
-void snd_hdac_ext_bus_exit(struct hdac_ext_bus *ebus)
+void snd_hdac_ext_bus_exit(struct hdac_bus *bus)
{
- snd_hdac_bus_exit(&ebus->bus);
- WARN_ON(!list_empty(&ebus->hlink_list));
+ snd_hdac_bus_exit(bus);
+ WARN_ON(!list_empty(&bus->hlink_list));
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_exit);
@@ -135,21 +137,15 @@ static void default_release(struct device *dev)
*
* Returns zero for success or a negative error code.
*/
-int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr)
+int snd_hdac_ext_bus_device_init(struct hdac_bus *bus, int addr,
+ struct hdac_device *hdev)
{
- struct hdac_ext_device *edev;
- struct hdac_device *hdev = NULL;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
char name[15];
int ret;
- edev = kzalloc(sizeof(*edev), GFP_KERNEL);
- if (!edev)
- return -ENOMEM;
- hdev = &edev->hdev;
- edev->ebus = ebus;
+ hdev->bus = bus;
- snprintf(name, sizeof(name), "ehdaudio%dD%d", ebus->idx, addr);
+ snprintf(name, sizeof(name), "ehdaudio%dD%d", bus->idx, addr);
ret = snd_hdac_device_init(hdev, bus, name, addr);
if (ret < 0) {
@@ -176,10 +172,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_init);
*/
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev)
{
- struct hdac_ext_device *edev = to_ehdac_device(hdev);
-
snd_hdac_device_exit(hdev);
- kfree(edev);
+ kfree(hdev);
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
@@ -188,14 +182,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_exit);
*
* @ebus: HD-audio extended bus
*/
-void snd_hdac_ext_bus_device_remove(struct hdac_ext_bus *ebus)
+void snd_hdac_ext_bus_device_remove(struct hdac_bus *bus)
{
struct hdac_device *codec, *__codec;
/*
* we need to remove all the codec devices objects created in the
* snd_hdac_ext_bus_device_init
*/
- list_for_each_entry_safe(codec, __codec, &ebus->bus.codec_list, list) {
+ list_for_each_entry_safe(codec, __codec, &bus->codec_list, list) {
snd_hdac_device_unregister(codec);
put_device(&codec->dev);
}
@@ -204,35 +198,31 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_device_remove);
#define dev_to_hdac(dev) (container_of((dev), \
struct hdac_device, dev))
-static inline struct hdac_ext_driver *get_edrv(struct device *dev)
+static inline struct hdac_driver *get_hdrv(struct device *dev)
{
struct hdac_driver *hdrv = drv_to_hdac_driver(dev->driver);
- struct hdac_ext_driver *edrv = to_ehdac_driver(hdrv);
-
- return edrv;
+ return hdrv;
}
-static inline struct hdac_ext_device *get_edev(struct device *dev)
+static inline struct hdac_device *get_hdev(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
- struct hdac_ext_device *edev = to_ehdac_device(hdev);
-
- return edev;
+ return hdev;
}
static int hda_ext_drv_probe(struct device *dev)
{
- return (get_edrv(dev))->probe(get_edev(dev));
+ return (get_hdrv(dev))->probe(get_hdev(dev));
}
static int hdac_ext_drv_remove(struct device *dev)
{
- return (get_edrv(dev))->remove(get_edev(dev));
+ return (get_hdrv(dev))->remove(get_hdev(dev));
}
static void hdac_ext_drv_shutdown(struct device *dev)
{
- return (get_edrv(dev))->shutdown(get_edev(dev));
+ return (get_hdrv(dev))->shutdown(get_hdev(dev));
}
/**
@@ -240,20 +230,20 @@ static void hdac_ext_drv_shutdown(struct device *dev)
*
* @drv: ext hda driver structure
*/
-int snd_hda_ext_driver_register(struct hdac_ext_driver *drv)
+int snd_hda_ext_driver_register(struct hdac_driver *drv)
{
- drv->hdac.type = HDA_DEV_ASOC;
- drv->hdac.driver.bus = &snd_hda_bus_type;
+ drv->type = HDA_DEV_ASOC;
+ drv->driver.bus = &snd_hda_bus_type;
/* we use default match */
if (drv->probe)
- drv->hdac.driver.probe = hda_ext_drv_probe;
+ drv->driver.probe = hda_ext_drv_probe;
if (drv->remove)
- drv->hdac.driver.remove = hdac_ext_drv_remove;
+ drv->driver.remove = hdac_ext_drv_remove;
if (drv->shutdown)
- drv->hdac.driver.shutdown = hdac_ext_drv_shutdown;
+ drv->driver.shutdown = hdac_ext_drv_shutdown;
- return driver_register(&drv->hdac.driver);
+ return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
@@ -262,8 +252,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ext_driver_register);
*
* @drv: ext hda driver structure
*/
-void snd_hda_ext_driver_unregister(struct hdac_ext_driver *drv)
+void snd_hda_ext_driver_unregister(struct hdac_driver *drv)
{
- driver_unregister(&drv->hdac.driver);
+ driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(snd_hda_ext_driver_unregister);
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c
index 84f3b8168716..5bc4a1d587d4 100644
--- a/sound/hda/ext/hdac_ext_controller.c
+++ b/sound/hda/ext/hdac_ext_controller.c
@@ -39,9 +39,8 @@
* @ebus: HD-audio extended core bus
* @enable: flag to turn on/off the capability
*/
-void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *ebus, bool enable)
+void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
{
- struct hdac_bus *bus = &ebus->bus;
if (!bus->ppcap) {
dev_err(bus->dev, "Address of PP capability is NULL");
@@ -60,9 +59,8 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
* @ebus: HD-audio extended core bus
* @enable: flag to enable/disable interrupt
*/
-void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *ebus, bool enable)
+void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
{
- struct hdac_bus *bus = &ebus->bus;
if (!bus->ppcap) {
dev_err(bus->dev, "Address of PP capability is NULL\n");
@@ -89,12 +87,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
* in hlink_list of extended hdac bus
* Note: this will be freed on bus exit by driver
*/
-int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
+int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_bus *bus)
{
int idx;
u32 link_count;
struct hdac_ext_link *hlink;
- struct hdac_bus *bus = &ebus->bus;
link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
@@ -114,7 +111,7 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus)
/* since link in On, update the ref */
hlink->ref_count = 1;
- list_add_tail(&hlink->list, &ebus->hlink_list);
+ list_add_tail(&hlink->list, &bus->hlink_list);
}
return 0;
@@ -127,12 +124,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_get_ml_capabilities);
* @ebus: HD-audio ext core bus
*/
-void snd_hdac_link_free_all(struct hdac_ext_bus *ebus)
+void snd_hdac_link_free_all(struct hdac_bus *bus)
{
struct hdac_ext_link *l;
- while (!list_empty(&ebus->hlink_list)) {
- l = list_first_entry(&ebus->hlink_list, struct hdac_ext_link, list);
+ while (!list_empty(&bus->hlink_list)) {
+ l = list_first_entry(&bus->hlink_list, struct hdac_ext_link, list);
list_del(&l->list);
kfree(l);
}
@@ -144,7 +141,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_link_free_all);
* @ebus: HD-audio extended core bus
* @codec_name: codec name
*/
-struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
+struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_bus *bus,
const char *codec_name)
{
int i;
@@ -153,10 +150,10 @@ struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *ebus,
if (sscanf(codec_name, "ehdaudio%dD%d", &bus_idx, &addr) != 2)
return NULL;
- if (ebus->idx != bus_idx)
+ if (bus->idx != bus_idx)
return NULL;
- list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
for (i = 0; i < HDA_MAX_CODECS; i++) {
if (hlink->lsdiid & (0x1 << addr))
return hlink;
@@ -219,12 +216,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down);
* snd_hdac_ext_bus_link_power_up_all -power up all hda link
* @ebus: HD-audio extended bus
*/
-int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus)
+int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink = NULL;
int ret;
- list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
snd_hdac_updatel(hlink->ml_addr,
AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
ret = check_hdac_link_power_active(hlink, true);
@@ -240,12 +237,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all);
* snd_hdac_ext_bus_link_power_down_all -power down all hda link
* @ebus: HD-audio extended bus
*/
-int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
+int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink = NULL;
int ret;
- list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
ret = check_hdac_link_power_active(hlink, false);
if (ret < 0)
@@ -256,39 +253,48 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus)
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all);
-int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_bus_link_get(struct hdac_bus *bus,
struct hdac_ext_link *link)
{
int ret = 0;
- mutex_lock(&ebus->lock);
+ mutex_lock(&bus->lock);
/*
* if we move from 0 to 1, count will be 1 so power up this link
* as well, also check the dma status and trigger that
*/
if (++link->ref_count == 1) {
- if (!ebus->cmd_dma_state) {
- snd_hdac_bus_init_cmd_io(&ebus->bus);
- ebus->cmd_dma_state = true;
+ if (!bus->cmd_dma_state) {
+ snd_hdac_bus_init_cmd_io(bus);
+ bus->cmd_dma_state = true;
}
ret = snd_hdac_ext_bus_link_power_up(link);
+
+ /*
+ * wait for 521usec for codec to report status
+ * HDA spec section 4.3 - Codec Discovery
+ */
+ udelay(521);
+ bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+ dev_dbg(bus->dev, "codec_mask = 0x%lx\n", bus->codec_mask);
+ snd_hdac_chip_writew(bus, STATESTS, bus->codec_mask);
}
- mutex_unlock(&ebus->lock);
+ mutex_unlock(&bus->lock);
return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get);
-int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_bus_link_put(struct hdac_bus *bus,
struct hdac_ext_link *link)
{
int ret = 0;
struct hdac_ext_link *hlink;
bool link_up = false;
- mutex_lock(&ebus->lock);
+ mutex_lock(&bus->lock);
/*
* if we move from 1 to 0, count will be 0
@@ -301,7 +307,7 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
* now check if all links are off, if so turn off
* cmd dma as well
*/
- list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
if (hlink->ref_count) {
link_up = true;
break;
@@ -309,12 +315,12 @@ int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus,
}
if (!link_up) {
- snd_hdac_bus_stop_cmd_io(&ebus->bus);
- ebus->cmd_dma_state = false;
+ snd_hdac_bus_stop_cmd_io(bus);
+ bus->cmd_dma_state = false;
}
}
- mutex_unlock(&ebus->lock);
+ mutex_unlock(&bus->lock);
return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c
index c96d7a7a36af..1bd27576db98 100644
--- a/sound/hda/ext/hdac_ext_stream.c
+++ b/sound/hda/ext/hdac_ext_stream.c
@@ -25,7 +25,7 @@
/**
* snd_hdac_ext_stream_init - initialize each stream (aka device)
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @stream: HD-audio ext core stream object to initialize
* @idx: stream index number
* @direction: stream direction (SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE)
@@ -34,18 +34,16 @@
* initialize the stream, if ppcap is enabled then init those and then
* invoke hdac stream initialization routine
*/
-void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_init(struct hdac_bus *bus,
struct hdac_ext_stream *stream,
int idx, int direction, int tag)
{
- struct hdac_bus *bus = &ebus->bus;
-
if (bus->ppcap) {
stream->pphc_addr = bus->ppcap + AZX_PPHC_BASE +
AZX_PPHC_INTERVAL * idx;
stream->pplc_addr = bus->ppcap + AZX_PPLC_BASE +
- AZX_PPLC_MULTI * ebus->num_streams +
+ AZX_PPLC_MULTI * bus->num_streams +
AZX_PPLC_INTERVAL * idx;
}
@@ -71,12 +69,12 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init);
/**
* snd_hdac_ext_stream_init_all - create and initialize the stream objects
* for an extended hda bus
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @start_idx: start index for streams
* @num_stream: number of streams to initialize
* @dir: direction of streams
*/
-int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
+int snd_hdac_ext_stream_init_all(struct hdac_bus *bus, int start_idx,
int num_stream, int dir)
{
int stream_tag = 0;
@@ -88,7 +86,7 @@ int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
if (!stream)
return -ENOMEM;
tag = ++stream_tag;
- snd_hdac_ext_stream_init(ebus, stream, idx, dir, tag);
+ snd_hdac_ext_stream_init(bus, stream, idx, dir, tag);
idx++;
}
@@ -100,17 +98,16 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all);
/**
* snd_hdac_stream_free_all - free hdac extended stream objects
*
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
*/
-void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus)
+void snd_hdac_stream_free_all(struct hdac_bus *bus)
{
struct hdac_stream *s, *_s;
struct hdac_ext_stream *stream;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
list_for_each_entry_safe(s, _s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s);
- snd_hdac_ext_stream_decouple(ebus, stream, false);
+ snd_hdac_ext_stream_decouple(bus, stream, false);
list_del(&s->list);
kfree(stream);
}
@@ -119,15 +116,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_free_all);
/**
* snd_hdac_ext_stream_decouple - decouple the hdac stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @stream: HD-audio ext core stream object to initialize
* @decouple: flag to decouple
*/
-void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_decouple(struct hdac_bus *bus,
struct hdac_ext_stream *stream, bool decouple)
{
struct hdac_stream *hstream = &stream->hstream;
- struct hdac_bus *bus = &ebus->bus;
u32 val;
int mask = AZX_PPCTL_PROCEN(hstream->index);
@@ -251,19 +247,18 @@ void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
EXPORT_SYMBOL_GPL(snd_hdac_ext_link_clear_stream_id);
static struct hdac_ext_stream *
-hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
+hdac_ext_link_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *stream = NULL;
- struct hdac_bus *hbus = &ebus->bus;
- if (!hbus->ppcap) {
- dev_err(hbus->dev, "stream type not supported\n");
+ if (!bus->ppcap) {
+ dev_err(bus->dev, "stream type not supported\n");
return NULL;
}
- list_for_each_entry(stream, &hbus->stream_list, list) {
+ list_for_each_entry(stream, &bus->stream_list, list) {
struct hdac_ext_stream *hstream = container_of(stream,
struct hdac_ext_stream,
hstream);
@@ -277,34 +272,33 @@ hdac_ext_link_stream_assign(struct hdac_ext_bus *ebus,
}
if (!hstream->link_locked) {
- snd_hdac_ext_stream_decouple(ebus, hstream, true);
+ snd_hdac_ext_stream_decouple(bus, hstream, true);
res = hstream;
break;
}
}
if (res) {
- spin_lock_irq(&hbus->reg_lock);
+ spin_lock_irq(&bus->reg_lock);
res->link_locked = 1;
res->link_substream = substream;
- spin_unlock_irq(&hbus->reg_lock);
+ spin_unlock_irq(&bus->reg_lock);
}
return res;
}
static struct hdac_ext_stream *
-hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
+hdac_ext_host_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *res = NULL;
struct hdac_stream *stream = NULL;
- struct hdac_bus *hbus = &ebus->bus;
- if (!hbus->ppcap) {
- dev_err(hbus->dev, "stream type not supported\n");
+ if (!bus->ppcap) {
+ dev_err(bus->dev, "stream type not supported\n");
return NULL;
}
- list_for_each_entry(stream, &hbus->stream_list, list) {
+ list_for_each_entry(stream, &bus->stream_list, list) {
struct hdac_ext_stream *hstream = container_of(stream,
struct hdac_ext_stream,
hstream);
@@ -313,17 +307,17 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
if (!stream->opened) {
if (!hstream->decoupled)
- snd_hdac_ext_stream_decouple(ebus, hstream, true);
+ snd_hdac_ext_stream_decouple(bus, hstream, true);
res = hstream;
break;
}
}
if (res) {
- spin_lock_irq(&hbus->reg_lock);
+ spin_lock_irq(&bus->reg_lock);
res->hstream.opened = 1;
res->hstream.running = 0;
res->hstream.substream = substream;
- spin_unlock_irq(&hbus->reg_lock);
+ spin_unlock_irq(&bus->reg_lock);
}
return res;
@@ -331,7 +325,7 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
/**
* snd_hdac_ext_stream_assign - assign a stream for the PCM
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @substream: PCM substream to assign
* @type: type of stream (coupled, host or link stream)
*
@@ -346,27 +340,26 @@ hdac_ext_host_stream_assign(struct hdac_ext_bus *ebus,
* the same stream object when it's used beforehand. when a stream is
* decoupled, it becomes a host stream and link stream.
*/
-struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_ext_bus *ebus,
+struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_bus *bus,
struct snd_pcm_substream *substream,
int type)
{
struct hdac_ext_stream *hstream = NULL;
struct hdac_stream *stream = NULL;
- struct hdac_bus *hbus = &ebus->bus;
switch (type) {
case HDAC_EXT_STREAM_TYPE_COUPLED:
- stream = snd_hdac_stream_assign(hbus, substream);
+ stream = snd_hdac_stream_assign(bus, substream);
if (stream)
hstream = container_of(stream,
struct hdac_ext_stream, hstream);
return hstream;
case HDAC_EXT_STREAM_TYPE_HOST:
- return hdac_ext_host_stream_assign(ebus, substream);
+ return hdac_ext_host_stream_assign(bus, substream);
case HDAC_EXT_STREAM_TYPE_LINK:
- return hdac_ext_link_stream_assign(ebus, substream);
+ return hdac_ext_link_stream_assign(bus, substream);
default:
return NULL;
@@ -384,7 +377,6 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_assign);
void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
{
struct hdac_bus *bus = stream->hstream.bus;
- struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
switch (type) {
case HDAC_EXT_STREAM_TYPE_COUPLED:
@@ -393,13 +385,13 @@ void snd_hdac_ext_stream_release(struct hdac_ext_stream *stream, int type)
case HDAC_EXT_STREAM_TYPE_HOST:
if (stream->decoupled && !stream->link_locked)
- snd_hdac_ext_stream_decouple(ebus, stream, false);
+ snd_hdac_ext_stream_decouple(bus, stream, false);
snd_hdac_stream_release(&stream->hstream);
break;
case HDAC_EXT_STREAM_TYPE_LINK:
if (stream->decoupled && !stream->hstream.opened)
- snd_hdac_ext_stream_decouple(ebus, stream, false);
+ snd_hdac_ext_stream_decouple(bus, stream, false);
spin_lock_irq(&bus->reg_lock);
stream->link_locked = 0;
stream->link_substream = NULL;
@@ -415,16 +407,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_release);
/**
* snd_hdac_ext_stream_spbcap_enable - enable SPIB for a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @enable: flag to enable/disable SPIB
* @index: stream index for which SPIB need to be enabled
*/
-void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_spbcap_enable(struct hdac_bus *bus,
bool enable, int index)
{
u32 mask = 0;
u32 register_mask = 0;
- struct hdac_bus *bus = &ebus->bus;
if (!bus->spbcap) {
dev_err(bus->dev, "Address of SPB capability is NULL\n");
@@ -446,14 +437,13 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_spbcap_enable);
/**
* snd_hdac_ext_stream_set_spib - sets the spib value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @stream: hdac_ext_stream
* @value: spib value to set
*/
-int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_set_spib(struct hdac_bus *bus,
struct hdac_ext_stream *stream, u32 value)
{
- struct hdac_bus *bus = &ebus->bus;
if (!bus->spbcap) {
dev_err(bus->dev, "Address of SPB capability is NULL\n");
@@ -468,15 +458,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib);
/**
* snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @stream: hdac_ext_stream
*
* Return maxfifo for the stream
*/
-int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_bus *bus,
struct hdac_ext_stream *stream)
{
- struct hdac_bus *bus = &ebus->bus;
if (!bus->spbcap) {
dev_err(bus->dev, "Address of SPB capability is NULL\n");
@@ -490,11 +479,10 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo);
/**
* snd_hdac_ext_stop_streams - stop all stream if running
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
*/
-void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus)
+void snd_hdac_ext_stop_streams(struct hdac_bus *bus)
{
- struct hdac_bus *bus = ebus_to_hbus(ebus);
struct hdac_stream *stream;
if (bus->chip_init) {
@@ -507,16 +495,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams);
/**
* snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @enable: flag to enable/disable DRSM
* @index: stream index for which DRSM need to be enabled
*/
-void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus,
+void snd_hdac_ext_stream_drsm_enable(struct hdac_bus *bus,
bool enable, int index)
{
u32 mask = 0;
u32 register_mask = 0;
- struct hdac_bus *bus = &ebus->bus;
if (!bus->drsmcap) {
dev_err(bus->dev, "Address of DRSM capability is NULL\n");
@@ -538,14 +525,13 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable);
/**
* snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @stream: hdac_ext_stream
* @value: dpib value to set
*/
-int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus,
+int snd_hdac_ext_stream_set_dpibr(struct hdac_bus *bus,
struct hdac_ext_stream *stream, u32 value)
{
- struct hdac_bus *bus = &ebus->bus;
if (!bus->drsmcap) {
dev_err(bus->dev, "Address of DRSM capability is NULL\n");
@@ -560,7 +546,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr);
/**
* snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream
- * @ebus: HD-audio ext core bus
+ * @bus: HD-audio core bus
* @stream: hdac_ext_stream
* @value: lpib value to set
*/
diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c
new file mode 100644
index 000000000000..6e46a9c73aed
--- /dev/null
+++ b/sound/hda/hdac_component.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+// hdac_component.c - routines for sync between HD-A core and DRM driver
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/component.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_component.h>
+#include <sound/hda_register.h>
+
+static void hdac_acomp_release(struct device *dev, void *res)
+{
+}
+
+static struct drm_audio_component *hdac_get_acomp(struct device *dev)
+{
+ return devres_find(dev, hdac_acomp_release, NULL, NULL);
+}
+
+/**
+ * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
+ * @bus: HDA core bus
+ * @enable: enable or disable the wakeup
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function should be called during the chip reset, also called at
+ * resume for updating STATESTS register read.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
+{
+ struct drm_audio_component *acomp = bus->audio_component;
+
+ if (!acomp || !acomp->ops)
+ return -ENODEV;
+
+ if (!acomp->ops->codec_wake_override)
+ return 0;
+
+ dev_dbg(bus->dev, "%s codec wakeup\n",
+ enable ? "enable" : "disable");
+
+ acomp->ops->codec_wake_override(acomp->dev, enable);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
+
+/**
+ * snd_hdac_display_power - Power up / down the power refcount
+ * @bus: HDA core bus
+ * @enable: power up or down
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function manages a refcount and calls the get_power() and
+ * put_power() ops accordingly, toggling the codec wakeup, too.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
+{
+ struct drm_audio_component *acomp = bus->audio_component;
+
+ if (!acomp || !acomp->ops)
+ return -ENODEV;
+
+ dev_dbg(bus->dev, "display power %s\n",
+ enable ? "enable" : "disable");
+
+ if (enable) {
+ if (!bus->drm_power_refcount++) {
+ if (acomp->ops->get_power)
+ acomp->ops->get_power(acomp->dev);
+ snd_hdac_set_codec_wakeup(bus, true);
+ snd_hdac_set_codec_wakeup(bus, false);
+ }
+ } else {
+ WARN_ON(!bus->drm_power_refcount);
+ if (!--bus->drm_power_refcount)
+ if (acomp->ops->put_power)
+ acomp->ops->put_power(acomp->dev);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_display_power);
+
+/**
+ * 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
+ * driver that needs the interaction with graphics driver.
+ *
+ * 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 dev_id, int rate)
+{
+ struct hdac_bus *bus = codec->bus;
+ struct drm_audio_component *acomp = bus->audio_component;
+ int port, pipe;
+
+ if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
+ return -ENODEV;
+ port = nid;
+ if (acomp->audio_ops && acomp->audio_ops->pin2port) {
+ port = acomp->audio_ops->pin2port(codec, nid);
+ if (port < 0)
+ return -EINVAL;
+ }
+ pipe = dev_id;
+ return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
+}
+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
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function queries the current state of the audio on the given
+ * digital port and fetches the ELD bytes onto the given buffer.
+ * It returns the number of bytes for the total ELD data, zero for
+ * invalid ELD, or a negative error code.
+ *
+ * The return size is the total bytes required for the whole ELD bytes,
+ * 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 dev_id,
+ bool *audio_enabled, char *buffer, int max_bytes)
+{
+ struct hdac_bus *bus = codec->bus;
+ struct drm_audio_component *acomp = bus->audio_component;
+ int port, pipe;
+
+ if (!acomp || !acomp->ops || !acomp->ops->get_eld)
+ return -ENODEV;
+
+ port = nid;
+ if (acomp->audio_ops && acomp->audio_ops->pin2port) {
+ port = acomp->audio_ops->pin2port(codec, nid);
+ if (port < 0)
+ return -EINVAL;
+ }
+ 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);
+
+static int hdac_component_master_bind(struct device *dev)
+{
+ struct drm_audio_component *acomp = hdac_get_acomp(dev);
+ int ret;
+
+ if (WARN_ON(!acomp))
+ return -EINVAL;
+
+ ret = component_bind_all(dev, acomp);
+ if (ret < 0)
+ return ret;
+
+ if (WARN_ON(!(acomp->dev && acomp->ops))) {
+ ret = -EINVAL;
+ goto out_unbind;
+ }
+
+ /* pin the module to avoid dynamic unbinding, but only if given */
+ if (!try_module_get(acomp->ops->owner)) {
+ ret = -ENODEV;
+ goto out_unbind;
+ }
+
+ if (acomp->audio_ops && acomp->audio_ops->master_bind) {
+ ret = acomp->audio_ops->master_bind(dev, acomp);
+ if (ret < 0)
+ goto module_put;
+ }
+
+ return 0;
+
+ module_put:
+ module_put(acomp->ops->owner);
+out_unbind:
+ component_unbind_all(dev, acomp);
+
+ return ret;
+}
+
+static void hdac_component_master_unbind(struct device *dev)
+{
+ struct drm_audio_component *acomp = hdac_get_acomp(dev);
+
+ if (acomp->audio_ops && acomp->audio_ops->master_unbind)
+ acomp->audio_ops->master_unbind(dev, acomp);
+ module_put(acomp->ops->owner);
+ component_unbind_all(dev, acomp);
+ WARN_ON(acomp->ops || acomp->dev);
+}
+
+static const struct component_master_ops hdac_component_master_ops = {
+ .bind = hdac_component_master_bind,
+ .unbind = hdac_component_master_unbind,
+};
+
+/**
+ * snd_hdac_acomp_register_notifier - Register audio component ops
+ * @bus: HDA core bus
+ * @aops: audio component ops
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function sets the given ops to be called by the graphics driver.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_acomp_register_notifier(struct hdac_bus *bus,
+ const struct drm_audio_component_audio_ops *aops)
+{
+ if (!bus->audio_component)
+ return -ENODEV;
+
+ bus->audio_component->audio_ops = aops;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_register_notifier);
+
+/**
+ * snd_hdac_acomp_init - Initialize audio component
+ * @bus: HDA core bus
+ * @match_master: match function for finding components
+ * @extra_size: Extra bytes to allocate
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function initializes and sets up the audio component to communicate
+ * with graphics driver.
+ *
+ * Unlike snd_hdac_i915_init(), this function doesn't synchronize with the
+ * binding with the DRM component. Each caller needs to sync via master_bind
+ * audio_ops.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_acomp_init(struct hdac_bus *bus,
+ const struct drm_audio_component_audio_ops *aops,
+ int (*match_master)(struct device *, void *),
+ size_t extra_size)
+{
+ struct component_match *match = NULL;
+ struct device *dev = bus->dev;
+ struct drm_audio_component *acomp;
+ int ret;
+
+ if (WARN_ON(hdac_get_acomp(dev)))
+ return -EBUSY;
+
+ acomp = devres_alloc(hdac_acomp_release, sizeof(*acomp) + extra_size,
+ GFP_KERNEL);
+ if (!acomp)
+ return -ENOMEM;
+ acomp->audio_ops = aops;
+ bus->audio_component = acomp;
+ devres_add(dev, acomp);
+
+ component_match_add(dev, &match, match_master, bus);
+ ret = component_master_add_with_match(dev, &hdac_component_master_ops,
+ match);
+ if (ret < 0)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ bus->audio_component = NULL;
+ devres_destroy(dev, hdac_acomp_release, NULL, NULL);
+ dev_info(dev, "failed to add audio component master (%d)\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_init);
+
+/**
+ * snd_hdac_acomp_exit - Finalize audio component
+ * @bus: HDA core bus
+ *
+ * This function is supposed to be used only by a HD-audio controller
+ * driver that needs the interaction with graphics driver.
+ *
+ * This function releases the audio component that has been used.
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_acomp_exit(struct hdac_bus *bus)
+{
+ struct device *dev = bus->dev;
+ struct drm_audio_component *acomp = bus->audio_component;
+
+ if (!acomp)
+ return 0;
+
+ WARN_ON(bus->drm_power_refcount);
+ if (bus->drm_power_refcount > 0 && acomp->ops)
+ acomp->ops->put_power(acomp->dev);
+
+ component_master_del(dev, &hdac_component_master_ops);
+
+ bus->audio_component = NULL;
+ devres_destroy(dev, hdac_acomp_release, NULL, NULL);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_acomp_exit);
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c
index 7ba100bb1c3f..dbf02a3a8d2f 100644
--- a/sound/hda/hdac_device.c
+++ b/sound/hda/hdac_device.c
@@ -738,7 +738,7 @@ static struct hda_rate_tbl rate_bits[] = {
*/
unsigned int snd_hdac_calc_stream_format(unsigned int rate,
unsigned int channels,
- unsigned int format,
+ snd_pcm_format_t format,
unsigned int maxbps,
unsigned short spdif_ctls)
{
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index cbe818eda336..b5282cbbe489 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -15,88 +15,12 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/component.h>
-#include <drm/i915_component.h>
#include <sound/core.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
#include <sound/hda_register.h>
-static struct i915_audio_component *hdac_acomp;
-
-/**
- * snd_hdac_set_codec_wakeup - Enable / disable HDMI/DP codec wakeup
- * @bus: HDA core bus
- * @enable: enable or disable the wakeup
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function should be called during the chip reset, also called at
- * resume for updating STATESTS register read.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
-{
- struct i915_audio_component *acomp = bus->audio_component;
-
- if (!acomp || !acomp->ops)
- return -ENODEV;
-
- if (!acomp->ops->codec_wake_override) {
- dev_warn(bus->dev,
- "Invalid codec wake callback\n");
- return 0;
- }
-
- dev_dbg(bus->dev, "%s codec wakeup\n",
- enable ? "enable" : "disable");
-
- acomp->ops->codec_wake_override(acomp->dev, enable);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_set_codec_wakeup);
-
-/**
- * snd_hdac_display_power - Power up / down the power refcount
- * @bus: HDA core bus
- * @enable: power up or down
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function manages a refcount and calls the i915 get_power() and
- * put_power() ops accordingly, toggling the codec wakeup, too.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
-{
- struct i915_audio_component *acomp = bus->audio_component;
-
- if (!acomp || !acomp->ops)
- return -ENODEV;
-
- dev_dbg(bus->dev, "display power %s\n",
- enable ? "enable" : "disable");
-
- if (enable) {
- if (!bus->i915_power_refcount++) {
- acomp->ops->get_power(acomp->dev);
- snd_hdac_set_codec_wakeup(bus, true);
- snd_hdac_set_codec_wakeup(bus, false);
- }
- } else {
- WARN_ON(!bus->i915_power_refcount);
- if (!--bus->i915_power_refcount)
- acomp->ops->put_power(acomp->dev);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_display_power);
+static struct completion bind_complete;
#define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \
((pci)->device == 0x0c0c) || \
@@ -119,7 +43,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_display_power);
*/
void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
{
- struct i915_audio_component *acomp = bus->audio_component;
+ struct drm_audio_component *acomp = bus->audio_component;
struct pci_dev *pci = to_pci_dev(bus->dev);
int cdclk_freq;
unsigned int bclk_m, bclk_n;
@@ -158,181 +82,11 @@ void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk);
-/* There is a fixed mapping between audio pin node and display port.
- * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- *
- * on VLV, ILK:
- * Pin Widget 4 - PORT B (port = 1 in i915 driver)
- * Pin Widget 5 - PORT C (port = 2 in i915 driver)
- * Pin Widget 6 - PORT D (port = 3 in i915 driver)
- */
-static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
-{
- int base_nid;
-
- switch (codec->vendor_id) {
- case 0x80860054: /* ILK */
- case 0x80862804: /* ILK */
- case 0x80862882: /* VLV */
- base_nid = 3;
- break;
- default:
- base_nid = 4;
- break;
- }
-
- if (WARN_ON(pin_nid <= base_nid || pin_nid > base_nid + 3))
- return -1;
- return pin_nid - base_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
- * driver that needs the interaction with i915 graphics.
- *
- * 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 dev_id, int rate)
-{
- struct hdac_bus *bus = codec->bus;
- struct i915_audio_component *acomp = bus->audio_component;
- int port, pipe;
-
- if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate)
- return -ENODEV;
- port = pin2port(codec, nid);
- if (port < 0)
- return -EINVAL;
- pipe = dev_id;
- return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
-}
-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
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function queries the current state of the audio on the given
- * digital port and fetches the ELD bytes onto the given buffer.
- * It returns the number of bytes for the total ELD data, zero for
- * invalid ELD, or a negative error code.
- *
- * The return size is the total bytes required for the whole ELD bytes,
- * 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 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, pipe;
-
- if (!acomp || !acomp->ops || !acomp->ops->get_eld)
- return -ENODEV;
-
- port = pin2port(codec, nid);
- if (port < 0)
- return -EINVAL;
-
- 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);
-
-static int hdac_component_master_bind(struct device *dev)
-{
- struct i915_audio_component *acomp = hdac_acomp;
- int ret;
-
- ret = component_bind_all(dev, acomp);
- if (ret < 0)
- return ret;
-
- if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
- acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
- ret = -EINVAL;
- goto out_unbind;
- }
-
- /*
- * Atm, we don't support dynamic unbinding initiated by the child
- * component, so pin its containing module until we unbind.
- */
- if (!try_module_get(acomp->ops->owner)) {
- ret = -ENODEV;
- goto out_unbind;
- }
-
- return 0;
-
-out_unbind:
- component_unbind_all(dev, acomp);
-
- return ret;
-}
-
-static void hdac_component_master_unbind(struct device *dev)
-{
- struct i915_audio_component *acomp = hdac_acomp;
-
- module_put(acomp->ops->owner);
- component_unbind_all(dev, acomp);
- WARN_ON(acomp->ops || acomp->dev);
-}
-
-static const struct component_master_ops hdac_component_master_ops = {
- .bind = hdac_component_master_bind,
- .unbind = hdac_component_master_unbind,
-};
-
-static int hdac_component_master_match(struct device *dev, void *data)
+static int i915_component_master_match(struct device *dev, void *data)
{
- /* i915 is the only supported component */
return !strcmp(dev->driver->name, "i915");
}
-/**
- * snd_hdac_i915_register_notifier - Register i915 audio component ops
- * @aops: i915 audio component ops
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function sets the given ops to be called by the i915 graphics driver.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops)
-{
- if (!hdac_acomp)
- return -ENODEV;
-
- hdac_acomp->audio_ops = aops;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier);
-
/* check whether intel graphics is present */
static bool i915_gfx_present(void)
{
@@ -345,6 +99,19 @@ static bool i915_gfx_present(void)
return pci_dev_present(ids);
}
+static int i915_master_bind(struct device *dev,
+ struct drm_audio_component *acomp)
+{
+ complete_all(&bind_complete);
+ /* clear audio_ops here as it was needed only for completion call */
+ acomp->audio_ops = NULL;
+ return 0;
+}
+
+static const struct drm_audio_component_audio_ops i915_init_ops = {
+ .master_bind = i915_master_bind
+};
+
/**
* snd_hdac_i915_init - Initialize i915 audio component
* @bus: HDA core bus
@@ -359,83 +126,31 @@ static bool i915_gfx_present(void)
*/
int snd_hdac_i915_init(struct hdac_bus *bus)
{
- struct component_match *match = NULL;
- struct device *dev = bus->dev;
- struct i915_audio_component *acomp;
- int ret;
-
- if (WARN_ON(hdac_acomp))
- return -EBUSY;
+ struct drm_audio_component *acomp;
+ int err;
if (!i915_gfx_present())
return -ENODEV;
- acomp = kzalloc(sizeof(*acomp), GFP_KERNEL);
- if (!acomp)
- return -ENOMEM;
- bus->audio_component = acomp;
- hdac_acomp = acomp;
-
- component_match_add(dev, &match, hdac_component_master_match, bus);
- ret = component_master_add_with_match(dev, &hdac_component_master_ops,
- match);
- if (ret < 0)
- goto out_err;
-
- /*
- * Atm, we don't support deferring the component binding, so make sure
- * i915 is loaded and that the binding successfully completes.
- */
- request_module("i915");
+ init_completion(&bind_complete);
+ err = snd_hdac_acomp_init(bus, &i915_init_ops,
+ i915_component_master_match,
+ sizeof(struct i915_audio_component) - sizeof(*acomp));
+ if (err < 0)
+ return err;
+ acomp = bus->audio_component;
+ if (!acomp)
+ return -ENODEV;
if (!acomp->ops) {
- ret = -ENODEV;
- goto out_master_del;
+ request_module("i915");
+ /* 10s timeout */
+ wait_for_completion_timeout(&bind_complete, 10 * 1000);
+ }
+ if (!acomp->ops) {
+ snd_hdac_acomp_exit(bus);
+ return -ENODEV;
}
- dev_dbg(dev, "bound to i915 component master\n");
-
return 0;
-out_master_del:
- component_master_del(dev, &hdac_component_master_ops);
-out_err:
- kfree(acomp);
- bus->audio_component = NULL;
- hdac_acomp = NULL;
- dev_info(dev, "failed to add i915 component master (%d)\n", ret);
-
- return ret;
}
EXPORT_SYMBOL_GPL(snd_hdac_i915_init);
-
-/**
- * snd_hdac_i915_exit - Finalize i915 audio component
- * @bus: HDA core bus
- *
- * This function is supposed to be used only by a HD-audio controller
- * driver that needs the interaction with i915 graphics.
- *
- * This function releases the i915 audio component that has been used.
- *
- * Returns zero for success or a negative error code.
- */
-int snd_hdac_i915_exit(struct hdac_bus *bus)
-{
- struct device *dev = bus->dev;
- struct i915_audio_component *acomp = bus->audio_component;
-
- if (!acomp)
- return 0;
-
- WARN_ON(bus->i915_power_refcount);
- if (bus->i915_power_refcount > 0 && acomp->ops)
- acomp->ops->put_power(acomp->dev);
-
- component_master_del(dev, &hdac_component_master_ops);
-
- kfree(acomp);
- bus->audio_component = NULL;
- hdac_acomp = NULL;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hdac_i915_exit);
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index e1472c7ab6c1..eee422390d8e 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -621,7 +621,7 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
unsigned int byte_size, struct snd_dma_buffer *bufp)
{
struct hdac_bus *bus = azx_dev->bus;
- u32 *bdl;
+ __le32 *bdl;
int err;
snd_hdac_dsp_lock(azx_dev);
@@ -651,7 +651,7 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
azx_dev->frags = 0;
- bdl = (u32 *)azx_dev->bdl.area;
+ bdl = (__le32 *)azx_dev->bdl.area;
err = setup_bdle(bus, bufp, azx_dev, &bdl, 0, byte_size, 0);
if (err < 0)
goto error;
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index 7e21621e492a..2647309bc675 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -621,15 +621,3 @@ int snd_cs8427_iec958_pcm(struct snd_i2c_device *cs8427, unsigned int rate)
}
EXPORT_SYMBOL(snd_cs8427_iec958_pcm);
-
-static int __init alsa_cs8427_module_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_cs8427_module_exit(void)
-{
-}
-
-module_init(alsa_cs8427_module_init)
-module_exit(alsa_cs8427_module_exit)
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index ef2a9afe9e19..c4a232f18a79 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -338,16 +338,3 @@ static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr)
snd_i2c_bit_stop(bus);
return err;
}
-
-
-static int __init alsa_i2c_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_i2c_exit(void)
-{
-}
-
-module_init(alsa_i2c_init)
-module_exit(alsa_i2c_exit)
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index bf377dc192aa..7f2761a2e7c8 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -911,15 +911,3 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
return 0;
}
EXPORT_SYMBOL(snd_akm4xxx_build_controls);
-
-static int __init alsa_akm4xxx_module_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_akm4xxx_module_exit(void)
-{
-}
-
-module_init(alsa_akm4xxx_module_init)
-module_exit(alsa_akm4xxx_module_exit)
diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c
index 2d22310dce05..239c4822427f 100644
--- a/sound/i2c/tea6330t.c
+++ b/sound/i2c/tea6330t.c
@@ -368,19 +368,3 @@ int snd_tea6330t_update_mixer(struct snd_card *card,
EXPORT_SYMBOL(snd_tea6330t_detect);
EXPORT_SYMBOL(snd_tea6330t_update_mixer);
-
-/*
- * INIT part
- */
-
-static int __init alsa_tea6330t_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_tea6330t_exit(void)
-{
-}
-
-module_init(alsa_tea6330t_init)
-module_exit(alsa_tea6330t_exit)
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 43b35a873d78..d7db1eeebc84 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -459,7 +459,7 @@ config SND_MSND_CLASSIC
Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
Monterey (not for the Pinnacle or Fiji).
- See <file:Documentation/sound/oss/MultiSound> for important information
+ See <file:Documentation/sound/cards/multisound.sh> for important information
about this driver. Note that it has been discontinued, but the
Voyetra Turtle Beach knowledge base entry for it is still available
at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index 923201414469..fba6d22f7f4b 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -85,7 +85,8 @@ static void snd_ad1816a_write_mask(struct snd_ad1816a *chip, unsigned char reg,
static unsigned char snd_ad1816a_get_format(struct snd_ad1816a *chip,
- unsigned int format, int channels)
+ snd_pcm_format_t format,
+ int channels)
{
unsigned char retval = AD1816A_FMT_LINEAR_8;
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index a826c138e7f5..3dfe7e592c25 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -260,7 +260,6 @@ static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
struct snd_card *card;
static unsigned int dev;
int error;
- struct snd_es1688 *chip;
if (snd_es968_pnp_is_probed)
return -EBUSY;
@@ -276,7 +275,6 @@ static int snd_es968_pnp_detect(struct pnp_card_link *pcard,
sizeof(struct snd_es1688), &card);
if (error < 0)
return error;
- chip = card->private_data;
error = snd_card_es968_pnp(card, dev, pcard, pid);
if (error < 0) {
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index f9c0662e9a22..50cdce0e8946 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -1029,19 +1029,3 @@ EXPORT_SYMBOL(snd_es1688_mixer_write);
EXPORT_SYMBOL(snd_es1688_create);
EXPORT_SYMBOL(snd_es1688_pcm);
EXPORT_SYMBOL(snd_es1688_mixer);
-
-/*
- * INIT part
- */
-
-static int __init alsa_es1688_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_es1688_exit(void)
-{
-}
-
-module_init(alsa_es1688_init)
-module_exit(alsa_es1688_exit)
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 2a6960c3e2a4..0d103d6f805e 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -1024,6 +1024,7 @@ static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
val = 3;
} else
retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x00) != 0x00;
+ /* fall through */
/* 4 source chips */
case 0x1868:
case 0x1878:
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c
index b9994cc9f5fb..af9eea41379f 100644
--- a/sound/isa/galaxy/galaxy.c
+++ b/sound/isa/galaxy/galaxy.c
@@ -260,6 +260,7 @@ static int snd_galaxy_match(struct device *dev, unsigned int n)
break;
case 2:
irq[n] = 9;
+ /* Fall through */
case 9:
wss_config[n] |= WSS_CONFIG_IRQ_9;
break;
@@ -304,6 +305,7 @@ static int snd_galaxy_match(struct device *dev, unsigned int n)
case 1:
if (dma1[n] == 0)
break;
+ /* Fall through */
default:
dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
return 0;
@@ -333,6 +335,7 @@ mpu:
break;
case 2:
mpu_irq[n] = 9;
+ /* Fall through */
case 9:
config[n] |= GALAXY_CONFIG_MPUIRQ_2;
break;
diff --git a/sound/isa/gus/gus_io.c b/sound/isa/gus/gus_io.c
index ca79878d8d8c..2fd32ef22c30 100644
--- a/sound/isa/gus/gus_io.c
+++ b/sound/isa/gus/gus_io.c
@@ -461,7 +461,7 @@ void snd_gf1_print_voice_registers(struct snd_gus_card * gus)
printk(KERN_INFO " -%i- GFA1 effect address = 0x%x\n", voice, snd_gf1_i_read_addr(gus, 0x11, ctrl & 4));
printk(KERN_INFO " -%i- GFA1 effect volume = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x16));
printk(KERN_INFO " -%i- GFA1 effect volume final = 0x%x\n", voice, snd_gf1_i_read16(gus, 0x1d));
- printk(KERN_INFO " -%i- GFA1 effect acumulator = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x14));
+ printk(KERN_INFO " -%i- GFA1 effect accumulator = 0x%x\n", voice, snd_gf1_i_read8(gus, 0x14));
}
if (mode & 0x20) {
printk(KERN_INFO " -%i- GFA1 left offset = 0x%x (%i)\n", voice, snd_gf1_i_read16(gus, 0x13), snd_gf1_i_read16(gus, 0x13) >> 4);
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 3cf9b13c780a..3b8a0c880db5 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -465,19 +465,3 @@ EXPORT_SYMBOL(snd_gf1_mem_alloc);
EXPORT_SYMBOL(snd_gf1_mem_xfree);
EXPORT_SYMBOL(snd_gf1_mem_free);
EXPORT_SYMBOL(snd_gf1_mem_lock);
-
-/*
- * INIT part
- */
-
-static int __init alsa_gus_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_gus_exit(void)
-{
-}
-
-module_init(alsa_gus_init)
-module_exit(alsa_gus_exit)
diff --git a/sound/isa/gus/gus_reset.c b/sound/isa/gus/gus_reset.c
index 3d1fed0c2620..59b3f683d49b 100644
--- a/sound/isa/gus/gus_reset.c
+++ b/sound/isa/gus/gus_reset.c
@@ -292,7 +292,6 @@ void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice)
{
unsigned long flags;
void (*private_free)(struct snd_gus_voice *voice);
- void *private_data;
if (voice == NULL || !voice->use)
return;
@@ -300,7 +299,6 @@ void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice)
snd_gf1_clear_voices(gus, voice->number, voice->number);
spin_lock_irqsave(&gus->voice_alloc, flags);
private_free = voice->private_free;
- private_data = voice->private_data;
voice->private_free = NULL;
voice->private_data = NULL;
if (voice->pcm)
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
index 569897f64fda..7c3203fe4869 100644
--- a/sound/isa/msnd/msnd.c
+++ b/sound/isa/msnd/msnd.c
@@ -54,7 +54,7 @@
#define LOGNAME "msnd"
-void snd_msnd_init_queue(void *base, int start, int size)
+void snd_msnd_init_queue(void __iomem *base, int start, int size)
{
writew(PCTODSP_BASED(start), base + JQS_wStart);
writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
@@ -270,7 +270,7 @@ int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
udelay(1);
if (chip->capturePeriods == 2) {
- void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
+ void __iomem *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
bank * DAQDS__size + DAQDS_wStart;
unsigned short offset = 0x3000 + chip->capturePeriodBytes;
@@ -309,7 +309,7 @@ int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
{
u16 DAPQ_tail;
int protect = start, nbanks = 0;
- void *DAQD;
+ void __iomem *DAQD;
static int play_banks_submitted;
/* unsigned long flags;
spin_lock_irqsave(&chip->lock, flags); not necessary */
@@ -370,7 +370,7 @@ static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
unsigned int pcm_count)
{
int n;
- void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+ void __iomem *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
chip->last_playbank = -1;
chip->playLimit = pcm_count * (pcm_periods - 1);
@@ -398,7 +398,7 @@ static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
unsigned int pcm_count)
{
int n;
- void *pDAQ;
+ void __iomem *pDAQ;
/* unsigned long flags; */
/* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
@@ -485,7 +485,7 @@ static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
clear_bit(F_WRITING, &chip->flags);
snd_msnd_enable_irq(chip);
- runtime->dma_area = chip->mappedbase;
+ runtime->dma_area = (__force void *)chip->mappedbase;
runtime->dma_bytes = 0x3000;
chip->playback_substream = substream;
@@ -508,7 +508,7 @@ static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
{
int i;
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
+ void __iomem *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
chip->play_sample_size = snd_pcm_format_width(params_format(params));
chip->play_channels = params_channels(params);
@@ -589,7 +589,7 @@ static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
set_bit(F_AUDIO_READ_INUSE, &chip->flags);
snd_msnd_enable_irq(chip);
- runtime->dma_area = chip->mappedbase + 0x3000;
+ runtime->dma_area = (__force void *)chip->mappedbase + 0x3000;
runtime->dma_bytes = 0x3000;
memset(runtime->dma_area, 0, runtime->dma_bytes);
chip->capture_substream = substream;
@@ -654,7 +654,7 @@ static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
{
int i;
struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
+ void __iomem *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
chip->capture_sample_size = snd_pcm_format_width(params_format(params));
chip->capture_channels = params_channels(params);
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
index 5f3c7dcd9f9d..80c718757eef 100644
--- a/sound/isa/msnd/msnd.h
+++ b/sound/isa/msnd/msnd.h
@@ -283,7 +283,7 @@ struct snd_msnd {
};
-void snd_msnd_init_queue(void *base, int start, int size);
+void snd_msnd_init_queue(void __iomem *base, int start, int size);
int snd_msnd_send_dsp_cmd(struct snd_msnd *chip, u8 cmd);
int snd_msnd_send_word(struct snd_msnd *chip,
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
index 013d8d1170fe..42876b0cb68b 100644
--- a/sound/isa/msnd/msnd_midi.c
+++ b/sound/isa/msnd/msnd_midi.c
@@ -119,7 +119,7 @@ void snd_msndmidi_input_read(void *mpuv)
{
unsigned long flags;
struct snd_msndmidi *mpu = mpuv;
- void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
+ void __iomem *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
u16 head, tail, size;
spin_lock_irqsave(&mpu->input_lock, flags);
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 6c584d9b6c42..11af9c40bc05 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -82,10 +82,10 @@
static void set_default_audio_parameters(struct snd_msnd *chip)
{
- chip->play_sample_size = DEFSAMPLESIZE;
+ chip->play_sample_size = snd_pcm_format_width(DEFSAMPLESIZE);
chip->play_sample_rate = DEFSAMPLERATE;
chip->play_channels = DEFCHANNELS;
- chip->capture_sample_size = DEFSAMPLESIZE;
+ chip->capture_sample_size = snd_pcm_format_width(DEFSAMPLESIZE);
chip->capture_sample_rate = DEFSAMPLERATE;
chip->capture_channels = DEFCHANNELS;
}
@@ -169,7 +169,7 @@ static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
{
struct snd_msnd *chip = dev_id;
- void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
+ void __iomem *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
u16 head, tail, size;
/* Send ack to DSP */
@@ -810,7 +810,7 @@ module_param(calibrate_signal, int, 0444);
#ifndef MSND_CLASSIC
module_param_array(digital, int, NULL, 0444);
module_param_hw_array(cfg, long, ioport, NULL, 0444);
-module_param_array(reset, int, 0, 0444);
+module_param_array(reset, int, NULL, 0444);
module_param_hw_array(mpu_io, long, ioport, NULL, 0444);
module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
module_param_hw_array(ide_io0, long, ioport, NULL, 0444);
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c
index 8894c7c18ad6..c6136c6b0214 100644
--- a/sound/isa/opti9xx/miro.c
+++ b/sound/isa/opti9xx/miro.c
@@ -176,10 +176,13 @@ static int aci_busy_wait(struct snd_miro_aci *aci)
switch (timeout-ACI_MINTIME) {
case 0 ... 9:
out /= 10;
+ /* fall through */
case 10 ... 19:
out /= 10;
+ /* fall through */
case 20 ... 30:
out /= 10;
+ /* fall through */
default:
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(out);
@@ -834,6 +837,7 @@ static unsigned char snd_miro_read(struct snd_miro *chip,
retval = inb(chip->mc_base + 9);
break;
}
+ /* fall through */
case OPTi9XX_HW_82C929:
retval = inb(chip->mc_base + reg);
@@ -863,6 +867,7 @@ static void snd_miro_write(struct snd_miro *chip, unsigned char reg,
outb(value, chip->mc_base + 9);
break;
}
+ /* fall through */
case OPTi9XX_HW_82C929:
outb(value, chip->mc_base + reg);
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 505cd81e19fa..ac0ab6eb40f0 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -261,6 +261,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
retval = inb(chip->mc_base + 9);
break;
}
+ /* Fall through */
case OPTi9XX_HW_82C928:
case OPTi9XX_HW_82C929:
@@ -303,6 +304,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
outb(value, chip->mc_base + 9);
break;
}
+ /* Fall through */
case OPTi9XX_HW_82C928:
case OPTi9XX_HW_82C929:
@@ -350,6 +352,7 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc);
/* enable wave audio */
snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
+ /* Fall through */
case OPTi9XX_HW_82C925:
/* enable WSS mode */
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index c2e41d2762f7..d45a6b9d6437 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -165,11 +165,8 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
return 0;
/* be sure loop points start < end */
- if (sp->v.loopstart > sp->v.loopend) {
- int tmp = sp->v.loopstart;
- sp->v.loopstart = sp->v.loopend;
- sp->v.loopend = tmp;
- }
+ if (sp->v.loopstart > sp->v.loopend)
+ swap(sp->v.loopstart, sp->v.loopend);
/* compute true data size to be loaded */
truesize = sp->v.size;
diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
index bc5af71d3bdb..f46f6ec3ea0c 100644
--- a/sound/isa/sb/emu8000_pcm.c
+++ b/sound/isa/sb/emu8000_pcm.c
@@ -470,7 +470,7 @@ static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
/* convert to word unit */
pos = (pos << 1) + rec->loop_start[voice];
count <<= 1;
- LOOP_WRITE(rec, pos, src, count, COPY_UESR);
+ LOOP_WRITE(rec, pos, src, count, COPY_USER);
return 0;
}
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index fa5780bb0c68..bf3db0d2ea12 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -60,18 +60,18 @@ MODULE_FIRMWARE("sb16/ima_adpcm_capture.csp");
* RIFF data format
*/
struct riff_header {
- __u32 name;
- __u32 len;
+ __le32 name;
+ __le32 len;
};
struct desc_header {
struct riff_header info;
- __u16 func_nr;
- __u16 VOC_type;
- __u16 flags_play_rec;
- __u16 flags_16bit_8bit;
- __u16 flags_stereo_mono;
- __u16 flags_rates;
+ __le16 func_nr;
+ __le16 VOC_type;
+ __le16 flags_play_rec;
+ __le16 flags_16bit_8bit;
+ __le16 flags_stereo_mono;
+ __le16 flags_rates;
};
/*
@@ -93,7 +93,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
struct snd_sb_csp_microcode __user * code);
static int snd_sb_csp_unload(struct snd_sb_csp * p);
static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags);
-static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec_mode);
+static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode);
static int snd_sb_csp_check_version(struct snd_sb_csp * p);
static int snd_sb_csp_use(struct snd_sb_csp * p);
@@ -314,7 +314,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
unsigned short func_nr = 0;
struct riff_header file_h, item_h, code_h;
- __u32 item_type;
+ __le32 item_type;
struct desc_header funcdesc_h;
unsigned long flags;
@@ -326,7 +326,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
if (copy_from_user(&file_h, data_ptr, sizeof(file_h)))
return -EFAULT;
- if ((file_h.name != RIFF_HEADER) ||
+ if ((le32_to_cpu(file_h.name) != RIFF_HEADER) ||
(le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {
snd_printd("%s: Invalid RIFF header\n", __func__);
return -EINVAL;
@@ -336,7 +336,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
return -EFAULT;
- if (item_type != CSP__HEADER) {
+ if (le32_to_cpu(item_type) != CSP__HEADER) {
snd_printd("%s: Invalid RIFF file type\n", __func__);
return -EINVAL;
}
@@ -346,12 +346,12 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
if (copy_from_user(&item_h, data_ptr, sizeof(item_h)))
return -EFAULT;
data_ptr += sizeof(item_h);
- if (item_h.name != LIST_HEADER)
+ if (le32_to_cpu(item_h.name) != LIST_HEADER)
continue;
if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
return -EFAULT;
- switch (item_type) {
+ switch (le32_to_cpu(item_type)) {
case FUNC_HEADER:
if (copy_from_user(&funcdesc_h, data_ptr + sizeof(item_type), sizeof(funcdesc_h)))
return -EFAULT;
@@ -378,7 +378,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
return -EFAULT;
/* init microcode blocks */
- if (code_h.name != INIT_HEADER)
+ if (le32_to_cpu(code_h.name) != INIT_HEADER)
break;
data_ptr += sizeof(code_h);
err = snd_sb_csp_load_user(p, data_ptr, le32_to_cpu(code_h.len),
@@ -391,7 +391,7 @@ static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))
return -EFAULT;
- if (code_h.name != MAIN_HEADER) {
+ if (le32_to_cpu(code_h.name) != MAIN_HEADER) {
snd_printd("%s: Missing 'main' microcode\n", __func__);
return -EINVAL;
}
@@ -726,7 +726,7 @@ static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
* autoload hardware codec if necessary
* return 0 if CSP is loaded and ready to run (p->running != 0)
*/
-static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec_mode)
+static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode)
{
unsigned long flags;
int err = 0;
@@ -736,7 +736,7 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec
return -EBUSY;
/* autoload microcode only if requested hardware codec is not already loaded */
- if (((1 << pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) {
+ if (((1U << (__force int)pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) {
p->running = SNDRV_SB_CSP_ST_AUTO;
} else {
switch (pcm_sfmt) {
@@ -1185,19 +1185,3 @@ static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buff
/* */
EXPORT_SYMBOL(snd_sb_csp_new);
-
-/*
- * INIT part
- */
-
-static int __init alsa_sb_csp_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_sb_csp_exit(void)
-{
-}
-
-module_init(alsa_sb_csp_init)
-module_exit(alsa_sb_csp_exit)
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 3e39ba220c39..37e6ce7b0b13 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -49,6 +49,9 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones");
MODULE_LICENSE("GPL");
+#define runtime_format_bits(runtime) \
+ ((unsigned int)pcm_format_to_bits((runtime)->format))
+
#ifdef CONFIG_SND_SB16_CSP
static void snd_sb16_csp_playback_prepare(struct snd_sb *chip, struct snd_pcm_runtime *runtime)
{
@@ -58,7 +61,7 @@ static void snd_sb16_csp_playback_prepare(struct snd_sb *chip, struct snd_pcm_ru
if (csp->running & SNDRV_SB_CSP_ST_LOADED) {
/* manually loaded codec */
if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) &&
- ((1U << runtime->format) == csp->acc_format)) {
+ (runtime_format_bits(runtime) == csp->acc_format)) {
/* Supported runtime PCM format for playback */
if (csp->ops.csp_use(csp) == 0) {
/* If CSP was successfully acquired */
@@ -66,7 +69,7 @@ static void snd_sb16_csp_playback_prepare(struct snd_sb *chip, struct snd_pcm_ru
}
} else if ((csp->mode & SNDRV_SB_CSP_MODE_QSOUND) && (csp->q_enabled)) {
/* QSound decoder is loaded and enabled */
- if ((1 << runtime->format) & (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
+ if (runtime_format_bits(runtime) & (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE)) {
/* Only for simple PCM formats */
if (csp->ops.csp_use(csp) == 0) {
@@ -106,7 +109,7 @@ static void snd_sb16_csp_capture_prepare(struct snd_sb *chip, struct snd_pcm_run
if (csp->running & SNDRV_SB_CSP_ST_LOADED) {
/* manually loaded codec */
if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) &&
- ((1U << runtime->format) == csp->acc_format)) {
+ (runtime_format_bits(runtime) == csp->acc_format)) {
/* Supported runtime PCM format for capture */
if (csp->ops.csp_use(csp) == 0) {
/* If CSP was successfully acquired */
@@ -897,19 +900,3 @@ EXPORT_SYMBOL(snd_sb16dsp_pcm);
EXPORT_SYMBOL(snd_sb16dsp_get_pcm_ops);
EXPORT_SYMBOL(snd_sb16dsp_configure);
EXPORT_SYMBOL(snd_sb16dsp_interrupt);
-
-/*
- * INIT part
- */
-
-static int __init alsa_sb16_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_sb16_exit(void)
-{
-}
-
-module_init(alsa_sb16_init)
-module_exit(alsa_sb16_exit)
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
index d45df5c54423..481797744b3c 100644
--- a/sound/isa/sb/sb8_main.c
+++ b/sound/isa/sb/sb8_main.c
@@ -381,7 +381,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
{
struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
snd_sb_ack_8bit(chip);
switch (chip->mode) {
@@ -391,7 +390,6 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
/* fallthru */
case SB_MODE_PLAYBACK_8:
substream = chip->playback_substream;
- runtime = substream->runtime;
if (chip->playback_format == SB_DSP_OUTPUT)
snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
snd_pcm_period_elapsed(substream);
@@ -402,7 +400,6 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
/* fallthru */
case SB_MODE_CAPTURE_8:
substream = chip->capture_substream;
- runtime = substream->runtime;
if (chip->capture_format == SB_DSP_INPUT)
snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START);
snd_pcm_period_elapsed(substream);
@@ -624,19 +621,3 @@ EXPORT_SYMBOL(snd_sb8dsp_interrupt);
/* sb8_midi.c */
EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);
EXPORT_SYMBOL(snd_sb8dsp_midi);
-
-/*
- * INIT part
- */
-
-static int __init alsa_sb8_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_sb8_exit(void)
-{
-}
-
-module_init(alsa_sb8_init)
-module_exit(alsa_sb8_exit)
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index 787a4ade4afd..90b254aaef74 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -305,19 +305,3 @@ EXPORT_SYMBOL(snd_sbmixer_add_ctl);
EXPORT_SYMBOL(snd_sbmixer_suspend);
EXPORT_SYMBOL(snd_sbmixer_resume);
#endif
-
-/*
- * INIT part
- */
-
-static int __init alsa_sb_common_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_sb_common_exit(void)
-{
-}
-
-module_init(alsa_sb_common_init)
-module_exit(alsa_sb_common_exit)
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 8a852042a066..32453f81b95a 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -541,7 +541,7 @@ static unsigned char snd_wss_get_rate(unsigned int rate)
}
static unsigned char snd_wss_get_format(struct snd_wss *chip,
- int format,
+ snd_pcm_format_t format,
int channels)
{
unsigned char rformat;
@@ -2279,19 +2279,3 @@ const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction)
&snd_wss_playback_ops : &snd_wss_capture_ops;
}
EXPORT_SYMBOL(snd_wss_get_pcm_ops);
-
-/*
- * INIT part
- */
-
-static int __init alsa_wss_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_wss_exit(void)
-{
-}
-
-module_init(alsa_wss_init);
-module_exit(alsa_wss_exit);
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index 9fb68b35de5a..3ec9391a4736 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -685,7 +685,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
@@ -698,7 +697,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops snd_sgio2audio_capture_ops = {
@@ -711,7 +709,6 @@ static const struct snd_pcm_ops snd_sgio2audio_capture_ops = {
.trigger = snd_sgio2audio_pcm_trigger,
.pointer = snd_sgio2audio_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
/*
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 1ef7cdf1d3e8..f4459d1a9d67 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -2941,19 +2941,3 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
}
EXPORT_SYMBOL(snd_ac97_tune_hardware);
-
-/*
- * INIT part
- */
-
-static int __init alsa_ac97_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ac97_exit(void)
-{
-}
-
-module_init(alsa_ac97_init)
-module_exit(alsa_ac97_exit)
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 39547e32e584..9f569379b77e 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -1484,12 +1484,9 @@ static struct snd_pcm_hardware snd_ali_capture =
static void snd_ali_pcm_free_substream(struct snd_pcm_runtime *runtime)
{
struct snd_ali_voice *pvoice = runtime->private_data;
- struct snd_ali *codec;
- if (pvoice) {
- codec = pvoice->codec;
+ if (pvoice)
snd_ali_free_voice(pvoice->codec, pvoice);
- }
}
static int snd_ali_open(struct snd_pcm_substream *substream, int rec,
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 64e0961f93ba..a31fe1550903 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -311,27 +311,29 @@ static void print_hwparams(struct snd_pcm_substream *substream,
snd_pcm_format_width(params_format(p)) / 8);
}
+#define INVALID_FORMAT (__force snd_pcm_format_t)(-1)
+
static snd_pcm_format_t hpi_to_alsa_formats[] = {
- -1, /* INVALID */
+ INVALID_FORMAT, /* INVALID */
SNDRV_PCM_FORMAT_U8, /* HPI_FORMAT_PCM8_UNSIGNED 1 */
SNDRV_PCM_FORMAT_S16, /* HPI_FORMAT_PCM16_SIGNED 2 */
- -1, /* HPI_FORMAT_MPEG_L1 3 */
+ INVALID_FORMAT, /* HPI_FORMAT_MPEG_L1 3 */
SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L2 4 */
SNDRV_PCM_FORMAT_MPEG, /* HPI_FORMAT_MPEG_L3 5 */
- -1, /* HPI_FORMAT_DOLBY_AC2 6 */
- -1, /* HPI_FORMAT_DOLBY_AC3 7 */
+ INVALID_FORMAT, /* HPI_FORMAT_DOLBY_AC2 6 */
+ INVALID_FORMAT, /* HPI_FORMAT_DOLBY_AC3 7 */
SNDRV_PCM_FORMAT_S16_BE,/* HPI_FORMAT_PCM16_BIGENDIAN 8 */
- -1, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */
- -1, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */
+ INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_HITS 9 */
+ INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_INSERTS 10 */
SNDRV_PCM_FORMAT_S32, /* HPI_FORMAT_PCM32_SIGNED 11 */
- -1, /* HPI_FORMAT_RAW_BITSTREAM 12 */
- -1, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */
+ INVALID_FORMAT, /* HPI_FORMAT_RAW_BITSTREAM 12 */
+ INVALID_FORMAT, /* HPI_FORMAT_AA_TAGIT1_HITS_EX1 13 */
SNDRV_PCM_FORMAT_FLOAT, /* HPI_FORMAT_PCM32_FLOAT 14 */
#if 1
/* ALSA can't handle 3 byte sample size together with power-of-2
* constraint on buffer_bytes, so disable this format
*/
- -1
+ INVALID_FORMAT
#else
/* SNDRV_PCM_FORMAT_S24_3LE */ /* HPI_FORMAT_PCM24_SIGNED 15 */
#endif
@@ -1023,7 +1025,7 @@ static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi,
format, sample_rate, 128000, 0);
if (!err)
err = hpi_outstream_query_format(h_stream, &hpi_format);
- if (!err && (hpi_to_alsa_formats[format] != -1))
+ if (!err && (hpi_to_alsa_formats[format] != INVALID_FORMAT))
formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);
}
return formats;
@@ -1205,7 +1207,7 @@ static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
format, sample_rate, 128000, 0);
if (!err)
err = hpi_instream_query_format(h_stream, &hpi_format);
- if (!err && (hpi_to_alsa_formats[format] != -1))
+ if (!err && (hpi_to_alsa_formats[format] != INVALID_FORMAT))
formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]);
}
return formats;
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
index 8d5abfa4e24b..2864698436a5 100644
--- a/sound/pci/asihpi/hpi6205.c
+++ b/sound/pci/asihpi/hpi6205.c
@@ -635,7 +635,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
{
struct hpi_message hm;
struct hpi_response hr;
- u32 max_streams;
HPI_DEBUG_LOG(VERBOSE, "init ADAPTER_GET_INFO\n");
memset(&hm, 0, sizeof(hm));
@@ -660,10 +659,6 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
pao->type = hr.u.ax.info.adapter_type;
pao->index = hr.u.ax.info.adapter_index;
- max_streams =
- hr.u.ax.info.num_outstreams +
- hr.u.ax.info.num_instreams;
-
HPI_DEBUG_LOG(VERBOSE,
"got adapter info type %x index %d serial %d\n",
hr.u.ax.info.adapter_type, hr.u.ax.info.adapter_index,
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 7ae63d452bba..a1e4944dcfe8 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -207,10 +207,10 @@ struct atiixp;
*/
struct atiixp_dma_desc {
- u32 addr; /* DMA buffer address */
+ __le32 addr; /* DMA buffer address */
u16 status; /* status bits */
u16 size; /* size of the packet in dwords */
- u32 next; /* address of the next packet descriptor */
+ __le32 next; /* address of the next packet descriptor */
};
/*
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index a586635664e0..dc1de860cedf 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -183,10 +183,10 @@ struct atiixp_modem;
*/
struct atiixp_dma_desc {
- u32 addr; /* DMA buffer address */
+ __le32 addr; /* DMA buffer address */
u16 status; /* status bits */
u16 size; /* size of the packet in dwords */
- u32 next; /* address of the next packet descriptor */
+ __le32 next; /* address of the next packet descriptor */
};
/*
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index bcc648bf6478..e3e31f07d766 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -241,7 +241,7 @@ static int vortex_core_init(vortex_t * card);
static int vortex_core_shutdown(vortex_t * card);
static void vortex_enable_int(vortex_t * card);
static irqreturn_t vortex_interrupt(int irq, void *dev_id);
-static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v);
+static int vortex_alsafmt_aspfmt(snd_pcm_format_t alsafmt, vortex_t *v);
/* Connection stuff. */
static void vortex_connect_default(vortex_t * vortex, int en);
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 4083c8b01619..2e5b460a847c 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -2770,7 +2770,7 @@ static int vortex_core_shutdown(vortex_t * vortex)
/* Alsa support. */
-static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v)
+static int vortex_alsafmt_aspfmt(snd_pcm_format_t alsafmt, vortex_t *v)
{
int fmt;
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index d8ade8771a32..ba971042f871 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -228,14 +228,14 @@ static int snd_bt87x_create_risc(struct snd_bt87x *chip, struct snd_pcm_substrea
unsigned int periods, unsigned int period_bytes)
{
unsigned int i, offset;
- u32 *risc;
+ __le32 *risc;
if (chip->dma_risc.area == NULL) {
if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci),
PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0)
return -ENOMEM;
}
- risc = (u32 *)chip->dma_risc.area;
+ risc = (__le32 *)chip->dma_risc.area;
offset = 0;
*risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_FM1);
*risc++ = cpu_to_le32(0);
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index abb01ce66983..8d0a3d357345 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -73,13 +73,10 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
{
struct proc_scb_info * scb_info = entry->private_data;
struct dsp_scb_descriptor * scb = scb_info->scb_desc;
- struct dsp_spos_instance * ins;
struct snd_cs46xx *chip = scb_info->chip;
int j,col;
void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
- ins = chip->dsp_spos_instance;
-
mutex_lock(&chip->spos_mutex);
snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index de409cda50aa..4590086d9cd8 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -192,8 +192,6 @@ static void process_bm0_irq(struct cs5535audio *cs5535au)
bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS);
spin_unlock(&cs5535au->reg_lock);
if (bm_stat & EOP) {
- struct cs5535audio_dma *dma;
- dma = cs5535au->playback_substream->runtime->private_data;
snd_pcm_period_elapsed(cs5535au->playback_substream);
} else {
dev_err(cs5535au->card->dev,
@@ -208,11 +206,8 @@ static void process_bm1_irq(struct cs5535audio *cs5535au)
spin_lock(&cs5535au->reg_lock);
bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS);
spin_unlock(&cs5535au->reg_lock);
- if (bm_stat & EOP) {
- struct cs5535audio_dma *dma;
- dma = cs5535au->capture_substream->runtime->private_data;
+ if (bm_stat & EOP)
snd_pcm_period_elapsed(cs5535au->capture_substream);
- }
}
static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h
index f4fcdf93f3c8..d84620a0c26c 100644
--- a/sound/pci/cs5535audio/cs5535audio.h
+++ b/sound/pci/cs5535audio/cs5535audio.h
@@ -67,9 +67,9 @@ struct cs5535audio_dma_ops {
};
struct cs5535audio_dma_desc {
- u32 addr;
- u16 size;
- u16 ctlreserved;
+ __le32 addr;
+ __le16 size;
+ __le16 ctlreserved;
};
struct cs5535audio_dma {
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c
index ee7065f6e162..326caec854e1 100644
--- a/sound/pci/cs5535audio/cs5535audio_pcm.c
+++ b/sound/pci/cs5535audio/cs5535audio_pcm.c
@@ -158,8 +158,8 @@ static int cs5535audio_build_dma_packets(struct cs5535audio *cs5535au,
lastdesc->addr = cpu_to_le32((u32) dma->desc_buf.addr);
lastdesc->size = 0;
lastdesc->ctlreserved = cpu_to_le16(PRD_JMP);
- jmpprd_addr = cpu_to_le32(lastdesc->addr +
- (sizeof(struct cs5535audio_dma_desc)*periods));
+ jmpprd_addr = (u32)dma->desc_buf.addr +
+ sizeof(struct cs5535audio_dma_desc) * periods;
dma->substream = substream;
dma->period_bytes = period_bytes;
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 8e6eb9d7984b..6a051a1c3724 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1319,7 +1319,7 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
break;
hw_write_20kx(hw, PLLCTL, pllctl);
- mdelay(40);
+ msleep(40);
}
if (i >= 3) {
dev_alert(hw->card->dev, "PLL initialization failed!!!\n");
@@ -1407,7 +1407,7 @@ static int hw_reset_dac(struct hw *hw)
/* To be effective, need to reset the DAC twice. */
for (i = 0; i < 2; i++) {
/* set gpio */
- mdelay(100);
+ msleep(100);
gpioorg = (u16)hw_read_20kx(hw, GPIO);
gpioorg &= 0xfffd;
hw_write_20kx(hw, GPIO, gpioorg);
@@ -2030,7 +2030,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
hw_write_20kx(hw, GIE, 0);
/* Reset all SRC pending interrupts */
hw_write_20kx(hw, SRCIP, 0);
- mdelay(30);
+ msleep(30);
/* Detect the card ID and configure GPIO accordingly. */
switch (hw->model) {
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index b866d6b2c923..3c966fafc754 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -1316,12 +1316,12 @@ static int hw_pll_init(struct hw *hw, unsigned int rsr)
set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 4 : 147 - 4);
set_field(&pllctl, PLLCTL_RD, 48000 == rsr ? 1 - 1 : 10 - 1);
hw_write_20kx(hw, PLL_CTL, pllctl);
- mdelay(40);
+ msleep(40);
pllctl = hw_read_20kx(hw, PLL_CTL);
set_field(&pllctl, PLLCTL_FD, 48000 == rsr ? 16 - 2 : 147 - 2);
hw_write_20kx(hw, PLL_CTL, pllctl);
- mdelay(40);
+ msleep(40);
for (i = 0; i < 1000; i++) {
pllstat = hw_read_20kx(hw, PLL_STAT);
@@ -1584,7 +1584,7 @@ static void hw_dac_stop(struct hw *hw)
data = hw_read_20kx(hw, GPIO_DATA);
data &= 0xFFFFFFFD;
hw_write_20kx(hw, GPIO_DATA, data);
- mdelay(10);
+ usleep_range(10000, 11000);
}
static void hw_dac_start(struct hw *hw)
@@ -1593,7 +1593,7 @@ static void hw_dac_start(struct hw *hw)
data = hw_read_20kx(hw, GPIO_DATA);
data |= 0x2;
hw_write_20kx(hw, GPIO_DATA, data);
- mdelay(50);
+ msleep(50);
}
static void hw_dac_reset(struct hw *hw)
@@ -1864,11 +1864,11 @@ static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
hw_write_20kx(hw, GPIO_DATA, data);
}
- mdelay(10);
+ usleep_range(10000, 11000);
/* Return the ADC to normal operation. */
data |= (0x1 << 15);
hw_write_20kx(hw, GPIO_DATA, data);
- mdelay(50);
+ msleep(50);
/* I2C write to register offset 0x0B to set ADC LRCLK polarity */
/* invert bit, interface format to I2S, word length to 24-bit, */
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c
index db710d0a609f..4777d50fbbf8 100644
--- a/sound/pci/ctxfi/ctmixer.c
+++ b/sound/pci/ctxfi/ctmixer.c
@@ -938,17 +938,18 @@ static int ct_mixer_topology_build(struct ct_mixer *mixer)
struct sum *sum;
struct amixer *amix_d, *amix_s;
enum CT_AMIXER_CTL i, j;
+ enum CT_SUM_CTL k;
/* Build topology from destination to source */
/* Set up Master mixer */
- for (i = AMIXER_MASTER_F, j = SUM_IN_F;
- i <= AMIXER_MASTER_S; i++, j++) {
+ for (i = AMIXER_MASTER_F, k = SUM_IN_F;
+ i <= AMIXER_MASTER_S; i++, k++) {
amix_d = mixer->amixers[i*CHN_NUM];
- sum = mixer->sums[j*CHN_NUM];
+ sum = mixer->sums[k*CHN_NUM];
amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
amix_d = mixer->amixers[i*CHN_NUM+1];
- sum = mixer->sums[j*CHN_NUM+1];
+ sum = mixer->sums[k*CHN_NUM+1];
amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
}
@@ -972,12 +973,12 @@ static int ct_mixer_topology_build(struct ct_mixer *mixer)
amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
/* Set up PCM-in mixer */
- for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) {
+ for (i = AMIXER_PCM_F, k = SUM_IN_F; i <= AMIXER_PCM_S; i++, k++) {
amix_d = mixer->amixers[i*CHN_NUM];
- sum = mixer->sums[j*CHN_NUM];
+ sum = mixer->sums[k*CHN_NUM];
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
amix_d = mixer->amixers[i*CHN_NUM+1];
- sum = mixer->sums[j*CHN_NUM+1];
+ sum = mixer->sums[k*CHN_NUM+1];
amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
}
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 358ef7dcf410..907cf1a46712 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -713,6 +713,7 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
break;
case SNDRV_PCM_FORMAT_S32_BE:
format.data_are_bigendian = 1;
+ /* fall through */
case SNDRV_PCM_FORMAT_S32_LE:
format.bits_per_sample = 32;
break;
@@ -764,6 +765,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
pipe->last_counter = 0;
pipe->position = 0;
*pipe->dma_counter = 0;
+ /* fall through */
case PIPE_STATE_PAUSED:
pipe->state = PIPE_STATE_STARTED;
break;
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index 44b390a667d5..be4d0489394a 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -294,7 +294,7 @@
struct audiopipe {
- volatile u32 *dma_counter; /* Commpage register that contains
+ volatile __le32 *dma_counter; /* Commpage register that contains
* the current dma position
* (lower 32 bits only)
*/
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index 22c786b8a889..cc3c79387194 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -73,19 +73,21 @@ register. write_control_reg sends the new control register value to the DSP. */
static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
char force)
{
+ __le32 ctl_reg, frq_reg;
+
if (wait_handshake(chip))
return -EIO;
dev_dbg(chip->card->dev,
"WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq);
- ctl = cpu_to_le32(ctl);
- frq = cpu_to_le32(frq);
+ ctl_reg = cpu_to_le32(ctl);
+ frq_reg = cpu_to_le32(frq);
- if (ctl != chip->comm_page->control_register ||
- frq != chip->comm_page->e3g_frq_register || force) {
- chip->comm_page->e3g_frq_register = frq;
- chip->comm_page->control_register = ctl;
+ if (ctl_reg != chip->comm_page->control_register ||
+ frq_reg != chip->comm_page->e3g_frq_register || force) {
+ chip->comm_page->e3g_frq_register = frq_reg;
+ chip->comm_page->control_register = ctl_reg;
clear_handshake(chip);
return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
}
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index 15aae2fad8e4..b181752b8481 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -679,7 +679,7 @@ static int restore_dsp_rettings(struct echoaudio *chip)
/* Gina20/Darla20 only. Should be harmless for other cards. */
chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF;
chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF;
- chip->comm_page->handshake = 0xffffffff;
+ chip->comm_page->handshake = cpu_to_le32(0xffffffff);
/* Restore output busses */
for (i = 0; i < num_busses_out(chip); i++) {
@@ -989,7 +989,7 @@ static int init_dsp_comm_page(struct echoaudio *chip)
/* Init the comm page */
chip->comm_page->comm_size =
cpu_to_le32(sizeof(struct comm_page));
- chip->comm_page->handshake = 0xffffffff;
+ chip->comm_page->handshake = cpu_to_le32(0xffffffff);
chip->comm_page->midi_out_free_count =
cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
chip->comm_page->sample_rate = cpu_to_le32(44100);
@@ -1087,7 +1087,7 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
/* The counter register is where the DSP writes the 32 bit DMA
position for a pipe. The DSP is constantly updating this value as
it moves data. The DMA counter is in units of bytes, not samples. */
- pipe->dma_counter = &chip->comm_page->position[pipe_index];
+ pipe->dma_counter = (__le32 *)&chip->comm_page->position[pipe_index];
*pipe->dma_counter = 0;
return pipe_index;
}
diff --git a/sound/pci/echoaudio/echoaudio_dsp.h b/sound/pci/echoaudio/echoaudio_dsp.h
index cb7d75a0a503..aa9129519795 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.h
+++ b/sound/pci/echoaudio/echoaudio_dsp.h
@@ -627,8 +627,8 @@ sg_entry struct is read by the DSP, so all values must be little-endian. */
#define MAX_SGLIST_ENTRIES 512
struct sg_entry {
- u32 addr;
- u32 size;
+ __le32 addr;
+ __le32 size;
};
@@ -643,18 +643,18 @@ struct sg_entry {
****************************************************************************/
struct comm_page { /* Base Length*/
- u32 comm_size; /* size of this object 0x000 4 */
- u32 flags; /* See Appendix A below 0x004 4 */
- u32 unused; /* Unused entry 0x008 4 */
- u32 sample_rate; /* Card sample rate in Hz 0x00c 4 */
- u32 handshake; /* DSP command handshake 0x010 4 */
- u32 cmd_start; /* Chs. to start mask 0x014 4 */
- u32 cmd_stop; /* Chs. to stop mask 0x018 4 */
- u32 cmd_reset; /* Chs. to reset mask 0x01c 4 */
- u16 audio_format[DSP_MAXPIPES]; /* Chs. audio format 0x020 32*2 */
+ __le32 comm_size; /* size of this object 0x000 4 */
+ __le32 flags; /* See Appendix A below 0x004 4 */
+ __le32 unused; /* Unused entry 0x008 4 */
+ __le32 sample_rate; /* Card sample rate in Hz 0x00c 4 */
+ __le32 handshake; /* DSP command handshake 0x010 4 */
+ __le32 cmd_start; /* Chs. to start mask 0x014 4 */
+ __le32 cmd_stop; /* Chs. to stop mask 0x018 4 */
+ __le32 cmd_reset; /* Chs. to reset mask 0x01c 4 */
+ __le16 audio_format[DSP_MAXPIPES]; /* Chs. audio format 0x020 32*2 */
struct sg_entry sglist_addr[DSP_MAXPIPES];
/* Chs. Physical sglist addrs 0x060 32*8 */
- u32 position[DSP_MAXPIPES];
+ __le32 position[DSP_MAXPIPES];
/* Positions for ea. ch. 0x160 32*4 */
s8 vu_meter[DSP_MAXPIPES];
/* VU meters 0x1e0 32*1 */
@@ -666,28 +666,28 @@ struct comm_page { /* Base Length*/
/* Input gain 0x230 16*1 */
s8 monitors[MONITOR_ARRAY_SIZE];
/* Monitor map 0x240 0x180 */
- u32 play_coeff[MAX_PLAY_TAPS];
+ __le32 play_coeff[MAX_PLAY_TAPS];
/* Gina/Darla play filters - obsolete 0x3c0 168*4 */
- u32 rec_coeff[MAX_REC_TAPS];
+ __le32 rec_coeff[MAX_REC_TAPS];
/* Gina/Darla record filters - obsolete 0x660 192*4 */
- u16 midi_input[MIDI_IN_BUFFER_SIZE];
+ __le16 midi_input[MIDI_IN_BUFFER_SIZE];
/* MIDI input data transfer buffer 0x960 256*2 */
u8 gd_clock_state; /* Chg Gina/Darla clock state 0xb60 1 */
u8 gd_spdif_status; /* Chg. Gina/Darla S/PDIF state 0xb61 1 */
u8 gd_resampler_state; /* Should always be 3 0xb62 1 */
u8 filler2; /* 0xb63 1 */
- u32 nominal_level_mask; /* -10 level enable mask 0xb64 4 */
- u16 input_clock; /* Chg. Input clock state 0xb68 2 */
- u16 output_clock; /* Chg. Output clock state 0xb6a 2 */
- u32 status_clocks; /* Current Input clock state 0xb6c 4 */
- u32 ext_box_status; /* External box status 0xb70 4 */
- u32 cmd_add_buffer; /* Pipes to add (obsolete) 0xb74 4 */
- u32 midi_out_free_count;
+ __le32 nominal_level_mask; /* -10 level enable mask 0xb64 4 */
+ __le16 input_clock; /* Chg. Input clock state 0xb68 2 */
+ __le16 output_clock; /* Chg. Output clock state 0xb6a 2 */
+ __le32 status_clocks; /* Current Input clock state 0xb6c 4 */
+ __le32 ext_box_status; /* External box status 0xb70 4 */
+ __le32 cmd_add_buffer; /* Pipes to add (obsolete) 0xb74 4 */
+ __le32 midi_out_free_count;
/* # of bytes free in MIDI output FIFO 0xb78 4 */
- u32 unused2; /* Cyclic pipes 0xb7c 4 */
- u32 control_register;
+ __le32 unused2; /* Cyclic pipes 0xb7c 4 */
+ __le32 control_register;
/* Mona, Gina24, Layla24, 3G ctrl reg 0xb80 4 */
- u32 e3g_frq_register; /* 3G frequency register 0xb84 4 */
+ __le32 e3g_frq_register; /* 3G frequency register 0xb84 4 */
u8 filler[24]; /* filler 0xb88 24*1 */
s8 vmixer[VMIXER_ARRAY_SIZE];
/* Vmixer levels 0xba0 64*1 */
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c
index 834b39e97db7..eea6fe530ab4 100644
--- a/sound/pci/echoaudio/echoaudio_gml.c
+++ b/sound/pci/echoaudio/echoaudio_gml.c
@@ -63,6 +63,8 @@ the control register. write_control_reg sends the new control register
value to the DSP. */
static int write_control_reg(struct echoaudio *chip, u32 value, char force)
{
+ __le32 reg_value;
+
/* Handle the digital input auto-mute */
if (chip->digital_in_automute)
value |= GML_DIGITAL_IN_AUTO_MUTE;
@@ -72,11 +74,11 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force)
dev_dbg(chip->card->dev, "write_control_reg: 0x%x\n", value);
/* Write the control register */
- value = cpu_to_le32(value);
- if (value != chip->comm_page->control_register || force) {
+ reg_value = cpu_to_le32(value);
+ if (reg_value != chip->comm_page->control_register || force) {
if (wait_handshake(chip))
return -EIO;
- chip->comm_page->control_register = value;
+ chip->comm_page->control_register = reg_value;
clear_handshake(chip);
return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
}
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 0e069aeab86d..c32eb7053715 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -70,11 +70,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
loopend = sampleend;
/* be sure loop points start < end */
- if (sp->v.loopstart >= sp->v.loopend) {
- int tmp = sp->v.loopstart;
- sp->v.loopstart = sp->v.loopend;
- sp->v.loopend = tmp;
- }
+ if (sp->v.loopstart >= sp->v.loopend)
+ swap(sp->v.loopstart, sp->v.loopend);
/* compute true data size to be loaded */
truesize = sp->v.size + BLANK_HEAD_SIZE;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index de2ecbe95d6c..90713741c2dc 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -526,7 +526,7 @@ static int snd_emu10k1_gpr_poke(struct snd_emu10k1 *emu,
if (!test_bit(gpr, icode->gpr_valid))
continue;
if (in_kernel)
- val = *(u32 *)&icode->gpr_map[gpr];
+ val = *(__force u32 *)&icode->gpr_map[gpr];
else if (get_user(val, &icode->gpr_map[gpr]))
return -EFAULT;
snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val);
@@ -560,8 +560,8 @@ static int snd_emu10k1_tram_poke(struct snd_emu10k1 *emu,
if (!test_bit(tram, icode->tram_valid))
continue;
if (in_kernel) {
- val = *(u32 *)&icode->tram_data_map[tram];
- addr = *(u32 *)&icode->tram_addr_map[tram];
+ val = *(__force u32 *)&icode->tram_data_map[tram];
+ addr = *(__force u32 *)&icode->tram_addr_map[tram];
} else {
if (get_user(val, &icode->tram_data_map[tram]) ||
get_user(addr, &icode->tram_addr_map[tram]))
@@ -611,8 +611,8 @@ static int snd_emu10k1_code_poke(struct snd_emu10k1 *emu,
if (!test_bit(pc / 2, icode->code_valid))
continue;
if (in_kernel) {
- lo = *(u32 *)&icode->code[pc + 0];
- hi = *(u32 *)&icode->code[pc + 1];
+ lo = *(__force u32 *)&icode->code[pc + 0];
+ hi = *(__force u32 *)&icode->code[pc + 1];
} else {
if (get_user(lo, &icode->code[pc + 0]) ||
get_user(hi, &icode->code[pc + 1]))
@@ -666,7 +666,7 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel)
if (!_tlv)
return NULL;
if (in_kernel)
- memcpy(data, (void *)_tlv, sizeof(data));
+ memcpy(data, (__force void *)_tlv, sizeof(data));
else if (copy_from_user(data, _tlv, sizeof(data)))
return NULL;
if (data[1] >= MAX_TLV_SIZE)
@@ -676,7 +676,7 @@ static unsigned int *copy_tlv(const unsigned int __user *_tlv, bool in_kernel)
return NULL;
memcpy(tlv, data, sizeof(data));
if (in_kernel) {
- memcpy(tlv + 2, (void *)(_tlv + 2), data[1]);
+ memcpy(tlv + 2, (__force void *)(_tlv + 2), data[1]);
} else if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
kfree(tlv);
return NULL;
@@ -693,7 +693,7 @@ static int copy_gctl(struct snd_emu10k1 *emu,
if (emu->support_tlv) {
if (in_kernel)
- memcpy(gctl, (void *)&_gctl[idx], sizeof(*gctl));
+ memcpy(gctl, (__force void *)&_gctl[idx], sizeof(*gctl));
else if (copy_from_user(gctl, &_gctl[idx], sizeof(*gctl)))
return -EFAULT;
return 0;
@@ -701,7 +701,7 @@ static int copy_gctl(struct snd_emu10k1 *emu,
octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
if (in_kernel)
- memcpy(gctl, (void *)&octl[idx], sizeof(*octl));
+ memcpy(gctl, (__force void *)&octl[idx], sizeof(*octl));
else if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
return -EFAULT;
gctl->tlv = NULL;
@@ -735,7 +735,7 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
for (i = 0, _id = icode->gpr_del_controls;
i < icode->gpr_del_control_count; i++, _id++) {
if (in_kernel)
- id = *(struct snd_ctl_elem_id *)_id;
+ id = *(__force struct snd_ctl_elem_id *)_id;
else if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
if (snd_emu10k1_look_for_ctl(emu, &id) == NULL)
@@ -833,7 +833,7 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
knew.device = gctl->id.device;
knew.subdevice = gctl->id.subdevice;
knew.info = snd_emu10k1_gpr_ctl_info;
- knew.tlv.p = copy_tlv(gctl->tlv, in_kernel);
+ knew.tlv.p = copy_tlv((__force const unsigned int __user *)gctl->tlv, in_kernel);
if (knew.tlv.p)
knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ;
@@ -897,7 +897,7 @@ static int snd_emu10k1_del_controls(struct snd_emu10k1 *emu,
for (i = 0, _id = icode->gpr_del_controls;
i < icode->gpr_del_control_count; i++, _id++) {
if (in_kernel)
- id = *(struct snd_ctl_elem_id *)_id;
+ id = *(__force struct snd_ctl_elem_id *)_id;
else if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT;
down_write(&card->controls_rwsem);
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 69f9b100bd24..9f2b6097f486 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -290,7 +290,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
struct snd_pcm_runtime *runtime = substream->runtime;
unsigned int silent_page, tmp;
int voice, stereo, w_16;
- unsigned char attn, send_amount[8];
+ unsigned char send_amount[8];
unsigned char send_routing[8];
unsigned long flags;
unsigned int pitch_target;
@@ -313,7 +313,6 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
/* volume parameters */
if (extra) {
- attn = 0;
memset(send_routing, 0, sizeof(send_routing));
send_routing[0] = 0;
send_routing[1] = 1;
@@ -779,7 +778,7 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START:
snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); /* do we need this? */
snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]);
- /* follow thru */
+ /* fall through */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
@@ -929,7 +928,7 @@ static int snd_emu10k1_efx_playback_trigger(struct snd_pcm_substream *substream,
}
snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra);
- /* follow thru */
+ /* fall through */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 39f79a6b5283..727eb3da1fda 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -2392,7 +2392,7 @@ static int snd_audiopci_probe(struct pci_dev *pci,
static int dev;
struct snd_card *card;
struct ensoniq *ensoniq;
- int err, pcm_devs[2];
+ int err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
@@ -2412,7 +2412,6 @@ static int snd_audiopci_probe(struct pci_dev *pci,
}
card->private_data = ensoniq;
- pcm_devs[0] = 0; pcm_devs[1] = 1;
#ifdef CHIP1370
if ((err = snd_ensoniq_1370_mixer(ensoniq)) < 0) {
snd_card_free(card);
diff --git a/sound/pci/hda/dell_wmi_helper.c b/sound/pci/hda/dell_wmi_helper.c
index 1b48a8c19d28..bbd6c87a4ed6 100644
--- a/sound/pci/hda/dell_wmi_helper.c
+++ b/sound/pci/hda/dell_wmi_helper.c
@@ -6,111 +6,18 @@
#if IS_ENABLED(CONFIG_DELL_LAPTOP)
#include <linux/dell-led.h>
-enum {
- MICMUTE_LED_ON,
- MICMUTE_LED_OFF,
- MICMUTE_LED_FOLLOW_CAPTURE,
- MICMUTE_LED_FOLLOW_MUTE,
-};
-
-static int dell_led_mode = MICMUTE_LED_FOLLOW_MUTE;
-static int dell_capture;
-static int dell_led_value;
static int (*dell_micmute_led_set_func)(int);
-static void (*dell_old_cap_hook)(struct hda_codec *,
- struct snd_kcontrol *,
- struct snd_ctl_elem_value *);
-
-static void call_micmute_led_update(void)
-{
- int val;
-
- switch (dell_led_mode) {
- case MICMUTE_LED_ON:
- val = 1;
- break;
- case MICMUTE_LED_OFF:
- val = 0;
- break;
- case MICMUTE_LED_FOLLOW_CAPTURE:
- val = dell_capture;
- break;
- case MICMUTE_LED_FOLLOW_MUTE:
- default:
- val = !dell_capture;
- break;
- }
-
- if (val == dell_led_value)
- return;
- dell_led_value = val;
- dell_micmute_led_set_func(dell_led_value);
-}
-
-static void update_dell_wmi_micmute_led(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- if (dell_old_cap_hook)
- dell_old_cap_hook(codec, kcontrol, ucontrol);
-
- if (!ucontrol || !dell_micmute_led_set_func)
- return;
- if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
- /* TODO: How do I verify if it's a mono or stereo here? */
- dell_capture = (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
- call_micmute_led_update();
- }
-}
-static int dell_mic_mute_led_mode_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static void dell_micmute_update(struct hda_codec *codec)
{
- static const char * const texts[] = {
- "On", "Off", "Follow Capture", "Follow Mute",
- };
-
- return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
-}
+ struct hda_gen_spec *spec = codec->spec;
-static int dell_mic_mute_led_mode_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.enumerated.item[0] = dell_led_mode;
- return 0;
+ dell_micmute_led_set_func(spec->micmute_led.led_value);
}
-static int dell_mic_mute_led_mode_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- unsigned int mode;
-
- mode = ucontrol->value.enumerated.item[0];
- if (mode > MICMUTE_LED_FOLLOW_MUTE)
- mode = MICMUTE_LED_FOLLOW_MUTE;
- if (mode == dell_led_mode)
- return 0;
- dell_led_mode = mode;
- call_micmute_led_update();
- return 1;
-}
-
-static const struct snd_kcontrol_new dell_mic_mute_mode_ctls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Mic Mute-LED Mode",
- .info = dell_mic_mute_led_mode_info,
- .get = dell_mic_mute_led_mode_get,
- .put = dell_mic_mute_led_mode_put,
- },
- {}
-};
-
static void alc_fixup_dell_wmi(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
bool removefunc = false;
if (action == HDA_FIXUP_ACT_PROBE) {
@@ -121,25 +28,14 @@ static void alc_fixup_dell_wmi(struct hda_codec *codec,
return;
}
- removefunc = true;
- if (dell_micmute_led_set_func(false) >= 0) {
- dell_led_value = 0;
- if (spec->gen.num_adc_nids > 1 && !spec->gen.dyn_adc_switch)
- codec_dbg(codec, "Skipping micmute LED control due to several ADCs");
- else {
- dell_old_cap_hook = spec->gen.cap_sync_hook;
- spec->gen.cap_sync_hook = update_dell_wmi_micmute_led;
- removefunc = false;
- add_mixer(spec, dell_mic_mute_mode_ctls);
- }
- }
-
+ removefunc = (dell_micmute_led_set_func(false) < 0) ||
+ (snd_hda_gen_add_micmute_led(codec,
+ dell_micmute_update) < 0);
}
if (dell_micmute_led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
symbol_put(dell_micmute_led_set);
dell_micmute_led_set_func = NULL;
- dell_old_cap_hook = NULL;
}
}
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index d91c87e41756..0a5085537034 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -37,15 +37,8 @@
#include "hda_jack.h"
#include <sound/hda_hwdep.h>
-#ifdef CONFIG_PM
-#define codec_in_pm(codec) atomic_read(&(codec)->core.in_pm)
-#define hda_codec_is_power_on(codec) \
- (!pm_runtime_suspended(hda_codec_dev(codec)))
-#else
-#define codec_in_pm(codec) 0
-#define hda_codec_is_power_on(codec) 1
-#endif
-
+#define codec_in_pm(codec) snd_hdac_is_in_pm(&codec->core)
+#define hda_codec_is_power_on(codec) snd_hdac_is_power_on(&codec->core)
#define codec_has_epss(codec) \
((codec)->core.power_caps & AC_PWRST_EPSS)
#define codec_has_clkstop(codec) \
@@ -858,6 +851,39 @@ static void snd_hda_codec_dev_release(struct device *dev)
kfree(codec);
}
+#define DEV_NAME_LEN 31
+
+static int snd_hda_codec_device_init(struct hda_bus *bus, struct snd_card *card,
+ unsigned int codec_addr, struct hda_codec **codecp)
+{
+ char name[DEV_NAME_LEN];
+ struct hda_codec *codec;
+ int err;
+
+ dev_dbg(card->dev, "%s: entry\n", __func__);
+
+ if (snd_BUG_ON(!bus))
+ return -EINVAL;
+ if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
+ return -EINVAL;
+
+ codec = kzalloc(sizeof(*codec), GFP_KERNEL);
+ if (!codec)
+ return -ENOMEM;
+
+ sprintf(name, "hdaudioC%dD%d", card->number, codec_addr);
+ err = snd_hdac_device_init(&codec->core, &bus->core, name, codec_addr);
+ if (err < 0) {
+ kfree(codec);
+ return err;
+ }
+
+ codec->core.type = HDA_DEV_LEGACY;
+ *codecp = codec;
+
+ return err;
+}
+
/**
* snd_hda_codec_new - create a HDA codec
* @bus: the bus to assign
@@ -869,7 +895,19 @@ static void snd_hda_codec_dev_release(struct device *dev)
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
unsigned int codec_addr, struct hda_codec **codecp)
{
- struct hda_codec *codec;
+ int ret;
+
+ ret = snd_hda_codec_device_init(bus, card, codec_addr, codecp);
+ if (ret < 0)
+ return ret;
+
+ return snd_hda_codec_device_new(bus, card, codec_addr, *codecp);
+}
+EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+
+int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
+ unsigned int codec_addr, struct hda_codec *codec)
+{
char component[31];
hda_nid_t fg;
int err;
@@ -879,25 +917,14 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
.dev_free = snd_hda_codec_dev_free,
};
+ dev_dbg(card->dev, "%s: entry\n", __func__);
+
if (snd_BUG_ON(!bus))
return -EINVAL;
if (snd_BUG_ON(codec_addr > HDA_MAX_CODEC_ADDRESS))
return -EINVAL;
- codec = kzalloc(sizeof(*codec), GFP_KERNEL);
- if (!codec)
- return -ENOMEM;
-
- sprintf(component, "hdaudioC%dD%d", card->number, codec_addr);
- err = snd_hdac_device_init(&codec->core, &bus->core, component,
- codec_addr);
- if (err < 0) {
- kfree(codec);
- return err;
- }
-
codec->core.dev.release = snd_hda_codec_dev_release;
- codec->core.type = HDA_DEV_LEGACY;
codec->core.exec_verb = codec_exec_verb;
codec->bus = bus;
@@ -957,15 +984,13 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
if (err < 0)
goto error;
- if (codecp)
- *codecp = codec;
return 0;
error:
put_device(hda_codec_dev(codec));
return err;
}
-EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+EXPORT_SYMBOL_GPL(snd_hda_codec_device_new);
/**
* snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
@@ -2846,14 +2871,13 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
{
unsigned int state;
- atomic_inc(&codec->core.in_pm);
-
+ snd_hdac_enter_pm(&codec->core);
if (codec->patch_ops.suspend)
codec->patch_ops.suspend(codec);
hda_cleanup_all_streams(codec);
state = hda_set_power_state(codec, AC_PWRST_D3);
update_power_acct(codec, true);
- atomic_dec(&codec->core.in_pm);
+ snd_hdac_leave_pm(&codec->core);
return state;
}
@@ -2862,8 +2886,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
*/
static void hda_call_codec_resume(struct hda_codec *codec)
{
- atomic_inc(&codec->core.in_pm);
-
+ snd_hdac_enter_pm(&codec->core);
if (codec->core.regmap)
regcache_mark_dirty(codec->core.regmap);
@@ -2886,7 +2909,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
hda_jackpoll_work(&codec->jackpoll_work.work);
else
snd_hda_jack_report_sync(codec);
- atomic_dec(&codec->core.in_pm);
+ snd_hdac_leave_pm(&codec->core);
}
static int hda_codec_runtime_suspend(struct device *dev)
@@ -2899,8 +2922,9 @@ static int hda_codec_runtime_suspend(struct device *dev)
list_for_each_entry(pcm, &codec->pcm_list_head, list)
snd_pcm_suspend_all(pcm->pcm);
state = hda_call_codec_suspend(codec);
- if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
- (state & AC_PWRST_CLK_STOP_OK))
+ if (codec->link_down_at_suspend ||
+ (codec_has_clkstop(codec) && codec_has_epss(codec) &&
+ (state & AC_PWRST_CLK_STOP_OK)))
snd_hdac_codec_link_down(&codec->core);
snd_hdac_link_power(&codec->core, false);
return 0;
@@ -2991,6 +3015,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec)
sync_power_up_states(codec);
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_build_controls);
/*
* PCM stuff
@@ -3196,6 +3221,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
return 0;
}
+EXPORT_SYMBOL_GPL(snd_hda_codec_parse_pcms);
/* assign all PCMs of the given codec */
int snd_hda_codec_build_pcms(struct hda_codec *codec)
@@ -3251,8 +3277,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec,
for (; knew->name; knew++) {
struct snd_kcontrol *kctl;
int addr = 0, idx = 0;
- if (knew->iface == -1) /* skip this codec private value */
- continue;
+ if (knew->iface == (__force snd_ctl_elem_iface_t)-1)
+ continue; /* skip this codec private value */
for (;;) {
kctl = snd_ctl_new1(knew, codec);
if (!kctl)
@@ -3842,7 +3868,7 @@ EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl);
* This function is a helper to set a pin ctl value more safely.
* It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the
* value in pin target array via snd_hda_codec_set_pin_target(), then
- * actually writes the value via either snd_hda_codec_update_cache() or
+ * actually writes the value via either snd_hda_codec_write_cache() or
* snd_hda_codec_write() depending on @cached flag.
*/
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
@@ -3851,7 +3877,7 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
val = snd_hda_correct_pin_ctl(codec, pin, val);
snd_hda_codec_set_pin_target(codec, pin, val);
if (cached)
- return snd_hda_codec_update_cache(codec, pin, 0,
+ return snd_hda_codec_write_cache(codec, pin, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, val);
else
return snd_hda_codec_write(codec, pin, 0,
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 681c360f29f9..0d98bb9068b1 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -84,6 +84,7 @@ struct hda_bus {
*/
typedef int (*hda_codec_patch_t)(struct hda_codec *);
+#define HDA_CODEC_ID_SKIP_PROBE 0x00000001
#define HDA_CODEC_ID_GENERIC_HDMI 0x00000101
#define HDA_CODEC_ID_GENERIC 0x00000201
@@ -258,6 +259,7 @@ struct hda_codec {
unsigned int power_save_node:1; /* advanced PM for each widget */
unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
unsigned int force_pin_prefix:1; /* Add location prefix */
+ unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
#ifdef CONFIG_PM
unsigned long power_on_acct;
unsigned long power_off_acct;
@@ -307,6 +309,8 @@ struct hda_codec {
*/
int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card,
unsigned int codec_addr, struct hda_codec **codecp);
+int snd_hda_codec_device_new(struct hda_bus *bus, struct snd_card *card,
+ unsigned int codec_addr, struct hda_codec *codec);
int snd_hda_codec_configure(struct hda_codec *codec);
int snd_hda_codec_update_widgets(struct hda_codec *codec);
@@ -381,9 +385,6 @@ snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
return snd_hdac_regmap_write(&codec->core, nid, verb, parm);
}
-#define snd_hda_codec_update_cache(codec, nid, flags, verb, parm) \
- snd_hda_codec_write_cache(codec, nid, flags, verb, parm)
-
/* the struct for codec->pin_configs */
struct hda_pincfg {
hda_nid_t nid;
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index db773e219aaa..579984ecdec3 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -209,7 +209,7 @@ static void parse_user_hints(struct hda_codec *codec)
*/
#define update_pin_ctl(codec, pin, val) \
- snd_hda_codec_update_cache(codec, pin, 0, \
+ snd_hda_codec_write_cache(codec, pin, 0, \
AC_VERB_SET_PIN_WIDGET_CONTROL, val)
/* restore the pinctl based on the cached value */
@@ -898,7 +898,7 @@ void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
hda_nid_t nid = path->path[i];
if (enable && path->multi[i])
- snd_hda_codec_update_cache(codec, nid, 0,
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_CONNECT_SEL,
path->idx[i]);
if (has_amp_in(codec, path, i))
@@ -930,7 +930,7 @@ static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
return;
if (codec->inv_eapd)
enable = !enable;
- snd_hda_codec_update_cache(codec, pin, 0,
+ snd_hda_codec_write_cache(codec, pin, 0,
AC_VERB_SET_EAPD_BTLENABLE,
enable ? 0x02 : 0x00);
}
@@ -3900,6 +3900,142 @@ static int parse_mic_boost(struct hda_codec *codec)
}
/*
+ * mic mute LED hook helpers
+ */
+enum {
+ MICMUTE_LED_ON,
+ MICMUTE_LED_OFF,
+ MICMUTE_LED_FOLLOW_CAPTURE,
+ MICMUTE_LED_FOLLOW_MUTE,
+};
+
+static void call_micmute_led_update(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int val;
+
+ switch (spec->micmute_led.led_mode) {
+ case MICMUTE_LED_ON:
+ val = 1;
+ break;
+ case MICMUTE_LED_OFF:
+ val = 0;
+ break;
+ case MICMUTE_LED_FOLLOW_CAPTURE:
+ val = !!spec->micmute_led.capture;
+ break;
+ case MICMUTE_LED_FOLLOW_MUTE:
+ default:
+ val = !spec->micmute_led.capture;
+ break;
+ }
+
+ if (val == spec->micmute_led.led_value)
+ return;
+ spec->micmute_led.led_value = val;
+ if (spec->micmute_led.update)
+ spec->micmute_led.update(codec);
+}
+
+static void update_micmute_led(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int mask;
+
+ if (spec->micmute_led.old_hook)
+ spec->micmute_led.old_hook(codec, kcontrol, ucontrol);
+
+ if (!ucontrol)
+ return;
+ mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ if (!strcmp("Capture Switch", ucontrol->id.name)) {
+ /* TODO: How do I verify if it's a mono or stereo here? */
+ if (ucontrol->value.integer.value[0] ||
+ ucontrol->value.integer.value[1])
+ spec->micmute_led.capture |= mask;
+ else
+ spec->micmute_led.capture &= ~mask;
+ call_micmute_led_update(codec);
+ }
+}
+
+static int micmute_led_mode_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char * const texts[] = {
+ "On", "Off", "Follow Capture", "Follow Mute",
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int micmute_led_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+
+ ucontrol->value.enumerated.item[0] = spec->micmute_led.led_mode;
+ return 0;
+}
+
+static int micmute_led_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct hda_gen_spec *spec = codec->spec;
+ unsigned int mode;
+
+ mode = ucontrol->value.enumerated.item[0];
+ if (mode > MICMUTE_LED_FOLLOW_MUTE)
+ mode = MICMUTE_LED_FOLLOW_MUTE;
+ if (mode == spec->micmute_led.led_mode)
+ return 0;
+ spec->micmute_led.led_mode = mode;
+ call_micmute_led_update(codec);
+ return 1;
+}
+
+static const struct snd_kcontrol_new micmute_led_mode_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mic Mute-LED Mode",
+ .info = micmute_led_mode_info,
+ .get = micmute_led_mode_get,
+ .put = micmute_led_mode_put,
+};
+
+/**
+ * snd_hda_gen_add_micmute_led - helper for setting up mic mute LED hook
+ * @codec: the HDA codec
+ * @hook: the callback for updating LED
+ *
+ * Called from the codec drivers for offering the mic mute LED controls.
+ * When established, it sets up cap_sync_hook and triggers the callback at
+ * each time when the capture mixer switch changes. The callback is supposed
+ * to update the LED accordingly.
+ *
+ * Returns 0 if the hook is established or a negative error code.
+ */
+int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
+ void (*hook)(struct hda_codec *))
+{
+ struct hda_gen_spec *spec = codec->spec;
+
+ spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
+ spec->micmute_led.capture = 0;
+ spec->micmute_led.led_value = 0;
+ spec->micmute_led.old_hook = spec->cap_sync_hook;
+ spec->micmute_led.update = hook;
+ spec->cap_sync_hook = update_micmute_led;
+ if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
+ return -ENOMEM;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led);
+
+/*
* parse digital I/Os and set up NIDs in BIOS auto-parse mode
*/
static void parse_digital(struct hda_codec *codec)
@@ -5837,7 +5973,7 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec)
hda_nid_t nid = pin->nid;
if (is_jack_detectable(codec, nid) &&
!snd_hda_jack_tbl_get(codec, nid))
- snd_hda_codec_update_cache(codec, nid, 0,
+ snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE, 0);
}
}
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
index 61772317de46..10123664fa61 100644
--- a/sound/pci/hda/hda_generic.h
+++ b/sound/pci/hda/hda_generic.h
@@ -86,6 +86,16 @@ struct badness_table {
extern const struct badness_table hda_main_out_badness;
extern const struct badness_table hda_extra_out_badness;
+struct hda_micmute_hook {
+ unsigned int led_mode;
+ unsigned int capture;
+ unsigned int led_value;
+ void (*update)(struct hda_codec *codec);
+ void (*old_hook)(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+};
+
struct hda_gen_spec {
char stream_name_analog[32]; /* analog PCM stream */
const struct hda_pcm_stream *stream_analog_playback;
@@ -276,6 +286,9 @@ struct hda_gen_spec {
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+ /* mic mute LED hook; called via cap_sync_hook */
+ struct hda_micmute_hook micmute_led;
+
/* PCM hooks */
void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
@@ -342,4 +355,7 @@ unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
+int snd_hda_gen_add_micmute_led(struct hda_codec *codec,
+ void (*hook)(struct hda_codec *));
+
#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1ae1850b3bfd..1b2ce304152a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1319,15 +1319,16 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = {
static int register_vga_switcheroo(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
+ struct pci_dev *p;
int err;
if (!hda->use_vga_switcheroo)
return 0;
- /* FIXME: currently only handling DIS controller
- * is there any machine with two switchable HDMI audio controllers?
- */
- err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops,
- VGA_SWITCHEROO_DIS);
+
+ p = get_bound_vga(chip->pci);
+ err = vga_switcheroo_register_audio_client(chip->pci, &azx_vs_ops, p);
+ pci_dev_put(p);
+
if (err < 0)
return err;
hda->vga_switcheroo_registered = 1;
@@ -1429,7 +1430,7 @@ static struct pci_dev *get_bound_vga(struct pci_dev *pci)
p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
pci->bus->number, 0);
if (p) {
- if ((p->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+ if ((p->class >> 16) == PCI_BASE_CLASS_DISPLAY)
return p;
pci_dev_put(p);
}
@@ -2207,7 +2208,7 @@ out_free:
*/
static struct snd_pci_quirk power_save_blacklist[] = {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
- SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0),
+ SND_PCI_QUIRK(0x1849, 0xc892, "Asrock B85M-ITX", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
SND_PCI_QUIRK(0x1849, 0x7662, "Asrock H81M-HDS", 0),
/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
@@ -2535,7 +2536,8 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
/* AMD Raven */
{ PCI_DEVICE(0x1022, 0x15e3),
- .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB },
+ .driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_ATI_SB |
+ AZX_DCAPS_PM_RUNTIME },
/* ATI HDMI */
{ PCI_DEVICE(0x1002, 0x0002),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 757857313426..fd476fb40e1b 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -148,7 +148,7 @@ static void ad_vmaster_eapd_hook(void *private_data, int enabled)
return;
if (codec->inv_eapd)
enabled = !enabled;
- snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
+ snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
AC_VERB_SET_EAPD_BTLENABLE,
enabled ? 0x02 : 0x00);
}
@@ -991,7 +991,7 @@ static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
if (spec->eapd_nid)
ad_vmaster_eapd_hook(private_data, enabled);
- snd_hda_codec_update_cache(codec, 0x01, 0,
+ snd_hda_codec_write_cache(codec, 0x01, 0,
AC_VERB_SET_GPIO_DATA,
enabled ? 0x00 : 0x02);
}
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 04e949aa01ad..0166a3d7cd55 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -897,7 +897,7 @@ struct ca0132_spec {
const struct hda_verb *base_init_verbs;
const struct hda_verb *base_exit_verbs;
const struct hda_verb *chip_init_verbs;
- const struct hda_verb *sbz_init_verbs;
+ const struct hda_verb *desktop_init_verbs;
struct hda_verb *spec_init_verbs;
struct auto_pin_cfg autocfg;
@@ -965,9 +965,11 @@ struct ca0132_spec {
long cur_ctl_vals[TUNING_CTLS_COUNT];
#endif
/*
- * Sound Blaster Z PCI region 2 iomem, used for input and output
- * switching, and other unknown commands.
+ * The Recon3D, Sound Blaster Z, Sound Blaster ZxR, and Sound Blaster
+ * AE-5 all use PCI region 2 to toggle GPIO and other currently unknown
+ * things.
*/
+ bool use_pci_mmio;
void __iomem *mem_base;
/*
@@ -991,8 +993,10 @@ struct ca0132_spec {
enum {
QUIRK_NONE,
QUIRK_ALIENWARE,
+ QUIRK_ALIENWARE_M17XR4,
QUIRK_SBZ,
QUIRK_R3DI,
+ QUIRK_R3D,
};
static const struct hda_pintbl alienware_pincfgs[] = {
@@ -1024,6 +1028,21 @@ static const struct hda_pintbl sbz_pincfgs[] = {
{}
};
+/* Recon3D pin configs taken from Windows Driver */
+static const struct hda_pintbl r3d_pincfgs[] = {
+ { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
+ { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+ { 0x0d, 0x014510f0 }, /* Digital Out */
+ { 0x0e, 0x01c520f0 }, /* SPDIF In */
+ { 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
+ { 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
+ { 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
+ { 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
+ { 0x13, 0x908700f0 }, /* What U Hear In*/
+ { 0x18, 0x50d000f0 }, /* N/A */
+ {}
+};
+
/* Recon3D integrated pin configs taken from Windows Driver */
static const struct hda_pintbl r3di_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1040,13 +1059,16 @@ static const struct hda_pintbl r3di_pincfgs[] = {
};
static const struct snd_pci_quirk ca0132_quirks[] = {
+ SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4),
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),
SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ),
SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ),
SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
- SND_PCI_QUIRK(0x1458, 0xA036, "Recon3Di", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
+ SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
{}
};
@@ -3070,6 +3092,24 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
*/
/*
+ * For cards with PCI-E region2 (Sound Blaster Z/ZxR, Recon3D, and AE-5)
+ * the mmio address 0x320 is used to set GPIO pins. The format for the data
+ * The first eight bits are just the number of the pin. So far, I've only seen
+ * this number go to 7.
+ */
+static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
+ bool enable)
+{
+ struct ca0132_spec *spec = codec->spec;
+ unsigned short gpio_data;
+
+ gpio_data = gpio_pin & 0xF;
+ gpio_data |= ((enable << 8) & 0x100);
+
+ writew(gpio_data, spec->mem_base + 0x320);
+}
+
+/*
* Sets up the GPIO pins so that they are discoverable. If this isn't done,
* the card shows as having no GPIO pins.
*/
@@ -3944,15 +3984,19 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
/*speaker out config*/
switch (spec->quirk) {
case QUIRK_SBZ:
- writew(0x0007, spec->mem_base + 0x320);
- writew(0x0104, spec->mem_base + 0x320);
- writew(0x0101, spec->mem_base + 0x320);
+ ca0132_mmio_gpio_set(codec, 7, false);
+ ca0132_mmio_gpio_set(codec, 4, true);
+ ca0132_mmio_gpio_set(codec, 1, true);
chipio_set_control_param(codec, 0x0D, 0x18);
break;
case QUIRK_R3DI:
chipio_set_control_param(codec, 0x0D, 0x24);
r3di_gpio_out_set(codec, R3DI_LINE_OUT);
break;
+ case QUIRK_R3D:
+ chipio_set_control_param(codec, 0x0D, 0x24);
+ ca0132_mmio_gpio_set(codec, 1, true);
+ break;
}
/* disable headphone node */
@@ -3980,15 +4024,19 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
/* Headphone out config*/
switch (spec->quirk) {
case QUIRK_SBZ:
- writew(0x0107, spec->mem_base + 0x320);
- writew(0x0104, spec->mem_base + 0x320);
- writew(0x0001, spec->mem_base + 0x320);
+ ca0132_mmio_gpio_set(codec, 7, true);
+ ca0132_mmio_gpio_set(codec, 4, true);
+ ca0132_mmio_gpio_set(codec, 1, false);
chipio_set_control_param(codec, 0x0D, 0x12);
break;
case QUIRK_R3DI:
chipio_set_control_param(codec, 0x0D, 0x21);
r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
break;
+ case QUIRK_R3D:
+ chipio_set_control_param(codec, 0x0D, 0x21);
+ ca0132_mmio_gpio_set(codec, 0x1, false);
+ break;
}
snd_hda_codec_write(codec, spec->out_pins[0], 0,
@@ -4022,15 +4070,19 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
/* Surround out config*/
switch (spec->quirk) {
case QUIRK_SBZ:
- writew(0x0007, spec->mem_base + 0x320);
- writew(0x0104, spec->mem_base + 0x320);
- writew(0x0101, spec->mem_base + 0x320);
+ ca0132_mmio_gpio_set(codec, 7, false);
+ ca0132_mmio_gpio_set(codec, 4, true);
+ ca0132_mmio_gpio_set(codec, 1, true);
chipio_set_control_param(codec, 0x0D, 0x18);
break;
case QUIRK_R3DI:
chipio_set_control_param(codec, 0x0D, 0x24);
r3di_gpio_out_set(codec, R3DI_LINE_OUT);
break;
+ case QUIRK_R3D:
+ ca0132_mmio_gpio_set(codec, 1, true);
+ chipio_set_control_param(codec, 0x0D, 0x24);
+ break;
}
/* enable line out node */
pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
@@ -4288,7 +4340,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
case REAR_MIC:
switch (spec->quirk) {
case QUIRK_SBZ:
- writew(0x0000, spec->mem_base + 0x320);
+ case QUIRK_R3D:
+ ca0132_mmio_gpio_set(codec, 0, false);
tmp = FLOAT_THREE;
break;
case QUIRK_R3DI:
@@ -4320,7 +4373,8 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
ca0132_mic_boost_set(codec, 0);
switch (spec->quirk) {
case QUIRK_SBZ:
- writew(0x0000, spec->mem_base + 0x320);
+ case QUIRK_R3D:
+ ca0132_mmio_gpio_set(codec, 0, false);
break;
case QUIRK_R3DI:
r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
@@ -4346,8 +4400,9 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
case FRONT_MIC:
switch (spec->quirk) {
case QUIRK_SBZ:
- writew(0x0100, spec->mem_base + 0x320);
- writew(0x0005, spec->mem_base + 0x320);
+ case QUIRK_R3D:
+ ca0132_mmio_gpio_set(codec, 0, true);
+ ca0132_mmio_gpio_set(codec, 5, false);
tmp = FLOAT_THREE;
break;
case QUIRK_R3DI:
@@ -5513,8 +5568,7 @@ static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid,
sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]);
- knew.tlv.c = 0;
- knew.tlv.p = 0;
+ knew.tlv.c = NULL;
switch (nid) {
case XBASS_XOVER:
@@ -5663,7 +5717,7 @@ static const char * const ca0132_alt_slave_pfxs[] = {
* I think this has to do with the pin for rear surround being 0x11,
* and the center/lfe being 0x10. Usually the pin order is the opposite.
*/
-const struct snd_pcm_chmap_elem ca0132_alt_chmaps[] = {
+static const struct snd_pcm_chmap_elem ca0132_alt_chmaps[] = {
{ .channels = 2,
.map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
{ .channels = 4,
@@ -5726,11 +5780,11 @@ static const struct snd_kcontrol_new ca0132_mixer[] = {
};
/*
- * SBZ specific control mixer. Removes auto-detect for mic, and adds surround
- * controls. Also sets both the Front Playback and Capture Volume controls to
- * alt so they set the DSP's decibel level.
+ * Desktop specific control mixer. Removes auto-detect for mic, and adds
+ * surround controls. Also sets both the Front Playback and Capture Volume
+ * controls to alt so they set the DSP's decibel level.
*/
-static const struct snd_kcontrol_new sbz_mixer[] = {
+static const struct snd_kcontrol_new desktop_mixer[] = {
CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
@@ -5801,8 +5855,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
*/
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
for (i = 0; i < num_fx; i++) {
- /* SBZ breaks if Echo Cancellation is used */
- if (spec->quirk == QUIRK_SBZ) {
+ /* SBZ and R3D break if Echo Cancellation is used. */
+ if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) {
if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
OUT_EFFECTS_COUNT))
continue;
@@ -5966,7 +6020,7 @@ static int ca0132_build_pcms(struct hda_codec *codec)
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
/* With the DSP enabled, desktops don't use this ADC. */
- if (spec->use_alt_functions) {
+ if (!spec->use_alt_functions) {
info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
if (!info)
return -ENOMEM;
@@ -6130,7 +6184,10 @@ static void ca0132_init_dmic(struct hda_codec *codec)
* Bit 6: set to select Data2, clear for Data1
* Bit 7: set to enable DMic, clear for AMic
*/
- val = 0x23;
+ if (spec->quirk == QUIRK_ALIENWARE_M17XR4)
+ val = 0x33;
+ else
+ val = 0x23;
/* keep a copy of dmic ctl val for enable/disable dmic purpuse */
spec->dmic_ctl = val;
snd_hda_codec_write(codec, spec->input_pins[0], 0,
@@ -6181,10 +6238,10 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
}
/*
- * Recon3Di r3di_setup_defaults sub functions.
+ * Recon3D r3d_setup_defaults sub functions.
*/
-static void r3di_dsp_scp_startup(struct hda_codec *codec)
+static void r3d_dsp_scp_startup(struct hda_codec *codec)
{
unsigned int tmp;
@@ -6205,7 +6262,7 @@ static void r3di_dsp_scp_startup(struct hda_codec *codec)
}
-static void r3di_dsp_initial_mic_setup(struct hda_codec *codec)
+static void r3d_dsp_initial_mic_setup(struct hda_codec *codec)
{
unsigned int tmp;
@@ -6415,10 +6472,10 @@ static void ca0132_setup_defaults(struct hda_codec *codec)
}
/*
- * Setup default parameters for Recon3Di DSP.
+ * Setup default parameters for Recon3D/Recon3Di DSP.
*/
-static void r3di_setup_defaults(struct hda_codec *codec)
+static void r3d_setup_defaults(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
unsigned int tmp;
@@ -6428,9 +6485,9 @@ static void r3di_setup_defaults(struct hda_codec *codec)
if (spec->dsp_state != DSP_DOWNLOADED)
return;
- r3di_dsp_scp_startup(codec);
+ r3d_dsp_scp_startup(codec);
- r3di_dsp_initial_mic_setup(codec);
+ r3d_dsp_initial_mic_setup(codec);
/*remove DSP headroom*/
tmp = FLOAT_ZERO;
@@ -6444,7 +6501,8 @@ static void r3di_setup_defaults(struct hda_codec *codec)
/* Set speaker source? */
dspio_set_uint_param(codec, 0x32, 0x00, tmp);
- r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
+ if (spec->quirk == QUIRK_R3DI)
+ r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
/* Setup effect defaults */
num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
@@ -6456,7 +6514,6 @@ static void r3di_setup_defaults(struct hda_codec *codec)
ca0132_effects[idx].def_vals[i]);
}
}
-
}
/*
@@ -6721,7 +6778,12 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
{
- ca0132_select_mic(codec);
+ struct ca0132_spec *spec = codec->spec;
+
+ if (spec->use_alt_functions)
+ ca0132_alt_select_in(codec);
+ else
+ ca0132_select_mic(codec);
}
static void ca0132_init_unsol(struct hda_codec *codec)
@@ -6792,8 +6854,8 @@ static struct hda_verb ca0132_init_verbs0[] = {
{}
};
-/* Extra init verbs for SBZ */
-static struct hda_verb sbz_init_verbs[] = {
+/* Extra init verbs for desktop cards. */
+static struct hda_verb ca0132_init_verbs1[] = {
{0x15, 0x70D, 0x20},
{0x15, 0x70E, 0x19},
{0x15, 0x707, 0x00},
@@ -6885,16 +6947,12 @@ static void sbz_region2_exit(struct hda_codec *codec)
writeb(0x0, spec->mem_base + 0x100);
for (i = 0; i < 8; i++)
writeb(0xb3, spec->mem_base + 0x304);
- /*
- * I believe these are GPIO, with the right most hex digit being the
- * gpio pin, and the second digit being on or off. We see this more in
- * the input/output select functions.
- */
- writew(0x0000, spec->mem_base + 0x320);
- writew(0x0001, spec->mem_base + 0x320);
- writew(0x0104, spec->mem_base + 0x320);
- writew(0x0005, spec->mem_base + 0x320);
- writew(0x0007, spec->mem_base + 0x320);
+
+ ca0132_mmio_gpio_set(codec, 0, false);
+ ca0132_mmio_gpio_set(codec, 1, false);
+ ca0132_mmio_gpio_set(codec, 4, true);
+ ca0132_mmio_gpio_set(codec, 5, false);
+ ca0132_mmio_gpio_set(codec, 7, false);
}
static void sbz_set_pin_ctl_default(struct hda_codec *codec)
@@ -6910,7 +6968,7 @@ static void sbz_set_pin_ctl_default(struct hda_codec *codec)
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
}
-static void sbz_clear_unsolicited(struct hda_codec *codec)
+static void ca0132_clear_unsolicited(struct hda_codec *codec)
{
hda_nid_t pins[7] = {0x0B, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13};
unsigned int i;
@@ -6963,21 +7021,22 @@ static void sbz_exit_chip(struct hda_codec *codec)
chipio_set_control_param(codec, 0x0D, 0x24);
- sbz_clear_unsolicited(codec);
+ ca0132_clear_unsolicited(codec);
sbz_set_pin_ctl_default(codec);
snd_hda_codec_write(codec, 0x0B, 0,
AC_VERB_SET_EAPD_BTLENABLE, 0x00);
- if (dspload_is_loaded(codec))
- dsp_reset(codec);
-
- snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
- VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x00);
-
sbz_region2_exit(codec);
}
+static void r3d_exit_chip(struct hda_codec *codec)
+{
+ ca0132_clear_unsolicited(codec);
+ snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+ snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
+}
+
static void ca0132_exit_chip(struct hda_codec *codec)
{
/* put any chip cleanup stuffs here. */
@@ -7092,9 +7151,27 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44);
}
-/*
- * Extra commands that don't really fit anywhere else.
- */
+static void r3d_pre_dsp_setup(struct hda_codec *codec)
+{
+
+ snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
+ snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
+ snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
+ snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
+
+ chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x1E);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x1C);
+ snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+ VENDOR_CHIPIO_8051_DATA_WRITE, 0x5B);
+
+ snd_hda_codec_write(codec, 0x11, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44);
+}
+
static void r3di_pre_dsp_setup(struct hda_codec *codec)
{
chipio_write(codec, 0x18b0a4, 0x000000c2);
@@ -7119,13 +7196,12 @@ static void r3di_pre_dsp_setup(struct hda_codec *codec)
AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04);
}
-
/*
* These are sent before the DSP is downloaded. Not sure
* what they do, or if they're necessary. Could possibly
* be removed. Figure they're better to leave in.
*/
-static void sbz_region2_startup(struct hda_codec *codec)
+static void ca0132_mmio_init(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
@@ -7165,7 +7241,7 @@ static void ca0132_alt_init(struct hda_codec *codec)
ca0132_gpio_init(codec);
sbz_pre_dsp_setup(codec);
snd_hda_sequence_write(codec, spec->chip_init_verbs);
- snd_hda_sequence_write(codec, spec->sbz_init_verbs);
+ snd_hda_sequence_write(codec, spec->desktop_init_verbs);
break;
case QUIRK_R3DI:
codec_dbg(codec, "R3DI alt_init");
@@ -7176,6 +7252,11 @@ static void ca0132_alt_init(struct hda_codec *codec)
snd_hda_sequence_write(codec, spec->chip_init_verbs);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x6FF, 0xC4);
break;
+ case QUIRK_R3D:
+ r3d_pre_dsp_setup(codec);
+ snd_hda_sequence_write(codec, spec->chip_init_verbs);
+ snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+ break;
}
}
@@ -7212,8 +7293,8 @@ static int ca0132_init(struct hda_codec *codec)
spec->dsp_state = DSP_DOWNLOAD_INIT;
spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
- if (spec->quirk == QUIRK_SBZ)
- sbz_region2_startup(codec);
+ if (spec->use_pci_mmio)
+ ca0132_mmio_init(codec);
snd_hda_power_up_pm(codec);
@@ -7223,22 +7304,22 @@ static int ca0132_init(struct hda_codec *codec)
snd_hda_sequence_write(codec, spec->base_init_verbs);
- if (spec->quirk != QUIRK_NONE)
+ if (spec->use_alt_functions)
ca0132_alt_init(codec);
ca0132_download_dsp(codec);
ca0132_refresh_widget_caps(codec);
- if (spec->quirk == QUIRK_SBZ)
- writew(0x0107, spec->mem_base + 0x320);
-
switch (spec->quirk) {
case QUIRK_R3DI:
- r3di_setup_defaults(codec);
+ case QUIRK_R3D:
+ r3d_setup_defaults(codec);
break;
- case QUIRK_NONE:
- case QUIRK_ALIENWARE:
+ case QUIRK_SBZ:
+ sbz_setup_defaults(codec);
+ break;
+ default:
ca0132_setup_defaults(codec);
ca0132_init_analog_mic2(codec);
ca0132_init_dmic(codec);
@@ -7267,20 +7348,12 @@ static int ca0132_init(struct hda_codec *codec)
ca0132_gpio_setup(codec);
snd_hda_sequence_write(codec, spec->spec_init_verbs);
- switch (spec->quirk) {
- case QUIRK_SBZ:
- sbz_setup_defaults(codec);
- ca0132_alt_select_out(codec);
- ca0132_alt_select_in(codec);
- break;
- case QUIRK_R3DI:
+ if (spec->use_alt_functions) {
ca0132_alt_select_out(codec);
ca0132_alt_select_in(codec);
- break;
- default:
+ } else {
ca0132_select_out(codec);
ca0132_select_mic(codec);
- break;
}
snd_hda_jack_report_sync(codec);
@@ -7309,16 +7382,17 @@ static void ca0132_free(struct hda_codec *codec)
case QUIRK_SBZ:
sbz_exit_chip(codec);
break;
+ case QUIRK_R3D:
+ r3d_exit_chip(codec);
+ break;
case QUIRK_R3DI:
r3di_gpio_shutdown(codec);
- snd_hda_sequence_write(codec, spec->base_exit_verbs);
- ca0132_exit_chip(codec);
- break;
- default:
- snd_hda_sequence_write(codec, spec->base_exit_verbs);
- ca0132_exit_chip(codec);
break;
}
+
+ snd_hda_sequence_write(codec, spec->base_exit_verbs);
+ ca0132_exit_chip(codec);
+
snd_hda_power_down(codec);
if (spec->mem_base)
iounmap(spec->mem_base);
@@ -7343,7 +7417,6 @@ static const struct hda_codec_ops ca0132_patch_ops = {
static void ca0132_config(struct hda_codec *codec)
{
struct ca0132_spec *spec = codec->spec;
- struct auto_pin_cfg *cfg = &spec->autocfg;
spec->dacs[0] = 0x2;
spec->dacs[1] = 0x3;
@@ -7380,8 +7453,15 @@ static void ca0132_config(struct hda_codec *codec)
spec->unsol_tag_amic1 = 0x11;
break;
case QUIRK_SBZ:
- codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
- snd_hda_apply_pincfgs(codec, sbz_pincfgs);
+ case QUIRK_R3D:
+ if (spec->quirk == QUIRK_SBZ) {
+ codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, sbz_pincfgs);
+ }
+ if (spec->quirk == QUIRK_R3D) {
+ codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
+ snd_hda_apply_pincfgs(codec, r3d_pincfgs);
+ }
spec->num_outputs = 2;
spec->out_pins[0] = 0x0B; /* Line out */
@@ -7405,12 +7485,7 @@ static void ca0132_config(struct hda_codec *codec)
/* SPDIF I/O */
spec->dig_out = 0x05;
spec->multiout.dig_out_nid = spec->dig_out;
- cfg->dig_out_pins[0] = 0x0c;
- cfg->dig_outs = 1;
- cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF;
spec->dig_in = 0x09;
- cfg->dig_in_pin = 0x0e;
- cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
break;
case QUIRK_R3DI:
codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
@@ -7438,9 +7513,6 @@ static void ca0132_config(struct hda_codec *codec)
/* SPDIF I/O */
spec->dig_out = 0x05;
spec->multiout.dig_out_nid = spec->dig_out;
- cfg->dig_out_pins[0] = 0x0c;
- cfg->dig_outs = 1;
- cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF;
break;
default:
spec->num_outputs = 2;
@@ -7463,12 +7535,7 @@ static void ca0132_config(struct hda_codec *codec)
/* SPDIF I/O */
spec->dig_out = 0x05;
spec->multiout.dig_out_nid = spec->dig_out;
- cfg->dig_out_pins[0] = 0x0c;
- cfg->dig_outs = 1;
- cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF;
spec->dig_in = 0x09;
- cfg->dig_in_pin = 0x0e;
- cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
break;
}
}
@@ -7476,46 +7543,36 @@ static void ca0132_config(struct hda_codec *codec)
static int ca0132_prepare_verbs(struct hda_codec *codec)
{
/* Verbs + terminator (an empty element) */
-#define NUM_SPEC_VERBS 4
+#define NUM_SPEC_VERBS 2
struct ca0132_spec *spec = codec->spec;
spec->chip_init_verbs = ca0132_init_verbs0;
- if (spec->quirk == QUIRK_SBZ)
- spec->sbz_init_verbs = sbz_init_verbs;
+ if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D)
+ spec->desktop_init_verbs = ca0132_init_verbs1;
spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
sizeof(struct hda_verb),
GFP_KERNEL);
if (!spec->spec_init_verbs)
return -ENOMEM;
- /* HP jack autodetection */
- spec->spec_init_verbs[0].nid = spec->unsol_tag_hp;
- spec->spec_init_verbs[0].param = AC_VERB_SET_UNSOLICITED_ENABLE;
- spec->spec_init_verbs[0].verb = AC_USRSP_EN | spec->unsol_tag_hp;
-
- /* MIC1 jack autodetection */
- spec->spec_init_verbs[1].nid = spec->unsol_tag_amic1;
- spec->spec_init_verbs[1].param = AC_VERB_SET_UNSOLICITED_ENABLE;
- spec->spec_init_verbs[1].verb = AC_USRSP_EN | spec->unsol_tag_amic1;
-
/* config EAPD */
- spec->spec_init_verbs[2].nid = 0x0b;
- spec->spec_init_verbs[2].param = 0x78D;
- spec->spec_init_verbs[2].verb = 0x00;
+ spec->spec_init_verbs[0].nid = 0x0b;
+ spec->spec_init_verbs[0].param = 0x78D;
+ spec->spec_init_verbs[0].verb = 0x00;
/* Previously commented configuration */
/*
- spec->spec_init_verbs[3].nid = 0x0b;
- spec->spec_init_verbs[3].param = AC_VERB_SET_EAPD_BTLENABLE;
+ spec->spec_init_verbs[2].nid = 0x0b;
+ spec->spec_init_verbs[2].param = AC_VERB_SET_EAPD_BTLENABLE;
+ spec->spec_init_verbs[2].verb = 0x02;
+
+ spec->spec_init_verbs[3].nid = 0x10;
+ spec->spec_init_verbs[3].param = 0x78D;
spec->spec_init_verbs[3].verb = 0x02;
spec->spec_init_verbs[4].nid = 0x10;
- spec->spec_init_verbs[4].param = 0x78D;
+ spec->spec_init_verbs[4].param = AC_VERB_SET_EAPD_BTLENABLE;
spec->spec_init_verbs[4].verb = 0x02;
-
- spec->spec_init_verbs[5].nid = 0x10;
- spec->spec_init_verbs[5].param = AC_VERB_SET_EAPD_BTLENABLE;
- spec->spec_init_verbs[5].verb = 0x02;
*/
/* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */
@@ -7547,25 +7604,19 @@ static int patch_ca0132(struct hda_codec *codec)
else
spec->quirk = QUIRK_NONE;
- /* Setup BAR Region 2 for Sound Blaster Z */
- if (spec->quirk == QUIRK_SBZ) {
- spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
- if (spec->mem_base == NULL) {
- codec_warn(codec, "pci_iomap failed!");
- codec_info(codec, "perhaps this is not an SBZ?");
- spec->quirk = QUIRK_NONE;
- }
- }
-
spec->dsp_state = DSP_DOWNLOAD_INIT;
spec->num_mixers = 1;
/* Set which mixers each quirk uses. */
switch (spec->quirk) {
case QUIRK_SBZ:
- spec->mixers[0] = sbz_mixer;
+ spec->mixers[0] = desktop_mixer;
snd_hda_codec_set_name(codec, "Sound Blaster Z");
break;
+ case QUIRK_R3D:
+ spec->mixers[0] = desktop_mixer;
+ snd_hda_codec_set_name(codec, "Recon3D");
+ break;
case QUIRK_R3DI:
spec->mixers[0] = r3di_mixer;
snd_hda_codec_set_name(codec, "Recon3Di");
@@ -7575,19 +7626,34 @@ static int patch_ca0132(struct hda_codec *codec)
break;
}
- /* Setup whether or not to use alt functions/controls */
+ /* Setup whether or not to use alt functions/controls/pci_mmio */
switch (spec->quirk) {
case QUIRK_SBZ:
+ case QUIRK_R3D:
+ spec->use_alt_controls = true;
+ spec->use_alt_functions = true;
+ spec->use_pci_mmio = true;
+ break;
case QUIRK_R3DI:
spec->use_alt_controls = true;
spec->use_alt_functions = true;
+ spec->use_pci_mmio = false;
break;
default:
spec->use_alt_controls = false;
spec->use_alt_functions = false;
+ spec->use_pci_mmio = false;
break;
}
+ if (spec->use_pci_mmio) {
+ spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
+ if (spec->mem_base == NULL) {
+ codec_warn(codec, "pci_iomap failed! Setting quirk to QUIRK_NONE.");
+ spec->quirk = QUIRK_NONE;
+ }
+ }
+
spec->base_init_verbs = ca0132_base_init_verbs;
spec->base_exit_verbs = ca0132_base_exit_verbs;
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index d6e079f4ec09..a7f91be45194 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -1096,25 +1096,6 @@ static int cs421x_init(struct hda_codec *codec)
return 0;
}
-static int cs421x_build_controls(struct hda_codec *codec)
-{
- struct cs_spec *spec = codec->spec;
- int err;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- if (spec->gen.autocfg.speaker_outs &&
- spec->vendor_nid == CS4210_VENDOR_NID) {
- err = snd_hda_ctl_add(codec, 0,
- snd_ctl_new1(&cs421x_speaker_boost_ctl, codec));
- if (err < 0)
- return err;
- }
- return 0;
-}
-
static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
{
unsigned int caps;
@@ -1144,6 +1125,14 @@ static int cs421x_parse_auto_config(struct hda_codec *codec)
return err;
parse_cs421x_digital(codec);
+
+ if (spec->gen.autocfg.speaker_outs &&
+ spec->vendor_nid == CS4210_VENDOR_NID) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &cs421x_speaker_boost_ctl))
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -1175,7 +1164,7 @@ static int cs421x_suspend(struct hda_codec *codec)
#endif
static const struct hda_codec_ops cs421x_patch_ops = {
- .build_controls = cs421x_build_controls,
+ .build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = cs421x_init,
.free = cs_free,
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index e7fcfc3b8885..cfd4e4f97f8f 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -37,8 +37,6 @@
struct conexant_spec {
struct hda_gen_spec gen;
- unsigned int beep_amp;
-
/* extra EAPD pins */
unsigned int num_eapds;
hda_nid_t eapds[4];
@@ -62,65 +60,48 @@ struct conexant_spec {
#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
- int idx, int dir)
-{
- spec->gen.beep_nid = nid;
- spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-}
-/* additional beep mixers; the actual parameters are overwritten at build */
+/* additional beep mixers; private_value will be overwritten */
static const struct snd_kcontrol_new cxt_beep_mixer[] = {
HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
- { } /* end */
};
-/* create beep controls if needed */
-static int add_beep_ctls(struct hda_codec *codec)
+static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
+ int idx, int dir)
{
- struct conexant_spec *spec = codec->spec;
- int err;
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+ int i;
- if (spec->beep_amp) {
- const struct snd_kcontrol_new *knew;
- for (knew = cxt_beep_mixer; knew->name; knew++) {
- struct snd_kcontrol *kctl;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
- }
+ spec->gen.beep_nid = nid;
+ for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &cxt_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
}
return 0;
}
-#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#define add_beep_ctls(codec) 0
-#endif
-
-/*
- * Automatic parser for CX20641 & co
- */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static void cx_auto_parse_beep(struct hda_codec *codec)
+static int cx_auto_parse_beep(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
hda_nid_t nid;
for_each_hda_codec_node(nid, codec)
- if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
- set_beep_amp(spec, nid, 0, HDA_OUTPUT);
- break;
- }
+ if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
+ return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+ return 0;
}
#else
-#define cx_auto_parse_beep(codec)
+#define cx_auto_parse_beep(codec) 0
#endif
+/*
+ * Automatic parser for CX20641 & co
+ */
+
/* parse EAPDs */
static void cx_auto_parse_eapd(struct hda_codec *codec)
{
@@ -179,21 +160,6 @@ static void cx_auto_vmaster_hook_mute_led(void *private_data, int enabled)
enabled ? 0x00 : 0x02);
}
-static int cx_auto_build_controls(struct hda_codec *codec)
-{
- int err;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- err = add_beep_ctls(codec);
- if (err < 0)
- return err;
-
- return 0;
-}
-
static int cx_auto_init(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
@@ -211,6 +177,7 @@ static void cx_auto_reboot_notify(struct hda_codec *codec)
struct conexant_spec *spec = codec->spec;
switch (codec->core.vendor_id) {
+ case 0x14f12008: /* CX8200 */
case 0x14f150f2: /* CX20722 */
case 0x14f150f4: /* CX20724 */
break;
@@ -218,13 +185,14 @@ static void cx_auto_reboot_notify(struct hda_codec *codec)
return;
}
- /* Turn the CX20722 codec into D3 to avoid spurious noises
+ /* Turn the problematic codec into D3 to avoid spurious noises
from the internal speaker during (and after) reboot */
cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3);
snd_hda_codec_write(codec, codec->core.afg, 0,
AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ msleep(10);
}
static void cx_auto_free(struct hda_codec *codec)
@@ -234,7 +202,7 @@ static void cx_auto_free(struct hda_codec *codec)
}
static const struct hda_codec_ops cx_auto_patch_ops = {
- .build_controls = cx_auto_build_controls,
+ .build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = cx_auto_init,
.reboot_notify = cx_auto_reboot_notify,
@@ -343,6 +311,7 @@ static void cxt_fixup_headphone_mic(struct hda_codec *codec,
snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
break;
case HDA_FIXUP_ACT_PROBE:
+ WARN_ON(spec->gen.cap_sync_hook);
spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
spec->gen.automute_hook = cxt_update_headset_mode;
break;
@@ -374,7 +343,7 @@ static void cxt_fixup_headset_mic(struct hda_codec *codec,
* control. */
#define update_mic_pin(codec, nid, val) \
- snd_hda_codec_update_cache(codec, nid, 0, \
+ snd_hda_codec_write_cache(codec, nid, 0, \
AC_VERB_SET_PIN_WIDGET_CONTROL, val)
static const struct hda_input_mux olpc_xo_dc_bias = {
@@ -695,16 +664,12 @@ static void cxt_fixup_gpio_mute_hook(void *private_data, int enabled)
}
/* turn on/off mic-mute LED via GPIO per capture hook */
-static void cxt_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void cxt_gpio_micmute_update(struct hda_codec *codec)
{
struct conexant_spec *spec = codec->spec;
- if (ucontrol)
- cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
- ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
+ cxt_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ spec->gen.micmute_led.led_value);
}
@@ -721,11 +686,11 @@ static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->gen.vmaster_mute.hook = cxt_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = cxt_fixup_gpio_mic_mute_hook;
spec->gpio_led = 0;
spec->mute_led_polarity = 0;
spec->gpio_mute_led_mask = 0x01;
spec->gpio_mic_led_mask = 0x02;
+ snd_hda_gen_add_micmute_led(codec, cxt_gpio_micmute_update);
}
snd_hda_add_verbs(codec, gpio_init);
if (spec->gpio_led)
@@ -964,6 +929,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
@@ -1036,7 +1002,6 @@ static int patch_conexant_auto(struct hda_codec *codec)
codec->spec = spec;
codec->patch_ops = cx_auto_patch_ops;
- cx_auto_parse_beep(codec);
cx_auto_parse_eapd(codec);
spec->gen.own_eapd_ctl = 1;
if (spec->dynamic_eapd)
@@ -1096,6 +1061,10 @@ static int patch_conexant_auto(struct hda_codec *codec)
if (err < 0)
goto error;
+ err = cx_auto_parse_beep(codec);
+ if (err < 0)
+ goto error;
+
/* Some laptops with Conexant chips show stalls in S3 resume,
* which falls into the single-cmd mode.
* Better to make reset, then.
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8840daf9c6a3..cb587dce67a9 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -33,6 +33,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/asoundef.h>
@@ -176,13 +177,13 @@ struct hdmi_spec {
/* i915/powerwell (Haswell+/Valleyview+) specific */
bool use_acomp_notifier; /* use i915 eld_notify callback for hotplug */
- struct i915_audio_component_audio_ops i915_audio_ops;
+ struct drm_audio_component_audio_ops drm_audio_ops;
struct hdac_chmap chmap;
hda_nid_t vendor_nid;
};
-#ifdef CONFIG_SND_HDA_I915
+#ifdef CONFIG_SND_HDA_COMPONENT
static inline bool codec_has_acomp(struct hda_codec *codec)
{
struct hdmi_spec *spec = codec->spec;
@@ -338,13 +339,13 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
if (!per_pin) {
/* no pin is bound to the pcm */
uinfo->count = 0;
- mutex_unlock(&spec->pcm_lock);
- return 0;
+ goto unlock;
}
eld = &per_pin->sink_eld;
uinfo->count = eld->eld_valid ? eld->eld_size : 0;
- mutex_unlock(&spec->pcm_lock);
+ unlock:
+ mutex_unlock(&spec->pcm_lock);
return 0;
}
@@ -356,6 +357,7 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
struct hdmi_spec_per_pin *per_pin;
struct hdmi_eld *eld;
int pcm_idx;
+ int err = 0;
pcm_idx = kcontrol->private_value;
mutex_lock(&spec->pcm_lock);
@@ -364,16 +366,15 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
/* no pin is bound to the pcm */
memset(ucontrol->value.bytes.data, 0,
ARRAY_SIZE(ucontrol->value.bytes.data));
- mutex_unlock(&spec->pcm_lock);
- return 0;
+ goto unlock;
}
- eld = &per_pin->sink_eld;
+ eld = &per_pin->sink_eld;
if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
eld->eld_size > ELD_MAX_SIZE) {
- mutex_unlock(&spec->pcm_lock);
snd_BUG();
- return -EINVAL;
+ err = -EINVAL;
+ goto unlock;
}
memset(ucontrol->value.bytes.data, 0,
@@ -381,9 +382,10 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
if (eld->eld_valid)
memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
eld->eld_size);
- mutex_unlock(&spec->pcm_lock);
- return 0;
+ unlock:
+ mutex_unlock(&spec->pcm_lock);
+ return err;
}
static const struct snd_kcontrol_new eld_bytes_ctl = {
@@ -764,8 +766,10 @@ static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
if (pin_idx < 0)
return;
+ mutex_lock(&spec->pcm_lock);
if (hdmi_present_sense(get_pin(spec, pin_idx), 1))
snd_hda_jack_report_sync(codec);
+ mutex_unlock(&spec->pcm_lock);
}
static void jack_callback(struct hda_codec *codec,
@@ -1206,8 +1210,8 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
pin_idx = hinfo_to_pin_index(codec, hinfo);
if (!spec->dyn_pcm_assign) {
if (snd_BUG_ON(pin_idx < 0)) {
- mutex_unlock(&spec->pcm_lock);
- return -EINVAL;
+ err = -EINVAL;
+ goto unlock;
}
} else {
/* no pin is assigned to the PCM
@@ -1215,16 +1219,13 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
*/
if (pin_idx < 0) {
err = hdmi_pcm_open_no_pin(hinfo, codec, substream);
- mutex_unlock(&spec->pcm_lock);
- return err;
+ goto unlock;
}
}
err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx);
- if (err < 0) {
- mutex_unlock(&spec->pcm_lock);
- return err;
- }
+ if (err < 0)
+ goto unlock;
per_cvt = get_cvt(spec, cvt_idx);
/* Claim converter */
@@ -1261,12 +1262,11 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
per_cvt->assigned = 0;
hinfo->nid = 0;
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
- mutex_unlock(&spec->pcm_lock);
- return -ENODEV;
+ err = -ENODEV;
+ goto unlock;
}
}
- mutex_unlock(&spec->pcm_lock);
/* Store the updated parameters */
runtime->hw.channels_min = hinfo->channels_min;
runtime->hw.channels_max = hinfo->channels_max;
@@ -1275,7 +1275,9 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- return 0;
+ unlock:
+ mutex_unlock(&spec->pcm_lock);
+ return err;
}
/*
@@ -1628,21 +1630,23 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
{
struct hda_codec *codec = per_pin->codec;
- struct hdmi_spec *spec = codec->spec;
int ret;
/* no temporary power up/down needed for component notifier */
- if (!codec_has_acomp(codec))
- snd_hda_power_up_pm(codec);
+ if (!codec_has_acomp(codec)) {
+ ret = snd_hda_power_up_pm(codec);
+ if (ret < 0 && pm_runtime_suspended(hda_codec_dev(codec))) {
+ snd_hda_power_down_pm(codec);
+ return false;
+ }
+ }
- mutex_lock(&spec->pcm_lock);
if (codec_has_acomp(codec)) {
sync_eld_via_acomp(codec, per_pin);
ret = false; /* don't call snd_hda_jack_report_sync() */
} else {
ret = hdmi_present_sense_via_verbs(per_pin, repoll);
}
- mutex_unlock(&spec->pcm_lock);
if (!codec_has_acomp(codec))
snd_hda_power_down_pm(codec);
@@ -1654,12 +1658,16 @@ static void hdmi_repoll_eld(struct work_struct *work)
{
struct hdmi_spec_per_pin *per_pin =
container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
+ struct hda_codec *codec = per_pin->codec;
+ struct hdmi_spec *spec = codec->spec;
if (per_pin->repoll_count++ > 6)
per_pin->repoll_count = 0;
+ mutex_lock(&spec->pcm_lock);
if (hdmi_present_sense(per_pin, per_pin->repoll_count))
snd_hda_jack_report_sync(per_pin->codec);
+ mutex_unlock(&spec->pcm_lock);
}
static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
@@ -1858,7 +1866,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
struct snd_pcm_runtime *runtime = substream->runtime;
bool non_pcm;
int pinctl;
- int err;
+ int err = 0;
mutex_lock(&spec->pcm_lock);
pin_idx = hinfo_to_pin_index(codec, hinfo);
@@ -1870,13 +1878,12 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
pin_cvt_fixup(codec, NULL, cvt_nid);
snd_hda_codec_setup_stream(codec, cvt_nid,
stream_tag, 0, format);
- mutex_unlock(&spec->pcm_lock);
- return 0;
+ goto unlock;
}
if (snd_BUG_ON(pin_idx < 0)) {
- mutex_unlock(&spec->pcm_lock);
- return -EINVAL;
+ err = -EINVAL;
+ goto unlock;
}
per_pin = get_pin(spec, pin_idx);
pin_nid = per_pin->pin_nid;
@@ -1915,6 +1922,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
/* snd_hda_set_dev_select() has been called before */
err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
stream_tag, format);
+ unlock:
mutex_unlock(&spec->pcm_lock);
return err;
}
@@ -1936,6 +1944,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
struct hdmi_spec_per_cvt *per_cvt;
struct hdmi_spec_per_pin *per_pin;
int pinctl;
+ int err = 0;
if (hinfo->nid) {
pcm_idx = hinfo_to_pcm_index(codec, hinfo);
@@ -1954,14 +1963,12 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
snd_hda_spdif_ctls_unassign(codec, pcm_idx);
clear_bit(pcm_idx, &spec->pcm_in_use);
pin_idx = hinfo_to_pin_index(codec, hinfo);
- if (spec->dyn_pcm_assign && pin_idx < 0) {
- mutex_unlock(&spec->pcm_lock);
- return 0;
- }
+ if (spec->dyn_pcm_assign && pin_idx < 0)
+ goto unlock;
if (snd_BUG_ON(pin_idx < 0)) {
- mutex_unlock(&spec->pcm_lock);
- return -EINVAL;
+ err = -EINVAL;
+ goto unlock;
}
per_pin = get_pin(spec, pin_idx);
@@ -1980,10 +1987,11 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
per_pin->setup = false;
per_pin->channels = 0;
mutex_unlock(&per_pin->lock);
+ unlock:
mutex_unlock(&spec->pcm_lock);
}
- return 0;
+ return err;
}
static const struct hda_pcm_ops generic_ops = {
@@ -2279,7 +2287,7 @@ static void generic_hdmi_free(struct hda_codec *codec)
int pin_idx, pcm_idx;
if (codec_has_acomp(codec))
- snd_hdac_i915_register_notifier(NULL);
+ snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
@@ -2462,6 +2470,38 @@ 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);
}
+/* There is a fixed mapping between audio pin node and display port.
+ * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ *
+ * on VLV, ILK:
+ * Pin Widget 4 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 5 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 6 - PORT D (port = 3 in i915 driver)
+ */
+static int intel_base_nid(struct hda_codec *codec)
+{
+ switch (codec->core.vendor_id) {
+ case 0x80860054: /* ILK */
+ case 0x80862804: /* ILK */
+ case 0x80862882: /* VLV */
+ return 4;
+ default:
+ return 5;
+ }
+}
+
+static int intel_pin2port(void *audio_ptr, int pin_nid)
+{
+ int base_nid = intel_base_nid(audio_ptr);
+
+ if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
+ return -1;
+ return pin_nid - base_nid + 1; /* intel port is 1-based */
+}
+
static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
{
struct hda_codec *codec = audio_ptr;
@@ -2472,16 +2512,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
if (port < 1 || port > 3)
return;
- switch (codec->core.vendor_id) {
- case 0x80860054: /* ILK */
- case 0x80862804: /* ILK */
- case 0x80862882: /* VLV */
- pin_nid = port + 0x03;
- break;
- default:
- pin_nid = port + 0x04;
- break;
- }
+ pin_nid = port + intel_base_nid(codec) - 1; /* intel port is 1-based */
/* skip notification during system suspend (but not in runtime PM);
* the state will be updated at resume
@@ -2489,7 +2520,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
return;
/* ditto during suspend/resume process itself */
- if (atomic_read(&(codec)->core.in_pm))
+ if (snd_hdac_is_in_pm(&codec->core))
return;
snd_hdac_i915_set_bclk(&codec->bus->core);
@@ -2502,14 +2533,16 @@ static void register_i915_notifier(struct hda_codec *codec)
struct hdmi_spec *spec = codec->spec;
spec->use_acomp_notifier = true;
- spec->i915_audio_ops.audio_ptr = codec;
+ spec->drm_audio_ops.audio_ptr = codec;
/* intel_audio_codec_enable() or intel_audio_codec_disable()
* will call pin_eld_notify with using audio_ptr pointer
* We need make sure audio_ptr is really setup
*/
wmb();
- spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify;
- snd_hdac_i915_register_notifier(&spec->i915_audio_ops);
+ spec->drm_audio_ops.pin2port = intel_pin2port;
+ spec->drm_audio_ops.pin_eld_notify = intel_pin_eld_notify;
+ snd_hdac_acomp_register_notifier(&codec->bus->core,
+ &spec->drm_audio_ops);
}
/* setup_stream ops override for HSW+ */
@@ -2542,6 +2575,8 @@ static int alloc_intel_hdmi(struct hda_codec *codec)
/* requires i915 binding */
if (!codec->bus->core.audio_component) {
codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+ /* set probe_id here to prevent generic fallback binding */
+ codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
return -ENODEV;
}
@@ -3741,6 +3776,11 @@ static int patch_atihdmi(struct hda_codec *codec)
spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
+ /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
+ * the link-down as is. Tell the core to allow it.
+ */
+ codec->link_down_at_suspend = 1;
+
return 0;
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index e9bd33ea538f..b20974ef1e13 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -43,11 +43,9 @@
/* extra amp-initialization sequence types */
enum {
+ ALC_INIT_UNDEFINED,
ALC_INIT_NONE,
ALC_INIT_DEFAULT,
- ALC_INIT_GPIO1,
- ALC_INIT_GPIO2,
- ALC_INIT_GPIO3,
};
enum {
@@ -85,19 +83,20 @@ struct alc_spec {
struct hda_gen_spec gen; /* must be at head */
/* codec parameterization */
- const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
- unsigned int num_mixers;
- unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
-
struct alc_customize_define cdefine;
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+ /* GPIO bits */
+ unsigned int gpio_mask;
+ unsigned int gpio_dir;
+ unsigned int gpio_data;
+ bool gpio_write_delay; /* add a delay before writing gpio_data */
+
/* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */
int mute_led_polarity;
hda_nid_t mute_led_nid;
hda_nid_t cap_mute_led_nid;
- unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
unsigned int gpio_mute_led_mask;
unsigned int gpio_mic_led_mask;
@@ -205,41 +204,87 @@ static void alc_process_coef_fw(struct hda_codec *codec,
}
/*
- * Append the given mixer and verb elements for the later use
- * The mixer array is referred in build_controls(), and init_verbs are
- * called in init().
+ * GPIO setup tables, used in initialization
*/
-static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
+
+/* Enable GPIO mask and set output */
+static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
{
- if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
+ struct alc_spec *spec = codec->spec;
+
+ spec->gpio_mask |= mask;
+ spec->gpio_dir |= mask;
+ spec->gpio_data |= mask;
+}
+
+static void alc_write_gpio_data(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+ spec->gpio_data);
+}
+
+static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+ bool on)
+{
+ struct alc_spec *spec = codec->spec;
+ unsigned int oldval = spec->gpio_data;
+
+ if (on)
+ spec->gpio_data |= mask;
+ else
+ spec->gpio_data &= ~mask;
+ if (oldval != spec->gpio_data)
+ alc_write_gpio_data(codec);
+}
+
+static void alc_write_gpio(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (!spec->gpio_mask)
return;
- spec->mixers[spec->num_mixers++] = mix;
+
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
+ if (spec->gpio_write_delay)
+ msleep(1);
+ alc_write_gpio_data(codec);
}
-/*
- * GPIO setup tables, used in initialization
- */
-/* Enable GPIO mask and set output */
-static const struct hda_verb alc_gpio1_init_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x01},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- { }
-};
+static void alc_fixup_gpio(struct hda_codec *codec, int action,
+ unsigned int mask)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ alc_setup_gpio(codec, mask);
+}
-static const struct hda_verb alc_gpio2_init_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
- { }
-};
+static void alc_fixup_gpio1(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x01);
+}
-static const struct hda_verb alc_gpio3_init_verbs[] = {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x03},
- { }
-};
+static void alc_fixup_gpio2(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x02);
+}
+
+static void alc_fixup_gpio3(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x03);
+}
+
+static void alc_fixup_gpio4(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_gpio(codec, action, 0x04);
+}
/*
* Fix hardware PLL issue
@@ -447,16 +492,8 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type)
{
alc_fill_eapd_coef(codec);
alc_auto_setup_eapd(codec, true);
+ alc_write_gpio(codec);
switch (type) {
- case ALC_INIT_GPIO1:
- snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
- break;
- case ALC_INIT_GPIO2:
- snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
- break;
- case ALC_INIT_GPIO3:
- snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
- break;
case ALC_INIT_DEFAULT:
switch (codec->core.vendor_id) {
case 0x10ec0260:
@@ -656,20 +693,22 @@ do_sku:
* 7~6 : Reserved
*/
tmp = (ass & 0x38) >> 3; /* external Amp control */
- switch (tmp) {
- case 1:
- spec->init_amp = ALC_INIT_GPIO1;
- break;
- case 3:
- spec->init_amp = ALC_INIT_GPIO2;
- break;
- case 7:
- spec->init_amp = ALC_INIT_GPIO3;
- break;
- case 5:
- default:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
+ if (spec->init_amp == ALC_INIT_UNDEFINED) {
+ switch (tmp) {
+ case 1:
+ alc_setup_gpio(codec, 0x01);
+ break;
+ case 3:
+ alc_setup_gpio(codec, 0x02);
+ break;
+ case 7:
+ alc_setup_gpio(codec, 0x03);
+ break;
+ case 5:
+ default:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
+ }
}
/* is laptop or Desktop and enable the function "Mute internal speaker
@@ -722,47 +761,14 @@ static void alc_fixup_inv_dmic(struct hda_codec *codec,
}
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new alc_beep_mixer[] = {
- HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
- HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
- { } /* end */
-};
-#endif
-
static int alc_build_controls(struct hda_codec *codec)
{
- struct alc_spec *spec = codec->spec;
- int i, err;
+ int err;
err = snd_hda_gen_build_controls(codec);
if (err < 0)
return err;
- for (i = 0; i < spec->num_mixers; i++) {
- err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
- if (err < 0)
- return err;
- }
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
- /* create beep controls if needed */
- if (spec->beep_amp) {
- const struct snd_kcontrol_new *knew;
- for (knew = alc_beep_mixer; knew->name; knew++) {
- struct snd_kcontrol *kctl;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
- }
- }
-#endif
-
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
return 0;
}
@@ -973,8 +979,30 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec)
* Digital-beep handlers
*/
#ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define set_beep_amp(spec, nid, idx, dir) \
- ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
+
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
+ HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+ HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
+};
+
+/* set up and create beep controls */
+static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
+ int idx, int dir)
+{
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &alc_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
+ }
+ return 0;
+}
static const struct snd_pci_quirk beep_white_list[] = {
SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
@@ -999,7 +1027,7 @@ static inline int has_cdefine_beep(struct hda_codec *codec)
return spec->cdefine.enable_pcbeep;
}
#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#define set_beep_amp(spec, nid, idx, dir) 0
#define has_cdefine_beep(codec) 0
#endif
@@ -1104,12 +1132,12 @@ static void alc880_fixup_vol_knob(struct hda_codec *codec,
static const struct hda_fixup alc880_fixups[] = {
[ALC880_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
},
[ALC880_FIXUP_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio2_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio2,
},
[ALC880_FIXUP_MEDION_RIM] = {
.type = HDA_FIXUP_VERBS,
@@ -1501,8 +1529,11 @@ static int patch_alc880(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -1544,8 +1575,8 @@ enum {
static void alc260_gpio1_automute(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gen.hp_jack_present);
+
+ alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
}
static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
@@ -1562,7 +1593,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
snd_hda_jack_detect_enable_callback(codec, 0x0f,
snd_hda_gen_hp_automute);
- snd_hda_add_verbs(codec, alc_gpio1_init_verbs);
+ alc_setup_gpio(codec, 0x01);
}
}
@@ -1589,8 +1620,6 @@ static void alc260_fixup_kn1(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
snd_hda_apply_pincfgs(codec, pincfgs);
- break;
- case HDA_FIXUP_ACT_PROBE:
spec->init_amp = ALC_INIT_NONE;
break;
}
@@ -1600,7 +1629,7 @@ static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- if (action == HDA_FIXUP_ACT_PROBE)
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
spec->init_amp = ALC_INIT_NONE;
}
@@ -1638,8 +1667,8 @@ static const struct hda_fixup alc260_fixups[] = {
},
},
[ALC260_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
},
[ALC260_FIXUP_GPIO1_TOGGLE] = {
.type = HDA_FIXUP_FUNC,
@@ -1751,8 +1780,11 @@ static int patch_alc260(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -1824,47 +1856,14 @@ static void alc889_fixup_coef(struct hda_codec *codec,
alc_update_coef_idx(codec, 7, 0, 0x2030);
}
-/* toggle speaker-output according to the hp-jack state */
-static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
-{
- unsigned int gpiostate, gpiomask, gpiodir;
-
- gpiostate = snd_hda_codec_read(codec, codec->core.afg, 0,
- AC_VERB_GET_GPIO_DATA, 0);
-
- if (!muted)
- gpiostate |= (1 << pin);
- else
- gpiostate &= ~(1 << pin);
-
- gpiomask = snd_hda_codec_read(codec, codec->core.afg, 0,
- AC_VERB_GET_GPIO_MASK, 0);
- gpiomask |= (1 << pin);
-
- gpiodir = snd_hda_codec_read(codec, codec->core.afg, 0,
- AC_VERB_GET_GPIO_DIRECTION, 0);
- gpiodir |= (1 << pin);
-
-
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_MASK, gpiomask);
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, gpiodir);
-
- msleep(1);
-
- snd_hda_codec_write(codec, codec->core.afg, 0,
- AC_VERB_SET_GPIO_DATA, gpiostate);
-}
-
/* set up GPIO at initialization */
static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- if (action != HDA_FIXUP_ACT_INIT)
- return;
- alc882_gpio_mute(codec, 0, 0);
- alc882_gpio_mute(codec, 1, 0);
+ struct alc_spec *spec = codec->spec;
+
+ spec->gpio_write_delay = true;
+ alc_fixup_gpio3(codec, fix, action);
}
/* Fix the connection of some pins for ALC889:
@@ -2143,20 +2142,20 @@ static const struct hda_fixup alc882_fixups[] = {
}
},
[ALC882_FIXUP_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
},
[ALC882_FIXUP_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio2_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio2,
},
[ALC882_FIXUP_GPIO3] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio3_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio3,
},
[ALC882_FIXUP_ASUS_W2JC] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = alc_gpio1_init_verbs,
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio1,
.chained = true,
.chain_id = ALC882_FIXUP_EAPD,
},
@@ -2366,6 +2365,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
+ SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -2375,12 +2375,37 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
};
static const struct hda_model_fixup alc882_fixup_models[] = {
+ {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
+ {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
+ {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
+ {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
+ {.id = ALC889_FIXUP_CD, .name = "cd"},
+ {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
+ {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
+ {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
+ {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
+ {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
+ {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
+ {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
+ {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
+ {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
+ {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
{.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
{.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
{.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
+ {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
+ {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
+ {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
+ {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
+ {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
+ {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
+ {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
+ {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
{.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
{.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+ {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
{.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+ {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
{}
};
@@ -2434,8 +2459,11 @@ static int patch_alc882(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog && spec->gen.beep_nid)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -2545,6 +2573,7 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
+ SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
@@ -2555,6 +2584,14 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = {
static const struct hda_model_fixup alc262_fixup_models[] = {
{.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
+ {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
+ {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
+ {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
+ {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
+ {.id = ALC262_FIXUP_BENQ, .name = "benq"},
+ {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
+ {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
{}
};
@@ -2596,8 +2633,11 @@ static int patch_alc262(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog && spec->gen.beep_nid)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog && spec->gen.beep_nid) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -2643,7 +2683,6 @@ static const struct snd_kcontrol_new alc268_beep_mixer[] = {
.put = alc268_beep_switch_put,
.private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
},
- { }
};
/* set PCBEEP vol = 0, mute connections */
@@ -2684,6 +2723,7 @@ static const struct hda_fixup alc268_fixups[] = {
static const struct hda_model_fixup alc268_fixup_models[] = {
{.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
{.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
+ {.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
{}
};
@@ -2711,7 +2751,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
static int patch_alc268(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err;
+ int i, err;
/* ALC268 has no aa-loopback mixer */
err = alc_alloc_spec(codec, 0);
@@ -2733,7 +2773,13 @@ static int patch_alc268(struct hda_codec *codec)
if (err > 0 && !spec->gen.no_analog &&
spec->gen.autocfg.speaker_pins[0] != 0x1d) {
- add_mixer(spec, alc268_beep_mixer);
+ for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &alc268_beep_mixer[i])) {
+ err = -ENOMEM;
+ goto error;
+ }
+ }
snd_hda_add_verbs(codec, alc268_beep_init_verbs);
if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
/* override the amp caps for beep generator */
@@ -3452,9 +3498,8 @@ static int alc269_resume(struct hda_codec *codec)
* suspend, and won't restore the data after resume, so we restore it
* in the driver.
*/
- if (spec->gpio_led)
- snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
+ if (spec->gpio_data)
+ alc_write_gpio_data(codec);
if (spec->has_alc5505_dsp)
alc5505_dsp_resume(codec);
@@ -3694,18 +3739,10 @@ static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
bool enabled)
{
struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_led;
if (spec->mute_led_polarity)
enabled = !enabled;
-
- if (enabled)
- spec->gpio_led &= ~mask;
- else
- spec->gpio_led |= mask;
- if (spec->gpio_led != oldval)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
+ alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
}
/* turn on/off mute LED via GPIO per vmaster hook */
@@ -3718,104 +3755,79 @@ static void alc_fixup_gpio_mute_hook(void *private_data, int enabled)
}
/* turn on/off mic-mute LED via GPIO per capture hook */
-static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void alc_gpio_micmute_update(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- if (ucontrol)
- alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
- ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1]);
+ alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ spec->gen.micmute_led.led_value);
}
-static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
- const struct hda_fixup *fix, int action)
+/* setup mute and mic-mute GPIO bits, add hooks appropriately */
+static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+ int action,
+ unsigned int mute_mask,
+ unsigned int micmute_mask)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
- {}
- };
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
+
+ if (action != HDA_FIXUP_ACT_PRE_PROBE)
+ return;
+ if (mute_mask) {
+ spec->gpio_mute_led_mask = mute_mask;
spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
- spec->gpio_mic_led_mask = 0x10;
- snd_hda_add_verbs(codec, gpio_init);
+ }
+ if (micmute_mask) {
+ spec->gpio_mic_led_mask = micmute_mask;
+ snd_hda_gen_add_micmute_led(codec, alc_gpio_micmute_update);
}
}
-static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
+}
- if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x02;
- spec->gpio_mic_led_mask = 0x20;
- snd_hda_add_verbs(codec, gpio_init);
- }
+static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20);
}
/* turn on/off mic-mute LED per capture hook */
-static void alc269_fixup_hp_cap_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void alc_cap_micmute_update(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- unsigned int pinval, enable, disable;
+ unsigned int pinval;
+ if (!spec->cap_mute_led_nid)
+ return;
pinval = snd_hda_codec_get_pin_target(codec, spec->cap_mute_led_nid);
pinval &= ~AC_PINCTL_VREFEN;
- enable = pinval | AC_PINCTL_VREF_80;
- disable = pinval | AC_PINCTL_VREF_HIZ;
-
- if (!ucontrol)
- return;
-
- if (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1])
- pinval = disable;
+ if (spec->gen.micmute_led.led_value)
+ pinval |= AC_PINCTL_VREF_80;
else
- pinval = enable;
-
- if (spec->cap_mute_led_nid)
- snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval);
+ pinval |= AC_PINCTL_VREF_HIZ;
+ snd_hda_set_pin_ctl_cache(codec, spec->cap_mute_led_nid, pinval);
}
static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x08 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x08 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
+ /* Like hp_gpio_mic1_led, but also needs GPIO4 low to
+ * enable headphone amp
+ */
+ spec->gpio_mask |= 0x10;
+ spec->gpio_dir |= 0x10;
spec->cap_mute_led_nid = 0x18;
- snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update);
codec->power_filter = led_power_filter;
}
}
@@ -3823,22 +3835,12 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- /* Like hp_gpio_mic1_led, but also needs GPIO4 low to enable headphone amp */
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
spec->cap_mute_led_nid = 0x18;
- snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update);
codec->power_filter = led_power_filter;
}
}
@@ -3888,38 +3890,29 @@ static int alc_register_micmute_input_device(struct hda_codec *codec)
return 0;
}
+/* GPIO1 = set according to SKU external amp
+ * GPIO2 = mic mute hotkey
+ * GPIO3 = mute LED
+ * GPIO4 = mic mute LED
+ */
static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- /* GPIO1 = set according to SKU external amp
- GPIO2 = mic mute hotkey
- GPIO3 = mute LED
- GPIO4 = mic mute LED */
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x1e },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x1a },
- { 0x01, AC_VERB_SET_GPIO_DATA, 0x02 },
- {}
- };
-
struct alc_spec *spec = codec->spec;
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->init_amp = ALC_INIT_DEFAULT;
if (alc_register_micmute_input_device(codec) != 0)
return;
- snd_hda_add_verbs(codec, gpio_init);
+ spec->gpio_mask |= 0x06;
+ spec->gpio_dir |= 0x02;
+ spec->gpio_data |= 0x02;
snd_hda_codec_write_cache(codec, codec->core.afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
gpio2_mic_hotkey_event);
-
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
- spec->gpio_mic_led_mask = 0x10;
return;
}
@@ -3927,40 +3920,28 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
return;
switch (action) {
- case HDA_FIXUP_ACT_PROBE:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
case HDA_FIXUP_ACT_FREE:
input_unregister_device(spec->kb_dev);
spec->kb_dev = NULL;
}
}
+/* Line2 = mic mute hotkey
+ * GPIO2 = mic mute LED
+ */
static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
- /* Line2 = mic mute hotkey
- GPIO2 = mic mute LED */
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
- {}
- };
-
struct alc_spec *spec = codec->spec;
+ alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->init_amp = ALC_INIT_DEFAULT;
if (alc_register_micmute_input_device(codec) != 0)
return;
- snd_hda_add_verbs(codec, gpio_init);
snd_hda_jack_detect_enable_callback(codec, 0x1b,
gpio2_mic_hotkey_event);
-
- spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
- spec->gpio_led = 0;
- spec->mute_led_polarity = 0;
- spec->gpio_mic_led_mask = 0x04;
return;
}
@@ -3968,9 +3949,6 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
return;
switch (action) {
- case HDA_FIXUP_ACT_PROBE:
- spec->init_amp = ALC_INIT_DEFAULT;
- break;
case HDA_FIXUP_ACT_FREE:
input_unregister_device(spec->kb_dev);
spec->kb_dev = NULL;
@@ -3986,14 +3964,10 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
{
struct alc_spec *spec = codec->spec;
+ alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1a);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
- spec->mute_led_polarity = 0;
- spec->mute_led_nid = 0x1a;
spec->cap_mute_led_nid = 0x18;
- spec->gen.vmaster_mute_enum = 1;
- codec->power_filter = led_power_filter;
+ snd_hda_gen_add_micmute_led(codec, alc_cap_micmute_update);
}
}
@@ -4841,6 +4815,7 @@ static void alc_probe_headset_mode(struct hda_codec *codec)
spec->headphone_mic_pin = cfg->inputs[i].pin;
}
+ WARN_ON(spec->gen.cap_sync_hook);
spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
spec->gen.automute_hook = alc_update_headset_mode;
spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
@@ -4932,13 +4907,10 @@ static void alc288_update_headset_jack_cb(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
struct alc_spec *spec = codec->spec;
- int present;
alc_update_headset_jack_cb(codec, jack);
/* Headset Mic enable or disable, only for Dell Dino */
- present = spec->gen.hp_jack_present ? 0x40 : 0;
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- present);
+ alc_update_gpio_data(codec, 0x40, spec->gen.hp_jack_present);
}
static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
@@ -4947,6 +4919,9 @@ static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
alc_fixup_headset_mode(codec, fix, action);
if (action == HDA_FIXUP_ACT_PROBE) {
struct alc_spec *spec = codec->spec;
+ /* toggled via hp_automute_hook */
+ spec->gpio_mask |= 0x40;
+ spec->gpio_dir |= 0x40;
spec->gen.hp_automute_hook = alc288_update_headset_jack_cb;
}
}
@@ -4967,7 +4942,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_PROBE) {
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
struct alc_spec *spec = codec->spec;
spec->shutup = alc_no_shutup;
}
@@ -4995,7 +4970,6 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->shutup = alc_no_shutup; /* reduce click noise */
spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */
spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
codec->power_save_node = 0; /* avoid click noises */
@@ -5050,10 +5024,9 @@ static void alc_fixup_dell_xps13(struct hda_codec *codec,
* it causes a click noise at start up
*/
snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+ spec->shutup = alc_shutup_dell_xps13;
break;
case HDA_FIXUP_ACT_PROBE:
- spec->shutup = alc_shutup_dell_xps13;
-
/* Make the internal mic the default input source. */
for (i = 0; i < imux->num_items; i++) {
if (spec->gen.imux_pins[i] == 0x12) {
@@ -5230,13 +5203,6 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- /* TX300 needs to set up GPIO2 for the speaker amp */
- static const struct hda_verb gpio2_verbs[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
- {}
- };
static const struct hda_pintbl dock_pins[] = {
{ 0x1b, 0x21114000 }, /* dock speaker pin */
{}
@@ -5244,13 +5210,18 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
- snd_hda_add_verbs(codec, gpio2_verbs);
+ spec->init_amp = ALC_INIT_DEFAULT;
+ /* TX300 needs to set up GPIO2 for the speaker amp */
+ alc_setup_gpio(codec, 0x04);
snd_hda_apply_pincfgs(codec, dock_pins);
spec->gen.auto_mute_via_amp = 1;
spec->gen.automute_hook = asus_tx300_automute;
snd_hda_jack_detect_enable_callback(codec, 0x1b,
snd_hda_gen_hp_automute);
break;
+ case HDA_FIXUP_ACT_PROBE:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
case HDA_FIXUP_ACT_BUILD:
/* this is a bit tricky; give more sane names for the main
* (tablet) speaker and the dock speaker, respectively
@@ -5324,30 +5295,26 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec,
int action)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- /* Set the hooks to turn the headphone amp on/off
- * as needed
- */
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ /* amp at GPIO4; toggled via alc280_hp_gpio4_automute_hook() */
+ spec->gpio_mask |= 0x10;
+ spec->gpio_dir |= 0x10;
spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook;
+ }
+}
- /* The GPIOs are currently off */
- spec->gpio_led = 0;
-
- /* GPIO3 is connected to the output mute LED,
- * high is on, low is off
- */
- spec->mute_led_polarity = 0;
- spec->gpio_mute_led_mask = 0x08;
+static void alc275_fixup_gpio4_off(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ struct alc_spec *spec = codec->spec;
- /* Initialize GPIO configuration */
- snd_hda_add_verbs(codec, gpio_init);
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gpio_mask |= 0x04;
+ spec->gpio_dir |= 0x04;
+ /* set data bit low */
}
}
@@ -5394,6 +5361,13 @@ static void alc274_fixup_bind_dacs(struct hda_codec *codec,
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
+static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ alc_fixup_no_shutup(codec, fix, action); /* reduce click noise */
+ hda_fixup_thinkpad_acpi(codec, fix, action);
+}
+
/* for dell wmi mic mute led */
#include "dell_wmi_helper.c"
@@ -5484,7 +5458,6 @@ enum {
ALC280_FIXUP_HP_9480M,
ALC288_FIXUP_DELL_HEADSET_MODE,
ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
- ALC288_FIXUP_DELL_XPS_13_GPIO6,
ALC288_FIXUP_DELL_XPS_13,
ALC288_FIXUP_DISABLE_AAMIX,
ALC292_FIXUP_DELL_E7X,
@@ -5532,13 +5505,8 @@ static const struct hda_fixup alc269_fixups[] = {
}
},
[ALC275_FIXUP_SONY_VAIO_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x04},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- { }
- },
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc275_fixup_gpio4_off,
.chained = true,
.chain_id = ALC269_FIXUP_SONY_VAIO
},
@@ -5946,7 +5914,7 @@ static const struct hda_fixup alc269_fixups[] = {
},
[ALC269_FIXUP_THINKPAD_ACPI] = {
.type = HDA_FIXUP_FUNC,
- .v.func = hda_fixup_thinkpad_acpi,
+ .v.func = alc_fixup_thinkpad_acpi,
.chained = true,
.chain_id = ALC269_FIXUP_SKU_IGNORE,
},
@@ -6105,22 +6073,11 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC288_FIXUP_DELL_HEADSET_MODE
},
- [ALC288_FIXUP_DELL_XPS_13_GPIO6] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- {0x01, AC_VERB_SET_GPIO_MASK, 0x40},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x40},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
- { }
- },
- .chained = true,
- .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
- },
[ALC288_FIXUP_DISABLE_AAMIX] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_disable_aamix,
.chained = true,
- .chain_id = ALC288_FIXUP_DELL_XPS_13_GPIO6
+ .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
},
[ALC288_FIXUP_DELL_XPS_13] = {
.type = HDA_FIXUP_FUNC,
@@ -6283,14 +6240,9 @@ static const struct hda_fixup alc269_fixups[] = {
.chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
},
[ALC256_FIXUP_ASUS_AIO_GPIO2] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* Set up GPIO2 for the speaker amp */
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
- { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
- {}
- },
+ .type = HDA_FIXUP_FUNC,
+ /* Set up GPIO2 for the speaker amp */
+ .v.func = alc_fixup_gpio4,
},
[ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
@@ -6522,6 +6474,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360),
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(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -6562,6 +6515,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC),
SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
+ SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
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),
@@ -6603,8 +6557,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
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, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+ SND_PCI_QUIRK(0x17aa, 0x312a, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
- SND_PCI_QUIRK(0x17aa, 0x3138, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
@@ -6704,13 +6658,95 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.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 = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"},
+ {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"},
{.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
{.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
{.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
{.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
{.id = ALC292_FIXUP_TPT460, .name = "tpt460"},
+ {.id = ALC298_FIXUP_TPT470_DOCK, .name = "tpt470-dock"},
{.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
{.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"},
+ {.id = ALC269_FIXUP_SONY_VAIO, .name = "vaio"},
+ {.id = ALC269_FIXUP_DELL_M101Z, .name = "dell-m101z"},
+ {.id = ALC269_FIXUP_ASUS_G73JW, .name = "asus-g73jw"},
+ {.id = ALC269_FIXUP_LENOVO_EAPD, .name = "lenovo-eapd"},
+ {.id = ALC275_FIXUP_SONY_HWEQ, .name = "sony-hweq"},
+ {.id = ALC269_FIXUP_PCM_44K, .name = "pcm44k"},
+ {.id = ALC269_FIXUP_LIFEBOOK, .name = "lifebook"},
+ {.id = ALC269_FIXUP_LIFEBOOK_EXTMIC, .name = "lifebook-extmic"},
+ {.id = ALC269_FIXUP_LIFEBOOK_HP_PIN, .name = "lifebook-hp-pin"},
+ {.id = ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC, .name = "lifebook-u7x7"},
+ {.id = ALC269VB_FIXUP_AMIC, .name = "alc269vb-amic"},
+ {.id = ALC269VB_FIXUP_DMIC, .name = "alc269vb-dmic"},
+ {.id = ALC269_FIXUP_HP_MUTE_LED_MIC1, .name = "hp-mute-led-mic1"},
+ {.id = ALC269_FIXUP_HP_MUTE_LED_MIC2, .name = "hp-mute-led-mic2"},
+ {.id = ALC269_FIXUP_HP_MUTE_LED_MIC3, .name = "hp-mute-led-mic3"},
+ {.id = ALC269_FIXUP_HP_GPIO_MIC1_LED, .name = "hp-gpio-mic1"},
+ {.id = ALC269_FIXUP_HP_LINE1_MIC1_LED, .name = "hp-line1-mic1"},
+ {.id = ALC269_FIXUP_NO_SHUTUP, .name = "noshutup"},
+ {.id = ALC286_FIXUP_SONY_MIC_NO_PRESENCE, .name = "sony-nomic"},
+ {.id = ALC269_FIXUP_ASPIRE_HEADSET_MIC, .name = "aspire-headset-mic"},
+ {.id = ALC269_FIXUP_ASUS_X101, .name = "asus-x101"},
+ {.id = ALC271_FIXUP_HP_GATE_MIC_JACK, .name = "acer-ao7xx"},
+ {.id = ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, .name = "acer-aspire-e1"},
+ {.id = ALC269_FIXUP_ACER_AC700, .name = "acer-ac700"},
+ {.id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, .name = "limit-mic-boost"},
+ {.id = ALC269VB_FIXUP_ASUS_ZENBOOK, .name = "asus-zenbook"},
+ {.id = ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, .name = "asus-zenbook-ux31a"},
+ {.id = ALC269VB_FIXUP_ORDISSIMO_EVE2, .name = "ordissimo"},
+ {.id = ALC282_FIXUP_ASUS_TX300, .name = "asus-tx300"},
+ {.id = ALC283_FIXUP_INT_MIC, .name = "alc283-int-mic"},
+ {.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"},
+ {.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"},
+ {.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"},
+ {.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"},
+ {.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"},
+ {.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"},
+ {.id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"},
+ {.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
+ {.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
+ {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
+ {.id = ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, .name = "alc255-dell-mute"},
+ {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
+ {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
+ {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
+ {.id = ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, .name = "hp-gpio2-hotkey"},
+ {.id = ALC280_FIXUP_HP_DOCK_PINS, .name = "hp-dock-pins"},
+ {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic"},
+ {.id = ALC280_FIXUP_HP_9480M, .name = "hp-9480m"},
+ {.id = ALC288_FIXUP_DELL_HEADSET_MODE, .name = "alc288-dell-headset"},
+ {.id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc288-dell1"},
+ {.id = ALC288_FIXUP_DELL_XPS_13, .name = "alc288-dell-xps13"},
+ {.id = ALC292_FIXUP_DELL_E7X, .name = "dell-e7x"},
+ {.id = ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, .name = "alc293-dell"},
+ {.id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc298-dell1"},
+ {.id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, .name = "alc298-dell-aio"},
+ {.id = ALC275_FIXUP_DELL_XPS, .name = "alc275-dell-xps"},
+ {.id = ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE, .name = "alc256-dell-xps13"},
+ {.id = ALC293_FIXUP_LENOVO_SPK_NOISE, .name = "lenovo-spk-noise"},
+ {.id = ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, .name = "lenovo-hotkey"},
+ {.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"},
+ {.id = ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"},
+ {.id = ALC295_FIXUP_DISABLE_DAC3, .name = "alc295-disable-dac3"},
+ {.id = ALC280_FIXUP_HP_HEADSET_MIC, .name = "alc280-hp-headset"},
+ {.id = ALC221_FIXUP_HP_FRONT_MIC, .name = "alc221-hp-mic"},
+ {.id = ALC298_FIXUP_SPK_VOLUME, .name = "alc298-spk-volume"},
+ {.id = ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, .name = "dell-inspiron-7559"},
+ {.id = ALC269_FIXUP_ATIV_BOOK_8, .name = "ativ-book"},
+ {.id = ALC221_FIXUP_HP_MIC_NO_PRESENCE, .name = "alc221-hp-mic"},
+ {.id = ALC256_FIXUP_ASUS_HEADSET_MODE, .name = "alc256-asus-headset"},
+ {.id = ALC256_FIXUP_ASUS_MIC, .name = "alc256-asus-mic"},
+ {.id = ALC256_FIXUP_ASUS_AIO_GPIO2, .name = "alc256-asus-aio"},
+ {.id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc233-asus"},
+ {.id = ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, .name = "alc233-eapd"},
+ {.id = ALC294_FIXUP_LENOVO_MIC_LOCATION, .name = "alc294-lenovo-mic"},
+ {.id = ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, .name = "alc225-wyse"},
+ {.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
+ {.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
+ {.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
+ {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
{}
};
#define ALC225_STANDARD_PINS \
@@ -6782,6 +6818,17 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x14, 0x90170110},
{0x19, 0x02a11030},
{0x21, 0x02211020}),
+ SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+ {0x14, 0x90170110},
+ {0x19, 0x02a11030},
+ {0x1a, 0x02a11040},
+ {0x1b, 0x01014020},
+ {0x21, 0x0221101f}),
+ SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+ {0x14, 0x90170110},
+ {0x19, 0x02a11020},
+ {0x1a, 0x02a11030},
+ {0x21, 0x0221101f}),
SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60140},
{0x14, 0x90170110},
@@ -6963,7 +7010,7 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
{0x12, 0x90a60130},
{0x19, 0x03a11020},
{0x21, 0x0321101f}),
- SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL_XPS_13_GPIO6,
+ SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
{0x12, 0x90a60120},
{0x14, 0x90170110},
{0x21, 0x0321101f}),
@@ -7120,18 +7167,6 @@ static int patch_alc269(struct hda_codec *codec)
spec->shutup = alc_default_shutup;
spec->init_hook = alc_default_init;
- snd_hda_pick_fixup(codec, alc269_fixup_models,
- alc269_fixup_tbl, alc269_fixups);
- snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups);
- snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
- alc269_fixups);
- snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
- alc_auto_parse_customize_define(codec);
-
- if (has_cdefine_beep(codec))
- spec->gen.beep_nid = 0x01;
-
switch (codec->core.vendor_id) {
case 0x10ec0269:
spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -7251,13 +7286,28 @@ static int patch_alc269(struct hda_codec *codec)
spec->init_hook = alc5505_dsp_init;
}
+ snd_hda_pick_fixup(codec, alc269_fixup_models,
+ alc269_fixup_tbl, alc269_fixups);
+ snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups);
+ snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
+ alc269_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ alc_auto_parse_customize_define(codec);
+
+ if (has_cdefine_beep(codec))
+ spec->gen.beep_nid = 0x01;
+
/* automatic parse from the BIOS config */
err = alc269_parse_auto_config(codec);
if (err < 0)
goto error;
- if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid)
- set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT);
+ if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) {
+ err = set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7386,8 +7436,11 @@ static int patch_alc861(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7427,16 +7480,21 @@ static void alc861vd_fixup_dallas(struct hda_codec *codec,
}
}
+/* reset GPIO1 */
+static void alc660vd_fixup_asus_gpio1(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->gpio_mask |= 0x02;
+ alc_fixup_gpio(codec, action, 0x01);
+}
+
static const struct hda_fixup alc861vd_fixups[] = {
[ALC660VD_FIX_ASUS_GPIO1] = {
- .type = HDA_FIXUP_VERBS,
- .v.verbs = (const struct hda_verb[]) {
- /* reset GPIO1 */
- {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
- {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
- {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
- { }
- }
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc660vd_fixup_asus_gpio1,
},
[ALC861VD_FIX_DALLAS] = {
.type = HDA_FIXUP_FUNC,
@@ -7475,8 +7533,11 @@ static int patch_alc861vd(struct hda_codec *codec)
if (err < 0)
goto error;
- if (!spec->gen.no_analog)
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (!spec->gen.no_analog) {
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ if (err < 0)
+ goto error;
+ }
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
@@ -7557,7 +7618,7 @@ static unsigned int gpio_led_power_filter(struct hda_codec *codec,
unsigned int power_state)
{
struct alc_spec *spec = codec->spec;
- if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_led)
+ if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
return AC_PWRST_D0;
return power_state;
}
@@ -7566,18 +7627,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- static const struct hda_verb gpio_init[] = {
- { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
- { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
- {}
- };
+ alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
- spec->gpio_led = 0;
spec->mute_led_polarity = 1;
- spec->gpio_mute_led_mask = 0x01;
- snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = gpio_led_power_filter;
}
}
@@ -8090,7 +8143,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
};
static const struct hda_model_fixup alc662_fixup_models[] = {
+ {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
+ {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
{.id = ALC272_FIXUP_MARIO, .name = "mario"},
+ {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
@@ -8099,8 +8155,23 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
+ {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
{.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
+ {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
{.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+ {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
+ {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
+ {.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
+ {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
+ {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
+ {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
+ {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
+ {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+ {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
+ {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
+ {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
+ {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
+ {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
{.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
{}
};
@@ -8194,18 +8265,20 @@ static int patch_alc662(struct hda_codec *codec)
if (!spec->gen.no_analog && spec->gen.beep_nid) {
switch (codec->core.vendor_id) {
case 0x10ec0662:
- set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+ err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
break;
case 0x10ec0272:
case 0x10ec0663:
case 0x10ec0665:
case 0x10ec0668:
- set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+ err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
break;
case 0x10ec0273:
- set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+ err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
break;
}
+ if (err < 0)
+ goto error;
}
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 63d15b545b33..046705b4691a 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -332,33 +332,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
}
/* hook for controlling mic-mute LED GPIO */
-static void stac_capture_led_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void stac_capture_led_update(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
- unsigned int mask;
- bool cur_mute, prev_mute;
- if (!kcontrol || !ucontrol)
- return;
-
- mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
- prev_mute = !spec->mic_enabled;
- if (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1])
- spec->mic_enabled |= mask;
+ if (spec->gen.micmute_led.led_value)
+ spec->gpio_data |= spec->mic_mute_led_gpio;
else
- spec->mic_enabled &= ~mask;
- cur_mute = !spec->mic_enabled;
- if (cur_mute != prev_mute) {
- if (cur_mute)
- spec->gpio_data |= spec->mic_mute_led_gpio;
- else
- spec->gpio_data &= ~spec->mic_mute_led_gpio;
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data);
- }
+ spec->gpio_data &= ~spec->mic_mute_led_gpio;
+ stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
}
static int stac_vrefout_set(struct hda_codec *codec,
@@ -4656,8 +4638,7 @@ static void stac_setup_gpio(struct hda_codec *codec)
spec->gpio_dir |= spec->mic_mute_led_gpio;
spec->mic_enabled = 0;
spec->gpio_data |= spec->mic_mute_led_gpio;
-
- spec->gen.cap_sync_hook = stac_capture_led_hook;
+ snd_hda_gen_add_micmute_led(codec, stac_capture_led_update);
}
}
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index fc30d1e8aa76..6b9617aee0e6 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -90,13 +90,6 @@ enum VIA_HDA_CODEC {
struct via_spec {
struct hda_gen_spec gen;
- /* codec parameterization */
- const struct snd_kcontrol_new *mixers[6];
- unsigned int num_mixers;
-
- const struct hda_verb *init_verbs[5];
- unsigned int num_iverbs;
-
/* HP mode source */
unsigned int dmic_enabled;
enum VIA_HDA_CODEC codec_type;
@@ -107,8 +100,6 @@ struct via_spec {
/* work to check hp jack state */
int hp_work_active;
int vt1708_jack_detect;
-
- unsigned int beep_amp;
};
static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
@@ -262,69 +253,51 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct snd_kcontrol_new via_pin_power_ctl_enum[] = {
- {
+static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Dynamic Power-Control",
.info = via_pin_power_ctl_info,
.get = via_pin_power_ctl_get,
.put = via_pin_power_ctl_put,
- },
- {} /* terminator */
};
#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static inline void set_beep_amp(struct via_spec *spec, hda_nid_t nid,
- int idx, int dir)
-{
- spec->gen.beep_nid = nid;
- spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-}
-
/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new cxt_beep_mixer[] = {
+static const struct snd_kcontrol_new via_beep_mixer[] = {
HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
- { } /* end */
};
-/* create beep controls if needed */
-static int add_beep_ctls(struct hda_codec *codec)
+static int set_beep_amp(struct via_spec *spec, hda_nid_t nid,
+ int idx, int dir)
{
- struct via_spec *spec = codec->spec;
- int err;
+ struct snd_kcontrol_new *knew;
+ unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+ int i;
- if (spec->beep_amp) {
- const struct snd_kcontrol_new *knew;
- for (knew = cxt_beep_mixer; knew->name; knew++) {
- struct snd_kcontrol *kctl;
- kctl = snd_ctl_new1(knew, codec);
- if (!kctl)
- return -ENOMEM;
- kctl->private_value = spec->beep_amp;
- err = snd_hda_ctl_add(codec, 0, kctl);
- if (err < 0)
- return err;
- }
+ spec->gen.beep_nid = nid;
+ for (i = 0; i < ARRAY_SIZE(via_beep_mixer); i++) {
+ knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+ &via_beep_mixer[i]);
+ if (!knew)
+ return -ENOMEM;
+ knew->private_value = beep_amp;
}
return 0;
}
-static void auto_parse_beep(struct hda_codec *codec)
+static int auto_parse_beep(struct hda_codec *codec)
{
struct via_spec *spec = codec->spec;
hda_nid_t nid;
for_each_hda_codec_node(nid, codec)
- if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
- set_beep_amp(spec, nid, 0, HDA_OUTPUT);
- break;
- }
+ if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
+ return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+ return 0;
}
#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#define add_beep_ctls(codec) 0
-#define auto_parse_beep(codec)
+#define auto_parse_beep(codec) 0
#endif
/* check AA path's mute status */
@@ -403,30 +376,6 @@ static void analog_low_current_mode(struct hda_codec *codec)
return __analog_low_current_mode(codec, false);
}
-static int via_build_controls(struct hda_codec *codec)
-{
- struct via_spec *spec = codec->spec;
- int err, i;
-
- err = snd_hda_gen_build_controls(codec);
- if (err < 0)
- return err;
-
- err = add_beep_ctls(codec);
- if (err < 0)
- return err;
-
- spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum;
-
- for (i = 0; i < spec->num_mixers; i++) {
- err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
struct hda_codec *codec,
struct snd_pcm_substream *substream,
@@ -481,7 +430,7 @@ static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
static int via_init(struct hda_codec *codec);
static const struct hda_codec_ops via_patch_ops = {
- .build_controls = via_build_controls,
+ .build_controls = snd_hda_gen_build_controls,
.build_pcms = snd_hda_gen_build_pcms,
.init = via_init,
.free = via_free,
@@ -545,16 +494,13 @@ static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = {
- {
+static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Jack Detect",
.count = 1,
.info = snd_ctl_boolean_mono_info,
.get = vt1708_jack_detect_get,
.put = vt1708_jack_detect_put,
- },
- {} /* terminator */
};
static const struct badness_table via_main_out_badness = {
@@ -586,12 +532,17 @@ static int via_parse_auto_config(struct hda_codec *codec)
if (err < 0)
return err;
- auto_parse_beep(codec);
-
err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
if (err < 0)
return err;
+ err = auto_parse_beep(codec);
+ if (err < 0)
+ return err;
+
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &via_pin_power_ctl_enum))
+ return -ENOMEM;
+
/* disable widget PM at start for compatibility */
codec->power_save_node = 0;
spec->gen.power_down_unused = 0;
@@ -600,12 +551,6 @@ static int via_parse_auto_config(struct hda_codec *codec)
static int via_init(struct hda_codec *codec)
{
- struct via_spec *spec = codec->spec;
- int i;
-
- for (i = 0; i < spec->num_iverbs; i++)
- snd_hda_sequence_write(codec, spec->init_verbs[i]);
-
/* init power states */
__analog_low_current_mode(codec, true);
@@ -623,7 +568,7 @@ static int vt1708_build_controls(struct hda_codec *codec)
int err;
int old_interval = codec->jackpoll_interval;
codec->jackpoll_interval = msecs_to_jiffies(100);
- err = via_build_controls(codec);
+ err = snd_hda_gen_build_controls(codec);
codec->jackpoll_interval = old_interval;
return err;
}
@@ -684,22 +629,29 @@ static int patch_vt1708(struct hda_codec *codec)
vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+ err = snd_hda_add_verbs(codec, vt1708_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
/* add jack detect on/off control */
- spec->mixers[spec->num_mixers++] = vt1708_jack_detect_ctl;
-
- spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs;
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {
+ err = -ENOMEM;
+ goto error;
+ }
/* clear jackpoll_interval again; it's set dynamically */
codec->jackpoll_interval = 0;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
static int patch_vt1709(struct hda_codec *codec)
@@ -715,12 +667,14 @@ static int patch_vt1709(struct hda_codec *codec)
spec->gen.mixer_nid = 0x18;
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
static int patch_vt1708S(struct hda_codec *codec);
@@ -741,12 +695,14 @@ static int patch_vt1708B(struct hda_codec *codec)
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1708S */
@@ -791,16 +747,20 @@ static int patch_vt1708S(struct hda_codec *codec)
if (codec->core.vendor_id == 0x11064397)
snd_hda_codec_set_name(codec, "VT1705");
+ err = snd_hda_add_verbs(codec, vt1708S_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1702 */
@@ -832,16 +792,20 @@ static int patch_vt1702(struct hda_codec *codec)
(0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
(1 << AC_AMPCAP_MUTE_SHIFT));
+ err = snd_hda_add_verbs(codec, vt1702_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1702_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1718S */
@@ -904,16 +868,20 @@ static int patch_vt1718S(struct hda_codec *codec)
override_mic_boost(codec, 0x29, 0, 3, 40);
add_secret_dac_path(codec);
+ err = snd_hda_add_verbs(codec, vt1718S_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1718S_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* Patch for VT1716S */
@@ -955,9 +923,9 @@ static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
- HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT),
- {
+static const struct snd_kcontrol_new vt1716s_dmic_mixer_vol =
+ HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT);
+static const struct snd_kcontrol_new vt1716s_dmic_mixer_sw = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Digital Mic Capture Switch",
.subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
@@ -965,16 +933,12 @@ static const struct snd_kcontrol_new vt1716s_dmic_mixer[] = {
.info = vt1716s_dmic_info,
.get = vt1716s_dmic_get,
.put = vt1716s_dmic_put,
- },
- {} /* end */
};
/* mono-out mixer elements */
-static const struct snd_kcontrol_new vt1716S_mono_out_mixer[] = {
- HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT),
- { } /* end */
-};
+static const struct snd_kcontrol_new vt1716S_mono_out_mixer =
+ HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT);
static const struct hda_verb vt1716S_init_verbs[] = {
/* Enable Boost Volume backdoor */
@@ -1000,19 +964,27 @@ static int patch_vt1716S(struct hda_codec *codec)
override_mic_boost(codec, 0x1a, 0, 3, 40);
override_mic_boost(codec, 0x1e, 0, 3, 40);
+ err = snd_hda_add_verbs(codec, vt1716S_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs;
+ if (err < 0)
+ goto error;
- spec->mixers[spec->num_mixers++] = vt1716s_dmic_mixer;
- spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer;
+ if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||
+ !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||
+ !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {
+ err = -ENOMEM;
+ goto error;
+ }
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* for vt2002P */
@@ -1107,19 +1079,23 @@ static int patch_vt2002P(struct hda_codec *codec)
snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
- /* automatic parse from the BIOS config */
- err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
if (spec->codec_type == VT1802)
- spec->init_verbs[spec->num_iverbs++] = vt1802_init_verbs;
+ err = snd_hda_add_verbs(codec, vt1802_init_verbs);
else
- spec->init_verbs[spec->num_iverbs++] = vt2002P_init_verbs;
+ err = snd_hda_add_verbs(codec, vt2002P_init_verbs);
+ if (err < 0)
+ goto error;
+
+ /* automatic parse from the BIOS config */
+ err = via_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* for vt1812 */
@@ -1148,16 +1124,20 @@ static int patch_vt1812(struct hda_codec *codec)
override_mic_boost(codec, 0x29, 0, 3, 40);
add_secret_dac_path(codec);
+ err = snd_hda_add_verbs(codec, vt1812_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt1812_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/* patch for vt3476 */
@@ -1185,16 +1165,20 @@ static int patch_vt3476(struct hda_codec *codec)
spec->gen.mixer_nid = 0x3f;
add_secret_dac_path(codec);
+ err = snd_hda_add_verbs(codec, vt3476_init_verbs);
+ if (err < 0)
+ goto error;
+
/* automatic parse from the BIOS config */
err = via_parse_auto_config(codec);
- if (err < 0) {
- via_free(codec);
- return err;
- }
-
- spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs;
+ if (err < 0)
+ goto error;
return 0;
+
+ error:
+ via_free(codec);
+ return err;
}
/*
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
index 65bb3ac6af4c..97f49b751e6e 100644
--- a/sound/pci/hda/thinkpad_helper.c
+++ b/sound/pci/hda/thinkpad_helper.c
@@ -27,17 +27,11 @@ static void update_tpacpi_mute_led(void *private_data, int enabled)
led_set_func(TPACPI_LED_MUTE, !enabled);
}
-static void update_tpacpi_micmute_led(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static void update_tpacpi_micmute(struct hda_codec *codec)
{
- if (!ucontrol || !led_set_func)
- return;
- if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) {
- /* TODO: How do I verify if it's a mono or stereo here? */
- bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1];
- led_set_func(TPACPI_LED_MICMUTE, !val);
- }
+ struct hda_gen_spec *spec = codec->spec;
+
+ led_set_func(TPACPI_LED_MICMUTE, spec->micmute_led.led_value);
}
static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
@@ -63,15 +57,10 @@ static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
spec->vmaster_mute.hook = update_tpacpi_mute_led;
removefunc = false;
}
- if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) {
- if (spec->num_adc_nids > 1 && !spec->dyn_adc_switch)
- codec_dbg(codec,
- "Skipping micmute LED control due to several ADCs");
- else {
- spec->cap_sync_hook = update_tpacpi_micmute_led;
- removefunc = false;
- }
- }
+ if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0 &&
+ snd_hda_gen_add_micmute_led(codec,
+ update_tpacpi_micmute) > 0)
+ removefunc = false;
}
if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) {
diff --git a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c
index 179ef7a5f0d1..a553897a4c4f 100644
--- a/sound/pci/ice1712/ak4xxx.c
+++ b/sound/pci/ice1712/ak4xxx.c
@@ -179,18 +179,6 @@ int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice)
return 0;
}
-static int __init alsa_ice1712_akm4xxx_module_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_ice1712_akm4xxx_module_exit(void)
-{
-}
-
-module_init(alsa_ice1712_akm4xxx_module_init)
-module_exit(alsa_ice1712_akm4xxx_module_exit)
-
EXPORT_SYMBOL(snd_ice1712_akm4xxx_init);
EXPORT_SYMBOL(snd_ice1712_akm4xxx_free);
EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls);
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index d7366ade5a25..c97b5528e4b8 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -314,26 +314,7 @@ static struct snd_kcontrol_new prodigy_hd2_controls[] = {
/* --------------- */
-/*
- * Logarithmic volume values for WM87*6
- * Computed as 20 * Log10(255 / x)
- */
-static const unsigned char wm_vol[256] = {
- 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
- 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
- 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
- 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
- 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0
-};
-
-#define WM_VOL_MAX (sizeof(wm_vol) - 1)
+#define WM_VOL_MAX 255
#define WM_VOL_MUTE 0x8000
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 4c24346340f4..5ee468d1aefe 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -351,7 +351,7 @@ enum {
struct ichdev {
unsigned int ichd; /* ich device number */
unsigned long reg_offset; /* offset to bmaddr */
- u32 *bdbar; /* CPU address (32bit) */
+ __le32 *bdbar; /* CPU address (32bit) */
unsigned int bdbar_addr; /* PCI bus address (32bit) */
struct snd_pcm_substream *substream;
unsigned int physbuf; /* physical address (32bit) */
@@ -677,7 +677,7 @@ static void snd_intel8x0_ali_codec_write(struct snd_ac97 *ac97, unsigned short r
static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ichdev)
{
int idx;
- u32 *bdbar = ichdev->bdbar;
+ __le32 *bdbar = ichdev->bdbar;
unsigned long port = ichdev->reg_offset;
iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
@@ -3143,7 +3143,7 @@ static int snd_intel8x0_create(struct snd_card *card,
int_sta_masks = 0;
for (i = 0; i < chip->bdbars_count; i++) {
ichdev = &chip->ichd[i];
- ichdev->bdbar = ((u32 *)chip->bdbars.area) +
+ ichdev->bdbar = ((__le32 *)chip->bdbars.area) +
(i * ICH_MAX_FRAGS * 2);
ichdev->bdbar_addr = chip->bdbars.addr +
(i * sizeof(u32) * ICH_MAX_FRAGS * 2);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 3a4769a97d29..943a726b1c1b 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -168,7 +168,7 @@ enum { ALID_MDMIN, ALID_MDMOUT, ALID_MDMLAST = ALID_MDMOUT };
struct ichdev {
unsigned int ichd; /* ich device number */
unsigned long reg_offset; /* offset to bmaddr */
- u32 *bdbar; /* CPU address (32bit) */
+ __le32 *bdbar; /* CPU address (32bit) */
unsigned int bdbar_addr; /* PCI bus address (32bit) */
struct snd_pcm_substream *substream;
unsigned int physbuf; /* physical address (32bit) */
@@ -395,7 +395,7 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97,
static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *ichdev)
{
int idx;
- u32 *bdbar = ichdev->bdbar;
+ __le32 *bdbar = ichdev->bdbar;
unsigned long port = ichdev->reg_offset;
iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
@@ -1217,7 +1217,7 @@ static int snd_intel8x0m_create(struct snd_card *card,
int_sta_masks = 0;
for (i = 0; i < chip->bdbars_count; i++) {
ichdev = &chip->ichd[i];
- ichdev->bdbar = ((u32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2);
+ ichdev->bdbar = ((__le32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2);
ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2);
int_sta_masks |= ichdev->int_sta_mask;
}
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 4206ba44d8bb..4e189a93f475 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -1326,7 +1326,7 @@ static int snd_korg1212_copy_to(struct snd_pcm_substream *substream,
}
#endif
if (in_kernel)
- memcpy((void *)dst, src, size);
+ memcpy((__force void *)dst, src, size);
else if (copy_to_user(dst, src, size))
return -EFAULT;
src++;
@@ -1365,7 +1365,7 @@ static int snd_korg1212_copy_from(struct snd_pcm_substream *substream,
}
#endif
if (in_kernel)
- memcpy((void *)dst, src, size);
+ memcpy(dst, (__force void *)src, size);
else if (copy_from_user(dst, src, size))
return -EFAULT;
dst++;
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 9ff600084973..254f24366892 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -369,9 +369,9 @@ static int setup_corb_rirb(struct lola *chip)
return err;
chip->corb.addr = chip->rb.addr;
- chip->corb.buf = (u32 *)chip->rb.area;
+ chip->corb.buf = (__le32 *)chip->rb.area;
chip->rirb.addr = chip->rb.addr + 2048;
- chip->rirb.buf = (u32 *)(chip->rb.area + 2048);
+ chip->rirb.buf = (__le32 *)(chip->rb.area + 2048);
/* disable ringbuffer DMAs */
lola_writeb(chip, BAR0, RIRBCTL, 0);
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
index f0b100059efd..bd852fed8bb6 100644
--- a/sound/pci/lola/lola.h
+++ b/sound/pci/lola/lola.h
@@ -220,7 +220,7 @@ struct lola_bar {
/* CORB/RIRB */
struct lola_rb {
- u32 *buf; /* CORB/RIRB buffer, 8 byte per each entry */
+ __le32 *buf; /* CORB/RIRB buffer, 8 byte per each entry */
dma_addr_t addr; /* physical address of CORB/RIRB buffer */
unsigned short rp, wp; /* read/write pointers */
int cmds; /* number of pending requests */
@@ -275,7 +275,7 @@ struct lola_mixer_array {
struct lola_mixer_widget {
unsigned int nid;
unsigned int caps;
- struct lola_mixer_array __user *array;
+ struct lola_mixer_array __iomem *array;
struct lola_mixer_array *array_saved;
unsigned int src_stream_outs;
unsigned int src_phys_ins;
diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c
index 310b26a756c9..e70276c3ea20 100644
--- a/sound/pci/lola/lola_pcm.c
+++ b/sound/pci/lola/lola_pcm.c
@@ -316,10 +316,10 @@ static int lola_pcm_hw_free(struct snd_pcm_substream *substream)
* set up a BDL entry
*/
static int setup_bdle(struct snd_pcm_substream *substream,
- struct lola_stream *str, u32 **bdlp,
+ struct lola_stream *str, __le32 **bdlp,
int ofs, int size)
{
- u32 *bdl = *bdlp;
+ __le32 *bdl = *bdlp;
while (size > 0) {
dma_addr_t addr;
@@ -355,14 +355,14 @@ static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm,
struct snd_pcm_substream *substream,
struct lola_stream *str)
{
- u32 *bdl;
+ __le32 *bdl;
int i, ofs, periods, period_bytes;
period_bytes = str->period_bytes;
periods = str->bufsize / period_bytes;
/* program the initial BDL entries */
- bdl = (u32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
+ bdl = (__le32 *)(pcm->bdl.area + LOLA_BDL_ENTRY_SIZE * str->index);
ofs = 0;
str->frags = 0;
for (i = 0; i < periods; i++) {
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index 6c85f13ab23f..54f6252faca6 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -1018,6 +1018,7 @@ static int snd_lx6464es_create(struct snd_card *card,
chip->port_dsp_bar = pci_ioremap_bar(pci, 2);
if (!chip->port_dsp_bar) {
dev_err(card->dev, "cannot remap PCI memory region\n");
+ err = -ENOMEM;
goto remap_pci_failed;
}
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 224e942f556d..62962178a9d7 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2103,7 +2103,7 @@ static const u16 minisrc_lpf[MINISRC_LPF_LEN] = {
static void snd_m3_assp_init(struct snd_m3 *chip)
{
unsigned int i;
- const u16 *data;
+ const __le16 *data;
/* zero kernel data */
for (i = 0; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
@@ -2121,7 +2121,7 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
KDATA_DMA_XFER0);
/* write kernel into code memory.. */
- data = (const u16 *)chip->assp_kernel_image->data;
+ data = (const __le16 *)chip->assp_kernel_image->data;
for (i = 0 ; i * 2 < chip->assp_kernel_image->size; i++) {
snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
REV_B_CODE_MEMORY_BEGIN + i,
@@ -2134,7 +2134,7 @@ static void snd_m3_assp_init(struct snd_m3 *chip)
* drop it there. It seems that the minisrc doesn't
* need vectors, so we won't bother with them..
*/
- data = (const u16 *)chip->assp_minisrc_image->data;
+ data = (const __le16 *)chip->assp_minisrc_image->data;
for (i = 0; i * 2 < chip->assp_minisrc_image->size; i++) {
snd_m3_assp_write(chip, MEMTYPE_INTERNAL_CODE,
0x400 + i, le16_to_cpu(data[i]));
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index a74f1ad7e7b8..9cd297a42f24 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -182,6 +182,7 @@ static int mixart_set_clock(struct mixart_mgr *mgr,
case PIPE_RUNNING:
if(rate != 0)
break;
+ /* fall through */
default:
if(rate == 0)
return 0; /* nothing to do */
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 8bf2ce32d4a8..71776bfe0485 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -107,7 +107,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
#ifndef __BIG_ENDIAN
size /= 4; /* u32 size */
for(i=0; i < size; i++) {
- ((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]);
+ ((u32*)resp->data)[i] = be32_to_cpu(((__be32*)resp->data)[i]);
}
#endif
@@ -519,7 +519,7 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
/* Traces are text: the swapped msg_data has to be swapped back ! */
int i;
for(i=0; i<(resp.size/4); i++) {
- (mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
+ ((__be32*)mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]);
}
#endif
((char*)mixart_msg_data)[resp.size - 1] = 0;
@@ -540,7 +540,7 @@ irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
dev_err(&mgr->pci->dev,
"canceled notification %x !\n", msg);
}
- /* no break, continue ! */
+ /* fall through */
case MSG_TYPE_ANSWER:
/* answer or notification to a message we are waiting for*/
mutex_lock(&mgr->msg_lock);
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 5bfd3ac80db5..bc92758de82c 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -73,30 +73,30 @@ static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
*/
struct snd_mixart_elf32_ehdr {
u8 e_ident[16];
- u16 e_type;
- u16 e_machine;
- u32 e_version;
- u32 e_entry;
- u32 e_phoff;
- u32 e_shoff;
- u32 e_flags;
- u16 e_ehsize;
- u16 e_phentsize;
- u16 e_phnum;
- u16 e_shentsize;
- u16 e_shnum;
- u16 e_shstrndx;
+ __be16 e_type;
+ __be16 e_machine;
+ __be32 e_version;
+ __be32 e_entry;
+ __be32 e_phoff;
+ __be32 e_shoff;
+ __be32 e_flags;
+ __be16 e_ehsize;
+ __be16 e_phentsize;
+ __be16 e_phnum;
+ __be16 e_shentsize;
+ __be16 e_shnum;
+ __be16 e_shstrndx;
};
struct snd_mixart_elf32_phdr {
- u32 p_type;
- u32 p_offset;
- u32 p_vaddr;
- u32 p_paddr;
- u32 p_filesz;
- u32 p_memsz;
- u32 p_flags;
- u32 p_align;
+ __be32 p_type;
+ __be32 p_offset;
+ __be32 p_vaddr;
+ __be32 p_paddr;
+ __be32 p_filesz;
+ __be32 p_memsz;
+ __be32 p_flags;
+ __be32 p_align;
};
static int mixart_load_elf(struct mixart_mgr *mgr, const struct firmware *dsp )
diff --git a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h
index 812e288ef2e7..2794cd385b8e 100644
--- a/sound/pci/mixart/mixart_hwdep.h
+++ b/sound/pci/mixart/mixart_hwdep.h
@@ -26,19 +26,19 @@
#include <sound/hwdep.h>
#ifndef readl_be
-#define readl_be(x) be32_to_cpu(__raw_readl(x))
+#define readl_be(x) be32_to_cpu((__force __be32)__raw_readl(x))
#endif
#ifndef writel_be
-#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr)
+#define writel_be(data,addr) __raw_writel((__force u32)cpu_to_be32(data),addr)
#endif
#ifndef readl_le
-#define readl_le(x) le32_to_cpu(__raw_readl(x))
+#define readl_le(x) le32_to_cpu((__force __le32)__raw_readl(x))
#endif
#ifndef writel_le
-#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr)
+#define writel_le(data,addr) __raw_writel((__force u32)cpu_to_le32(data),addr)
#endif
#define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x))
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 44f3b48d47b1..23017e3bc76c 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -470,10 +470,10 @@ struct snd_riptide {
};
struct sgd { /* scatter gather desriptor */
- u32 dwNextLink;
- u32 dwSegPtrPhys;
- u32 dwSegLen;
- u32 dwStat_Ctl;
+ __le32 dwNextLink;
+ __le32 dwSegPtrPhys;
+ __le32 dwSegLen;
+ __le32 dwStat_Ctl;
};
struct pcmhw { /* pcm descriptor */
@@ -1017,7 +1017,7 @@ getsamplerate(struct cmdif *cif, unsigned char *intdec, unsigned int *rate)
static int
setsampleformat(struct cmdif *cif,
unsigned char mixer, unsigned char id,
- unsigned char channels, unsigned char format)
+ unsigned char channels, snd_pcm_format_t format)
{
unsigned char w, ch, sig, order;
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 7fbdb703bfcd..7218f38b59db 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1433,14 +1433,12 @@ static int snd_sonicvibes_midi(struct sonicvibes *sonic,
{
struct snd_mpu401 * mpu = rmidi->private_data;
struct snd_card *card = sonic->card;
- struct snd_rawmidi_str *dir;
unsigned int idx;
int err;
mpu->private_data = sonic;
mpu->open_input = snd_sonicvibes_midi_input_open;
mpu->close_input = snd_sonicvibes_midi_input_close;
- dir = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_midi_controls); idx++)
if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_midi_controls[idx], sonic))) < 0)
return err;
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index cedf13b64803..2f18b1cdc2cd 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -123,7 +123,7 @@ static int snd_trident_probe(struct pci_dev *pci,
} else {
strcpy(card->shortname, "Trident ");
}
- strcat(card->shortname, card->driver);
+ strcat(card->shortname, str);
sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d",
card->shortname, trident->port, trident->irq);
diff --git a/sound/pci/trident/trident.h b/sound/pci/trident/trident.h
index 9624e5937719..2d62c1921255 100644
--- a/sound/pci/trident/trident.h
+++ b/sound/pci/trident/trident.h
@@ -264,7 +264,7 @@ struct snd_trident_memblk_arg {
};
struct snd_trident_tlb {
- unsigned int * entries; /* 16k-aligned TLB table */
+ __le32 *entries; /* 16k-aligned TLB table */
dma_addr_t entries_dmaaddr; /* 16k-aligned PCI address to TLB table */
unsigned long * shadow_entries; /* shadow entries with virtual addresses */
struct snd_dma_buffer buffer;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index 49c64fae3466..5523e193d556 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3359,7 +3359,7 @@ static int snd_trident_tlb_alloc(struct snd_trident *trident)
dev_err(trident->card->dev, "unable to allocate TLB buffer\n");
return -ENOMEM;
}
- trident->tlb.entries = (unsigned int*)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4);
+ trident->tlb.entries = (__le32 *)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4);
trident->tlb.entries_dmaaddr = ALIGN(trident->tlb.buffer.addr, SNDRV_TRIDENT_MAX_PAGES * 4);
/* allocate shadow TLB page table (virtual addresses) */
trident->tlb.shadow_entries =
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index d4298af6d3ee..c0d0bf44f365 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -275,7 +275,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
length >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
for (; length > 0; length--) {
- outl(cpu_to_le32(*addr), port);
+ outl(*addr, port);
addr++;
}
addr = (u32 *)runtime->dma_area;
@@ -285,7 +285,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
count >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
for (; count > 0; count--) {
- outl(cpu_to_le32(*addr), port);
+ outl(*addr, port);
addr++;
}
@@ -313,7 +313,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
length >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
for (; length > 0; length--)
- *addr++ = le32_to_cpu(inl(port));
+ *addr++ = inl(port);
addr = (u32 *)runtime->dma_area;
pipe->hw_ptr = 0;
}
@@ -321,7 +321,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
count >>= 2; /* in 32bit words */
/* Transfer using pseudo-dma. */
for (; count > 0; count--)
- *addr++ = le32_to_cpu(inl(port));
+ *addr++ = inl(port);
vx2_release_pseudo_dma(chip);
}
diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h
index aa9bb065f385..e2fa7e360d79 100644
--- a/sound/pci/ymfpci/ymfpci.h
+++ b/sound/pci/ymfpci/ymfpci.h
@@ -185,50 +185,50 @@
*/
struct snd_ymfpci_playback_bank {
- u32 format;
- u32 loop_default;
- u32 base; /* 32-bit address */
- u32 loop_start; /* 32-bit offset */
- u32 loop_end; /* 32-bit offset */
- u32 loop_frac; /* 8-bit fraction - loop_start */
- u32 delta_end; /* pitch delta end */
- u32 lpfK_end;
- u32 eg_gain_end;
- u32 left_gain_end;
- u32 right_gain_end;
- u32 eff1_gain_end;
- u32 eff2_gain_end;
- u32 eff3_gain_end;
- u32 lpfQ;
- u32 status;
- u32 num_of_frames;
- u32 loop_count;
- u32 start;
- u32 start_frac;
- u32 delta;
- u32 lpfK;
- u32 eg_gain;
- u32 left_gain;
- u32 right_gain;
- u32 eff1_gain;
- u32 eff2_gain;
- u32 eff3_gain;
- u32 lpfD1;
- u32 lpfD2;
+ __le32 format;
+ __le32 loop_default;
+ __le32 base; /* 32-bit address */
+ __le32 loop_start; /* 32-bit offset */
+ __le32 loop_end; /* 32-bit offset */
+ __le32 loop_frac; /* 8-bit fraction - loop_start */
+ __le32 delta_end; /* pitch delta end */
+ __le32 lpfK_end;
+ __le32 eg_gain_end;
+ __le32 left_gain_end;
+ __le32 right_gain_end;
+ __le32 eff1_gain_end;
+ __le32 eff2_gain_end;
+ __le32 eff3_gain_end;
+ __le32 lpfQ;
+ __le32 status;
+ __le32 num_of_frames;
+ __le32 loop_count;
+ __le32 start;
+ __le32 start_frac;
+ __le32 delta;
+ __le32 lpfK;
+ __le32 eg_gain;
+ __le32 left_gain;
+ __le32 right_gain;
+ __le32 eff1_gain;
+ __le32 eff2_gain;
+ __le32 eff3_gain;
+ __le32 lpfD1;
+ __le32 lpfD2;
};
struct snd_ymfpci_capture_bank {
- u32 base; /* 32-bit address */
- u32 loop_end; /* 32-bit offset */
- u32 start; /* 32-bit offset */
- u32 num_of_loops; /* counter */
+ __le32 base; /* 32-bit address */
+ __le32 loop_end; /* 32-bit offset */
+ __le32 start; /* 32-bit offset */
+ __le32 num_of_loops; /* counter */
};
struct snd_ymfpci_effect_bank {
- u32 base; /* 32-bit address */
- u32 loop_end; /* 32-bit offset */
- u32 start; /* 32-bit offset */
- u32 temp;
+ __le32 base; /* 32-bit address */
+ __le32 loop_end; /* 32-bit offset */
+ __le32 start; /* 32-bit offset */
+ __le32 temp;
};
struct snd_ymfpci_pcm;
@@ -316,7 +316,7 @@ struct snd_ymfpci {
dma_addr_t work_base_addr;
struct snd_dma_buffer ac3_tmp_base;
- u32 *ctrl_playback;
+ __le32 *ctrl_playback;
struct snd_ymfpci_playback_bank *bank_playback[YDSXG_PLAYBACK_VOICES][2];
struct snd_ymfpci_capture_bank *bank_capture[YDSXG_CAPTURE_VOICES][2];
struct snd_ymfpci_effect_bank *bank_effect[YDSXG_EFFECT_VOICES][2];
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 6f81396aadc9..a4926fb03991 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -336,7 +336,7 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_
unsigned int subs = ypcm->substream->number;
unsigned int next_bank = 1 - chip->active_bank;
struct snd_ymfpci_playback_bank *bank;
- u32 volume;
+ __le32 volume;
bank = &voice->bank[next_bank];
volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15);
@@ -505,7 +505,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int
u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate);
struct snd_ymfpci_playback_bank *bank;
unsigned int nbank;
- u32 vol_left, vol_right;
+ __le32 vol_left, vol_right;
u8 use_left, use_right;
unsigned long flags;
@@ -2135,7 +2135,7 @@ static int snd_ymfpci_memalloc(struct snd_ymfpci *chip)
chip->bank_base_playback = ptr;
chip->bank_base_playback_addr = ptr_addr;
- chip->ctrl_playback = (u32 *)ptr;
+ chip->ctrl_playback = (__le32 *)ptr;
chip->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
ptr += ALIGN(playback_ctrl_size, 0x100);
ptr_addr += ALIGN(playback_ctrl_size, 0x100);
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
index 4a2354b5ae00..98a6863e933c 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
@@ -276,7 +276,6 @@ static const struct snd_pcm_ops pdacf_pcm_capture_ops = {
.trigger = pdacf_pcm_trigger,
.pointer = pdacf_pcm_capture_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c
index 8cde40226355..4c4ef1fec69f 100644
--- a/sound/pcmcia/vx/vxp_ops.c
+++ b/sound/pcmcia/vx/vxp_ops.c
@@ -375,7 +375,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
length >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
for (; length > 0; length--) {
- outw(cpu_to_le16(*addr), port);
+ outw(*addr, port);
addr++;
}
addr = (unsigned short *)runtime->dma_area;
@@ -385,7 +385,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
count >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
for (; count > 0; count--) {
- outw(cpu_to_le16(*addr), port);
+ outw(*addr, port);
addr++;
}
vx_release_pseudo_dma(chip);
@@ -417,7 +417,7 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
length >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
for (; length > 0; length--)
- *addr++ = le16_to_cpu(inw(port));
+ *addr++ = inw(port);
addr = (unsigned short *)runtime->dma_area;
pipe->hw_ptr = 0;
}
@@ -425,12 +425,12 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
count >>= 1; /* in 16bit words */
/* Transfer using pseudo-dma. */
for (; count > 1; count--)
- *addr++ = le16_to_cpu(inw(port));
+ *addr++ = inw(port);
/* Disable DMA */
pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK;
vx_outb(chip, DIALOG, pchip->regDIALOG);
/* Read the last word (16 bits) */
- *addr = le16_to_cpu(inw(port));
+ *addr = inw(port);
/* Disable 16-bit accesses */
pchip->regDIALOG &= ~VXP_DLG_DMA16_SEL_MASK;
vx_outb(chip, DIALOG, pchip->regDIALOG);
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
index 36f34f434ecb..abe031c9d592 100644
--- a/sound/ppc/snd_ps3.c
+++ b/sound/ppc/snd_ps3.c
@@ -930,6 +930,7 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
{
int i, ret;
u64 lpar_addr, lpar_size;
+ static u64 dummy_mask;
if (WARN_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1)))
return -ENODEV;
@@ -970,6 +971,10 @@ static int snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
goto clean_mmio;
}
+ dummy_mask = DMA_BIT_MASK(32);
+ dev->core.dma_mask = &dummy_mask;
+ dma_set_coherent_mask(&dev->core, dummy_mask);
+
snd_ps3_audio_set_base_addr(dev->d_region->bus_addr);
/* CONFIG_SND_PS3_DEFAULT_START_DELAY */
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 41af6b9cc350..1cf11cf51e1d 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -57,6 +57,7 @@ source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
source "sound/soc/mediatek/Kconfig"
+source "sound/soc/meson/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 06389a5385d7..62a5f87c3cfc 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += img/
obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mediatek/
+obj-$(CONFIG_SND_SOC) += meson/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index 6cbf9cf4d1a4..58c1dcb4d255 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -8,6 +8,7 @@ config SND_SOC_AMD_CZ_DA7219MX98357_MACH
select SND_SOC_DA7219
select SND_SOC_MAX98357A
select SND_SOC_ADAU7002
+ select REGULATOR
depends on SND_SOC_AMD_ACP && I2C
help
This option enables machine driver for DA7219 and MAX9835.
diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c
index ccddc6650b9c..8e3275a96a82 100644
--- a/sound/soc/amd/acp-da7219-max98357a.c
+++ b/sound/soc/amd/acp-da7219-max98357a.c
@@ -32,6 +32,8 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/acpi.h>
@@ -148,7 +150,8 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
&constraints_rates);
- machine->i2s_instance = I2S_BT_INSTANCE;
+ machine->i2s_instance = I2S_SP_INSTANCE;
+ machine->capture_channel = CAP_CHANNEL1;
return da7219_clk_enable(substream);
}
@@ -163,7 +166,7 @@ static int cz_max_startup(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
- machine->i2s_instance = I2S_SP_INSTANCE;
+ machine->i2s_instance = I2S_BT_INSTANCE;
return da7219_clk_enable(substream);
}
@@ -172,13 +175,24 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
da7219_clk_disable();
}
-static int cz_dmic_startup(struct snd_pcm_substream *substream)
+static int cz_dmic0_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
+
+ machine->i2s_instance = I2S_BT_INSTANCE;
+ return da7219_clk_enable(substream);
+}
+
+static int cz_dmic1_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
machine->i2s_instance = I2S_SP_INSTANCE;
+ machine->capture_channel = CAP_CHANNEL0;
return da7219_clk_enable(substream);
}
@@ -197,23 +211,39 @@ static const struct snd_soc_ops cz_max_play_ops = {
.shutdown = cz_max_shutdown,
};
-static const struct snd_soc_ops cz_dmic_cap_ops = {
- .startup = cz_dmic_startup,
+static const struct snd_soc_ops cz_dmic0_cap_ops = {
+ .startup = cz_dmic0_startup,
+ .shutdown = cz_dmic_shutdown,
+};
+
+static const struct snd_soc_ops cz_dmic1_cap_ops = {
+ .startup = cz_dmic1_startup,
.shutdown = cz_dmic_shutdown,
};
static struct snd_soc_dai_link cz_dai_7219_98357[] = {
{
- .name = "amd-da7219-play-cap",
- .stream_name = "Playback and Capture",
+ .name = "amd-da7219-play",
+ .stream_name = "Playback",
.platform_name = "acp_audio_dma.0.auto",
- .cpu_dai_name = "designware-i2s.3.auto",
+ .cpu_dai_name = "designware-i2s.1.auto",
.codec_dai_name = "da7219-hifi",
.codec_name = "i2c-DLGS7219:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.init = cz_da7219_init,
.dpcm_playback = 1,
+ .ops = &cz_da7219_cap_ops,
+ },
+ {
+ .name = "amd-da7219-cap",
+ .stream_name = "Capture",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.2.auto",
+ .codec_dai_name = "da7219-hifi",
+ .codec_name = "i2c-DLGS7219:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.ops = &cz_da7219_cap_ops,
},
@@ -221,7 +251,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.name = "amd-max98357-play",
.stream_name = "HiFi Playback",
.platform_name = "acp_audio_dma.0.auto",
- .cpu_dai_name = "designware-i2s.1.auto",
+ .cpu_dai_name = "designware-i2s.3.auto",
.codec_dai_name = "HiFi",
.codec_name = "MX98357A:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
@@ -230,8 +260,22 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.ops = &cz_max_play_ops,
},
{
- .name = "dmic",
- .stream_name = "DMIC Capture",
+ /* C panel DMIC */
+ .name = "dmic0",
+ .stream_name = "DMIC0 Capture",
+ .platform_name = "acp_audio_dma.0.auto",
+ .cpu_dai_name = "designware-i2s.3.auto",
+ .codec_dai_name = "adau7002-hifi",
+ .codec_name = "ADAU7002:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .dpcm_capture = 1,
+ .ops = &cz_dmic0_cap_ops,
+ },
+ {
+ /* A/B panel DMIC */
+ .name = "dmic1",
+ .stream_name = "DMIC1 Capture",
.platform_name = "acp_audio_dma.0.auto",
.cpu_dai_name = "designware-i2s.2.auto",
.codec_dai_name = "adau7002-hifi",
@@ -239,7 +283,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
- .ops = &cz_dmic_cap_ops,
+ .ops = &cz_dmic1_cap_ops,
},
};
@@ -278,11 +322,52 @@ static struct snd_soc_card cz_card = {
.num_controls = ARRAY_SIZE(cz_mc_controls),
};
+static struct regulator_consumer_supply acp_da7219_supplies[] = {
+ REGULATOR_SUPPLY("VDD", "i2c-DLGS7219:00"),
+ REGULATOR_SUPPLY("VDDMIC", "i2c-DLGS7219:00"),
+ REGULATOR_SUPPLY("VDDIO", "i2c-DLGS7219:00"),
+ REGULATOR_SUPPLY("IOVDD", "ADAU7002:00"),
+};
+
+static struct regulator_init_data acp_da7219_data = {
+ .constraints = {
+ .always_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(acp_da7219_supplies),
+ .consumer_supplies = acp_da7219_supplies,
+};
+
+static struct regulator_config acp_da7219_cfg = {
+ .init_data = &acp_da7219_data,
+};
+
+static struct regulator_ops acp_da7219_ops = {
+};
+
+static struct regulator_desc acp_da7219_desc = {
+ .name = "reg-fixed-1.8V",
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .ops = &acp_da7219_ops,
+ .fixed_uV = 1800000, /* 1.8V */
+ .n_voltages = 1,
+};
+
static int cz_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card;
struct acp_platform_info *machine;
+ struct regulator_dev *rdev;
+
+ acp_da7219_cfg.dev = &pdev->dev;
+ rdev = devm_regulator_register(&pdev->dev, &acp_da7219_desc,
+ &acp_da7219_cfg);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "Failed to register regulator: %d\n",
+ (int)PTR_ERR(rdev));
+ return -EINVAL;
+ }
machine = devm_kzalloc(&pdev->dev, sizeof(struct acp_platform_info),
GFP_KERNEL);
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 77203841c535..e359938e3d7e 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -224,13 +224,11 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
switch (asic_type) {
case CHIP_STONEY:
dmadscr[i].xfer_val |=
- BIT(22) |
(ACP_DMA_ATTR_SHARED_MEM_TO_DAGB_GARLIC << 16) |
(size / 2);
break;
default:
dmadscr[i].xfer_val |=
- BIT(22) |
(ACP_DMA_ATTR_SHAREDMEM_TO_DAGB_ONION << 16) |
(size / 2);
}
@@ -322,22 +320,87 @@ static void config_acp_dma(void __iomem *acp_mmio,
struct audio_substream_data *rtd,
u32 asic_type)
{
+ u16 ch_acp_sysmem, ch_acp_i2s;
+
acp_pte_config(acp_mmio, rtd->pg, rtd->num_of_pages,
rtd->pte_offset);
+
+ if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ ch_acp_sysmem = rtd->ch1;
+ ch_acp_i2s = rtd->ch2;
+ } else {
+ ch_acp_i2s = rtd->ch1;
+ ch_acp_sysmem = rtd->ch2;
+ }
/* Configure System memory <-> ACP SRAM DMA descriptors */
set_acp_sysmem_dma_descriptors(acp_mmio, rtd->size,
rtd->direction, rtd->pte_offset,
- rtd->ch1, rtd->sram_bank,
+ ch_acp_sysmem, rtd->sram_bank,
rtd->dma_dscr_idx_1, asic_type);
/* Configure ACP SRAM <-> I2S DMA descriptors */
set_acp_to_i2s_dma_descriptors(acp_mmio, rtd->size,
rtd->direction, rtd->sram_bank,
- rtd->destination, rtd->ch2,
+ rtd->destination, ch_acp_i2s,
rtd->dma_dscr_idx_2, asic_type);
}
+static void acp_dma_cap_channel_enable(void __iomem *acp_mmio,
+ u16 cap_channel)
+{
+ u32 val, ch_reg, imr_reg, res_reg;
+
+ switch (cap_channel) {
+ case CAP_CHANNEL1:
+ ch_reg = mmACP_I2SMICSP_RER1;
+ res_reg = mmACP_I2SMICSP_RCR1;
+ imr_reg = mmACP_I2SMICSP_IMR1;
+ break;
+ case CAP_CHANNEL0:
+ default:
+ ch_reg = mmACP_I2SMICSP_RER0;
+ res_reg = mmACP_I2SMICSP_RCR0;
+ imr_reg = mmACP_I2SMICSP_IMR0;
+ break;
+ }
+ val = acp_reg_read(acp_mmio,
+ mmACP_I2S_16BIT_RESOLUTION_EN);
+ if (val & ACP_I2S_MIC_16BIT_RESOLUTION_EN) {
+ acp_reg_write(0x0, acp_mmio, ch_reg);
+ /* Set 16bit resolution on capture */
+ acp_reg_write(0x2, acp_mmio, res_reg);
+ }
+ val = acp_reg_read(acp_mmio, imr_reg);
+ val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
+ val &= ~ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
+ acp_reg_write(val, acp_mmio, imr_reg);
+ acp_reg_write(0x1, acp_mmio, ch_reg);
+}
+
+static void acp_dma_cap_channel_disable(void __iomem *acp_mmio,
+ u16 cap_channel)
+{
+ u32 val, ch_reg, imr_reg;
+
+ switch (cap_channel) {
+ case CAP_CHANNEL1:
+ imr_reg = mmACP_I2SMICSP_IMR1;
+ ch_reg = mmACP_I2SMICSP_RER1;
+ break;
+ case CAP_CHANNEL0:
+ default:
+ imr_reg = mmACP_I2SMICSP_IMR0;
+ ch_reg = mmACP_I2SMICSP_RER0;
+ break;
+ }
+ val = acp_reg_read(acp_mmio, imr_reg);
+ val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK;
+ val |= ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK;
+ acp_reg_write(val, acp_mmio, imr_reg);
+ acp_reg_write(0x0, acp_mmio, ch_reg);
+}
+
/* Start a given DMA channel transfer */
-static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
+static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num, bool is_circular)
{
u32 dma_ctrl;
@@ -356,10 +419,8 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
switch (ch_num) {
case ACP_TO_I2S_DMA_CH_NUM:
- case ACP_TO_SYSRAM_CH_NUM:
case I2S_TO_ACP_DMA_CH_NUM:
case ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM:
- case ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM:
case I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM:
dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK;
break;
@@ -368,8 +429,11 @@ static void acp_dma_start(void __iomem *acp_mmio, u16 ch_num)
break;
}
- /* circular for both DMA channel */
- dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+ /* enable for ACP to SRAM DMA channel */
+ if (is_circular == true)
+ dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
+ else
+ dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK;
acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num);
}
@@ -613,6 +677,7 @@ static int acp_deinit(void __iomem *acp_mmio)
/* ACP DMA irq handler routine for playback, capture usecases */
static irqreturn_t dma_irq_handler(int irq, void *arg)
{
+ u16 dscr_idx;
u32 intr_flag, ext_intr_status;
struct audio_drv_data *irq_data;
void __iomem *acp_mmio;
@@ -644,32 +709,39 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) {
valid_irq = true;
+ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_14) ==
+ CAPTURE_START_DMA_DESCR_CH15)
+ dscr_idx = CAPTURE_END_DMA_DESCR_CH14;
+ else
+ dscr_idx = CAPTURE_START_DMA_DESCR_CH14;
+ config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx,
+ 1, 0);
+ acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false);
+
snd_pcm_period_elapsed(irq_data->capture_i2ssp_stream);
acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16,
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
}
- if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) {
- valid_irq = true;
- acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16,
- acp_mmio, mmACP_EXTERNAL_INTR_STAT);
- }
-
if ((intr_flag & BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) != 0) {
valid_irq = true;
+ if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_10) ==
+ CAPTURE_START_DMA_DESCR_CH11)
+ dscr_idx = CAPTURE_END_DMA_DESCR_CH10;
+ else
+ dscr_idx = CAPTURE_START_DMA_DESCR_CH10;
+ config_acp_dma_channel(acp_mmio,
+ ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
+ dscr_idx, 1, 0);
+ acp_dma_start(acp_mmio, ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM,
+ false);
+
snd_pcm_period_elapsed(irq_data->capture_i2sbt_stream);
acp_reg_write((intr_flag &
BIT(I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM)) << 16,
acp_mmio, mmACP_EXTERNAL_INTR_STAT);
}
- if ((intr_flag & BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) != 0) {
- valid_irq = true;
- acp_reg_write((intr_flag &
- BIT(ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM)) << 16,
- acp_mmio, mmACP_EXTERNAL_INTR_STAT);
- }
-
if (valid_irq)
return IRQ_HANDLED;
else
@@ -773,7 +845,10 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
if (WARN_ON(!rtd))
return -EINVAL;
- rtd->i2s_instance = pinfo->i2s_instance;
+ if (pinfo) {
+ rtd->i2s_instance = pinfo->i2s_instance;
+ rtd->capture_channel = pinfo->capture_channel;
+ }
if (adata->asic_type == CHIP_STONEY) {
val = acp_reg_read(adata->acp_mmio,
mmACP_I2S_16BIT_RESOLUTION_EN);
@@ -841,8 +916,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
switch (rtd->i2s_instance) {
case I2S_BT_INSTANCE:
rtd->pte_offset = ACP_ST_BT_CAPTURE_PTE_OFFSET;
- rtd->ch1 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
- rtd->ch2 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
+ rtd->ch1 = I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM;
+ rtd->ch2 = ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM;
rtd->sram_bank = ACP_SRAM_BANK_4_ADDRESS;
rtd->destination = FROM_BLUETOOTH;
rtd->dma_dscr_idx_1 = CAPTURE_START_DMA_DESCR_CH10;
@@ -851,13 +926,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH;
rtd->byte_cnt_low_reg_offset =
mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW;
+ rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_11;
adata->capture_i2sbt_stream = substream;
break;
case I2S_SP_INSTANCE:
default:
rtd->pte_offset = ACP_CAPTURE_PTE_OFFSET;
- rtd->ch1 = ACP_TO_SYSRAM_CH_NUM;
- rtd->ch2 = I2S_TO_ACP_DMA_CH_NUM;
+ rtd->ch1 = I2S_TO_ACP_DMA_CH_NUM;
+ rtd->ch2 = ACP_TO_SYSRAM_CH_NUM;
switch (adata->asic_type) {
case CHIP_STONEY:
rtd->pte_offset = ACP_ST_CAPTURE_PTE_OFFSET;
@@ -874,6 +950,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
mmACP_I2S_RECEIVED_BYTE_CNT_HIGH;
rtd->byte_cnt_low_reg_offset =
mmACP_I2S_RECEIVED_BYTE_CNT_LOW;
+ rtd->dma_curr_dscr = mmACP_DMA_CUR_DSCR_15;
adata->capture_i2ssp_stream = substream;
}
}
@@ -927,6 +1004,8 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
u32 buffersize;
u32 pos = 0;
u64 bytescount = 0;
+ u16 dscr;
+ u32 period_bytes, delay;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
@@ -934,12 +1013,25 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
if (!rtd)
return -EINVAL;
- buffersize = frames_to_bytes(runtime, runtime->buffer_size);
- bytescount = acp_get_byte_count(rtd);
-
- if (bytescount > rtd->bytescount)
- bytescount -= rtd->bytescount;
- pos = do_div(bytescount, buffersize);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
+ dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
+ if (dscr == rtd->dma_dscr_idx_1)
+ pos = period_bytes;
+ else
+ pos = 0;
+ bytescount = acp_get_byte_count(rtd);
+ if (bytescount > rtd->bytescount)
+ bytescount -= rtd->bytescount;
+ delay = do_div(bytescount, period_bytes);
+ runtime->delay = bytes_to_frames(runtime, delay);
+ } else {
+ buffersize = frames_to_bytes(runtime, runtime->buffer_size);
+ bytescount = acp_get_byte_count(rtd);
+ if (bytescount > rtd->bytescount)
+ bytescount -= rtd->bytescount;
+ pos = do_div(bytescount, buffersize);
+ }
return bytes_to_frames(runtime, pos);
}
@@ -953,16 +1045,24 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
+ u16 ch_acp_sysmem, ch_acp_i2s;
if (!rtd)
return -EINVAL;
+ if (rtd->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ ch_acp_sysmem = rtd->ch1;
+ ch_acp_i2s = rtd->ch2;
+ } else {
+ ch_acp_i2s = rtd->ch1;
+ ch_acp_sysmem = rtd->ch2;
+ }
config_acp_dma_channel(rtd->acp_mmio,
- rtd->ch1,
+ ch_acp_sysmem,
rtd->dma_dscr_idx_1,
NUM_DSCRS_PER_CHANNEL, 0);
config_acp_dma_channel(rtd->acp_mmio,
- rtd->ch2,
+ ch_acp_i2s,
rtd->dma_dscr_idx_2,
NUM_DSCRS_PER_CHANNEL, 0);
return 0;
@@ -971,7 +1071,6 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret;
- u64 bytescount = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_substream_data *rtd = runtime->private_data;
@@ -982,37 +1081,32 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- bytescount = acp_get_byte_count(rtd);
- if (rtd->bytescount == 0)
- rtd->bytescount = bytescount;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- acp_dma_start(rtd->acp_mmio, rtd->ch1);
- acp_dma_start(rtd->acp_mmio, rtd->ch2);
+ rtd->bytescount = acp_get_byte_count(rtd);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (rtd->capture_channel == CAP_CHANNEL0) {
+ acp_dma_cap_channel_disable(rtd->acp_mmio,
+ CAP_CHANNEL1);
+ acp_dma_cap_channel_enable(rtd->acp_mmio,
+ CAP_CHANNEL0);
+ }
+ if (rtd->capture_channel == CAP_CHANNEL1) {
+ acp_dma_cap_channel_disable(rtd->acp_mmio,
+ CAP_CHANNEL0);
+ acp_dma_cap_channel_enable(rtd->acp_mmio,
+ CAP_CHANNEL1);
+ }
+ acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
} else {
- acp_dma_start(rtd->acp_mmio, rtd->ch2);
- acp_dma_start(rtd->acp_mmio, rtd->ch1);
+ acp_dma_start(rtd->acp_mmio, rtd->ch1, true);
+ acp_dma_start(rtd->acp_mmio, rtd->ch2, true);
}
ret = 0;
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- /* For playback, non circular dma should be stopped first
- * i.e Sysram to acp dma transfer channel(rtd->ch1) should be
- * stopped before stopping cirular dma which is acp sram to i2s
- * fifo dma transfer channel(rtd->ch2). Where as in Capture
- * scenario, i2s fifo to acp sram dma channel(rtd->ch2) stopped
- * first before stopping acp sram to sysram which is circular
- * dma(rtd->ch1).
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- acp_dma_stop(rtd->acp_mmio, rtd->ch1);
- ret = acp_dma_stop(rtd->acp_mmio, rtd->ch2);
- } else {
- acp_dma_stop(rtd->acp_mmio, rtd->ch2);
- ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
- }
- rtd->bytescount = 0;
+ acp_dma_stop(rtd->acp_mmio, rtd->ch2);
+ ret = acp_dma_stop(rtd->acp_mmio, rtd->ch1);
break;
default:
ret = -EINVAL;
diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h
index 9cd3e96c84d4..be3963e8f4fa 100644
--- a/sound/soc/amd/acp.h
+++ b/sound/soc/amd/acp.h
@@ -55,6 +55,8 @@
#define I2S_SP_INSTANCE 0x01
#define I2S_BT_INSTANCE 0x02
+#define CAP_CHANNEL0 0x00
+#define CAP_CHANNEL1 0x01
#define ACP_TILE_ON_MASK 0x03
#define ACP_TILE_OFF_MASK 0x02
@@ -72,16 +74,16 @@
#define ACP_TO_I2S_DMA_CH_NUM 13
/* Capture DMA channels */
-#define ACP_TO_SYSRAM_CH_NUM 14
-#define I2S_TO_ACP_DMA_CH_NUM 15
+#define I2S_TO_ACP_DMA_CH_NUM 14
+#define ACP_TO_SYSRAM_CH_NUM 15
/* Playback DMA Channels for I2S BT instance */
#define SYSRAM_TO_ACP_BT_INSTANCE_CH_NUM 8
#define ACP_TO_I2S_DMA_BT_INSTANCE_CH_NUM 9
/* Capture DMA Channels for I2S BT Instance */
-#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 10
-#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 11
+#define I2S_TO_ACP_DMA_BT_INSTANCE_CH_NUM 10
+#define ACP_TO_SYSRAM_BT_INSTANCE_CH_NUM 11
#define NUM_DSCRS_PER_CHANNEL 2
@@ -125,6 +127,7 @@ struct audio_substream_data {
unsigned int order;
u16 num_of_pages;
u16 i2s_instance;
+ u16 capture_channel;
u16 direction;
u16 ch1;
u16 ch2;
@@ -135,6 +138,7 @@ struct audio_substream_data {
u32 sram_bank;
u32 byte_cnt_high_reg_offset;
u32 byte_cnt_low_reg_offset;
+ u32 dma_curr_dscr;
uint64_t size;
u64 bytescount;
void __iomem *acp_mmio;
@@ -155,6 +159,7 @@ struct audio_drv_data {
*/
struct acp_platform_info {
u16 i2s_instance;
+ u16 capture_channel;
};
union acp_dma_count {
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 5d3b5af9fd92..d88c1d995036 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -206,7 +206,6 @@ struct atmel_i2s_dev {
struct regmap *regmap;
struct clk *pclk;
struct clk *gclk;
- struct clk *aclk;
struct snd_dmaengine_dai_dma_data playback;
struct snd_dmaengine_dai_dma_data capture;
unsigned int fmt;
@@ -303,7 +302,7 @@ static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
{
int i, best;
- if (!dev->gclk || !dev->aclk) {
+ if (!dev->gclk) {
dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
return -EINVAL;
}
@@ -421,7 +420,7 @@ static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
bool enabled)
{
unsigned int mr, mr_mask;
- unsigned long aclk_rate;
+ unsigned long gclk_rate;
int ret;
mr = 0;
@@ -445,35 +444,18 @@ static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
/* Disable/unprepare the PMC generated clock. */
clk_disable_unprepare(dev->gclk);
- /* Disable/unprepare the PLL audio clock. */
- clk_disable_unprepare(dev->aclk);
return 0;
}
if (!dev->gck_param)
return -EINVAL;
- aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
+ gclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
- /* Fist change the PLL audio clock frequency ... */
- ret = clk_set_rate(dev->aclk, aclk_rate);
+ ret = clk_set_rate(dev->gclk, gclk_rate);
if (ret)
return ret;
- /*
- * ... then set the PMC generated clock rate to the very same frequency
- * to set the gclk parent to aclk.
- */
- ret = clk_set_rate(dev->gclk, aclk_rate);
- if (ret)
- return ret;
-
- /* Prepare and enable the PLL audio clock first ... */
- ret = clk_prepare_enable(dev->aclk);
- if (ret)
- return ret;
-
- /* ... then prepare and enable the PMC generated clock. */
ret = clk_prepare_enable(dev->gclk);
if (ret)
return ret;
@@ -668,28 +650,14 @@ static int atmel_i2s_probe(struct platform_device *pdev)
return err;
}
- /* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
- dev->aclk = devm_clk_get(&pdev->dev, "aclk");
+ /* Get audio clock to generate the I2S Master Clock (I2S_MCK) */
dev->gclk = devm_clk_get(&pdev->dev, "gclk");
- if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
- if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
- PTR_ERR(dev->gclk) == -EPROBE_DEFER)
+ if (IS_ERR(dev->gclk)) {
+ if (PTR_ERR(dev->gclk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* Master Mode not supported */
- dev->aclk = NULL;
dev->gclk = NULL;
- } else if (IS_ERR(dev->gclk)) {
- err = PTR_ERR(dev->gclk);
- dev_err(&pdev->dev,
- "failed to get the PMC generated clock: %d\n", err);
- return err;
- } else if (IS_ERR(dev->aclk)) {
- err = PTR_ERR(dev->aclk);
- dev_err(&pdev->dev,
- "failed to get the PLL audio clock: %d\n", err);
- return err;
}
-
dev->dev = &pdev->dev;
dev->regmap = regmap;
platform_set_drvdata(pdev, dev);
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 63cf62e9c9aa..efb095dbcd71 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -74,12 +74,12 @@ 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 if GPIOLIB
select SND_SOC_ES8316 if I2C
select SND_SOC_ES8328_SPI if SPI_MASTER
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_ES7134
+ select SND_SOC_ES7241
select SND_SOC_GTM601
select SND_SOC_HDAC_HDMI
select SND_SOC_ICS43432
@@ -141,8 +141,10 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5668 if I2C
select SND_SOC_RT5670 if I2C
select SND_SOC_RT5677 if I2C && SPI_MASTER
+ select SND_SOC_RT5682 if I2C
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
+ select SND_SOC_SIMPLE_AMPLIFIER
select SND_SOC_SIRF_AUDIO_CODEC
select SND_SOC_SPDIF
select SND_SOC_SSM2305
@@ -572,10 +574,6 @@ config SND_SOC_DA732X
config SND_SOC_DA9055
tristate
-config SND_SOC_DIO2125
- tristate "Dioo DIO2125 Amplifier"
- select GPIOLIB
-
config SND_SOC_DMIC
tristate
@@ -588,6 +586,9 @@ config SND_SOC_HDMI_CODEC
config SND_SOC_ES7134
tristate "Everest Semi ES7134 CODEC"
+config SND_SOC_ES7241
+ tristate "Everest Semi ES7241 CODEC"
+
config SND_SOC_ES8316
tristate "Everest Semi ES8316 CODEC"
depends on I2C
@@ -778,6 +779,7 @@ config SND_SOC_RL6231
default y if SND_SOC_RT5668=y
default y if SND_SOC_RT5670=y
default y if SND_SOC_RT5677=y
+ default y if SND_SOC_RT5682=y
default y if SND_SOC_RT1305=y
default m if SND_SOC_RT5514=m
default m if SND_SOC_RT5616=m
@@ -791,6 +793,7 @@ config SND_SOC_RL6231
default m if SND_SOC_RT5668=m
default m if SND_SOC_RT5670=m
default m if SND_SOC_RT5677=m
+ default m if SND_SOC_RT5682=m
default m if SND_SOC_RT1305=m
config SND_SOC_RL6347A
@@ -871,6 +874,9 @@ config SND_SOC_RT5677_SPI
tristate
default SND_SOC_RT5677 && SPI
+config SND_SOC_RT5682
+ tristate
+
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate "Freescale SGTL5000 CODEC"
@@ -891,6 +897,10 @@ config SND_SOC_SIGMADSP_REGMAP
tristate
select SND_SOC_SIGMADSP
+config SND_SOC_SIMPLE_AMPLIFIER
+ tristate "Simple Audio Amplifier"
+ select GPIOLIB
+
config SND_SOC_SIRF_AUDIO_CODEC
tristate "SiRF SoC internal audio codec"
select REGMAP_MMIO
@@ -953,8 +963,11 @@ config SND_SOC_TAS5086
depends on I2C
config SND_SOC_TAS571X
- tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers"
+ tristate "Texas Instruments TAS571x power amplifiers"
depends on I2C
+ help
+ Enable support for Texas Instruments TAS5707, TAS5711, TAS5717,
+ TAS5719 and TAS5721 power amplifiers
config SND_SOC_TAS5720
tristate "Texas Instruments TAS5720 Mono Audio amplifier"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index e023fdf85221..7ae7c85e8219 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -71,6 +71,7 @@ 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-es7241-objs := es7241.o
snd-soc-es8316-objs := es8316.o
snd-soc-es8328-objs := es8328.o
snd-soc-es8328-i2c-objs := es8328-i2c.o
@@ -146,6 +147,7 @@ snd-soc-rt5668-objs := rt5668.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
snd-soc-rt5677-spi-objs := rt5677-spi.o
+snd-soc-rt5682-objs := rt5682.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
@@ -249,9 +251,9 @@ snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
snd-soc-zx-aud96p22-objs := zx_aud96p22.o
# Amp
-snd-soc-dio2125-objs := dio2125.o
snd-soc-max9877-objs := max9877.o
snd-soc-max98504-objs := max98504.o
+snd-soc-simple-amplifier-objs := simple-amplifier.o
snd-soc-tpa6130a2-objs := tpa6130a2.o
snd-soc-tas2552-objs := tas2552.o
@@ -329,6 +331,7 @@ 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_ES7241) += snd-soc-es7241.o
obj-$(CONFIG_SND_SOC_ES8316) += snd-soc-es8316.o
obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o
obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
@@ -405,6 +408,7 @@ obj-$(CONFIG_SND_SOC_RT5668) += snd-soc-rt5668.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
+obj-$(CONFIG_SND_SOC_RT5682) += snd-soc-rt5682.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
@@ -507,7 +511,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.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_SIMPLE_AMPLIFIER) += snd-soc-simple-amplifier.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 ae41edd1c406..57169b8ff14e 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -299,6 +299,7 @@ static const struct snd_soc_dapm_route adau17x1_dsp_dapm_routes[] = {
{ "DSP", NULL, "Left Decimator" },
{ "DSP", NULL, "Right Decimator" },
+ { "DSP", NULL, "Playback" },
};
static const struct snd_soc_dapm_route adau17x1_no_dsp_dapm_routes[] = {
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index db21ecbe0762..8b9ca7e7a682 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -648,6 +648,7 @@ static int adav80x_set_pll(struct snd_soc_component *component, int pll_id,
pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV;
break;
}
+ /* fall through */
default:
return -EINVAL;
}
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index 31ec0ba2e639..299ada4dfaa0 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -558,7 +558,7 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
}
#endif /* CONFIG_PM */
-struct snd_soc_component_driver soc_codec_dev_ak4458 = {
+static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
.probe = ak4458_probe,
.remove = ak4458_remove,
.controls = ak4458_snd_controls,
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
index b7ee13406d93..2fa83a1a84cf 100644
--- a/sound/soc/codecs/ak4554.c
+++ b/sound/soc/codecs/ak4554.c
@@ -1,13 +1,8 @@
-/*
- * ak4554.c
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+// ak4554.c
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
#include <linux/module.h>
#include <sound/soc.h>
@@ -97,6 +92,6 @@ static struct platform_driver ak4554_driver = {
};
module_platform_driver(ak4554_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SoC AK4554 driver");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 8523ff9351cf..c1181a20714d 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -1,18 +1,14 @@
-/*
- * ak4613.c -- Asahi Kasei ALSA Soc Audio driver
- *
- * Copyright (C) 2015 Renesas Electronics Corporation
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on ak4642.c by Kuninori Morimoto
- * Based on wm8731.c by Richard Purdie
- * Based on ak4535.c by Richard Purdie
- * Based on wm8753.c by Liam Girdwood
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ak4613.c -- Asahi Kasei ALSA Soc Audio driver
+//
+// Copyright (C) 2015 Renesas Electronics Corporation
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on ak4642.c by Kuninori Morimoto
+// Based on wm8731.c by Richard Purdie
+// Based on ak4535.c by Richard Purdie
+// Based on wm8753.c by Liam Girdwood
#include <linux/clk.h>
#include <linux/delay.h>
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 605055964529..353237025514 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -1,17 +1,13 @@
-/*
- * ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on wm8731.c by Richard Purdie
- * Based on ak4535.c by Richard Purdie
- * Based on wm8753.c by Liam Girdwood
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Based on wm8731.c by Richard Purdie
+// Based on ak4535.c by Richard Purdie
+// Based on wm8753.c by Liam Girdwood
/* ** CAUTION **
*
@@ -709,4 +705,4 @@ module_i2c_driver(ak4642_i2c_driver);
MODULE_DESCRIPTION("Soc AK4642 driver");
MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index f4ed5cc40661..448bb90c9c8e 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -322,13 +322,13 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev)
return regcache_sync(ak5558->regmap);
}
-const struct dev_pm_ops ak5558_pm = {
+static const struct dev_pm_ops ak5558_pm = {
SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
};
-struct snd_soc_component_driver soc_codec_dev_ak5558 = {
+static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
.probe = ak5558_probe,
.remove = ak5558_remove,
.controls = ak5558_snd_controls,
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 2a7a4168c072..3c266eeb89bf 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -219,7 +219,7 @@ static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg)
{
/* Unreadable registers are considered volatile */
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
- return 1;
+ return true;
return reg == CS4270_CHIPID;
}
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c
index 196e9c343aeb..45e50fe3bf25 100644
--- a/sound/soc/codecs/cs47l24.c
+++ b/sound/soc/codecs/cs47l24.c
@@ -235,6 +235,9 @@ ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP2", 1),
+WM_ADSP_FW_CONTROL("DSP3", 2),
};
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -1283,6 +1286,12 @@ static int cs47l24_probe(struct platform_device *pdev)
return ret;
}
+ ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
+ if (ret != 0)
+ dev_warn(&pdev->dev,
+ "Failed to set compressed IRQ as a wake source: %d\n",
+ ret);
+
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
@@ -1306,6 +1315,7 @@ static int cs47l24_probe(struct platform_device *pdev)
err_spk_irqs:
arizona_free_spk_irqs(arizona);
err_dsp_irq:
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
return ret;
@@ -1323,6 +1333,7 @@ static int cs47l24_remove(struct platform_device *pdev)
arizona_free_spk_irqs(arizona);
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24);
return 0;
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 07dd33b09596..ab174b5114dc 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -362,8 +362,27 @@ static int cx20442_component_probe(struct snd_soc_component *component)
return -ENOMEM;
cx20442->por = regulator_get(component->dev, "POR");
- if (IS_ERR(cx20442->por))
- dev_warn(component->dev, "failed to get the regulator");
+ if (IS_ERR(cx20442->por)) {
+ int err = PTR_ERR(cx20442->por);
+
+ dev_warn(component->dev, "failed to get POR supply (%d)", err);
+ /*
+ * When running on a non-dt platform and requested regulator
+ * is not available, regulator_get() never returns
+ * -EPROBE_DEFER as it is not able to justify if the regulator
+ * may still appear later. On the other hand, the board can
+ * still set full constraints flag at late_initcall in order
+ * to instruct regulator_get() to return a dummy one if
+ * sufficient. Hence, if we get -ENODEV here, let's convert
+ * it to -EPROBE_DEFER and wait for the board to decide or
+ * let Deferred Probe infrastructure handle this error.
+ */
+ if (err == -ENODEV)
+ err = -EPROBE_DEFER;
+ kfree(cx20442);
+ return err;
+ }
+
cx20442->tty = NULL;
snd_soc_component_set_drvdata(component, cx20442);
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index a664111b7184..e172913d04a4 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -1,19 +1,14 @@
-/*
- * DA7210 ALSA Soc codec driver
- *
- * Copyright (c) 2009 Dialog Semiconductor
- * Written by David Chen <Dajun.chen@diasemi.com>
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// DA7210 ALSA Soc codec driver
+//
+// Copyright (c) 2009 Dialog Semiconductor
+// Written by David Chen <Dajun.chen@diasemi.com>
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S
#include <linux/delay.h>
#include <linux/i2c.h>
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 54cb5f24969f..92d006a5283e 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -1140,9 +1140,9 @@ static bool da7213_volatile_register(struct device *dev, unsigned int reg)
case DA7213_ALC_OFFSET_AUTO_M_R:
case DA7213_ALC_OFFSET_AUTO_U_R:
case DA7213_ALC_CIC_OP_LVL_DATA:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c
index a49ab751a036..2c7d5088e6f2 100644
--- a/sound/soc/codecs/da7219-aad.c
+++ b/sound/soc/codecs/da7219-aad.c
@@ -59,6 +59,7 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
container_of(work, struct da7219_aad_priv, btn_det_work);
struct snd_soc_component *component = da7219_aad->component;
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
u8 statusa, micbias_ctrl;
bool micbias_up = false;
int retries = 0;
@@ -86,6 +87,8 @@ static void da7219_aad_btn_det_work(struct work_struct *work)
if (retries >= DA7219_AAD_MICBIAS_CHK_RETRIES)
dev_warn(component->dev, "Mic bias status check timed out");
+ da7219->micbias_on_event = true;
+
/*
* Mic bias pulse required to enable mic, must be done before enabling
* button detection to prevent erroneous button readings.
@@ -439,6 +442,8 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data)
snd_soc_component_update_bits(component, DA7219_ACCDET_CONFIG_1,
DA7219_BUTTON_CONFIG_MASK, 0);
+ da7219->micbias_on_event = false;
+
/* Disable mic bias */
snd_soc_dapm_disable_pin(dapm, "Mic Bias");
snd_soc_dapm_sync(dapm);
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index 980a6a8bf56d..e46e9f4bc994 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -768,6 +768,30 @@ static const struct snd_kcontrol_new da7219_st_out_filtr_mix_controls[] = {
* DAPM Events
*/
+static int da7219_mic_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (da7219->micbias_on_event) {
+ /*
+ * Delay only for first capture after bias enabled to
+ * avoid possible DC offset related noise.
+ */
+ da7219->micbias_on_event = false;
+ msleep(da7219->mic_pga_delay);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static int da7219_dai_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -937,12 +961,12 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("MIC"),
/* Input PGAs */
- SND_SOC_DAPM_PGA("Mic PGA", DA7219_MIC_1_CTRL,
- DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
- NULL, 0),
- SND_SOC_DAPM_PGA("Mixin PGA", DA7219_MIXIN_L_CTRL,
- DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
- NULL, 0),
+ SND_SOC_DAPM_PGA_E("Mic PGA", DA7219_MIC_1_CTRL,
+ DA7219_MIC_1_AMP_EN_SHIFT, DA7219_NO_INVERT,
+ NULL, 0, da7219_mic_pga_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("Mixin PGA", DA7219_MIXIN_L_CTRL,
+ DA7219_MIXIN_L_AMP_EN_SHIFT, DA7219_NO_INVERT,
+ NULL, 0, da7219_settling_event, SND_SOC_DAPM_POST_PMU),
/* Input Filters */
SND_SOC_DAPM_ADC("ADC", NULL, DA7219_ADC_L_CTRL, DA7219_ADC_L_EN_SHIFT,
@@ -1847,6 +1871,14 @@ static void da7219_handle_pdata(struct snd_soc_component *component)
snd_soc_component_write(component, DA7219_MICBIAS_CTRL, micbias_lvl);
+ /*
+ * Calculate delay required to compensate for DC offset in
+ * Mic PGA, based on Mic Bias voltage.
+ */
+ da7219->mic_pga_delay = DA7219_MIC_PGA_BASE_DELAY +
+ (pdata->micbias_lvl *
+ DA7219_MIC_PGA_OFFSET_DELAY);
+
/* Mic */
switch (pdata->mic_amp_in_sel) {
case DA7219_MIC_AMP_IN_SEL_DIFF:
@@ -2143,9 +2175,9 @@ static bool da7219_volatile_register(struct device *dev, unsigned int reg)
case DA7219_ACCDET_IRQ_EVENT_B:
case DA7219_ACCDET_CONFIG_8:
case DA7219_SYSTEM_STATUS:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h
index 1b00023e33cd..3a006862f0e7 100644
--- a/sound/soc/codecs/da7219.h
+++ b/sound/soc/codecs/da7219.h
@@ -781,8 +781,10 @@
#define DA7219_SYS_STAT_CHECK_DELAY 50
/* Power up/down Delays */
-#define DA7219_SETTLING_DELAY 40
-#define DA7219_MIN_GAIN_DELAY 30
+#define DA7219_SETTLING_DELAY 40
+#define DA7219_MIN_GAIN_DELAY 30
+#define DA7219_MIC_PGA_BASE_DELAY 100
+#define DA7219_MIC_PGA_OFFSET_DELAY 40
enum da7219_clk_src {
DA7219_CLKSRC_MCLK = 0,
@@ -828,6 +830,8 @@ struct da7219_priv {
bool master;
bool alc_en;
+ bool micbias_on_event;
+ unsigned int mic_pga_delay;
u8 gain_ramp_ctrl;
};
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index afdf90c78884..f6a7bf9560e7 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1041,9 +1041,9 @@ static bool da9055_volatile_register(struct device *dev,
case DA9055_HP_R_GAIN_STATUS:
case DA9055_LINE_GAIN_STATUS:
case DA9055_ALC_CIC_OP_LVL_DATA:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/es7134.c b/sound/soc/codecs/es7134.c
index 58515bb1a303..6d7bca7b78ca 100644
--- a/sound/soc/codecs/es7134.c
+++ b/sound/soc/codecs/es7134.c
@@ -17,6 +17,7 @@
* in the file called COPYING.
*/
+#include <linux/of_platform.h>
#include <linux/module.h>
#include <sound/soc.h>
@@ -24,6 +25,82 @@
* The everest 7134 is a very simple DA converter with no register
*/
+struct es7134_clock_mode {
+ unsigned int rate_min;
+ unsigned int rate_max;
+ unsigned int *mclk_fs;
+ unsigned int mclk_fs_num;
+};
+
+struct es7134_chip {
+ struct snd_soc_dai_driver *dai_drv;
+ const struct es7134_clock_mode *modes;
+ unsigned int mode_num;
+ const struct snd_soc_dapm_widget *extra_widgets;
+ unsigned int extra_widget_num;
+ const struct snd_soc_dapm_route *extra_routes;
+ unsigned int extra_route_num;
+};
+
+struct es7134_data {
+ unsigned int mclk;
+ const struct es7134_chip *chip;
+};
+
+static int es7134_check_mclk(struct snd_soc_dai *dai,
+ struct es7134_data *priv,
+ unsigned int rate)
+{
+ unsigned int mfs = priv->mclk / rate;
+ int i, j;
+
+ for (i = 0; i < priv->chip->mode_num; i++) {
+ const struct es7134_clock_mode *mode = &priv->chip->modes[i];
+
+ if (rate < mode->rate_min || rate > mode->rate_max)
+ continue;
+
+ for (j = 0; j < mode->mclk_fs_num; j++) {
+ if (mode->mclk_fs[j] == mfs)
+ return 0;
+ }
+
+ dev_err(dai->dev, "unsupported mclk_fs %u for rate %u\n",
+ mfs, rate);
+ return -EINVAL;
+ }
+
+ /* should not happen */
+ dev_err(dai->dev, "unsupported rate: %u\n", rate);
+ return -EINVAL;
+}
+
+static int es7134_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ /* mclk has not been provided, assume it is OK */
+ if (!priv->mclk)
+ return 0;
+
+ return es7134_check_mclk(dai, priv, params_rate(params));
+}
+
+static int es7134_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct es7134_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
+ priv->mclk = freq;
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
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 |
@@ -38,8 +115,38 @@ static int es7134_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return 0;
}
+static int es7134_component_probe(struct snd_soc_component *c)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(c);
+ struct es7134_data *priv = snd_soc_component_get_drvdata(c);
+ const struct es7134_chip *chip = priv->chip;
+ int ret;
+
+ if (chip->extra_widget_num) {
+ ret = snd_soc_dapm_new_controls(dapm, chip->extra_widgets,
+ chip->extra_widget_num);
+ if (ret) {
+ dev_err(c->dev, "failed to add extra widgets\n");
+ return ret;
+ }
+ }
+
+ if (chip->extra_route_num) {
+ ret = snd_soc_dapm_add_routes(dapm, chip->extra_routes,
+ chip->extra_route_num);
+ if (ret) {
+ dev_err(c->dev, "failed to add extra routes\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops es7134_dai_ops = {
.set_fmt = es7134_set_fmt,
+ .hw_params = es7134_hw_params,
+ .set_sysclk = es7134_set_sysclk,
};
static struct snd_soc_dai_driver es7134_dai = {
@@ -48,7 +155,11 @@ static struct snd_soc_dai_driver es7134_dai = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_192000,
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000),
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S18_3LE |
SNDRV_PCM_FMTBIT_S20_3LE |
@@ -58,18 +169,56 @@ static struct snd_soc_dai_driver es7134_dai = {
.ops = &es7134_dai_ops,
};
+static const struct es7134_clock_mode es7134_modes[] = {
+ {
+ /* Single speed mode */
+ .rate_min = 8000,
+ .rate_max = 50000,
+ .mclk_fs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
+ .mclk_fs_num = 5,
+ }, {
+ /* Double speed mode */
+ .rate_min = 84000,
+ .rate_max = 100000,
+ .mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512 },
+ .mclk_fs_num = 5,
+ }, {
+ /* Quad speed mode */
+ .rate_min = 167000,
+ .rate_max = 192000,
+ .mclk_fs = (unsigned int[]) { 128, 192, 256 },
+ .mclk_fs_num = 3,
+ },
+};
+
+/* Digital I/O are also supplied by VDD on the es7134 */
+static const struct snd_soc_dapm_route es7134_extra_routes[] = {
+ { "Playback", NULL, "VDD", }
+};
+
+static const struct es7134_chip es7134_chip = {
+ .dai_drv = &es7134_dai,
+ .modes = es7134_modes,
+ .mode_num = ARRAY_SIZE(es7134_modes),
+ .extra_routes = es7134_extra_routes,
+ .extra_route_num = ARRAY_SIZE(es7134_extra_routes),
+};
+
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),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VDD", 0, 0),
};
static const struct snd_soc_dapm_route es7134_dapm_routes[] = {
{ "AOUTL", NULL, "DAC" },
{ "AOUTR", NULL, "DAC" },
+ { "DAC", NULL, "VDD" },
};
static const struct snd_soc_component_driver es7134_component_driver = {
+ .probe = es7134_component_probe,
.dapm_widgets = es7134_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(es7134_dapm_widgets),
.dapm_routes = es7134_dapm_routes,
@@ -80,17 +229,87 @@ static const struct snd_soc_component_driver es7134_component_driver = {
.non_legacy_dai_naming = 1,
};
+static struct snd_soc_dai_driver es7154_dai = {
+ .name = "es7154-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000),
+ .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 es7134_clock_mode es7154_modes[] = {
+ {
+ /* Single speed mode */
+ .rate_min = 8000,
+ .rate_max = 50000,
+ .mclk_fs = (unsigned int[]) { 32, 64, 128, 192, 256,
+ 384, 512, 768, 1024 },
+ .mclk_fs_num = 9,
+ }, {
+ /* Double speed mode */
+ .rate_min = 84000,
+ .rate_max = 100000,
+ .mclk_fs = (unsigned int[]) { 128, 192, 256, 384, 512,
+ 768, 1024},
+ .mclk_fs_num = 7,
+ }
+};
+
+/* Es7154 has a separate supply for digital I/O */
+static const struct snd_soc_dapm_widget es7154_extra_widgets[] = {
+ SND_SOC_DAPM_REGULATOR_SUPPLY("PVDD", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7154_extra_routes[] = {
+ { "Playback", NULL, "PVDD", }
+};
+
+static const struct es7134_chip es7154_chip = {
+ .dai_drv = &es7154_dai,
+ .modes = es7154_modes,
+ .mode_num = ARRAY_SIZE(es7154_modes),
+ .extra_routes = es7154_extra_routes,
+ .extra_route_num = ARRAY_SIZE(es7154_extra_routes),
+ .extra_widgets = es7154_extra_widgets,
+ .extra_widget_num = ARRAY_SIZE(es7154_extra_widgets),
+};
+
static int es7134_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+ struct es7134_data *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
+ priv->chip = of_device_get_match_data(dev);
+ if (!priv->chip) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
return devm_snd_soc_register_component(&pdev->dev,
&es7134_component_driver,
- &es7134_dai, 1);
+ priv->chip->dai_drv, 1);
}
#ifdef CONFIG_OF
static const struct of_device_id es7134_ids[] = {
- { .compatible = "everest,es7134", },
- { .compatible = "everest,es7144", },
+ { .compatible = "everest,es7134", .data = &es7134_chip },
+ { .compatible = "everest,es7144", .data = &es7134_chip },
+ { .compatible = "everest,es7154", .data = &es7154_chip },
{ }
};
MODULE_DEVICE_TABLE(of, es7134_ids);
diff --git a/sound/soc/codecs/es7241.c b/sound/soc/codecs/es7241.c
new file mode 100644
index 000000000000..87991bd4acef
--- /dev/null
+++ b/sound/soc/codecs/es7241.c
@@ -0,0 +1,322 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/gpio/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <sound/soc.h>
+
+struct es7241_clock_mode {
+ unsigned int rate_min;
+ unsigned int rate_max;
+ unsigned int *slv_mfs;
+ unsigned int slv_mfs_num;
+ unsigned int mst_mfs;
+ unsigned int mst_m0:1;
+ unsigned int mst_m1:1;
+};
+
+struct es7241_chip {
+ const struct es7241_clock_mode *modes;
+ unsigned int mode_num;
+};
+
+struct es7241_data {
+ struct gpio_desc *reset;
+ struct gpio_desc *m0;
+ struct gpio_desc *m1;
+ unsigned int fmt;
+ unsigned int mclk;
+ bool is_slave;
+ const struct es7241_chip *chip;
+};
+
+static void es7241_set_mode(struct es7241_data *priv, int m0, int m1)
+{
+ /* put the device in reset */
+ gpiod_set_value_cansleep(priv->reset, 0);
+
+ /* set the mode */
+ gpiod_set_value_cansleep(priv->m0, m0);
+ gpiod_set_value_cansleep(priv->m1, m1);
+
+ /* take the device out of reset - datasheet does not specify a delay */
+ gpiod_set_value_cansleep(priv->reset, 1);
+}
+
+static int es7241_set_slave_mode(struct es7241_data *priv,
+ const struct es7241_clock_mode *mode,
+ unsigned int mfs)
+{
+ int j;
+
+ if (!mfs)
+ goto out_ok;
+
+ for (j = 0; j < mode->slv_mfs_num; j++) {
+ if (mode->slv_mfs[j] == mfs)
+ goto out_ok;
+ }
+
+ return -EINVAL;
+
+out_ok:
+ es7241_set_mode(priv, 1, 1);
+ return 0;
+}
+
+static int es7241_set_master_mode(struct es7241_data *priv,
+ const struct es7241_clock_mode *mode,
+ unsigned int mfs)
+{
+ /*
+ * We can't really set clock ratio, if the mclk/lrclk is different
+ * from what we provide, then error out
+ */
+ if (mfs && mfs != mode->mst_mfs)
+ return -EINVAL;
+
+ es7241_set_mode(priv, mode->mst_m0, mode->mst_m1);
+
+ return 0;
+}
+
+static int es7241_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ unsigned int mfs = priv->mclk / rate;
+ int i;
+
+ for (i = 0; i < priv->chip->mode_num; i++) {
+ const struct es7241_clock_mode *mode = &priv->chip->modes[i];
+
+ if (rate < mode->rate_min || rate >= mode->rate_max)
+ continue;
+
+ if (priv->is_slave)
+ return es7241_set_slave_mode(priv, mode, mfs);
+ else
+ return es7241_set_master_mode(priv, mode, mfs);
+ }
+
+ /* should not happen */
+ dev_err(dai->dev, "unsupported rate: %u\n", rate);
+ return -EINVAL;
+}
+
+static int es7241_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ if (dir == SND_SOC_CLOCK_IN && clk_id == 0) {
+ priv->mclk = freq;
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+static int es7241_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct es7241_data *priv = snd_soc_dai_get_drvdata(dai);
+
+ if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
+ dev_err(dai->dev, "Unsupported dai clock inversion\n");
+ return -EINVAL;
+ }
+
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != priv->fmt) {
+ dev_err(dai->dev, "Invalid dai format\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ priv->is_slave = true;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ priv->is_slave = false;
+ break;
+
+ default:
+ dev_err(dai->dev, "Unsupported clock configuration\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops es7241_dai_ops = {
+ .set_fmt = es7241_set_fmt,
+ .hw_params = es7241_hw_params,
+ .set_sysclk = es7241_set_sysclk,
+};
+
+static struct snd_soc_dai_driver es7241_dai = {
+ .name = "es7241-hifi",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_3LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ },
+ .ops = &es7241_dai_ops,
+};
+
+static const struct es7241_clock_mode es7241_modes[] = {
+ {
+ /* Single speed mode */
+ .rate_min = 8000,
+ .rate_max = 50000,
+ .slv_mfs = (unsigned int[]) { 256, 384, 512, 768, 1024 },
+ .slv_mfs_num = 5,
+ .mst_mfs = 256,
+ .mst_m0 = 0,
+ .mst_m1 = 0,
+ }, {
+ /* Double speed mode */
+ .rate_min = 50000,
+ .rate_max = 100000,
+ .slv_mfs = (unsigned int[]) { 128, 192 },
+ .slv_mfs_num = 2,
+ .mst_mfs = 128,
+ .mst_m0 = 1,
+ .mst_m1 = 0,
+ }, {
+ /* Quad speed mode */
+ .rate_min = 100000,
+ .rate_max = 200000,
+ .slv_mfs = (unsigned int[]) { 64 },
+ .slv_mfs_num = 1,
+ .mst_mfs = 64,
+ .mst_m0 = 0,
+ .mst_m1 = 1,
+ },
+};
+
+static const struct es7241_chip es7241_chip = {
+ .modes = es7241_modes,
+ .mode_num = ARRAY_SIZE(es7241_modes),
+};
+
+static const struct snd_soc_dapm_widget es7241_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("AINL"),
+ SND_SOC_DAPM_INPUT("AINR"),
+ SND_SOC_DAPM_DAC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VDDP", 0, 0),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VDDD", 0, 0),
+ SND_SOC_DAPM_REGULATOR_SUPPLY("VDDA", 0, 0),
+};
+
+static const struct snd_soc_dapm_route es7241_dapm_routes[] = {
+ { "ADC", NULL, "AINL", },
+ { "ADC", NULL, "AINR", },
+ { "ADC", NULL, "VDDA", },
+ { "Capture", NULL, "VDDP", },
+ { "Capture", NULL, "VDDD", },
+};
+
+static const struct snd_soc_component_driver es7241_component_driver = {
+ .dapm_widgets = es7241_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(es7241_dapm_widgets),
+ .dapm_routes = es7241_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(es7241_dapm_routes),
+ .idle_bias_on = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static void es7241_parse_fmt(struct device *dev, struct es7241_data *priv)
+{
+ bool is_leftj;
+
+ /*
+ * The format is given by a pull resistor on the SDOUT pin:
+ * pull-up for i2s, pull-down for left justified.
+ */
+ is_leftj = of_property_read_bool(dev->of_node,
+ "everest,sdout-pull-down");
+ if (is_leftj)
+ priv->fmt = SND_SOC_DAIFMT_LEFT_J;
+ else
+ priv->fmt = SND_SOC_DAIFMT_I2S;
+}
+
+static int es7241_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct es7241_data *priv;
+ int err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
+ priv->chip = of_device_get_match_data(dev);
+ if (!priv->chip) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ es7241_parse_fmt(dev, priv);
+
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->reset)) {
+ err = PTR_ERR(priv->reset);
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get 'reset' gpio: %d", err);
+ return err;
+ }
+
+ priv->m0 = devm_gpiod_get_optional(dev, "m0", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->m0)) {
+ err = PTR_ERR(priv->m0);
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get 'm0' gpio: %d", err);
+ return err;
+ }
+
+ priv->m1 = devm_gpiod_get_optional(dev, "m1", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->m1)) {
+ err = PTR_ERR(priv->m1);
+ if (err != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get 'm1' gpio: %d", err);
+ return err;
+ }
+
+ return devm_snd_soc_register_component(&pdev->dev,
+ &es7241_component_driver,
+ &es7241_dai, 1);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id es7241_ids[] = {
+ { .compatible = "everest,es7241", .data = &es7241_chip },
+ { }
+};
+MODULE_DEVICE_TABLE(of, es7241_ids);
+#endif
+
+static struct platform_driver es7241_driver = {
+ .driver = {
+ .name = "es7241",
+ .of_match_table = of_match_ptr(es7241_ids),
+ },
+ .probe = es7241_probe,
+};
+
+module_platform_driver(es7241_driver);
+
+MODULE_DESCRIPTION("ASoC ES7241 audio codec driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 84f7a7a36e4b..7b8533abf637 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -85,7 +85,7 @@ struct hdac_hdmi_pin {
bool mst_capable;
struct hdac_hdmi_port *ports;
int num_ports;
- struct hdac_ext_device *edev;
+ struct hdac_device *hdev;
};
struct hdac_hdmi_port {
@@ -126,6 +126,9 @@ struct hdac_hdmi_drv_data {
};
struct hdac_hdmi_priv {
+ struct hdac_device *hdev;
+ struct snd_soc_component *component;
+ struct snd_card *card;
struct hdac_hdmi_dai_port_map dai_map[HDA_MAX_CVTS];
struct list_head pin_list;
struct list_head cvt_list;
@@ -139,7 +142,7 @@ struct hdac_hdmi_priv {
struct snd_soc_dai_driver *dai_drv;
};
-#define hdev_to_hdmi_priv(_hdev) ((to_ehdac_device(_hdev))->private_data)
+#define hdev_to_hdmi_priv(_hdev) dev_get_drvdata(&(_hdev)->dev)
static struct hdac_hdmi_pcm *
hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
@@ -158,7 +161,7 @@ hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi,
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;
+ struct hdac_device *hdev = port->pin->hdev;
if (is_connect)
snd_soc_dapm_enable_pin(port->dapm, port->jack_pin);
@@ -172,7 +175,7 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
* ports.
*/
if (pcm->jack_event == 0) {
- dev_dbg(&edev->hdev.dev,
+ dev_dbg(&hdev->dev,
"jack report for pcm=%d\n",
pcm->pcm_id);
snd_soc_jack_report(pcm->jack, SND_JACK_AVOUT,
@@ -198,19 +201,18 @@ static void hdac_hdmi_jack_report(struct hdac_hdmi_pcm *pcm,
/*
* 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 *edev, hda_nid_t nid)
+static int hdac_hdmi_get_port_len(struct hdac_device *hdev, hda_nid_t nid)
{
unsigned int caps;
unsigned int type, param;
- caps = get_wcaps(&edev->hdev, nid);
+ caps = get_wcaps(hdev, nid);
type = get_wcaps_type(caps);
if (!(caps & AC_WCAP_DIGITAL) || (type != AC_WID_PIN))
return 0;
- param = snd_hdac_read_parm_uncached(&edev->hdev, nid,
- AC_PAR_DEVLIST_LEN);
+ param = snd_hdac_read_parm_uncached(hdev, nid, AC_PAR_DEVLIST_LEN);
if (param == -1)
return param;
@@ -222,10 +224,10 @@ static int hdac_hdmi_get_port_len(struct hdac_ext_device *edev, hda_nid_t nid)
* 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 *edev,
+static int hdac_hdmi_port_select_get(struct hdac_device *hdev,
struct hdac_hdmi_port *port)
{
- return snd_hdac_codec_read(&edev->hdev, port->pin->nid,
+ return snd_hdac_codec_read(hdev, port->pin->nid,
0, AC_VERB_GET_DEVICE_SEL, 0);
}
@@ -233,7 +235,7 @@ static int hdac_hdmi_port_select_get(struct hdac_ext_device *edev,
* 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 *edev,
+static int hdac_hdmi_port_select_set(struct hdac_device *hdev,
struct hdac_hdmi_port *port)
{
int num_ports;
@@ -242,8 +244,7 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev,
return 0;
/* AC_PAR_DEVLIST_LEN is 0 based. */
- num_ports = hdac_hdmi_get_port_len(edev, port->pin->nid);
-
+ num_ports = hdac_hdmi_get_port_len(hdev, port->pin->nid);
if (num_ports < 0)
return -EIO;
/*
@@ -253,13 +254,13 @@ static int hdac_hdmi_port_select_set(struct hdac_ext_device *edev,
if (num_ports + 1 < port->id)
return 0;
- snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+ snd_hdac_codec_write(hdev, port->pin->nid, 0,
AC_VERB_SET_DEVICE_SEL, port->id);
- if (port->id != hdac_hdmi_port_select_get(edev, port))
+ if (port->id != hdac_hdmi_port_select_get(hdev, port))
return -EIO;
- dev_dbg(&edev->hdev.dev, "Selected the port=%d\n", port->id);
+ dev_dbg(&hdev->dev, "Selected the port=%d\n", port->id);
return 0;
}
@@ -277,13 +278,6 @@ static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
return NULL;
}
-static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
-{
- struct hdac_device *hdev = dev_to_hdac_dev(dev);
-
- return to_ehdac_device(hdev);
-}
-
static unsigned int sad_format(const u8 *sad)
{
return ((sad[0] >> 0x3) & 0x1f);
@@ -324,15 +318,13 @@ format_constraint:
}
static void
-hdac_hdmi_set_dip_index(struct hdac_ext_device *edev, hda_nid_t pin_nid,
+hdac_hdmi_set_dip_index(struct hdac_device *hdev, hda_nid_t pin_nid,
int packet_index, int byte_index)
{
int val;
val = (packet_index << 5) | (byte_index & 0x1f);
-
- snd_hdac_codec_write(&edev->hdev, pin_nid, 0,
- AC_VERB_SET_HDMI_DIP_INDEX, val);
+ snd_hdac_codec_write(hdev, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
}
struct dp_audio_infoframe {
@@ -347,14 +339,14 @@ struct dp_audio_infoframe {
u8 LFEPBL01_LSV36_DM_INH7;
};
-static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
+static int hdac_hdmi_setup_audio_infoframe(struct hdac_device *hdev,
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 = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_cvt *cvt = pcm->cvt;
u8 *dip;
int ret;
@@ -363,11 +355,11 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
u8 conn_type;
int channels, ca;
- ca = snd_hdac_channel_allocation(&edev->hdev, port->eld.info.spk_alloc,
+ ca = snd_hdac_channel_allocation(hdev, 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(&edev->hdev, cvt->nid, channels);
+ hdmi->chmap.ops.set_channel_count(hdev, cvt->nid, channels);
snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca,
pcm->channels, pcm->chmap, pcm->chmap_set);
@@ -400,32 +392,31 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *edev,
break;
default:
- dev_err(&edev->hdev.dev, "Invalid connection type: %d\n",
- conn_type);
+ dev_err(&hdev->dev, "Invalid connection type: %d\n", conn_type);
return -EIO;
}
/* stop infoframe transmission */
- hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
- snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+ hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+ snd_hdac_codec_write(hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE);
/* Fill infoframe. Index auto-incremented */
- hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
+ hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
if (conn_type == DRM_ELD_CONN_TYPE_HDMI) {
for (i = 0; i < sizeof(buffer); i++)
- snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+ snd_hdac_codec_write(hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, buffer[i]);
} else {
for (i = 0; i < sizeof(dp_ai); i++)
- snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+ snd_hdac_codec_write(hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_DATA, dip[i]);
}
/* Start infoframe */
- hdac_hdmi_set_dip_index(edev, pin->nid, 0x0, 0x0);
- snd_hdac_codec_write(&edev->hdev, pin->nid, 0,
+ hdac_hdmi_set_dip_index(hdev, pin->nid, 0x0, 0x0);
+ snd_hdac_codec_write(hdev, pin->nid, 0,
AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST);
return 0;
@@ -435,12 +426,12 @@ 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)
{
- struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+ struct hdac_device *hdev = hdmi->hdev;
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_pcm *pcm;
- dev_dbg(&edev->hdev.dev, "%s: strm_tag: %d\n", __func__, tx_mask);
+ dev_dbg(&hdev->dev, "%s: strm_tag: %d\n", __func__, tx_mask);
dai_map = &hdmi->dai_map[dai->id];
@@ -455,8 +446,8 @@ static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai,
static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai)
{
- struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+ struct hdac_device *hdev = hdmi->hdev;
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_port *port;
struct hdac_hdmi_pcm *pcm;
@@ -469,7 +460,7 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
return -ENODEV;
if ((!port->eld.monitor_present) || (!port->eld.eld_valid)) {
- dev_err(&edev->hdev.dev,
+ dev_err(&hdev->dev,
"device is not configured for this pin:port%d:%d\n",
port->pin->nid, port->id);
return -ENODEV;
@@ -489,28 +480,28 @@ static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev,
+static int hdac_hdmi_query_port_connlist(struct hdac_device *hdev,
struct hdac_hdmi_pin *pin,
struct hdac_hdmi_port *port)
{
- if (!(get_wcaps(&edev->hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
- dev_warn(&edev->hdev.dev,
+ if (!(get_wcaps(hdev, pin->nid) & AC_WCAP_CONN_LIST)) {
+ dev_warn(&hdev->dev,
"HDMI: pin %d wcaps %#x does not support connection list\n",
- pin->nid, get_wcaps(&edev->hdev, pin->nid));
+ pin->nid, get_wcaps(hdev, pin->nid));
return -EINVAL;
}
- if (hdac_hdmi_port_select_set(edev, port) < 0)
+ if (hdac_hdmi_port_select_set(hdev, port) < 0)
return -EIO;
- port->num_mux_nids = snd_hdac_get_connections(&edev->hdev, pin->nid,
+ port->num_mux_nids = snd_hdac_get_connections(hdev, pin->nid,
port->mux_nids, HDA_MAX_CONNECTIONS);
if (port->num_mux_nids == 0)
- dev_warn(&edev->hdev.dev,
+ dev_warn(&hdev->dev,
"No connections found for pin:port %d:%d\n",
pin->nid, port->id);
- dev_dbg(&edev->hdev.dev, "num_mux_nids %d for pin:port %d:%d\n",
+ dev_dbg(&hdev->dev, "num_mux_nids %d for pin:port %d:%d\n",
port->num_mux_nids, pin->nid, port->id);
return port->num_mux_nids;
@@ -526,7 +517,7 @@ static int hdac_hdmi_query_port_connlist(struct hdac_ext_device *edev,
* connected.
*/
static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
- struct hdac_ext_device *edev,
+ struct hdac_device *hdev,
struct hdac_hdmi_priv *hdmi,
struct hdac_hdmi_cvt *cvt)
{
@@ -541,7 +532,7 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
list_for_each_entry(port, &pcm->port_list, head) {
mutex_lock(&pcm->lock);
- ret = hdac_hdmi_query_port_connlist(edev,
+ ret = hdac_hdmi_query_port_connlist(hdev,
port->pin, port);
mutex_unlock(&pcm->lock);
if (ret < 0)
@@ -568,8 +559,8 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
+ struct hdac_device *hdev = hdmi->hdev;
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_cvt *cvt;
struct hdac_hdmi_port *port;
@@ -578,7 +569,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
dai_map = &hdmi->dai_map[dai->id];
cvt = dai_map->cvt;
- port = hdac_hdmi_get_port_from_cvt(edev, hdmi, cvt);
+ port = hdac_hdmi_get_port_from_cvt(hdev, hdmi, cvt);
/*
* To make PA and other userland happy.
@@ -589,7 +580,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
if ((!port->eld.monitor_present) ||
(!port->eld.eld_valid)) {
- dev_warn(&edev->hdev.dev,
+ dev_warn(&hdev->dev,
"Failed: present?:%d ELD valid?:%d pin:port: %d:%d\n",
port->eld.monitor_present, port->eld.eld_valid,
port->pin->nid, port->id);
@@ -611,8 +602,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_pcm *pcm;
@@ -695,10 +685,10 @@ static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route,
route->connected = handler;
}
-static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
+static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_device *hdev,
struct hdac_hdmi_port *port)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = NULL;
struct hdac_hdmi_port *p;
@@ -715,33 +705,32 @@ static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev,
return NULL;
}
-static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev,
+static void hdac_hdmi_set_power_state(struct hdac_device *hdev,
hda_nid_t nid, unsigned int pwr_state)
{
int count;
unsigned int state;
- if (get_wcaps(&edev->hdev, nid) & AC_WCAP_POWER) {
- if (!snd_hdac_check_power_state(&edev->hdev, nid, pwr_state)) {
+ if (get_wcaps(hdev, nid) & AC_WCAP_POWER) {
+ if (!snd_hdac_check_power_state(hdev, nid, pwr_state)) {
for (count = 0; count < 10; count++) {
- snd_hdac_codec_read(&edev->hdev, nid, 0,
+ snd_hdac_codec_read(hdev, nid, 0,
AC_VERB_SET_POWER_STATE,
pwr_state);
- state = snd_hdac_sync_power_state(&edev->hdev,
+ state = snd_hdac_sync_power_state(hdev,
nid, pwr_state);
if (!(state & AC_PWRST_ERROR))
break;
}
}
-
}
}
-static void hdac_hdmi_set_amp(struct hdac_ext_device *edev,
+static void hdac_hdmi_set_amp(struct hdac_device *hdev,
hda_nid_t nid, int val)
{
- if (get_wcaps(&edev->hdev, nid) & AC_WCAP_OUT_AMP)
- snd_hdac_codec_write(&edev->hdev, nid, 0,
+ if (get_wcaps(hdev, nid) & AC_WCAP_OUT_AMP)
+ snd_hdac_codec_write(hdev, nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, val);
}
@@ -750,40 +739,40 @@ 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_device *hdev = dev_to_hdac_dev(w->dapm->dev);
struct hdac_hdmi_pcm *pcm;
- dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
+ dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
__func__, w->name, event);
- pcm = hdac_hdmi_get_pcm(edev, port);
+ pcm = hdac_hdmi_get_pcm(hdev, port);
if (!pcm)
return -EIO;
/* set the device if pin is mst_capable */
- if (hdac_hdmi_port_select_set(edev, port) < 0)
+ if (hdac_hdmi_port_select_set(hdev, port) < 0)
return -EIO;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D0);
+ hdac_hdmi_set_power_state(hdev, port->pin->nid, AC_PWRST_D0);
/* Enable out path for this pin widget */
- snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+ snd_hdac_codec_write(hdev, port->pin->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
- hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_UNMUTE);
+ hdac_hdmi_set_amp(hdev, port->pin->nid, AMP_OUT_UNMUTE);
- return hdac_hdmi_setup_audio_infoframe(edev, pcm, port);
+ return hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
case SND_SOC_DAPM_POST_PMD:
- hdac_hdmi_set_amp(edev, port->pin->nid, AMP_OUT_MUTE);
+ hdac_hdmi_set_amp(hdev, port->pin->nid, AMP_OUT_MUTE);
/* Disable out path for this pin widget */
- snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+ snd_hdac_codec_write(hdev, port->pin->nid, 0,
AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
- hdac_hdmi_set_power_state(edev, port->pin->nid, AC_PWRST_D3);
+ hdac_hdmi_set_power_state(hdev, port->pin->nid, AC_PWRST_D3);
break;
}
@@ -795,11 +784,11 @@ 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 = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm;
- dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
+ dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
__func__, w->name, event);
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt);
@@ -808,29 +797,29 @@ static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0);
+ hdac_hdmi_set_power_state(hdev, cvt->nid, AC_PWRST_D0);
/* Enable transmission */
- snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+ snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_1, 1);
/* Category Code (CC) to zero */
- snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+ snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_DIGI_CONVERT_2, 0);
- snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+ snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag);
- snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+ snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, pcm->format);
break;
case SND_SOC_DAPM_POST_PMD:
- snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+ snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_CHANNEL_STREAMID, 0);
- snd_hdac_codec_write(&edev->hdev, cvt->nid, 0,
+ snd_hdac_codec_write(hdev, cvt->nid, 0,
AC_VERB_SET_STREAM_FORMAT, 0);
- hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3);
+ hdac_hdmi_set_power_state(hdev, cvt->nid, AC_PWRST_D3);
break;
}
@@ -842,10 +831,10 @@ 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);
+ struct hdac_device *hdev = dev_to_hdac_dev(w->dapm->dev);
int mux_idx;
- dev_dbg(&edev->hdev.dev, "%s: widget: %s event: %x\n",
+ dev_dbg(&hdev->dev, "%s: widget: %s event: %x\n",
__func__, w->name, event);
if (!kc)
@@ -854,11 +843,11 @@ static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w,
mux_idx = dapm_kcontrol_get_value(kc);
/* set the device if pin is mst_capable */
- if (hdac_hdmi_port_select_set(edev, port) < 0)
+ if (hdac_hdmi_port_select_set(hdev, port) < 0)
return -EIO;
if (mux_idx > 0) {
- snd_hdac_codec_write(&edev->hdev, port->pin->nid, 0,
+ snd_hdac_codec_write(hdev, port->pin->nid, 0,
AC_VERB_SET_CONNECT_SEL, (mux_idx - 1));
}
@@ -877,8 +866,8 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol);
struct snd_soc_dapm_context *dapm = w->dapm;
struct hdac_hdmi_port *port = w->priv;
- struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = NULL;
const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]];
@@ -931,12 +920,12 @@ static int hdac_hdmi_set_pin_port_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_port_muxs(struct hdac_ext_device *edev,
+static int hdac_hdmi_create_pin_port_muxs(struct hdac_device *hdev,
struct hdac_hdmi_port *port,
struct snd_soc_dapm_widget *widget,
const char *widget_name)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pin *pin = port->pin;
struct snd_kcontrol_new *kc;
struct hdac_hdmi_cvt *cvt;
@@ -948,17 +937,17 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
int i = 0;
int num_items = hdmi->num_cvt + 1;
- kc = devm_kzalloc(&edev->hdev.dev, sizeof(*kc), GFP_KERNEL);
+ kc = devm_kzalloc(&hdev->dev, sizeof(*kc), GFP_KERNEL);
if (!kc)
return -ENOMEM;
- se = devm_kzalloc(&edev->hdev.dev, sizeof(*se), GFP_KERNEL);
+ se = devm_kzalloc(&hdev->dev, sizeof(*se), GFP_KERNEL);
if (!se)
return -ENOMEM;
snprintf(kc_name, NAME_SIZE, "Pin %d port %d Input",
pin->nid, port->id);
- kc->name = devm_kstrdup(&edev->hdev.dev, kc_name, GFP_KERNEL);
+ kc->name = devm_kstrdup(&hdev->dev, kc_name, GFP_KERNEL);
if (!kc->name)
return -ENOMEM;
@@ -976,35 +965,35 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_ext_device *edev,
se->mask = roundup_pow_of_two(se->items) - 1;
sprintf(mux_items, "NONE");
- items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL);
+ items[i] = devm_kstrdup(&hdev->dev, mux_items, GFP_KERNEL);
if (!items[i])
return -ENOMEM;
list_for_each_entry(cvt, &hdmi->cvt_list, head) {
i++;
sprintf(mux_items, "cvt %d", cvt->nid);
- items[i] = devm_kstrdup(&edev->hdev.dev, mux_items, GFP_KERNEL);
+ items[i] = devm_kstrdup(&hdev->dev, mux_items, GFP_KERNEL);
if (!items[i])
return -ENOMEM;
}
- se->texts = devm_kmemdup(&edev->hdev.dev, items,
+ se->texts = devm_kmemdup(&hdev->dev, items,
(num_items * sizeof(char *)), GFP_KERNEL);
if (!se->texts)
return -ENOMEM;
- return hdac_hdmi_fill_widget_info(&edev->hdev.dev, widget,
+ return hdac_hdmi_fill_widget_info(&hdev->dev, widget,
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 */
-static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev,
+static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_device *hdev,
struct snd_soc_dapm_widget *widgets,
struct snd_soc_dapm_route *route, int rindex)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
const struct snd_kcontrol_new *kc;
struct soc_enum *se;
int mux_index = hdmi->num_cvt + hdmi->num_ports;
@@ -1046,8 +1035,8 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
{
struct snd_soc_dapm_widget *widgets;
struct snd_soc_dapm_route *route;
- struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = dev_to_hdac_dev(dapm->dev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct snd_soc_dai_driver *dai_drv = hdmi->dai_drv;
char widget_name[NAME_SIZE];
struct hdac_hdmi_cvt *cvt;
@@ -1099,7 +1088,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
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,
+ ret = hdac_hdmi_create_pin_port_muxs(hdev,
&pin->ports[j], &widgets[i],
widget_name);
if (ret < 0)
@@ -1134,7 +1123,7 @@ static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm)
}
}
- hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i);
+ hdac_hdmi_add_pinmux_cvt_route(hdev, widgets, route, i);
snd_soc_dapm_new_controls(dapm, widgets,
((2 * hdmi->num_ports) + hdmi->num_cvt));
@@ -1146,9 +1135,9 @@ 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)
+static int hdac_hdmi_init_dai_map(struct hdac_device *hdev)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_dai_port_map *dai_map;
struct hdac_hdmi_cvt *cvt;
int dai_id = 0;
@@ -1164,7 +1153,7 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
dai_id++;
if (dai_id == HDA_MAX_CVTS) {
- dev_warn(&edev->hdev.dev,
+ dev_warn(&hdev->dev,
"Max dais supported: %d\n", dai_id);
break;
}
@@ -1173,9 +1162,9 @@ static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev)
return 0;
}
-static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
+static int hdac_hdmi_add_cvt(struct hdac_device *hdev, hda_nid_t nid)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_cvt *cvt;
char name[NAME_SIZE];
@@ -1190,10 +1179,10 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid)
list_add_tail(&cvt->head, &hdmi->cvt_list);
hdmi->num_cvt++;
- return hdac_hdmi_query_cvt_params(&edev->hdev, cvt);
+ return hdac_hdmi_query_cvt_params(hdev, cvt);
}
-static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
+static int hdac_hdmi_parse_eld(struct hdac_device *hdev,
struct hdac_hdmi_port *port)
{
unsigned int ver, mnl;
@@ -1202,7 +1191,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
>> DRM_ELD_VER_SHIFT;
if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) {
- dev_err(&edev->hdev.dev, "HDMI: Unknown ELD version %d\n", ver);
+ dev_err(&hdev->dev, "HDMI: Unknown ELD version %d\n", ver);
return -EINVAL;
}
@@ -1210,7 +1199,7 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT;
if (mnl > ELD_MAX_MNL) {
- dev_err(&edev->hdev.dev, "HDMI: MNL Invalid %d\n", mnl);
+ dev_err(&hdev->dev, "HDMI: MNL Invalid %d\n", mnl);
return -EINVAL;
}
@@ -1222,8 +1211,8 @@ static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev,
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 = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = pin->hdev;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm;
int size = 0;
int port_id = -1;
@@ -1241,14 +1230,14 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
if (pin->mst_capable)
port_id = port->id;
- size = snd_hdac_acomp_get_eld(&edev->hdev, pin->nid, port_id,
+ size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id,
&port->eld.monitor_present,
port->eld.eld_buffer,
ELD_MAX_SIZE);
if (size > 0) {
size = min(size, ELD_MAX_SIZE);
- if (hdac_hdmi_parse_eld(edev, port) < 0)
+ if (hdac_hdmi_parse_eld(hdev, port) < 0)
size = -EINVAL;
}
@@ -1260,11 +1249,11 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
port->eld.eld_size = 0;
}
- pcm = hdac_hdmi_get_pcm(edev, port);
+ pcm = hdac_hdmi_get_pcm(hdev, port);
if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_err(&edev->hdev.dev, "%s: disconnect for pin:port %d:%d\n",
+ dev_err(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
__func__, pin->nid, port->id);
/*
@@ -1316,9 +1305,9 @@ static int hdac_hdmi_add_ports(struct hdac_hdmi_priv *hdmi,
return 0;
}
-static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
+static int hdac_hdmi_add_pin(struct hdac_device *hdev, hda_nid_t nid)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pin *pin;
int ret;
@@ -1328,7 +1317,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid)
pin->nid = nid;
pin->mst_capable = false;
- pin->edev = edev;
+ pin->hdev = hdev;
ret = hdac_hdmi_add_ports(hdmi, pin);
if (ret < 0)
return ret;
@@ -1459,15 +1448,14 @@ static int hdac_hdmi_create_dais(struct hdac_device *hdev,
* Parse all nodes and store the cvt/pin nids in array
* Add one time initialization for pin and cvt widgets
*/
-static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
+static int hdac_hdmi_parse_and_map_nid(struct hdac_device *hdev,
struct snd_soc_dai_driver **dais, int *num_dais)
{
hda_nid_t nid;
int i, num_nodes;
struct hdac_hdmi_cvt *temp_cvt, *cvt_next;
struct hdac_hdmi_pin *temp_pin, *pin_next;
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
- struct hdac_device *hdev = &edev->hdev;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
int ret;
hdac_hdmi_skl_enable_all_pins(hdev);
@@ -1492,13 +1480,13 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
switch (type) {
case AC_WID_AUD_OUT:
- ret = hdac_hdmi_add_cvt(edev, nid);
+ ret = hdac_hdmi_add_cvt(hdev, nid);
if (ret < 0)
goto free_widgets;
break;
case AC_WID_PIN:
- ret = hdac_hdmi_add_pin(edev, nid);
+ ret = hdac_hdmi_add_pin(hdev, nid);
if (ret < 0)
goto free_widgets;
break;
@@ -1518,7 +1506,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
}
*num_dais = hdmi->num_cvt;
- ret = hdac_hdmi_init_dai_map(edev);
+ ret = hdac_hdmi_init_dai_map(hdev);
if (ret < 0)
goto free_widgets;
@@ -1542,19 +1530,24 @@ free_widgets:
return ret;
}
+static int hdac_hdmi_pin2port(void *aptr, int pin)
+{
+ return pin - 4; /* map NID 0x05 -> port #1 */
+}
+
static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
{
- struct hdac_ext_device *edev = aptr;
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_device *hdev = aptr;
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pin *pin = NULL;
struct hdac_hdmi_port *hport = NULL;
- struct snd_soc_component *component = edev->scodec;
+ struct snd_soc_component *component = hdmi->component;
int i;
/* Don't know how this mapping is derived */
hda_nid_t pin_nid = port + 0x04;
- dev_dbg(&edev->hdev.dev, "%s: for pin:%d port=%d\n", __func__,
+ dev_dbg(&hdev->dev, "%s: for pin:%d port=%d\n", __func__,
pin_nid, pipe);
/*
@@ -1567,7 +1560,7 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
SNDRV_CTL_POWER_D0)
return;
- if (atomic_read(&edev->hdev.in_pm))
+ if (atomic_read(&hdev->in_pm))
return;
list_for_each_entry(pin, &hdmi->pin_list, head) {
@@ -1595,7 +1588,8 @@ static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
}
-static struct i915_audio_component_audio_ops aops = {
+static struct drm_audio_component_audio_ops aops = {
+ .pin2port = hdac_hdmi_pin2port,
.pin_eld_notify = hdac_hdmi_eld_notify_cb,
};
@@ -1614,15 +1608,15 @@ static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
/* create jack pin kcontrols */
static int create_fill_jack_kcontrols(struct snd_soc_card *card,
- struct hdac_ext_device *edev)
+ struct hdac_device *hdev)
{
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_component *component = edev->scodec;
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
+ struct snd_soc_component *component = hdmi->component;
kc = devm_kcalloc(component->dev, hdmi->num_ports,
sizeof(*kc), GFP_KERNEL);
@@ -1659,8 +1653,8 @@ static int create_fill_jack_kcontrols(struct snd_soc_card *card,
int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
struct snd_soc_dapm_context *dapm)
{
- struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+ struct hdac_device *hdev = hdmi->hdev;
struct hdac_hdmi_pin *pin;
struct snd_soc_dapm_widget *widgets;
struct snd_soc_dapm_route *route;
@@ -1715,7 +1709,7 @@ int hdac_hdmi_jack_port_init(struct snd_soc_component *component,
return ret;
/* Add Jack Pin switch Kcontrol */
- ret = create_fill_jack_kcontrols(dapm->card, edev);
+ ret = create_fill_jack_kcontrols(dapm->card, hdev);
if (ret < 0)
return ret;
@@ -1735,8 +1729,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
struct snd_soc_jack *jack)
{
struct snd_soc_component *component = dai->component;
- struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+ struct hdac_device *hdev = hdmi->hdev;
struct hdac_hdmi_pcm *pcm;
struct snd_pcm *snd_pcm;
int err;
@@ -1758,7 +1752,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
if (snd_pcm) {
err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
if (err < 0) {
- dev_err(&edev->hdev.dev,
+ dev_err(&hdev->dev,
"chmap control add failed with err: %d for pcm: %d\n",
err, device);
kfree(pcm);
@@ -1772,7 +1766,7 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device,
}
EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init);
-static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
+static void hdac_hdmi_present_sense_all_pins(struct hdac_device *hdev,
struct hdac_hdmi_priv *hdmi, bool detect_pin_caps)
{
int i;
@@ -1781,7 +1775,7 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
list_for_each_entry(pin, &hdmi->pin_list, head) {
if (detect_pin_caps) {
- if (hdac_hdmi_get_port_len(edev, pin->nid) == 0)
+ if (hdac_hdmi_get_port_len(hdev, pin->nid) == 0)
pin->mst_capable = false;
else
pin->mst_capable = true;
@@ -1798,68 +1792,67 @@ static void hdac_hdmi_present_sense_all_pins(struct hdac_ext_device *edev,
static int hdmi_codec_probe(struct snd_soc_component *component)
{
- struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+ struct hdac_device *hdev = hdmi->hdev;
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(component);
struct hdac_ext_link *hlink = NULL;
int ret;
- edev->scodec = component;
+ hdmi->component = component;
/*
* hold the ref while we probe, also no need to drop the ref on
* exit, we call pm_runtime_suspend() so that will do for us
*/
- hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev));
+ hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&edev->hdev.dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
}
- snd_hdac_ext_bus_link_get(edev->ebus, hlink);
+ snd_hdac_ext_bus_link_get(hdev->bus, hlink);
ret = create_fill_widget_route_map(dapm);
if (ret < 0)
return ret;
- aops.audio_ptr = edev;
- ret = snd_hdac_i915_register_notifier(&aops);
+ aops.audio_ptr = hdev;
+ ret = snd_hdac_acomp_register_notifier(hdev->bus, &aops);
if (ret < 0) {
- dev_err(&edev->hdev.dev, "notifier register failed: err: %d\n",
- ret);
+ dev_err(&hdev->dev, "notifier register failed: err: %d\n", ret);
return ret;
}
- hdac_hdmi_present_sense_all_pins(edev, hdmi, true);
+ hdac_hdmi_present_sense_all_pins(hdev, hdmi, true);
/* Imp: Store the card pointer in hda_codec */
- edev->card = dapm->card->snd_card;
+ hdmi->card = dapm->card->snd_card;
/*
* hdac_device core already sets the state to active and calls
* get_noresume. So enable runtime and set the device to suspend.
*/
- pm_runtime_enable(&edev->hdev.dev);
- pm_runtime_put(&edev->hdev.dev);
- pm_runtime_suspend(&edev->hdev.dev);
+ pm_runtime_enable(&hdev->dev);
+ pm_runtime_put(&hdev->dev);
+ pm_runtime_suspend(&hdev->dev);
return 0;
}
static void hdmi_codec_remove(struct snd_soc_component *component)
{
- struct hdac_ext_device *edev = snd_soc_component_get_drvdata(component);
+ struct hdac_hdmi_priv *hdmi = snd_soc_component_get_drvdata(component);
+ struct hdac_device *hdev = hdmi->hdev;
- pm_runtime_disable(&edev->hdev.dev);
+ pm_runtime_disable(&hdev->dev);
}
#ifdef CONFIG_PM
static int hdmi_codec_prepare(struct device *dev)
{
- struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_device *hdev = &edev->hdev;
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
- pm_runtime_get_sync(&edev->hdev.dev);
+ pm_runtime_get_sync(&hdev->dev);
/*
* Power down afg.
@@ -1876,16 +1869,15 @@ static int hdmi_codec_prepare(struct device *dev)
static void hdmi_codec_complete(struct device *dev)
{
- struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
- struct hdac_device *hdev = &edev->hdev;
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
/* Power up afg */
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
AC_PWRST_D0);
- hdac_hdmi_skl_enable_all_pins(&edev->hdev);
- hdac_hdmi_skl_enable_dp12(&edev->hdev);
+ hdac_hdmi_skl_enable_all_pins(hdev);
+ hdac_hdmi_skl_enable_dp12(hdev);
/*
* As the ELD notify callback request is not entertained while the
@@ -1893,9 +1885,9 @@ static void hdmi_codec_complete(struct device *dev)
* all pins here. pin capablity change is not support, so use the
* already set pin caps.
*/
- hdac_hdmi_present_sense_all_pins(edev, hdmi, false);
+ hdac_hdmi_present_sense_all_pins(hdev, hdmi, false);
- pm_runtime_put_sync(&edev->hdev.dev);
+ pm_runtime_put_sync(&hdev->dev);
}
#else
#define hdmi_codec_prepare NULL
@@ -1922,7 +1914,6 @@ static void hdac_hdmi_get_chmap(struct hdac_device *hdev, int pcm_idx,
static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
unsigned char *chmap, int prepared)
{
- struct hdac_ext_device *edev = to_ehdac_device(hdev);
struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
struct hdac_hdmi_port *port;
@@ -1938,7 +1929,7 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
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);
+ hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
mutex_unlock(&pcm->lock);
}
@@ -1987,10 +1978,9 @@ static struct hdac_hdmi_drv_data intel_drv_data = {
.vendor_nid = INTEL_VENDOR_NID,
};
-static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
+static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
{
- struct hdac_device *hdev = &edev->hdev;
- struct hdac_hdmi_priv *hdmi_priv;
+ struct hdac_hdmi_priv *hdmi_priv = NULL;
struct snd_soc_dai_driver *hdmi_dais = NULL;
struct hdac_ext_link *hlink = NULL;
int num_dais = 0;
@@ -1999,24 +1989,24 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
const struct hda_device_id *hdac_id = hdac_get_device_id(hdev, hdrv);
/* hold the ref while we probe */
- hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdev.dev));
+ hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev));
if (!hlink) {
- dev_err(&edev->hdev.dev, "hdac link not found\n");
+ dev_err(&hdev->dev, "hdac link not found\n");
return -EIO;
}
- snd_hdac_ext_bus_link_get(edev->ebus, hlink);
+ snd_hdac_ext_bus_link_get(hdev->bus, hlink);
hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
if (hdmi_priv == NULL)
return -ENOMEM;
- edev->private_data = hdmi_priv;
snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
+ hdmi_priv->hdev = hdev;
if (!hdac_id)
return -ENODEV;
@@ -2027,7 +2017,7 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
else
hdmi_priv->drv_data = &intel_drv_data;
- dev_set_drvdata(&hdev->dev, edev);
+ dev_set_drvdata(&hdev->dev, hdmi_priv);
INIT_LIST_HEAD(&hdmi_priv->pin_list);
INIT_LIST_HEAD(&hdmi_priv->cvt_list);
@@ -2038,15 +2028,15 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
* Turned off in the runtime_suspend during the first explicit
* pm_runtime_suspend call.
*/
- ret = snd_hdac_display_power(edev->hdev.bus, true);
+ ret = snd_hdac_display_power(hdev->bus, true);
if (ret < 0) {
- dev_err(&edev->hdev.dev,
+ dev_err(&hdev->dev,
"Cannot turn on display power on i915 err: %d\n",
ret);
return ret;
}
- ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais);
+ ret = hdac_hdmi_parse_and_map_nid(hdev, &hdmi_dais, &num_dais);
if (ret < 0) {
dev_err(&hdev->dev,
"Failed in parse and map nid with err: %d\n", ret);
@@ -2058,14 +2048,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
ret = devm_snd_soc_register_component(&hdev->dev, &hdmi_hda_codec,
hdmi_dais, num_dais);
- snd_hdac_ext_bus_link_put(edev->ebus, hlink);
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return ret;
}
-static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
+static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
{
- struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(&edev->hdev);
+ struct hdac_hdmi_priv *hdmi = hdev_to_hdmi_priv(hdev);
struct hdac_hdmi_pin *pin, *pin_next;
struct hdac_hdmi_cvt *cvt, *cvt_next;
struct hdac_hdmi_pcm *pcm, *pcm_next;
@@ -2103,12 +2093,79 @@ static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev)
}
#ifdef CONFIG_PM
+/*
+ * Power management sequences
+ * ==========================
+ *
+ * The following explains the PM handling of HDAC HDMI with its parent
+ * device SKL and display power usage
+ *
+ * Probe
+ * -----
+ * In SKL probe,
+ * 1. skl_probe_work() powers up the display (refcount++ -> 1)
+ * 2. enumerates the codecs on the link
+ * 3. powers down the display (refcount-- -> 0)
+ *
+ * In HDAC HDMI probe,
+ * 1. hdac_hdmi_dev_probe() powers up the display (refcount++ -> 1)
+ * 2. probe the codec
+ * 3. put the HDAC HDMI device to runtime suspend
+ * 4. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Once children are runtime suspended, SKL device also goes to runtime
+ * suspend
+ *
+ * HDMI Playback
+ * -------------
+ * Open HDMI device,
+ * 1. skl_runtime_resume() invoked
+ * 2. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
+ *
+ * Close HDMI device,
+ * 1. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ * 2. skl_runtime_suspend() invoked
+ *
+ * S0/S3 Cycle with playback in progress
+ * -------------------------------------
+ * When the device is opened for playback, the device is runtime active
+ * already and the display refcount is 1 as explained above.
+ *
+ * Entering to S3,
+ * 1. hdmi_codec_prepare() invoke the runtime resume of codec which just
+ * increments the PM runtime usage count of the codec since the device
+ * is in use already
+ * 2. skl_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Wakeup from S3,
+ * 1. skl_resume() powers up the display (refcount++ -> 1)
+ * 2. hdmi_codec_complete() invokes the runtime suspend of codec which just
+ * decrements the PM runtime usage count of the codec since the device
+ * is in use already
+ *
+ * Once playback is stopped, the display refcount is set to 0 as explained
+ * above in the HDMI playback sequence. The PM handlings are designed in
+ * such way that to balance the refcount of display power when the codec
+ * device put to S3 while playback is going on.
+ *
+ * S0/S3 Cycle without playback in progress
+ * ----------------------------------------
+ * Entering to S3,
+ * 1. hdmi_codec_prepare() invoke the runtime resume of codec
+ * 2. skl_runtime_resume() invoked
+ * 3. hdac_hdmi_runtime_resume() powers up the display (refcount++ -> 1)
+ * 4. skl_suspend() powers down the display (refcount-- -> 0)
+ *
+ * Wakeup from S3,
+ * 1. skl_resume() powers up the display (refcount++ -> 1)
+ * 2. hdmi_codec_complete() invokes the runtime suspend of codec
+ * 3. hdac_hdmi_runtime_suspend() powers down the display (refcount-- -> 0)
+ * 4. skl_runtime_suspend() invoked
+ */
static int hdac_hdmi_runtime_suspend(struct device *dev)
{
- struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_device *hdev = &edev->hdev;
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
- struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink = NULL;
int err;
@@ -2129,27 +2186,25 @@ static int hdac_hdmi_runtime_suspend(struct device *dev)
AC_PWRST_D3);
err = snd_hdac_display_power(bus, false);
if (err < 0) {
- dev_err(bus->dev, "Cannot turn on display power on i915\n");
+ dev_err(dev, "Cannot turn on display power on i915\n");
return err;
}
- hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
}
- snd_hdac_ext_bus_link_put(ebus, hlink);
+ snd_hdac_ext_bus_link_put(bus, hlink);
return 0;
}
static int hdac_hdmi_runtime_resume(struct device *dev)
{
- struct hdac_ext_device *edev = to_hda_ext_device(dev);
- struct hdac_device *hdev = &edev->hdev;
+ struct hdac_device *hdev = dev_to_hdac_dev(dev);
struct hdac_bus *bus = hdev->bus;
- struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink = NULL;
int err;
@@ -2159,22 +2214,22 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
if (!bus)
return 0;
- hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev));
+ hlink = snd_hdac_ext_bus_get_link(bus, dev_name(dev));
if (!hlink) {
dev_err(dev, "hdac link not found\n");
return -EIO;
}
- snd_hdac_ext_bus_link_get(ebus, hlink);
+ snd_hdac_ext_bus_link_get(bus, hlink);
err = snd_hdac_display_power(bus, true);
if (err < 0) {
- dev_err(bus->dev, "Cannot turn on display power on i915\n");
+ dev_err(dev, "Cannot turn on display power on i915\n");
return err;
}
- hdac_hdmi_skl_enable_all_pins(&edev->hdev);
- hdac_hdmi_skl_enable_dp12(&edev->hdev);
+ hdac_hdmi_skl_enable_all_pins(hdev);
+ hdac_hdmi_skl_enable_dp12(hdev);
/* Power up afg */
snd_hdac_codec_read(hdev, hdev->afg, 0, AC_VERB_SET_POWER_STATE,
@@ -2206,14 +2261,12 @@ static const struct hda_device_id hdmi_list[] = {
MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
-static struct hdac_ext_driver hdmi_driver = {
- . hdac = {
- .driver = {
- .name = "HDMI HDA Codec",
- .pm = &hdac_hdmi_pm,
- },
- .id_table = hdmi_list,
+static struct hdac_driver hdmi_driver = {
+ .driver = {
+ .name = "HDMI HDA Codec",
+ .pm = &hdac_hdmi_pm,
},
+ .id_table = hdmi_list,
.probe = hdac_hdmi_dev_probe,
.remove = hdac_hdmi_dev_remove,
};
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 38e4a8515709..d00734d31e04 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -291,10 +291,6 @@ static const struct snd_soc_dapm_widget hdmi_widgets[] = {
SND_SOC_DAPM_OUTPUT("TX"),
};
-static const struct snd_soc_dapm_route hdmi_routes[] = {
- { "TX", NULL, "Playback" },
-};
-
enum {
DAI_ID_I2S = 0,
DAI_ID_SPDIF,
@@ -689,9 +685,23 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
return snd_ctl_add(rtd->card->snd_card, kctl);
}
+static int hdmi_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_dapm_context *dapm;
+ struct snd_soc_dapm_route route = {
+ .sink = "TX",
+ .source = dai->driver->playback.stream_name,
+ };
+
+ dapm = snd_soc_component_get_dapm(dai->component);
+
+ return snd_soc_dapm_add_routes(dapm, &route, 1);
+}
+
static const struct snd_soc_dai_driver hdmi_i2s_dai = {
.name = "i2s-hifi",
.id = DAI_ID_I2S,
+ .probe = hdmi_dai_probe,
.playback = {
.stream_name = "I2S Playback",
.channels_min = 2,
@@ -707,6 +717,7 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = {
static const struct snd_soc_dai_driver hdmi_spdif_dai = {
.name = "spdif-hifi",
.id = DAI_ID_SPDIF,
+ .probe = hdmi_dai_probe,
.playback = {
.stream_name = "SPDIF Playback",
.channels_min = 2,
@@ -733,8 +744,6 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
static const struct snd_soc_component_driver hdmi_driver = {
.dapm_widgets = hdmi_widgets,
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
- .dapm_routes = hdmi_routes,
- .num_dapm_routes = ARRAY_SIZE(hdmi_routes),
.of_xlate_dai_id = hdmi_of_xlate_dai_id,
.idle_bias_on = 1,
.use_pmdown_time = 1,
diff --git a/sound/soc/codecs/max98373.c b/sound/soc/codecs/max98373.c
index a92586106932..92b7125ea169 100644
--- a/sound/soc/codecs/max98373.c
+++ b/sound/soc/codecs/max98373.c
@@ -488,6 +488,7 @@ static const DECLARE_TLV_DB_RANGE(max98373_bde_gain_tlv,
static bool max98373_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case MAX98373_R2000_SW_RESET:
case MAX98373_R2001_INT_RAW1 ... MAX98373_R200C_INT_EN3:
case MAX98373_R2010_IRQ_CTRL:
case MAX98373_R2014_THERM_WARN_THRESH
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 74d7f52c7e73..6e6134589588 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -52,9 +52,9 @@ static bool max9850_volatile_register(struct device *dev, unsigned int reg)
switch (reg) {
case MAX9850_STATUSA:
case MAX9850_STATUSB:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index 17104f8dc1a9..e3c8cd17daf2 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -362,11 +362,8 @@ static const struct snd_soc_dapm_route nau8540_dapm_routes[] = {
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");
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 6bd14453f06e..468d5143e2c4 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -1274,7 +1274,7 @@ static int nau8824_calc_fll_param(unsigned int fll_in,
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;
+ fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
fvco_max < fvco) {
fvco_max = fvco;
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index dc6ea4987b7d..b9fed99d8b5e 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -2016,7 +2016,7 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs,
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;
+ fvco = 256ULL * fs * 2 * mclk_src_scaling[i].param;
if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX &&
fvco_max < fvco) {
fvco_max = fvco;
diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c
index 21f15219b3ad..8df6447c76a6 100644
--- a/sound/soc/codecs/pcm1789.c
+++ b/sound/soc/codecs/pcm1789.c
@@ -262,8 +262,7 @@ int pcm1789_common_exit(struct device *dev)
{
struct pcm1789_private *priv = dev_get_drvdata(dev);
- if (&priv->work)
- flush_work(&priv->work);
+ flush_work(&priv->work);
return 0;
}
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index 88fde70b1e9e..690c26e7389e 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -265,7 +265,7 @@ static int pcm186x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct pcm186x_priv *priv = snd_soc_component_get_drvdata(component);
unsigned int rate = params_rate(params);
- unsigned int format = params_format(params);
+ snd_pcm_format_t format = params_format(params);
unsigned int width = params_width(params);
unsigned int channels = params_channels(params);
unsigned int div_lrck;
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
index f4c8c45f4010..c4452efc7970 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -1066,7 +1066,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305)
pr_debug("Left_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
pr_info("Left channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
- r0l = 562949953421312;
+ r0l = 562949953421312ULL;
if (rhl != 0)
do_div(r0l, rhl);
pr_debug("Left_r0 = 0x%llx\n", r0l);
@@ -1083,7 +1083,7 @@ static void rt1305_calibrate(struct rt1305_priv *rt1305)
pr_debug("Right_rhl = 0x%x rh=0x%x rl=0x%x\n", rhl, rh, rl);
pr_info("Right channel %d.%dohm\n", (r0ohm/10), (r0ohm%10));
- r0r = 562949953421312;
+ r0r = 562949953421312ULL;
if (rhl != 0)
do_div(r0r, rhl);
pr_debug("Right_r0 = 0x%llx\n", r0r);
@@ -1150,17 +1150,11 @@ static int rt1305_i2c_probe(struct i2c_client *i2c,
rt1305_reset(rt1305->regmap);
rt1305_calibrate(rt1305);
- return snd_soc_register_component(&i2c->dev, &soc_component_dev_rt1305,
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt1305,
rt1305_dai, ARRAY_SIZE(rt1305_dai));
}
-static int rt1305_i2c_remove(struct i2c_client *i2c)
-{
- snd_soc_unregister_component(&i2c->dev);
-
- return 0;
-}
-
static void rt1305_i2c_shutdown(struct i2c_client *client)
{
struct rt1305_priv *rt1305 = i2c_get_clientdata(client);
@@ -1180,7 +1174,6 @@ static struct i2c_driver rt1305_i2c_driver = {
#endif
},
.probe = rt1305_i2c_probe,
- .remove = rt1305_i2c_remove,
.shutdown = rt1305_i2c_shutdown,
.id_table = rt1305_i2c_id,
};
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 18686ffb0cd5..6478d10c4f4a 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -268,7 +268,6 @@ static const struct snd_pcm_ops rt5514_spi_pcm_ops = {
.hw_params = rt5514_spi_hw_params,
.hw_free = rt5514_spi_hw_free,
.pointer = rt5514_spi_pcm_pointer,
- .mmap = snd_pcm_lib_mmap_vmalloc,
.page = snd_pcm_lib_get_vmalloc_page,
};
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 1570b91bf018..dca82dd6e3bf 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -64,8 +64,8 @@ static const struct reg_sequence rt5514_patch[] = {
{RT5514_ANA_CTRL_LDO10, 0x00028604},
{RT5514_ANA_CTRL_ADCFED, 0x00000800},
{RT5514_ASRC_IN_CTRL1, 0x00000003},
- {RT5514_DOWNFILTER0_CTRL3, 0x10000362},
- {RT5514_DOWNFILTER1_CTRL3, 0x10000362},
+ {RT5514_DOWNFILTER0_CTRL3, 0x10000352},
+ {RT5514_DOWNFILTER1_CTRL3, 0x10000352},
};
static const struct reg_default rt5514_reg[] = {
@@ -92,10 +92,10 @@ static const struct reg_default rt5514_reg[] = {
{RT5514_ASRC_IN_CTRL1, 0x00000003},
{RT5514_DOWNFILTER0_CTRL1, 0x00020c2f},
{RT5514_DOWNFILTER0_CTRL2, 0x00020c2f},
- {RT5514_DOWNFILTER0_CTRL3, 0x10000362},
+ {RT5514_DOWNFILTER0_CTRL3, 0x10000352},
{RT5514_DOWNFILTER1_CTRL1, 0x00020c2f},
{RT5514_DOWNFILTER1_CTRL2, 0x00020c2f},
- {RT5514_DOWNFILTER1_CTRL3, 0x10000362},
+ {RT5514_DOWNFILTER1_CTRL3, 0x10000352},
{RT5514_ANA_CTRL_LDO10, 0x00028604},
{RT5514_ANA_CTRL_LDO18_16, 0x02000345},
{RT5514_ANA_CTRL_ADC12, 0x0000a2a8},
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index cf6dce69eb2a..865f49ac38dd 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -105,9 +105,9 @@ static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
case RT5631_INDEX_ADD:
case RT5631_INDEX_DATA:
case RT5631_EQ_CTRL:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
@@ -164,9 +164,9 @@ static bool rt5631_readable_register(struct device *dev, unsigned int reg)
case RT5631_VENDOR_ID:
case RT5631_VENDOR_ID1:
case RT5631_VENDOR_ID2:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
@@ -229,10 +229,10 @@ static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG,
static const struct snd_kcontrol_new rt5631_snd_controls[] = {
/* MIC */
SOC_ENUM("MIC1 Mode Control", rt5631_mic1_mode_enum),
- SOC_SINGLE_TLV("MIC1 Boost", RT5631_MIC_CTRL_2,
+ SOC_SINGLE_TLV("MIC1 Boost Volume", RT5631_MIC_CTRL_2,
RT5631_MIC1_BOOST_SHIFT, 8, 0, mic_bst_tlv),
SOC_ENUM("MIC2 Mode Control", rt5631_mic2_mode_enum),
- SOC_SINGLE_TLV("MIC2 Boost", RT5631_MIC_CTRL_2,
+ SOC_SINGLE_TLV("MIC2 Boost Volume", RT5631_MIC_CTRL_2,
RT5631_MIC2_BOOST_SHIFT, 8, 0, mic_bst_tlv),
/* MONO IN */
SOC_ENUM("MONOIN Mode Control", rt5631_monoin_mode_enum),
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 8bf8d360c25f..27770143ae8f 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1665,6 +1665,7 @@ static int get_sdp_info(struct snd_soc_component *component, int dai_id)
break;
case RT5640_IF_113:
ret |= RT5640_U_IF1;
+ /* fall through */
case RT5640_IF_312:
case RT5640_IF_213:
ret |= RT5640_U_IF2;
@@ -1680,6 +1681,7 @@ static int get_sdp_info(struct snd_soc_component *component, int dai_id)
break;
case RT5640_IF_223:
ret |= RT5640_U_IF1;
+ /* fall through */
case RT5640_IF_123:
case RT5640_IF_321:
ret |= RT5640_U_IF2;
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 6b5669f3e85d..985852fd9723 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -331,11 +331,13 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
SOC_DOUBLE_TLV("Mono DAC Playback Volume", RT5651_DAC2_DIG_VOL,
RT5651_L_VOL_SFT, RT5651_R_VOL_SFT,
175, 0, dac_vol_tlv),
- /* IN1/IN2 Control */
+ /* IN1/IN2/IN3 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5651_IN1_IN2,
RT5651_BST_SFT1, 8, 0, bst_tlv),
SOC_SINGLE_TLV("IN2 Boost", RT5651_IN1_IN2,
RT5651_BST_SFT2, 8, 0, bst_tlv),
+ SOC_SINGLE_TLV("IN3 Boost", RT5651_IN3,
+ RT5651_BST_SFT1, 8, 0, bst_tlv),
/* INL/INR Volume Control */
SOC_DOUBLE_TLV("IN Capture Volume", RT5651_INL1_INR1_VOL,
RT5651_INL_VOL_SFT, RT5651_INR_VOL_SFT,
@@ -1581,6 +1583,24 @@ static void rt5651_disable_micbias1_for_ovcd(struct snd_soc_component *component
snd_soc_dapm_mutex_unlock(dapm);
}
+static void rt5651_enable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+ RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_NOR);
+ rt5651->ovcd_irq_enabled = true;
+}
+
+static void rt5651_disable_micbias1_ovcd_irq(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
+ RT5651_IRQ_MB1_OC_MASK, RT5651_IRQ_MB1_OC_BP);
+ rt5651->ovcd_irq_enabled = false;
+}
+
static void rt5651_clear_micbias1_ovcd(struct snd_soc_component *component)
{
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL2,
@@ -1622,10 +1642,80 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
return val == 0;
}
-/* Jack detect timings */
+/* Jack detect and button-press timings */
#define JACK_SETTLE_TIME 100 /* milli seconds */
#define JACK_DETECT_COUNT 5
#define JACK_DETECT_MAXCOUNT 20 /* Aprox. 2 seconds worth of tries */
+#define JACK_UNPLUG_TIME 80 /* milli seconds */
+#define BP_POLL_TIME 10 /* milli seconds */
+#define BP_POLL_MAXCOUNT 200 /* assume something is wrong after this */
+#define BP_THRESHOLD 3
+
+static void rt5651_start_button_press_work(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ rt5651->poll_count = 0;
+ rt5651->press_count = 0;
+ rt5651->release_count = 0;
+ rt5651->pressed = false;
+ rt5651->press_reported = false;
+ rt5651_clear_micbias1_ovcd(component);
+ schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
+
+static void rt5651_button_press_work(struct work_struct *work)
+{
+ struct rt5651_priv *rt5651 =
+ container_of(work, struct rt5651_priv, bp_work.work);
+ struct snd_soc_component *component = rt5651->component;
+
+ /* Check the jack was not removed underneath us */
+ if (!rt5651_jack_inserted(component))
+ return;
+
+ if (rt5651_micbias1_ovcd(component)) {
+ rt5651->release_count = 0;
+ rt5651->press_count++;
+ /* Remember till after JACK_UNPLUG_TIME wait */
+ if (rt5651->press_count >= BP_THRESHOLD)
+ rt5651->pressed = true;
+ rt5651_clear_micbias1_ovcd(component);
+ } else {
+ rt5651->press_count = 0;
+ rt5651->release_count++;
+ }
+
+ /*
+ * The pins get temporarily shorted on jack unplug, so we poll for
+ * at least JACK_UNPLUG_TIME milli-seconds before reporting a press.
+ */
+ rt5651->poll_count++;
+ if (rt5651->poll_count < (JACK_UNPLUG_TIME / BP_POLL_TIME)) {
+ schedule_delayed_work(&rt5651->bp_work,
+ msecs_to_jiffies(BP_POLL_TIME));
+ return;
+ }
+
+ if (rt5651->pressed && !rt5651->press_reported) {
+ dev_dbg(component->dev, "headset button press\n");
+ snd_soc_jack_report(rt5651->hp_jack, SND_JACK_BTN_0,
+ SND_JACK_BTN_0);
+ rt5651->press_reported = true;
+ }
+
+ if (rt5651->release_count >= BP_THRESHOLD) {
+ if (rt5651->press_reported) {
+ dev_dbg(component->dev, "headset button release\n");
+ snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+ }
+ /* Re-enable OVCD IRQ to detect next press */
+ rt5651_enable_micbias1_ovcd_irq(component);
+ return; /* Stop polling */
+ }
+
+ schedule_delayed_work(&rt5651->bp_work, msecs_to_jiffies(BP_POLL_TIME));
+}
static int rt5651_detect_headset(struct snd_soc_component *component)
{
@@ -1676,15 +1766,58 @@ static void rt5651_jack_detect_work(struct work_struct *work)
{
struct rt5651_priv *rt5651 =
container_of(work, struct rt5651_priv, jack_detect_work);
+ struct snd_soc_component *component = rt5651->component;
int report = 0;
- if (rt5651_jack_inserted(rt5651->component)) {
- rt5651_enable_micbias1_for_ovcd(rt5651->component);
- report = rt5651_detect_headset(rt5651->component);
- rt5651_disable_micbias1_for_ovcd(rt5651->component);
+ if (!rt5651_jack_inserted(component)) {
+ /* Jack removed, or spurious IRQ? */
+ if (rt5651->hp_jack->status & SND_JACK_HEADPHONE) {
+ if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+ cancel_delayed_work_sync(&rt5651->bp_work);
+ rt5651_disable_micbias1_ovcd_irq(component);
+ rt5651_disable_micbias1_for_ovcd(component);
+ }
+ snd_soc_jack_report(rt5651->hp_jack, 0,
+ SND_JACK_HEADSET | SND_JACK_BTN_0);
+ dev_dbg(component->dev, "jack unplugged\n");
+ }
+ } else if (!(rt5651->hp_jack->status & SND_JACK_HEADPHONE)) {
+ /* Jack inserted */
+ WARN_ON(rt5651->ovcd_irq_enabled);
+ rt5651_enable_micbias1_for_ovcd(component);
+ report = rt5651_detect_headset(component);
+ if (report == SND_JACK_HEADSET) {
+ /* Enable ovcd IRQ for button press detect. */
+ rt5651_enable_micbias1_ovcd_irq(component);
+ } else {
+ /* No more need for overcurrent detect. */
+ rt5651_disable_micbias1_for_ovcd(component);
+ }
+ dev_dbg(component->dev, "detect report %#02x\n", report);
+ snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
+ } else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) {
+ dev_dbg(component->dev, "OVCD IRQ\n");
+
+ /*
+ * The ovcd IRQ keeps firing while the button is pressed, so
+ * we disable it and start polling the button until released.
+ *
+ * The disable will make the IRQ pin 0 again and since we get
+ * IRQs on both edges (so as to detect both jack plugin and
+ * unplug) this means we will immediately get another IRQ.
+ * The ovcd_irq_enabled check above makes the 2ND IRQ a NOP.
+ */
+ rt5651_disable_micbias1_ovcd_irq(component);
+ rt5651_start_button_press_work(component);
+
+ /*
+ * If the jack-detect IRQ flag goes high (unplug) after our
+ * above rt5651_jack_inserted() check and before we have
+ * disabled the OVCD IRQ, the IRQ pin will stay high and as
+ * we react to edges, we miss the unplug event -> recheck.
+ */
+ queue_work(system_long_wq, &rt5651->jack_detect_work);
}
-
- snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
}
static irqreturn_t rt5651_irq(int irq, void *data)
@@ -1696,14 +1829,18 @@ static irqreturn_t rt5651_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int rt5651_set_jack(struct snd_soc_component *component,
- struct snd_soc_jack *hp_jack, void *data)
+static void rt5651_cancel_work(void *data)
{
- struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
- int ret;
+ struct rt5651_priv *rt5651 = data;
- if (!rt5651->irq)
- return -EINVAL;
+ cancel_work_sync(&rt5651->jack_detect_work);
+ cancel_delayed_work_sync(&rt5651->bp_work);
+}
+
+static void rt5651_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hp_jack)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
/* IRQ output on GPIO1 */
snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
@@ -1730,10 +1867,10 @@ static int rt5651_set_jack(struct snd_soc_component *component,
RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
break;
case RT5651_JD_NULL:
- return 0;
+ return;
default:
dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
- return -EINVAL;
+ return;
}
/* Enable jack detect power */
@@ -1767,19 +1904,39 @@ static int rt5651_set_jack(struct snd_soc_component *component,
RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
rt5651->hp_jack = hp_jack;
-
- ret = devm_request_threaded_irq(component->dev, rt5651->irq, NULL,
- rt5651_irq,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT, "rt5651", rt5651);
- if (ret) {
- dev_err(component->dev, "Failed to reguest IRQ: %d\n", ret);
- return ret;
+ if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+ rt5651_enable_micbias1_for_ovcd(component);
+ rt5651_enable_micbias1_ovcd_irq(component);
}
+ enable_irq(rt5651->irq);
/* sync initial jack state */
queue_work(system_power_efficient_wq, &rt5651->jack_detect_work);
+}
+
+static void rt5651_disable_jack_detect(struct snd_soc_component *component)
+{
+ struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
+
+ disable_irq(rt5651->irq);
+ rt5651_cancel_work(rt5651);
+
+ if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+ rt5651_disable_micbias1_ovcd_irq(component);
+ rt5651_disable_micbias1_for_ovcd(component);
+ snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
+ }
+
+ rt5651->hp_jack = NULL;
+}
+
+static int rt5651_set_jack(struct snd_soc_component *component,
+ struct snd_soc_jack *jack, void *data)
+{
+ if (jack)
+ rt5651_enable_jack_detect(component, jack);
+ else
+ rt5651_disable_jack_detect(component);
return 0;
}
@@ -2034,8 +2191,26 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
rt5651->irq = i2c->irq;
rt5651->hp_mute = 1;
+ INIT_DELAYED_WORK(&rt5651->bp_work, rt5651_button_press_work);
INIT_WORK(&rt5651->jack_detect_work, rt5651_jack_detect_work);
+ /* Make sure work is stopped on probe-error / remove */
+ ret = devm_add_action_or_reset(&i2c->dev, rt5651_cancel_work, rt5651);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(&i2c->dev, rt5651->irq, rt5651_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_ONESHOT, "rt5651", rt5651);
+ if (ret == 0) {
+ /* Gets re-enabled by rt5651_set_jack() */
+ disable_irq(rt5651->irq);
+ } else {
+ dev_warn(&i2c->dev, "Failed to reguest IRQ %d: %d\n",
+ rt5651->irq, ret);
+ rt5651->irq = -ENXIO;
+ }
+
ret = devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_rt5651,
rt5651_dai, ARRAY_SIZE(rt5651_dai));
@@ -2043,15 +2218,6 @@ static int rt5651_i2c_probe(struct i2c_client *i2c,
return ret;
}
-static int rt5651_i2c_remove(struct i2c_client *i2c)
-{
- struct rt5651_priv *rt5651 = i2c_get_clientdata(i2c);
-
- cancel_work_sync(&rt5651->jack_detect_work);
-
- return 0;
-}
-
static struct i2c_driver rt5651_i2c_driver = {
.driver = {
.name = "rt5651",
@@ -2059,7 +2225,6 @@ static struct i2c_driver rt5651_i2c_driver = {
.of_match_table = of_match_ptr(rt5651_of_match),
},
.probe = rt5651_i2c_probe,
- .remove = rt5651_i2c_remove,
.id_table = rt5651_i2c_id,
};
module_i2c_driver(rt5651_i2c_driver);
diff --git a/sound/soc/codecs/rt5651.h b/sound/soc/codecs/rt5651.h
index 3a0968c53fde..ac6de6fb5414 100644
--- a/sound/soc/codecs/rt5651.h
+++ b/sound/soc/codecs/rt5651.h
@@ -2071,8 +2071,16 @@ struct rt5651_pll_code {
struct rt5651_priv {
struct snd_soc_component *component;
struct regmap *regmap;
+ /* Jack and button detect data */
struct snd_soc_jack *hp_jack;
struct work_struct jack_detect_work;
+ struct delayed_work bp_work;
+ bool ovcd_irq_enabled;
+ bool pressed;
+ bool press_reported;
+ int press_count;
+ int release_count;
+ int poll_count;
unsigned int jd_src;
unsigned int ovcd_th;
unsigned int ovcd_sf;
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 8a0181a2db08..9b7a1833d331 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -4417,6 +4417,7 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
break;
case 25:
slot_width_25 = 0x8080;
+ /* fall through */
case 24:
val |= (2 << 8);
break;
@@ -5007,7 +5008,7 @@ static const struct regmap_config rt5677_regmap = {
};
static const struct of_device_id rt5677_of_match[] = {
- { .compatible = "realtek,rt5677", RT5677 },
+ { .compatible = "realtek,rt5677", .data = (const void *)RT5677 },
{ }
};
MODULE_DEVICE_TABLE(of, rt5677_of_match);
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
new file mode 100644
index 000000000000..640d400ca013
--- /dev/null
+++ b/sound/soc/codecs/rt5682.c
@@ -0,0 +1,2681 @@
+/*
+ * rt5682.c -- RT5682 ALSA SoC audio component driver
+ *
+ * Copyright 2018 Realtek Semiconductor Corp.
+ * Author: Bard Liao <bardliao@realtek.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/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/acpi.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/rt5682.h>
+
+#include "rl6231.h"
+#include "rt5682.h"
+
+#define RT5682_NUM_SUPPLIES 3
+
+static const char *rt5682_supply_names[RT5682_NUM_SUPPLIES] = {
+ "AVDD",
+ "MICVDD",
+ "VBAT",
+};
+
+struct rt5682_priv {
+ struct snd_soc_component *component;
+ struct rt5682_platform_data pdata;
+ struct regmap *regmap;
+ struct snd_soc_jack *hs_jack;
+ struct regulator_bulk_data supplies[RT5682_NUM_SUPPLIES];
+ struct delayed_work jack_detect_work;
+ struct delayed_work jd_check_work;
+ struct mutex calibrate_mutex;
+
+ int sysclk;
+ int sysclk_src;
+ int lrck[RT5682_AIFS];
+ int bclk[RT5682_AIFS];
+ int master[RT5682_AIFS];
+
+ int pll_src;
+ int pll_in;
+ int pll_out;
+
+ int jack_type;
+};
+
+static const struct reg_sequence patch_list[] = {
+ {0x01c1, 0x1000},
+};
+
+static const struct reg_default rt5682_reg[] = {
+ {0x0002, 0x8080},
+ {0x0003, 0x8000},
+ {0x0005, 0x0000},
+ {0x0006, 0x0000},
+ {0x0008, 0x800f},
+ {0x000b, 0x0000},
+ {0x0010, 0x4040},
+ {0x0011, 0x0000},
+ {0x0012, 0x1404},
+ {0x0013, 0x1000},
+ {0x0014, 0xa00a},
+ {0x0015, 0x0404},
+ {0x0016, 0x0404},
+ {0x0019, 0xafaf},
+ {0x001c, 0x2f2f},
+ {0x001f, 0x0000},
+ {0x0022, 0x5757},
+ {0x0023, 0x0039},
+ {0x0024, 0x000b},
+ {0x0026, 0xc0c4},
+ {0x0029, 0x8080},
+ {0x002a, 0xa0a0},
+ {0x002b, 0x0300},
+ {0x0030, 0x0000},
+ {0x003c, 0x0080},
+ {0x0044, 0x0c0c},
+ {0x0049, 0x0000},
+ {0x0061, 0x0000},
+ {0x0062, 0x0000},
+ {0x0063, 0x003f},
+ {0x0064, 0x0000},
+ {0x0065, 0x0000},
+ {0x0066, 0x0030},
+ {0x0067, 0x0000},
+ {0x006b, 0x0000},
+ {0x006c, 0x0000},
+ {0x006d, 0x2200},
+ {0x006e, 0x0a10},
+ {0x0070, 0x8000},
+ {0x0071, 0x8000},
+ {0x0073, 0x0000},
+ {0x0074, 0x0000},
+ {0x0075, 0x0002},
+ {0x0076, 0x0001},
+ {0x0079, 0x0000},
+ {0x007a, 0x0000},
+ {0x007b, 0x0000},
+ {0x007c, 0x0100},
+ {0x007e, 0x0000},
+ {0x0080, 0x0000},
+ {0x0081, 0x0000},
+ {0x0082, 0x0000},
+ {0x0083, 0x0000},
+ {0x0084, 0x0000},
+ {0x0085, 0x0000},
+ {0x0086, 0x0005},
+ {0x0087, 0x0000},
+ {0x0088, 0x0000},
+ {0x008c, 0x0003},
+ {0x008d, 0x0000},
+ {0x008e, 0x0060},
+ {0x008f, 0x1000},
+ {0x0091, 0x0c26},
+ {0x0092, 0x0073},
+ {0x0093, 0x0000},
+ {0x0094, 0x0080},
+ {0x0098, 0x0000},
+ {0x009a, 0x0000},
+ {0x009b, 0x0000},
+ {0x009c, 0x0000},
+ {0x009d, 0x0000},
+ {0x009e, 0x100c},
+ {0x009f, 0x0000},
+ {0x00a0, 0x0000},
+ {0x00a3, 0x0002},
+ {0x00a4, 0x0001},
+ {0x00ae, 0x2040},
+ {0x00af, 0x0000},
+ {0x00b6, 0x0000},
+ {0x00b7, 0x0000},
+ {0x00b8, 0x0000},
+ {0x00b9, 0x0002},
+ {0x00be, 0x0000},
+ {0x00c0, 0x0160},
+ {0x00c1, 0x82a0},
+ {0x00c2, 0x0000},
+ {0x00d0, 0x0000},
+ {0x00d1, 0x2244},
+ {0x00d2, 0x3300},
+ {0x00d3, 0x2200},
+ {0x00d4, 0x0000},
+ {0x00d9, 0x0009},
+ {0x00da, 0x0000},
+ {0x00db, 0x0000},
+ {0x00dc, 0x00c0},
+ {0x00dd, 0x2220},
+ {0x00de, 0x3131},
+ {0x00df, 0x3131},
+ {0x00e0, 0x3131},
+ {0x00e2, 0x0000},
+ {0x00e3, 0x4000},
+ {0x00e4, 0x0aa0},
+ {0x00e5, 0x3131},
+ {0x00e6, 0x3131},
+ {0x00e7, 0x3131},
+ {0x00e8, 0x3131},
+ {0x00ea, 0xb320},
+ {0x00eb, 0x0000},
+ {0x00f0, 0x0000},
+ {0x00f1, 0x00d0},
+ {0x00f2, 0x00d0},
+ {0x00f6, 0x0000},
+ {0x00fa, 0x0000},
+ {0x00fb, 0x0000},
+ {0x00fc, 0x0000},
+ {0x00fd, 0x0000},
+ {0x00fe, 0x10ec},
+ {0x00ff, 0x6530},
+ {0x0100, 0xa0a0},
+ {0x010b, 0x0000},
+ {0x010c, 0xae00},
+ {0x010d, 0xaaa0},
+ {0x010e, 0x8aa2},
+ {0x010f, 0x02a2},
+ {0x0110, 0xc000},
+ {0x0111, 0x04a2},
+ {0x0112, 0x2800},
+ {0x0113, 0x0000},
+ {0x0117, 0x0100},
+ {0x0125, 0x0410},
+ {0x0132, 0x6026},
+ {0x0136, 0x5555},
+ {0x0138, 0x3700},
+ {0x013a, 0x2000},
+ {0x013b, 0x2000},
+ {0x013c, 0x2005},
+ {0x013f, 0x0000},
+ {0x0142, 0x0000},
+ {0x0145, 0x0002},
+ {0x0146, 0x0000},
+ {0x0147, 0x0000},
+ {0x0148, 0x0000},
+ {0x0149, 0x0000},
+ {0x0150, 0x79a1},
+ {0x0151, 0x0000},
+ {0x0160, 0x4ec0},
+ {0x0161, 0x0080},
+ {0x0162, 0x0200},
+ {0x0163, 0x0800},
+ {0x0164, 0x0000},
+ {0x0165, 0x0000},
+ {0x0166, 0x0000},
+ {0x0167, 0x000f},
+ {0x0168, 0x000f},
+ {0x0169, 0x0021},
+ {0x0190, 0x413d},
+ {0x0194, 0x0000},
+ {0x0195, 0x0000},
+ {0x0197, 0x0022},
+ {0x0198, 0x0000},
+ {0x0199, 0x0000},
+ {0x01af, 0x0000},
+ {0x01b0, 0x0400},
+ {0x01b1, 0x0000},
+ {0x01b2, 0x0000},
+ {0x01b3, 0x0000},
+ {0x01b4, 0x0000},
+ {0x01b5, 0x0000},
+ {0x01b6, 0x01c3},
+ {0x01b7, 0x02a0},
+ {0x01b8, 0x03e9},
+ {0x01b9, 0x1389},
+ {0x01ba, 0xc351},
+ {0x01bb, 0x0009},
+ {0x01bc, 0x0018},
+ {0x01bd, 0x002a},
+ {0x01be, 0x004c},
+ {0x01bf, 0x0097},
+ {0x01c0, 0x433d},
+ {0x01c2, 0x0000},
+ {0x01c3, 0x0000},
+ {0x01c4, 0x0000},
+ {0x01c5, 0x0000},
+ {0x01c6, 0x0000},
+ {0x01c7, 0x0000},
+ {0x01c8, 0x40af},
+ {0x01c9, 0x0702},
+ {0x01ca, 0x0000},
+ {0x01cb, 0x0000},
+ {0x01cc, 0x5757},
+ {0x01cd, 0x5757},
+ {0x01ce, 0x5757},
+ {0x01cf, 0x5757},
+ {0x01d0, 0x5757},
+ {0x01d1, 0x5757},
+ {0x01d2, 0x5757},
+ {0x01d3, 0x5757},
+ {0x01d4, 0x5757},
+ {0x01d5, 0x5757},
+ {0x01d6, 0x0000},
+ {0x01d7, 0x0008},
+ {0x01d8, 0x0029},
+ {0x01d9, 0x3333},
+ {0x01da, 0x0000},
+ {0x01db, 0x0004},
+ {0x01dc, 0x0000},
+ {0x01de, 0x7c00},
+ {0x01df, 0x0320},
+ {0x01e0, 0x06a1},
+ {0x01e1, 0x0000},
+ {0x01e2, 0x0000},
+ {0x01e3, 0x0000},
+ {0x01e4, 0x0000},
+ {0x01e6, 0x0001},
+ {0x01e7, 0x0000},
+ {0x01e8, 0x0000},
+ {0x01ea, 0x0000},
+ {0x01eb, 0x0000},
+ {0x01ec, 0x0000},
+ {0x01ed, 0x0000},
+ {0x01ee, 0x0000},
+ {0x01ef, 0x0000},
+ {0x01f0, 0x0000},
+ {0x01f1, 0x0000},
+ {0x01f2, 0x0000},
+ {0x01f3, 0x0000},
+ {0x01f4, 0x0000},
+ {0x0210, 0x6297},
+ {0x0211, 0xa005},
+ {0x0212, 0x824c},
+ {0x0213, 0xf7ff},
+ {0x0214, 0xf24c},
+ {0x0215, 0x0102},
+ {0x0216, 0x00a3},
+ {0x0217, 0x0048},
+ {0x0218, 0xa2c0},
+ {0x0219, 0x0400},
+ {0x021a, 0x00c8},
+ {0x021b, 0x00c0},
+ {0x021c, 0x0000},
+ {0x0250, 0x4500},
+ {0x0251, 0x40b3},
+ {0x0252, 0x0000},
+ {0x0253, 0x0000},
+ {0x0254, 0x0000},
+ {0x0255, 0x0000},
+ {0x0256, 0x0000},
+ {0x0257, 0x0000},
+ {0x0258, 0x0000},
+ {0x0259, 0x0000},
+ {0x025a, 0x0005},
+ {0x0270, 0x0000},
+ {0x02ff, 0x0110},
+ {0x0300, 0x001f},
+ {0x0301, 0x032c},
+ {0x0302, 0x5f21},
+ {0x0303, 0x4000},
+ {0x0304, 0x4000},
+ {0x0305, 0x06d5},
+ {0x0306, 0x8000},
+ {0x0307, 0x0700},
+ {0x0310, 0x4560},
+ {0x0311, 0xa4a8},
+ {0x0312, 0x7418},
+ {0x0313, 0x0000},
+ {0x0314, 0x0006},
+ {0x0315, 0xffff},
+ {0x0316, 0xc400},
+ {0x0317, 0x0000},
+ {0x03c0, 0x7e00},
+ {0x03c1, 0x8000},
+ {0x03c2, 0x8000},
+ {0x03c3, 0x8000},
+ {0x03c4, 0x8000},
+ {0x03c5, 0x8000},
+ {0x03c6, 0x8000},
+ {0x03c7, 0x8000},
+ {0x03c8, 0x8000},
+ {0x03c9, 0x8000},
+ {0x03ca, 0x8000},
+ {0x03cb, 0x8000},
+ {0x03cc, 0x8000},
+ {0x03d0, 0x0000},
+ {0x03d1, 0x0000},
+ {0x03d2, 0x0000},
+ {0x03d3, 0x0000},
+ {0x03d4, 0x2000},
+ {0x03d5, 0x2000},
+ {0x03d6, 0x0000},
+ {0x03d7, 0x0000},
+ {0x03d8, 0x2000},
+ {0x03d9, 0x2000},
+ {0x03da, 0x2000},
+ {0x03db, 0x2000},
+ {0x03dc, 0x0000},
+ {0x03dd, 0x0000},
+ {0x03de, 0x0000},
+ {0x03df, 0x2000},
+ {0x03e0, 0x0000},
+ {0x03e1, 0x0000},
+ {0x03e2, 0x0000},
+ {0x03e3, 0x0000},
+ {0x03e4, 0x0000},
+ {0x03e5, 0x0000},
+ {0x03e6, 0x0000},
+ {0x03e7, 0x0000},
+ {0x03e8, 0x0000},
+ {0x03e9, 0x0000},
+ {0x03ea, 0x0000},
+ {0x03eb, 0x0000},
+ {0x03ec, 0x0000},
+ {0x03ed, 0x0000},
+ {0x03ee, 0x0000},
+ {0x03ef, 0x0000},
+ {0x03f0, 0x0800},
+ {0x03f1, 0x0800},
+ {0x03f2, 0x0800},
+ {0x03f3, 0x0800},
+};
+
+static bool rt5682_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5682_RESET:
+ case RT5682_CBJ_CTRL_2:
+ case RT5682_INT_ST_1:
+ case RT5682_4BTN_IL_CMD_1:
+ case RT5682_AJD1_CTRL:
+ case RT5682_HP_CALIB_CTRL_1:
+ case RT5682_DEVICE_ID:
+ case RT5682_I2C_MODE:
+ case RT5682_HP_CALIB_CTRL_10:
+ case RT5682_EFUSE_CTRL_2:
+ case RT5682_JD_TOP_VC_VTRL:
+ case RT5682_HP_IMP_SENS_CTRL_19:
+ case RT5682_IL_CMD_1:
+ case RT5682_SAR_IL_CMD_2:
+ case RT5682_SAR_IL_CMD_4:
+ case RT5682_SAR_IL_CMD_10:
+ case RT5682_SAR_IL_CMD_11:
+ case RT5682_EFUSE_CTRL_6...RT5682_EFUSE_CTRL_11:
+ case RT5682_HP_CALIB_STA_1...RT5682_HP_CALIB_STA_11:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt5682_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT5682_RESET:
+ case RT5682_VERSION_ID:
+ case RT5682_VENDOR_ID:
+ case RT5682_DEVICE_ID:
+ case RT5682_HP_CTRL_1:
+ case RT5682_HP_CTRL_2:
+ case RT5682_HPL_GAIN:
+ case RT5682_HPR_GAIN:
+ case RT5682_I2C_CTRL:
+ case RT5682_CBJ_BST_CTRL:
+ case RT5682_CBJ_CTRL_1:
+ case RT5682_CBJ_CTRL_2:
+ case RT5682_CBJ_CTRL_3:
+ case RT5682_CBJ_CTRL_4:
+ case RT5682_CBJ_CTRL_5:
+ case RT5682_CBJ_CTRL_6:
+ case RT5682_CBJ_CTRL_7:
+ case RT5682_DAC1_DIG_VOL:
+ case RT5682_STO1_ADC_DIG_VOL:
+ case RT5682_STO1_ADC_BOOST:
+ case RT5682_HP_IMP_GAIN_1:
+ case RT5682_HP_IMP_GAIN_2:
+ case RT5682_SIDETONE_CTRL:
+ case RT5682_STO1_ADC_MIXER:
+ case RT5682_AD_DA_MIXER:
+ case RT5682_STO1_DAC_MIXER:
+ case RT5682_A_DAC1_MUX:
+ case RT5682_DIG_INF2_DATA:
+ case RT5682_REC_MIXER:
+ case RT5682_CAL_REC:
+ case RT5682_ALC_BACK_GAIN:
+ case RT5682_PWR_DIG_1:
+ case RT5682_PWR_DIG_2:
+ case RT5682_PWR_ANLG_1:
+ case RT5682_PWR_ANLG_2:
+ case RT5682_PWR_ANLG_3:
+ case RT5682_PWR_MIXER:
+ case RT5682_PWR_VOL:
+ case RT5682_CLK_DET:
+ case RT5682_RESET_LPF_CTRL:
+ case RT5682_RESET_HPF_CTRL:
+ case RT5682_DMIC_CTRL_1:
+ case RT5682_I2S1_SDP:
+ case RT5682_I2S2_SDP:
+ case RT5682_ADDA_CLK_1:
+ case RT5682_ADDA_CLK_2:
+ case RT5682_I2S1_F_DIV_CTRL_1:
+ case RT5682_I2S1_F_DIV_CTRL_2:
+ case RT5682_TDM_CTRL:
+ case RT5682_TDM_ADDA_CTRL_1:
+ case RT5682_TDM_ADDA_CTRL_2:
+ case RT5682_DATA_SEL_CTRL_1:
+ case RT5682_TDM_TCON_CTRL:
+ case RT5682_GLB_CLK:
+ case RT5682_PLL_CTRL_1:
+ case RT5682_PLL_CTRL_2:
+ case RT5682_PLL_TRACK_1:
+ case RT5682_PLL_TRACK_2:
+ case RT5682_PLL_TRACK_3:
+ case RT5682_PLL_TRACK_4:
+ case RT5682_PLL_TRACK_5:
+ case RT5682_PLL_TRACK_6:
+ case RT5682_PLL_TRACK_11:
+ case RT5682_SDW_REF_CLK:
+ case RT5682_DEPOP_1:
+ case RT5682_DEPOP_2:
+ case RT5682_HP_CHARGE_PUMP_1:
+ case RT5682_HP_CHARGE_PUMP_2:
+ case RT5682_MICBIAS_1:
+ case RT5682_MICBIAS_2:
+ case RT5682_PLL_TRACK_12:
+ case RT5682_PLL_TRACK_14:
+ case RT5682_PLL2_CTRL_1:
+ case RT5682_PLL2_CTRL_2:
+ case RT5682_PLL2_CTRL_3:
+ case RT5682_PLL2_CTRL_4:
+ case RT5682_RC_CLK_CTRL:
+ case RT5682_I2S_M_CLK_CTRL_1:
+ case RT5682_I2S2_F_DIV_CTRL_1:
+ case RT5682_I2S2_F_DIV_CTRL_2:
+ case RT5682_EQ_CTRL_1:
+ case RT5682_EQ_CTRL_2:
+ case RT5682_IRQ_CTRL_1:
+ case RT5682_IRQ_CTRL_2:
+ case RT5682_IRQ_CTRL_3:
+ case RT5682_IRQ_CTRL_4:
+ case RT5682_INT_ST_1:
+ case RT5682_GPIO_CTRL_1:
+ case RT5682_GPIO_CTRL_2:
+ case RT5682_GPIO_CTRL_3:
+ case RT5682_HP_AMP_DET_CTRL_1:
+ case RT5682_HP_AMP_DET_CTRL_2:
+ case RT5682_MID_HP_AMP_DET:
+ case RT5682_LOW_HP_AMP_DET:
+ case RT5682_DELAY_BUF_CTRL:
+ case RT5682_SV_ZCD_1:
+ case RT5682_SV_ZCD_2:
+ case RT5682_IL_CMD_1:
+ case RT5682_IL_CMD_2:
+ case RT5682_IL_CMD_3:
+ case RT5682_IL_CMD_4:
+ case RT5682_IL_CMD_5:
+ case RT5682_IL_CMD_6:
+ case RT5682_4BTN_IL_CMD_1:
+ case RT5682_4BTN_IL_CMD_2:
+ case RT5682_4BTN_IL_CMD_3:
+ case RT5682_4BTN_IL_CMD_4:
+ case RT5682_4BTN_IL_CMD_5:
+ case RT5682_4BTN_IL_CMD_6:
+ case RT5682_4BTN_IL_CMD_7:
+ case RT5682_ADC_STO1_HP_CTRL_1:
+ case RT5682_ADC_STO1_HP_CTRL_2:
+ case RT5682_AJD1_CTRL:
+ case RT5682_JD1_THD:
+ case RT5682_JD2_THD:
+ case RT5682_JD_CTRL_1:
+ case RT5682_DUMMY_1:
+ case RT5682_DUMMY_2:
+ case RT5682_DUMMY_3:
+ case RT5682_DAC_ADC_DIG_VOL1:
+ case RT5682_BIAS_CUR_CTRL_2:
+ case RT5682_BIAS_CUR_CTRL_3:
+ case RT5682_BIAS_CUR_CTRL_4:
+ case RT5682_BIAS_CUR_CTRL_5:
+ case RT5682_BIAS_CUR_CTRL_6:
+ case RT5682_BIAS_CUR_CTRL_7:
+ case RT5682_BIAS_CUR_CTRL_8:
+ case RT5682_BIAS_CUR_CTRL_9:
+ case RT5682_BIAS_CUR_CTRL_10:
+ case RT5682_VREF_REC_OP_FB_CAP_CTRL:
+ case RT5682_CHARGE_PUMP_1:
+ case RT5682_DIG_IN_CTRL_1:
+ case RT5682_PAD_DRIVING_CTRL:
+ case RT5682_SOFT_RAMP_DEPOP:
+ case RT5682_CHOP_DAC:
+ case RT5682_CHOP_ADC:
+ case RT5682_CALIB_ADC_CTRL:
+ case RT5682_VOL_TEST:
+ case RT5682_SPKVDD_DET_STA:
+ case RT5682_TEST_MODE_CTRL_1:
+ case RT5682_TEST_MODE_CTRL_2:
+ case RT5682_TEST_MODE_CTRL_3:
+ case RT5682_TEST_MODE_CTRL_4:
+ case RT5682_TEST_MODE_CTRL_5:
+ case RT5682_PLL1_INTERNAL:
+ case RT5682_PLL2_INTERNAL:
+ case RT5682_STO_NG2_CTRL_1:
+ case RT5682_STO_NG2_CTRL_2:
+ case RT5682_STO_NG2_CTRL_3:
+ case RT5682_STO_NG2_CTRL_4:
+ case RT5682_STO_NG2_CTRL_5:
+ case RT5682_STO_NG2_CTRL_6:
+ case RT5682_STO_NG2_CTRL_7:
+ case RT5682_STO_NG2_CTRL_8:
+ case RT5682_STO_NG2_CTRL_9:
+ case RT5682_STO_NG2_CTRL_10:
+ case RT5682_STO1_DAC_SIL_DET:
+ case RT5682_SIL_PSV_CTRL1:
+ case RT5682_SIL_PSV_CTRL2:
+ case RT5682_SIL_PSV_CTRL3:
+ case RT5682_SIL_PSV_CTRL4:
+ case RT5682_SIL_PSV_CTRL5:
+ case RT5682_HP_IMP_SENS_CTRL_01:
+ case RT5682_HP_IMP_SENS_CTRL_02:
+ case RT5682_HP_IMP_SENS_CTRL_03:
+ case RT5682_HP_IMP_SENS_CTRL_04:
+ case RT5682_HP_IMP_SENS_CTRL_05:
+ case RT5682_HP_IMP_SENS_CTRL_06:
+ case RT5682_HP_IMP_SENS_CTRL_07:
+ case RT5682_HP_IMP_SENS_CTRL_08:
+ case RT5682_HP_IMP_SENS_CTRL_09:
+ case RT5682_HP_IMP_SENS_CTRL_10:
+ case RT5682_HP_IMP_SENS_CTRL_11:
+ case RT5682_HP_IMP_SENS_CTRL_12:
+ case RT5682_HP_IMP_SENS_CTRL_13:
+ case RT5682_HP_IMP_SENS_CTRL_14:
+ case RT5682_HP_IMP_SENS_CTRL_15:
+ case RT5682_HP_IMP_SENS_CTRL_16:
+ case RT5682_HP_IMP_SENS_CTRL_17:
+ case RT5682_HP_IMP_SENS_CTRL_18:
+ case RT5682_HP_IMP_SENS_CTRL_19:
+ case RT5682_HP_IMP_SENS_CTRL_20:
+ case RT5682_HP_IMP_SENS_CTRL_21:
+ case RT5682_HP_IMP_SENS_CTRL_22:
+ case RT5682_HP_IMP_SENS_CTRL_23:
+ case RT5682_HP_IMP_SENS_CTRL_24:
+ case RT5682_HP_IMP_SENS_CTRL_25:
+ case RT5682_HP_IMP_SENS_CTRL_26:
+ case RT5682_HP_IMP_SENS_CTRL_27:
+ case RT5682_HP_IMP_SENS_CTRL_28:
+ case RT5682_HP_IMP_SENS_CTRL_29:
+ case RT5682_HP_IMP_SENS_CTRL_30:
+ case RT5682_HP_IMP_SENS_CTRL_31:
+ case RT5682_HP_IMP_SENS_CTRL_32:
+ case RT5682_HP_IMP_SENS_CTRL_33:
+ case RT5682_HP_IMP_SENS_CTRL_34:
+ case RT5682_HP_IMP_SENS_CTRL_35:
+ case RT5682_HP_IMP_SENS_CTRL_36:
+ case RT5682_HP_IMP_SENS_CTRL_37:
+ case RT5682_HP_IMP_SENS_CTRL_38:
+ case RT5682_HP_IMP_SENS_CTRL_39:
+ case RT5682_HP_IMP_SENS_CTRL_40:
+ case RT5682_HP_IMP_SENS_CTRL_41:
+ case RT5682_HP_IMP_SENS_CTRL_42:
+ case RT5682_HP_IMP_SENS_CTRL_43:
+ case RT5682_HP_LOGIC_CTRL_1:
+ case RT5682_HP_LOGIC_CTRL_2:
+ case RT5682_HP_LOGIC_CTRL_3:
+ case RT5682_HP_CALIB_CTRL_1:
+ case RT5682_HP_CALIB_CTRL_2:
+ case RT5682_HP_CALIB_CTRL_3:
+ case RT5682_HP_CALIB_CTRL_4:
+ case RT5682_HP_CALIB_CTRL_5:
+ case RT5682_HP_CALIB_CTRL_6:
+ case RT5682_HP_CALIB_CTRL_7:
+ case RT5682_HP_CALIB_CTRL_9:
+ case RT5682_HP_CALIB_CTRL_10:
+ case RT5682_HP_CALIB_CTRL_11:
+ case RT5682_HP_CALIB_STA_1:
+ case RT5682_HP_CALIB_STA_2:
+ case RT5682_HP_CALIB_STA_3:
+ case RT5682_HP_CALIB_STA_4:
+ case RT5682_HP_CALIB_STA_5:
+ case RT5682_HP_CALIB_STA_6:
+ case RT5682_HP_CALIB_STA_7:
+ case RT5682_HP_CALIB_STA_8:
+ case RT5682_HP_CALIB_STA_9:
+ case RT5682_HP_CALIB_STA_10:
+ case RT5682_HP_CALIB_STA_11:
+ case RT5682_SAR_IL_CMD_1:
+ case RT5682_SAR_IL_CMD_2:
+ case RT5682_SAR_IL_CMD_3:
+ case RT5682_SAR_IL_CMD_4:
+ case RT5682_SAR_IL_CMD_5:
+ case RT5682_SAR_IL_CMD_6:
+ case RT5682_SAR_IL_CMD_7:
+ case RT5682_SAR_IL_CMD_8:
+ case RT5682_SAR_IL_CMD_9:
+ case RT5682_SAR_IL_CMD_10:
+ case RT5682_SAR_IL_CMD_11:
+ case RT5682_SAR_IL_CMD_12:
+ case RT5682_SAR_IL_CMD_13:
+ case RT5682_EFUSE_CTRL_1:
+ case RT5682_EFUSE_CTRL_2:
+ case RT5682_EFUSE_CTRL_3:
+ case RT5682_EFUSE_CTRL_4:
+ case RT5682_EFUSE_CTRL_5:
+ case RT5682_EFUSE_CTRL_6:
+ case RT5682_EFUSE_CTRL_7:
+ case RT5682_EFUSE_CTRL_8:
+ case RT5682_EFUSE_CTRL_9:
+ case RT5682_EFUSE_CTRL_10:
+ case RT5682_EFUSE_CTRL_11:
+ case RT5682_JD_TOP_VC_VTRL:
+ case RT5682_DRC1_CTRL_0:
+ case RT5682_DRC1_CTRL_1:
+ case RT5682_DRC1_CTRL_2:
+ case RT5682_DRC1_CTRL_3:
+ case RT5682_DRC1_CTRL_4:
+ case RT5682_DRC1_CTRL_5:
+ case RT5682_DRC1_CTRL_6:
+ case RT5682_DRC1_HARD_LMT_CTRL_1:
+ case RT5682_DRC1_HARD_LMT_CTRL_2:
+ case RT5682_DRC1_PRIV_1:
+ case RT5682_DRC1_PRIV_2:
+ case RT5682_DRC1_PRIV_3:
+ case RT5682_DRC1_PRIV_4:
+ case RT5682_DRC1_PRIV_5:
+ case RT5682_DRC1_PRIV_6:
+ case RT5682_DRC1_PRIV_7:
+ case RT5682_DRC1_PRIV_8:
+ case RT5682_EQ_AUTO_RCV_CTRL1:
+ case RT5682_EQ_AUTO_RCV_CTRL2:
+ case RT5682_EQ_AUTO_RCV_CTRL3:
+ case RT5682_EQ_AUTO_RCV_CTRL4:
+ case RT5682_EQ_AUTO_RCV_CTRL5:
+ case RT5682_EQ_AUTO_RCV_CTRL6:
+ case RT5682_EQ_AUTO_RCV_CTRL7:
+ case RT5682_EQ_AUTO_RCV_CTRL8:
+ case RT5682_EQ_AUTO_RCV_CTRL9:
+ case RT5682_EQ_AUTO_RCV_CTRL10:
+ case RT5682_EQ_AUTO_RCV_CTRL11:
+ case RT5682_EQ_AUTO_RCV_CTRL12:
+ case RT5682_EQ_AUTO_RCV_CTRL13:
+ case RT5682_ADC_L_EQ_LPF1_A1:
+ case RT5682_R_EQ_LPF1_A1:
+ case RT5682_L_EQ_LPF1_H0:
+ case RT5682_R_EQ_LPF1_H0:
+ case RT5682_L_EQ_BPF1_A1:
+ case RT5682_R_EQ_BPF1_A1:
+ case RT5682_L_EQ_BPF1_A2:
+ case RT5682_R_EQ_BPF1_A2:
+ case RT5682_L_EQ_BPF1_H0:
+ case RT5682_R_EQ_BPF1_H0:
+ case RT5682_L_EQ_BPF2_A1:
+ case RT5682_R_EQ_BPF2_A1:
+ case RT5682_L_EQ_BPF2_A2:
+ case RT5682_R_EQ_BPF2_A2:
+ case RT5682_L_EQ_BPF2_H0:
+ case RT5682_R_EQ_BPF2_H0:
+ case RT5682_L_EQ_BPF3_A1:
+ case RT5682_R_EQ_BPF3_A1:
+ case RT5682_L_EQ_BPF3_A2:
+ case RT5682_R_EQ_BPF3_A2:
+ case RT5682_L_EQ_BPF3_H0:
+ case RT5682_R_EQ_BPF3_H0:
+ case RT5682_L_EQ_BPF4_A1:
+ case RT5682_R_EQ_BPF4_A1:
+ case RT5682_L_EQ_BPF4_A2:
+ case RT5682_R_EQ_BPF4_A2:
+ case RT5682_L_EQ_BPF4_H0:
+ case RT5682_R_EQ_BPF4_H0:
+ case RT5682_L_EQ_HPF1_A1:
+ case RT5682_R_EQ_HPF1_A1:
+ case RT5682_L_EQ_HPF1_H0:
+ case RT5682_R_EQ_HPF1_H0:
+ case RT5682_L_EQ_PRE_VOL:
+ case RT5682_R_EQ_PRE_VOL:
+ case RT5682_L_EQ_POST_VOL:
+ case RT5682_R_EQ_POST_VOL:
+ case RT5682_I2C_MODE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
+
+/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
+static const DECLARE_TLV_DB_RANGE(bst_tlv,
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0),
+ 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0),
+ 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0),
+ 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0),
+ 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0),
+ 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0)
+);
+
+/* Interface data select */
+static const char * const rt5682_data_select[] = {
+ "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if2_adc_enum,
+ RT5682_DIG_INF2_DATA, RT5682_IF2_ADC_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_01_adc_enum,
+ RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC1_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_23_adc_enum,
+ RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC2_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_45_adc_enum,
+ RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC3_SEL_SFT, rt5682_data_select);
+
+static SOC_ENUM_SINGLE_DECL(rt5682_if1_67_adc_enum,
+ RT5682_TDM_ADDA_CTRL_1, RT5682_IF1_ADC4_SEL_SFT, rt5682_data_select);
+
+static const struct snd_kcontrol_new rt5682_if2_adc_swap_mux =
+ SOC_DAPM_ENUM("IF2 ADC Swap Mux", rt5682_if2_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_01_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 01 ADC Swap Mux", rt5682_if1_01_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_23_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 23 ADC Swap Mux", rt5682_if1_23_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_45_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 45 ADC Swap Mux", rt5682_if1_45_adc_enum);
+
+static const struct snd_kcontrol_new rt5682_if1_67_adc_swap_mux =
+ SOC_DAPM_ENUM("IF1 67 ADC Swap Mux", rt5682_if1_67_adc_enum);
+
+static void rt5682_reset(struct regmap *regmap)
+{
+ regmap_write(regmap, RT5682_RESET, 0);
+ regmap_write(regmap, RT5682_I2C_MODE, 1);
+}
+/**
+ * rt5682_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @component: SoC audio component device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5682 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the component driver will turn on
+ * ASRC for these filters if ASRC is selected as their clock source.
+ */
+int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+ unsigned int filter_mask, unsigned int clk_src)
+{
+
+ switch (clk_src) {
+ case RT5682_CLK_SEL_SYS:
+ case RT5682_CLK_SEL_I2S1_ASRC:
+ case RT5682_CLK_SEL_I2S2_ASRC:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (filter_mask & RT5682_DA_STEREO1_FILTER) {
+ snd_soc_component_update_bits(component, RT5682_PLL_TRACK_2,
+ RT5682_FILTER_CLK_SEL_MASK,
+ clk_src << RT5682_FILTER_CLK_SEL_SFT);
+ }
+
+ if (filter_mask & RT5682_AD_STEREO1_FILTER) {
+ snd_soc_component_update_bits(component, RT5682_PLL_TRACK_3,
+ RT5682_FILTER_CLK_SEL_MASK,
+ clk_src << RT5682_FILTER_CLK_SEL_SFT);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5682_sel_asrc_clk_src);
+
+static int rt5682_button_detect(struct snd_soc_component *component)
+{
+ int btn_type, val;
+
+ val = snd_soc_component_read32(component, RT5682_4BTN_IL_CMD_1);
+ btn_type = val & 0xfff0;
+ snd_soc_component_write(component, RT5682_4BTN_IL_CMD_1, val);
+ pr_debug("%s btn_type=%x\n", __func__, btn_type);
+ snd_soc_component_update_bits(component,
+ RT5682_SAR_IL_CMD_2, 0x10, 0x10);
+
+ return btn_type;
+}
+
+static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
+ bool enable)
+{
+ if (enable) {
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_EN);
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_13,
+ RT5682_SAR_SOUR_MASK, RT5682_SAR_SOUR_BTN);
+ snd_soc_component_write(component, RT5682_IL_CMD_1, 0x0040);
+ snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+ RT5682_4BTN_IL_MASK | RT5682_4BTN_IL_RST_MASK,
+ RT5682_4BTN_IL_EN | RT5682_4BTN_IL_NOR);
+ snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3,
+ RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_EN);
+ } else {
+ snd_soc_component_update_bits(component, RT5682_IRQ_CTRL_3,
+ RT5682_IL_IRQ_MASK, RT5682_IL_IRQ_DIS);
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_BUTT_DET_MASK, RT5682_SAR_BUTT_DET_DIS);
+ snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+ RT5682_4BTN_IL_MASK, RT5682_4BTN_IL_DIS);
+ snd_soc_component_update_bits(component, RT5682_4BTN_IL_CMD_2,
+ RT5682_4BTN_IL_RST_MASK, RT5682_4BTN_IL_RST);
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_13,
+ RT5682_SAR_SOUR_MASK, RT5682_SAR_SOUR_TYPE);
+ }
+}
+
+/**
+ * rt5682_headset_detect - Detect headset.
+ * @component: SoC audio component device.
+ * @jack_insert: Jack insert or not.
+ *
+ * Detect whether is headset or not when jack inserted.
+ *
+ * Returns detect status.
+ */
+static int rt5682_headset_detect(struct snd_soc_component *component,
+ int jack_insert)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(component);
+ unsigned int val, count;
+
+ if (jack_insert) {
+ snd_soc_dapm_force_enable_pin(dapm, "CBJ Power");
+ snd_soc_dapm_sync(dapm);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+ RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
+
+ count = 0;
+ val = snd_soc_component_read32(component, RT5682_CBJ_CTRL_2)
+ & RT5682_JACK_TYPE_MASK;
+ while (val == 0 && count < 50) {
+ usleep_range(10000, 15000);
+ val = snd_soc_component_read32(component,
+ RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
+ count++;
+ }
+
+ switch (val) {
+ case 0x1:
+ case 0x2:
+ rt5682->jack_type = SND_JACK_HEADSET;
+ rt5682_enable_push_button_irq(component, true);
+ break;
+ default:
+ rt5682->jack_type = SND_JACK_HEADPHONE;
+ }
+
+ } else {
+ rt5682_enable_push_button_irq(component, false);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+ RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW);
+ snd_soc_dapm_disable_pin(dapm, "CBJ Power");
+ snd_soc_dapm_sync(dapm);
+
+ rt5682->jack_type = 0;
+ }
+
+ dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
+ return rt5682->jack_type;
+}
+
+static irqreturn_t rt5682_irq(int irq, void *data)
+{
+ struct rt5682_priv *rt5682 = data;
+
+ mod_delayed_work(system_power_efficient_wq,
+ &rt5682->jack_detect_work, msecs_to_jiffies(250));
+
+ return IRQ_HANDLED;
+}
+
+static void rt5682_jd_check_handler(struct work_struct *work)
+{
+ struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
+ jd_check_work.work);
+
+ if (snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
+ & RT5682_JDH_RS_MASK) {
+ /* jack out */
+ rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+
+ snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+ } else {
+ schedule_delayed_work(&rt5682->jd_check_work, 500);
+ }
+}
+
+static int rt5682_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ switch (rt5682->pdata.jd_src) {
+ case RT5682_JD1:
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_2,
+ RT5682_EXT_JD_SRC, RT5682_EXT_JD_SRC_MANUAL);
+ snd_soc_component_write(component, RT5682_CBJ_CTRL_1, 0xd042);
+ snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_3,
+ RT5682_CBJ_IN_BUF_EN, RT5682_CBJ_IN_BUF_EN);
+ snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
+ RT5682_SAR_POW_MASK, RT5682_SAR_POW_EN);
+ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+ RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_IRQ);
+ regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+ RT5682_POW_IRQ | RT5682_POW_JDH |
+ RT5682_POW_ANA, RT5682_POW_IRQ |
+ RT5682_POW_JDH | RT5682_POW_ANA);
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_2,
+ RT5682_PWR_JDH | RT5682_PWR_JDL,
+ RT5682_PWR_JDH | RT5682_PWR_JDL);
+ regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+ RT5682_JD1_EN_MASK | RT5682_JD1_POL_MASK,
+ RT5682_JD1_EN | RT5682_JD1_POL_NOR);
+ mod_delayed_work(system_power_efficient_wq,
+ &rt5682->jack_detect_work, msecs_to_jiffies(250));
+ break;
+
+ case RT5682_JD_NULL:
+ regmap_update_bits(rt5682->regmap, RT5682_IRQ_CTRL_2,
+ RT5682_JD1_EN_MASK, RT5682_JD1_DIS);
+ regmap_update_bits(rt5682->regmap, RT5682_RC_CLK_CTRL,
+ RT5682_POW_JDH | RT5682_POW_JDL, 0);
+ break;
+
+ default:
+ dev_warn(component->dev, "Wrong JD source\n");
+ break;
+ }
+
+ rt5682->hs_jack = hs_jack;
+
+ return 0;
+}
+
+static void rt5682_jack_detect_handler(struct work_struct *work)
+{
+ struct rt5682_priv *rt5682 =
+ container_of(work, struct rt5682_priv, jack_detect_work.work);
+ int val, btn_type;
+
+ while (!rt5682->component)
+ usleep_range(10000, 15000);
+
+ while (!rt5682->component->card->instantiated)
+ usleep_range(10000, 15000);
+
+ mutex_lock(&rt5682->calibrate_mutex);
+
+ val = snd_soc_component_read32(rt5682->component, RT5682_AJD1_CTRL)
+ & RT5682_JDH_RS_MASK;
+ if (!val) {
+ /* jack in */
+ if (rt5682->jack_type == 0) {
+ /* jack was out, report jack type */
+ rt5682->jack_type =
+ rt5682_headset_detect(rt5682->component, 1);
+ } else {
+ /* jack is already in, report button event */
+ rt5682->jack_type = SND_JACK_HEADSET;
+ btn_type = rt5682_button_detect(rt5682->component);
+ /**
+ * rt5682 can report three kinds of button behavior,
+ * one click, double click and hold. However,
+ * currently we will report button pressed/released
+ * event. So all the three button behaviors are
+ * treated as button pressed.
+ */
+ switch (btn_type) {
+ case 0x8000:
+ case 0x4000:
+ case 0x2000:
+ rt5682->jack_type |= SND_JACK_BTN_0;
+ break;
+ case 0x1000:
+ case 0x0800:
+ case 0x0400:
+ rt5682->jack_type |= SND_JACK_BTN_1;
+ break;
+ case 0x0200:
+ case 0x0100:
+ case 0x0080:
+ rt5682->jack_type |= SND_JACK_BTN_2;
+ break;
+ case 0x0040:
+ case 0x0020:
+ case 0x0010:
+ rt5682->jack_type |= SND_JACK_BTN_3;
+ break;
+ case 0x0000: /* unpressed */
+ break;
+ default:
+ btn_type = 0;
+ dev_err(rt5682->component->dev,
+ "Unexpected button code 0x%04x\n",
+ btn_type);
+ break;
+ }
+ }
+ } else {
+ /* jack out */
+ rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
+ }
+
+ snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
+ SND_JACK_HEADSET |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3);
+
+ if (rt5682->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3))
+ schedule_delayed_work(&rt5682->jd_check_work, 0);
+ else
+ cancel_delayed_work_sync(&rt5682->jd_check_work);
+
+ mutex_unlock(&rt5682->calibrate_mutex);
+}
+
+static const struct snd_kcontrol_new rt5682_snd_controls[] = {
+ /* Headphone Output Volume */
+ SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5682_HPL_GAIN,
+ RT5682_HPR_GAIN, RT5682_G_HP_SFT, 15, 1, hp_vol_tlv),
+
+ /* DAC Digital Volume */
+ SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5682_DAC1_DIG_VOL,
+ RT5682_L_VOL_SFT, RT5682_R_VOL_SFT, 175, 0, dac_vol_tlv),
+
+ /* IN Boost Volume */
+ SOC_SINGLE_TLV("CBJ Boost Volume", RT5682_CBJ_BST_CTRL,
+ RT5682_BST_CBJ_SFT, 8, 0, bst_tlv),
+
+ /* ADC Digital Volume Control */
+ SOC_DOUBLE("STO1 ADC Capture Switch", RT5682_STO1_ADC_DIG_VOL,
+ RT5682_L_MUTE_SFT, RT5682_R_MUTE_SFT, 1, 1),
+ SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5682_STO1_ADC_DIG_VOL,
+ RT5682_L_VOL_SFT, RT5682_R_VOL_SFT, 127, 0, adc_vol_tlv),
+
+ /* ADC Boost Volume Control */
+ SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5682_STO1_ADC_BOOST,
+ RT5682_STO1_ADC_L_BST_SFT, RT5682_STO1_ADC_R_BST_SFT,
+ 3, 0, adc_bst_tlv),
+};
+
+
+static int rt5682_div_sel(struct rt5682_priv *rt5682,
+ int target, const int div[], int size)
+{
+ int i;
+
+ if (rt5682->sysclk < target) {
+ pr_err("sysclk rate %d is too low\n",
+ rt5682->sysclk);
+ return 0;
+ }
+
+ for (i = 0; i < size - 1; i++) {
+ pr_info("div[%d]=%d\n", i, div[i]);
+ if (target * div[i] == rt5682->sysclk)
+ return i;
+ if (target * div[i + 1] > rt5682->sysclk) {
+ pr_err("can't find div for sysclk %d\n",
+ rt5682->sysclk);
+ return i;
+ }
+ }
+
+ if (target * div[i] < rt5682->sysclk)
+ pr_err("sysclk rate %d is too high\n",
+ rt5682->sysclk);
+
+ return size - 1;
+
+}
+
+/**
+ * set_dmic_clk - Set parameter of dmic.
+ *
+ * @w: DAPM widget.
+ * @kcontrol: The kcontrol of this widget.
+ * @event: Event id.
+ *
+ * Choose dmic clock between 1MHz and 3MHz.
+ * It is better for clock to approximate 3MHz.
+ */
+static int set_dmic_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ int idx = -EINVAL;
+ static const int div[] = {2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128};
+
+ idx = rt5682_div_sel(rt5682, 1500000, div, ARRAY_SIZE(div));
+
+ snd_soc_component_update_bits(component, RT5682_DMIC_CTRL_1,
+ RT5682_DMIC_CLK_MASK, idx << RT5682_DMIC_CLK_SFT);
+
+ return 0;
+}
+
+static int set_filter_clk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ int ref, val, reg, sft, mask, idx = -EINVAL;
+ static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+ static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+
+ val = snd_soc_component_read32(component, RT5682_GPIO_CTRL_1) &
+ RT5682_GP4_PIN_MASK;
+ if (w->shift == RT5682_PWR_ADC_S1F_BIT &&
+ val == RT5682_GP4_PIN_ADCDAT2)
+ ref = 256 * rt5682->lrck[RT5682_AIF2];
+ else
+ ref = 256 * rt5682->lrck[RT5682_AIF1];
+
+ idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f));
+
+ if (w->shift == RT5682_PWR_ADC_S1F_BIT) {
+ reg = RT5682_PLL_TRACK_3;
+ sft = RT5682_ADC_OSR_SFT;
+ mask = RT5682_ADC_OSR_MASK;
+ } else {
+ reg = RT5682_PLL_TRACK_2;
+ sft = RT5682_DAC_OSR_SFT;
+ mask = RT5682_DAC_OSR_MASK;
+ }
+
+ snd_soc_component_update_bits(component, reg,
+ RT5682_FILTER_CLK_DIV_MASK, idx << RT5682_FILTER_CLK_DIV_SFT);
+
+ /* select over sample rate */
+ for (idx = 0; idx < ARRAY_SIZE(div_o); idx++) {
+ if (rt5682->sysclk <= 12288000 * div_o[idx])
+ break;
+ }
+
+ snd_soc_component_update_bits(component, RT5682_ADDA_CLK_1,
+ mask, idx << sft);
+
+ return 0;
+}
+
+static int is_sys_clk_from_pll1(struct snd_soc_dapm_widget *w,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int val;
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ val = snd_soc_component_read32(component, RT5682_GLB_CLK);
+ val &= RT5682_SCLK_SRC_MASK;
+ if (val == RT5682_SCLK_SRC_PLL1)
+ return 1;
+ else
+ return 0;
+}
+
+static int is_using_asrc(struct snd_soc_dapm_widget *w,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg, shift, val;
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ switch (w->shift) {
+ case RT5682_ADC_STO1_ASRC_SFT:
+ reg = RT5682_PLL_TRACK_3;
+ shift = RT5682_FILTER_CLK_SEL_SFT;
+ break;
+ case RT5682_DAC_STO1_ASRC_SFT:
+ reg = RT5682_PLL_TRACK_2;
+ shift = RT5682_FILTER_CLK_SEL_SFT;
+ break;
+ default:
+ return 0;
+ }
+
+ val = (snd_soc_component_read32(component, reg) >> shift) & 0xf;
+ switch (val) {
+ case RT5682_CLK_SEL_I2S1_ASRC:
+ case RT5682_CLK_SEL_I2S2_ASRC:
+ return 1;
+ default:
+ return 0;
+ }
+
+}
+
+/* Digital Mixer */
+static const struct snd_kcontrol_new rt5682_sto1_adc_l_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5682_STO1_ADC_MIXER,
+ RT5682_M_STO1_ADC_L1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5682_STO1_ADC_MIXER,
+ RT5682_M_STO1_ADC_L2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_adc_r_mix[] = {
+ SOC_DAPM_SINGLE("ADC1 Switch", RT5682_STO1_ADC_MIXER,
+ RT5682_M_STO1_ADC_R1_SFT, 1, 1),
+ SOC_DAPM_SINGLE("ADC2 Switch", RT5682_STO1_ADC_MIXER,
+ RT5682_M_STO1_ADC_R2_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682_AD_DA_MIXER,
+ RT5682_M_ADCMIX_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5682_AD_DA_MIXER,
+ RT5682_M_DAC1_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("Stereo ADC Switch", RT5682_AD_DA_MIXER,
+ RT5682_M_ADCMIX_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC1 Switch", RT5682_AD_DA_MIXER,
+ RT5682_M_DAC1_R_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_dac_l_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5682_STO1_DAC_MIXER,
+ RT5682_M_DAC_L1_STO_L_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5682_STO1_DAC_MIXER,
+ RT5682_M_DAC_R1_STO_L_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5682_sto1_dac_r_mix[] = {
+ SOC_DAPM_SINGLE("DAC L1 Switch", RT5682_STO1_DAC_MIXER,
+ RT5682_M_DAC_L1_STO_R_SFT, 1, 1),
+ SOC_DAPM_SINGLE("DAC R1 Switch", RT5682_STO1_DAC_MIXER,
+ RT5682_M_DAC_R1_STO_R_SFT, 1, 1),
+};
+
+/* Analog Input Mixer */
+static const struct snd_kcontrol_new rt5682_rec1_l_mix[] = {
+ SOC_DAPM_SINGLE("CBJ Switch", RT5682_REC_MIXER,
+ RT5682_M_CBJ_RM1_L_SFT, 1, 1),
+};
+
+/* STO1 ADC1 Source */
+/* MX-26 [13] [5] */
+static const char * const rt5682_sto1_adc1_src[] = {
+ "DAC MIX", "ADC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_sto1_adc1l_enum, RT5682_STO1_ADC_MIXER,
+ RT5682_STO1_ADC1L_SRC_SFT, rt5682_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc1l_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682_sto1_adc1l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_sto1_adc1r_enum, RT5682_STO1_ADC_MIXER,
+ RT5682_STO1_ADC1R_SRC_SFT, rt5682_sto1_adc1_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc1r_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5682_sto1_adc1r_enum);
+
+/* STO1 ADC Source */
+/* MX-26 [11:10] [3:2] */
+static const char * const rt5682_sto1_adc_src[] = {
+ "ADC1 L", "ADC1 R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_sto1_adcl_enum, RT5682_STO1_ADC_MIXER,
+ RT5682_STO1_ADCL_SRC_SFT, rt5682_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adcl_mux =
+ SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5682_sto1_adcl_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_sto1_adcr_enum, RT5682_STO1_ADC_MIXER,
+ RT5682_STO1_ADCR_SRC_SFT, rt5682_sto1_adc_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adcr_mux =
+ SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5682_sto1_adcr_enum);
+
+/* STO1 ADC2 Source */
+/* MX-26 [12] [4] */
+static const char * const rt5682_sto1_adc2_src[] = {
+ "DAC MIX", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_sto1_adc2l_enum, RT5682_STO1_ADC_MIXER,
+ RT5682_STO1_ADC2L_SRC_SFT, rt5682_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc2l_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5682_sto1_adc2l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_sto1_adc2r_enum, RT5682_STO1_ADC_MIXER,
+ RT5682_STO1_ADC2R_SRC_SFT, rt5682_sto1_adc2_src);
+
+static const struct snd_kcontrol_new rt5682_sto1_adc2r_mux =
+ SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5682_sto1_adc2r_enum);
+
+/* MX-79 [6:4] I2S1 ADC data location */
+static const unsigned int rt5682_if1_adc_slot_values[] = {
+ 0,
+ 2,
+ 4,
+ 6,
+};
+
+static const char * const rt5682_if1_adc_slot_src[] = {
+ "Slot 0", "Slot 2", "Slot 4", "Slot 6"
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_if1_adc_slot_enum,
+ RT5682_TDM_CTRL, RT5682_TDM_ADC_LCA_SFT, RT5682_TDM_ADC_LCA_MASK,
+ rt5682_if1_adc_slot_src, rt5682_if1_adc_slot_values);
+
+static const struct snd_kcontrol_new rt5682_if1_adc_slot_mux =
+ SOC_DAPM_ENUM("IF1 ADC Slot location", rt5682_if1_adc_slot_enum);
+
+/* Analog DAC L1 Source, Analog DAC R1 Source*/
+/* MX-2B [4], MX-2B [0]*/
+static const char * const rt5682_alg_dac1_src[] = {
+ "Stereo1 DAC Mixer", "DAC1"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_alg_dac_l1_enum, RT5682_A_DAC1_MUX,
+ RT5682_A_DACL1_SFT, rt5682_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5682_alg_dac_l1_mux =
+ SOC_DAPM_ENUM("Analog DAC L1 Source", rt5682_alg_dac_l1_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5682_alg_dac_r1_enum, RT5682_A_DAC1_MUX,
+ RT5682_A_DACR1_SFT, rt5682_alg_dac1_src);
+
+static const struct snd_kcontrol_new rt5682_alg_dac_r1_mux =
+ SOC_DAPM_ENUM("Analog DAC R1 Source", rt5682_alg_dac_r1_enum);
+
+/* Out Switch */
+static const struct snd_kcontrol_new hpol_switch =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
+ RT5682_L_MUTE_SFT, 1, 1);
+static const struct snd_kcontrol_new hpor_switch =
+ SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5682_HP_CTRL_1,
+ RT5682_R_MUTE_SFT, 1, 1);
+
+static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_component_write(component,
+ RT5682_HP_LOGIC_CTRL_2, 0x0012);
+ snd_soc_component_write(component,
+ RT5682_HP_CTRL_2, 0x6000);
+ snd_soc_component_update_bits(component, RT5682_STO_NG2_CTRL_1,
+ RT5682_NG2_EN_MASK, RT5682_NG2_EN);
+ snd_soc_component_update_bits(component,
+ RT5682_DEPOP_1, 0x60, 0x60);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_component_update_bits(component,
+ RT5682_DEPOP_1, 0x60, 0x0);
+ snd_soc_component_write(component,
+ RT5682_HP_CTRL_2, 0x0000);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+
+}
+
+static int set_dmic_power(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /*Add delay to avoid pop noise*/
+ msleep(150);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5655_set_verf(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ switch (w->shift) {
+ case RT5682_PWR_VREF1_BIT:
+ snd_soc_component_update_bits(component,
+ RT5682_PWR_ANLG_1, RT5682_PWR_FV1, 0);
+ break;
+
+ case RT5682_PWR_VREF2_BIT:
+ snd_soc_component_update_bits(component,
+ RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(15000, 20000);
+ switch (w->shift) {
+ case RT5682_PWR_VREF1_BIT:
+ snd_soc_component_update_bits(component,
+ RT5682_PWR_ANLG_1, RT5682_PWR_FV1,
+ RT5682_PWR_FV1);
+ break;
+
+ case RT5682_PWR_VREF2_BIT:
+ snd_soc_component_update_bits(component,
+ RT5682_PWR_ANLG_1, RT5682_PWR_FV2,
+ RT5682_PWR_FV2);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static const unsigned int rt5682_adcdat_pin_values[] = {
+ 1,
+ 3,
+};
+
+static const char * const rt5682_adcdat_pin_select[] = {
+ "ADCDAT1",
+ "ADCDAT2",
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(rt5682_adcdat_pin_enum,
+ RT5682_GPIO_CTRL_1, RT5682_GP4_PIN_SFT, RT5682_GP4_PIN_MASK,
+ rt5682_adcdat_pin_select, rt5682_adcdat_pin_values);
+
+static const struct snd_kcontrol_new rt5682_adcdat_pin_ctrl =
+ SOC_DAPM_ENUM("ADCDAT", rt5682_adcdat_pin_enum);
+
+static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("LDO2", RT5682_PWR_ANLG_3, RT5682_PWR_LDO2_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL1", RT5682_PWR_ANLG_3, RT5682_PWR_PLL_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL2B", RT5682_PWR_ANLG_3, RT5682_PWR_PLL2B_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLL2F", RT5682_PWR_ANLG_3, RT5682_PWR_PLL2F_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Vref1", RT5682_PWR_ANLG_1, RT5682_PWR_VREF1_BIT, 0,
+ rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("Vref2", RT5682_PWR_ANLG_1, RT5682_PWR_VREF2_BIT, 0,
+ rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+ /* ASRC */
+ SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682_PLL_TRACK_1,
+ RT5682_DAC_STO1_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5682_PLL_TRACK_1,
+ RT5682_ADC_STO1_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("AD ASRC", 1, RT5682_PLL_TRACK_1,
+ RT5682_AD_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DA ASRC", 1, RT5682_PLL_TRACK_1,
+ RT5682_DA_ASRC_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC ASRC", 1, RT5682_PLL_TRACK_1,
+ RT5682_DMIC_ASRC_SFT, 0, NULL, 0),
+
+ /* Input Side */
+ SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5682_PWR_ANLG_2, RT5682_PWR_MB1_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5682_PWR_ANLG_2, RT5682_PWR_MB2_BIT,
+ 0, NULL, 0),
+
+ /* Input Lines */
+ SND_SOC_DAPM_INPUT("DMIC L1"),
+ SND_SOC_DAPM_INPUT("DMIC R1"),
+
+ SND_SOC_DAPM_INPUT("IN1P"),
+
+ SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
+ set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5682_DMIC_CTRL_1,
+ RT5682_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU),
+
+ /* Boost */
+ SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM,
+ 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("CBJ Power", RT5682_PWR_ANLG_3,
+ RT5682_PWR_CBJ_BIT, 0, NULL, 0),
+
+ /* REC Mixer */
+ SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682_rec1_l_mix,
+ ARRAY_SIZE(rt5682_rec1_l_mix)),
+ SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5682_PWR_ANLG_2,
+ RT5682_PWR_RM1_L_BIT, 0, NULL, 0),
+
+ /* ADCs */
+ SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5682_PWR_DIG_1,
+ RT5682_PWR_ADC_L1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5682_PWR_DIG_1,
+ RT5682_PWR_ADC_R1_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5682_CHOP_ADC,
+ RT5682_CKGEN_ADC1_SFT, 0, NULL, 0),
+
+ /* ADC Mux */
+ SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_sto1_adc1l_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_sto1_adc1r_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_sto1_adc2l_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_sto1_adc2r_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_sto1_adcl_mux),
+ SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_sto1_adcr_mux),
+ SND_SOC_DAPM_MUX("IF1_ADC Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_if1_adc_slot_mux),
+
+ /* ADC Mixer */
+ SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5682_PWR_DIG_2,
+ RT5682_PWR_ADC_S1F_BIT, 0, set_filter_clk,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5682_STO1_ADC_DIG_VOL,
+ RT5682_L_MUTE_SFT, 1, rt5682_sto1_adc_l_mix,
+ ARRAY_SIZE(rt5682_sto1_adc_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5682_STO1_ADC_DIG_VOL,
+ RT5682_R_MUTE_SFT, 1, rt5682_sto1_adc_r_mix,
+ ARRAY_SIZE(rt5682_sto1_adc_r_mix)),
+ SND_SOC_DAPM_SUPPLY("BTN Detection Mode", RT5682_SAR_IL_CMD_1,
+ 14, 1, NULL, 0),
+
+ /* ADC PGA */
+ SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Interface */
+ SND_SOC_DAPM_SUPPLY("I2S1", RT5682_PWR_DIG_1, RT5682_PWR_I2S1_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("I2S2", RT5682_PWR_DIG_1, RT5682_PWR_I2S2_BIT,
+ 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Digital Interface Select */
+ SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_if1_01_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_if1_23_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_if1_45_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_if1_67_adc_swap_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_if2_adc_swap_mux),
+
+ SND_SOC_DAPM_MUX("ADCDAT Mux", SND_SOC_NOPM, 0, 0,
+ &rt5682_adcdat_pin_ctrl),
+
+ /* Audio Interface */
+ SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0,
+ RT5682_I2S1_SDP, RT5682_SEL_ADCDAT_SFT, 1),
+ SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0,
+ RT5682_I2S2_SDP, RT5682_I2S2_PIN_CFG_SFT, 1),
+ SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* Output Side */
+ /* DAC mixer before sound effect */
+ SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
+ rt5682_dac_l_mix, ARRAY_SIZE(rt5682_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
+ rt5682_dac_r_mix, ARRAY_SIZE(rt5682_dac_r_mix)),
+
+ /* DAC channel Mux */
+ SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0,
+ &rt5682_alg_dac_l1_mux),
+ SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0,
+ &rt5682_alg_dac_r1_mux),
+
+ /* DAC Mixer */
+ SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5682_PWR_DIG_2,
+ RT5682_PWR_DAC_S1F_BIT, 0, set_filter_clk,
+ SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0,
+ rt5682_sto1_dac_l_mix, ARRAY_SIZE(rt5682_sto1_dac_l_mix)),
+ SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0,
+ rt5682_sto1_dac_r_mix, ARRAY_SIZE(rt5682_sto1_dac_r_mix)),
+
+ /* DACs */
+ SND_SOC_DAPM_DAC("DAC L1", NULL, RT5682_PWR_DIG_1,
+ RT5682_PWR_DAC_L1_BIT, 0),
+ SND_SOC_DAPM_DAC("DAC R1", NULL, RT5682_PWR_DIG_1,
+ RT5682_PWR_DAC_R1_BIT, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 3, RT5682_CHOP_DAC,
+ RT5682_CKGEN_DAC1_SFT, 0, NULL, 0),
+
+ /* HPO */
+ SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5682_hp_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_SUPPLY("HP Amp L", RT5682_PWR_ANLG_1,
+ RT5682_PWR_HA_L_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HP Amp R", RT5682_PWR_ANLG_1,
+ RT5682_PWR_HA_R_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, RT5682_DEPOP_1,
+ RT5682_PUMP_EN_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("Capless", 2, RT5682_DEPOP_1,
+ RT5682_CAPLESS_EN_SFT, 0, NULL, 0),
+
+ SND_SOC_DAPM_SWITCH("HPOL Playback", SND_SOC_NOPM, 0, 0,
+ &hpol_switch),
+ SND_SOC_DAPM_SWITCH("HPOR Playback", SND_SOC_NOPM, 0, 0,
+ &hpor_switch),
+
+ /* CLK DET */
+ SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5682_CLK_DET,
+ RT5682_SYS_CLK_DET_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLKDET PLL1", RT5682_CLK_DET,
+ RT5682_PLL1_CLK_DET_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLKDET PLL2", RT5682_CLK_DET,
+ RT5682_PLL2_CLK_DET_SFT, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CLKDET", RT5682_CLK_DET,
+ RT5682_POW_CLK_DET_SFT, 0, NULL, 0),
+
+ /* Output Lines */
+ SND_SOC_DAPM_OUTPUT("HPOL"),
+ SND_SOC_DAPM_OUTPUT("HPOR"),
+
+};
+
+static const struct snd_soc_dapm_route rt5682_dapm_routes[] = {
+ /*PLL*/
+ {"ADC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+ {"DAC Stereo1 Filter", NULL, "PLL1", is_sys_clk_from_pll1},
+
+ /*ASRC*/
+ {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
+ {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc},
+ {"ADC STO1 ASRC", NULL, "AD ASRC"},
+ {"ADC STO1 ASRC", NULL, "CLKDET"},
+ {"DAC STO1 ASRC", NULL, "DA ASRC"},
+ {"DAC STO1 ASRC", NULL, "CLKDET"},
+
+ /*Vref*/
+ {"MICBIAS1", NULL, "Vref1"},
+ {"MICBIAS1", NULL, "Vref2"},
+ {"MICBIAS2", NULL, "Vref1"},
+ {"MICBIAS2", NULL, "Vref2"},
+
+ {"CLKDET SYS", NULL, "CLKDET"},
+
+ {"IN1P", NULL, "LDO2"},
+
+ {"BST1 CBJ", NULL, "IN1P"},
+ {"BST1 CBJ", NULL, "CBJ Power"},
+ {"CBJ Power", NULL, "Vref2"},
+
+ {"RECMIX1L", "CBJ Switch", "BST1 CBJ"},
+ {"RECMIX1L", NULL, "RECMIX1L Power"},
+
+ {"ADC1 L", NULL, "RECMIX1L"},
+ {"ADC1 L", NULL, "ADC1 L Power"},
+ {"ADC1 L", NULL, "ADC1 clock"},
+
+ {"DMIC L1", NULL, "DMIC CLK"},
+ {"DMIC L1", NULL, "DMIC1 Power"},
+ {"DMIC R1", NULL, "DMIC CLK"},
+ {"DMIC R1", NULL, "DMIC1 Power"},
+ {"DMIC CLK", NULL, "DMIC ASRC"},
+
+ {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"},
+ {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"},
+ {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"},
+ {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"},
+
+ {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"},
+ {"Stereo1 ADC L1 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+ {"Stereo1 ADC L2 Mux", "DMIC", "DMIC L1"},
+ {"Stereo1 ADC L2 Mux", "DAC MIX", "Stereo1 DAC MIXL"},
+
+ {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"},
+ {"Stereo1 ADC R1 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+ {"Stereo1 ADC R2 Mux", "DMIC", "DMIC R1"},
+ {"Stereo1 ADC R2 Mux", "DAC MIX", "Stereo1 DAC MIXR"},
+
+ {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"},
+ {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"},
+ {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"},
+
+ {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"},
+ {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"},
+ {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"},
+
+ {"ADC Stereo1 Filter", NULL, "BTN Detection Mode"},
+
+ {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"},
+ {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"},
+
+ {"IF1 01 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+ {"IF1 01 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+ {"IF1 01 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+ {"IF1 01 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+ {"IF1 23 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+ {"IF1 23 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+ {"IF1 23 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+ {"IF1 23 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+ {"IF1 45 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+ {"IF1 45 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+ {"IF1 45 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+ {"IF1 45 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+ {"IF1 67 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+ {"IF1 67 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+ {"IF1 67 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+ {"IF1 67 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+
+ {"IF1_ADC Mux", "Slot 0", "IF1 01 ADC Swap Mux"},
+ {"IF1_ADC Mux", "Slot 2", "IF1 23 ADC Swap Mux"},
+ {"IF1_ADC Mux", "Slot 4", "IF1 45 ADC Swap Mux"},
+ {"IF1_ADC Mux", "Slot 6", "IF1 67 ADC Swap Mux"},
+ {"IF1_ADC Mux", NULL, "I2S1"},
+ {"ADCDAT Mux", "ADCDAT1", "IF1_ADC Mux"},
+ {"AIF1TX", NULL, "ADCDAT Mux"},
+ {"IF2 ADC Swap Mux", "L/R", "Stereo1 ADC MIX"},
+ {"IF2 ADC Swap Mux", "R/L", "Stereo1 ADC MIX"},
+ {"IF2 ADC Swap Mux", "L/L", "Stereo1 ADC MIX"},
+ {"IF2 ADC Swap Mux", "R/R", "Stereo1 ADC MIX"},
+ {"ADCDAT Mux", "ADCDAT2", "IF2 ADC Swap Mux"},
+ {"AIF2TX", NULL, "ADCDAT Mux"},
+
+ {"IF1 DAC1 L", NULL, "AIF1RX"},
+ {"IF1 DAC1 L", NULL, "I2S1"},
+ {"IF1 DAC1 L", NULL, "DAC Stereo1 Filter"},
+ {"IF1 DAC1 R", NULL, "AIF1RX"},
+ {"IF1 DAC1 R", NULL, "I2S1"},
+ {"IF1 DAC1 R", NULL, "DAC Stereo1 Filter"},
+
+ {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"},
+ {"DAC1 MIXL", "DAC1 Switch", "IF1 DAC1 L"},
+ {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"},
+ {"DAC1 MIXR", "DAC1 Switch", "IF1 DAC1 R"},
+
+ {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"},
+ {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"},
+
+ {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"},
+ {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"},
+
+ {"DAC L1 Source", "DAC1", "DAC1 MIXL"},
+ {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"},
+ {"DAC R1 Source", "DAC1", "DAC1 MIXR"},
+ {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"},
+
+ {"DAC L1", NULL, "DAC L1 Source"},
+ {"DAC R1", NULL, "DAC R1 Source"},
+
+ {"DAC L1", NULL, "DAC 1 Clock"},
+ {"DAC R1", NULL, "DAC 1 Clock"},
+
+ {"HP Amp", NULL, "DAC L1"},
+ {"HP Amp", NULL, "DAC R1"},
+ {"HP Amp", NULL, "HP Amp L"},
+ {"HP Amp", NULL, "HP Amp R"},
+ {"HP Amp", NULL, "Capless"},
+ {"HP Amp", NULL, "Charge Pump"},
+ {"HP Amp", NULL, "CLKDET SYS"},
+ {"HP Amp", NULL, "CBJ Power"},
+ {"HP Amp", NULL, "Vref2"},
+ {"HPOL Playback", "Switch", "HP Amp"},
+ {"HPOR Playback", "Switch", "HP Amp"},
+ {"HPOL", NULL, "HPOL Playback"},
+ {"HPOR", NULL, "HPOR Playback"},
+};
+
+static int rt5682_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int slot_width)
+{
+ struct snd_soc_component *component = dai->component;
+ unsigned int cl, val = 0;
+
+ if (tx_mask || rx_mask)
+ snd_soc_component_update_bits(component, RT5682_TDM_ADDA_CTRL_2,
+ RT5682_TDM_EN, RT5682_TDM_EN);
+ else
+ snd_soc_component_update_bits(component, RT5682_TDM_ADDA_CTRL_2,
+ RT5682_TDM_EN, 0);
+
+ switch (slots) {
+ case 4:
+ val |= RT5682_TDM_TX_CH_4;
+ val |= RT5682_TDM_RX_CH_4;
+ break;
+ case 6:
+ val |= RT5682_TDM_TX_CH_6;
+ val |= RT5682_TDM_RX_CH_6;
+ break;
+ case 8:
+ val |= RT5682_TDM_TX_CH_8;
+ val |= RT5682_TDM_RX_CH_8;
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT5682_TDM_CTRL,
+ RT5682_TDM_TX_CH_MASK | RT5682_TDM_RX_CH_MASK, val);
+
+ switch (slot_width) {
+ case 8:
+ if (tx_mask || rx_mask)
+ return -EINVAL;
+ cl = RT5682_I2S1_TX_CHL_8 | RT5682_I2S1_RX_CHL_8;
+ break;
+ case 16:
+ val = RT5682_TDM_CL_16;
+ cl = RT5682_I2S1_TX_CHL_16 | RT5682_I2S1_RX_CHL_16;
+ break;
+ case 20:
+ val = RT5682_TDM_CL_20;
+ cl = RT5682_I2S1_TX_CHL_20 | RT5682_I2S1_RX_CHL_20;
+ break;
+ case 24:
+ val = RT5682_TDM_CL_24;
+ cl = RT5682_I2S1_TX_CHL_24 | RT5682_I2S1_RX_CHL_24;
+ break;
+ case 32:
+ val = RT5682_TDM_CL_32;
+ cl = RT5682_I2S1_TX_CHL_32 | RT5682_I2S1_RX_CHL_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_component_update_bits(component, RT5682_TDM_TCON_CTRL,
+ RT5682_TDM_CL_MASK, val);
+ snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+ RT5682_I2S1_TX_CHL_MASK | RT5682_I2S1_RX_CHL_MASK, cl);
+
+ return 0;
+}
+
+
+static int rt5682_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ unsigned int len_1 = 0, len_2 = 0;
+ int pre_div, frame_size;
+
+ rt5682->lrck[dai->id] = params_rate(params);
+ pre_div = rl6231_get_clk_info(rt5682->sysclk, rt5682->lrck[dai->id]);
+
+ frame_size = snd_soc_params_to_frame_size(params);
+ if (frame_size < 0) {
+ dev_err(component->dev, "Unsupported frame size: %d\n",
+ frame_size);
+ return -EINVAL;
+ }
+
+ dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n",
+ rt5682->lrck[dai->id], pre_div, dai->id);
+
+ switch (params_width(params)) {
+ case 16:
+ break;
+ case 20:
+ len_1 |= RT5682_I2S1_DL_20;
+ len_2 |= RT5682_I2S2_DL_20;
+ break;
+ case 24:
+ len_1 |= RT5682_I2S1_DL_24;
+ len_2 |= RT5682_I2S2_DL_24;
+ break;
+ case 32:
+ len_1 |= RT5682_I2S1_DL_32;
+ len_2 |= RT5682_I2S2_DL_24;
+ break;
+ case 8:
+ len_1 |= RT5682_I2S2_DL_8;
+ len_2 |= RT5682_I2S2_DL_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5682_AIF1:
+ snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+ RT5682_I2S1_DL_MASK, len_1);
+ if (rt5682->master[RT5682_AIF1]) {
+ snd_soc_component_update_bits(component,
+ RT5682_ADDA_CLK_1, RT5682_I2S_M_DIV_MASK,
+ pre_div << RT5682_I2S_M_DIV_SFT);
+ }
+ if (params_channels(params) == 1) /* mono mode */
+ snd_soc_component_update_bits(component,
+ RT5682_I2S1_SDP, RT5682_I2S1_MONO_MASK,
+ RT5682_I2S1_MONO_EN);
+ else
+ snd_soc_component_update_bits(component,
+ RT5682_I2S1_SDP, RT5682_I2S1_MONO_MASK,
+ RT5682_I2S1_MONO_DIS);
+ break;
+ case RT5682_AIF2:
+ snd_soc_component_update_bits(component, RT5682_I2S2_SDP,
+ RT5682_I2S2_DL_MASK, len_2);
+ if (rt5682->master[RT5682_AIF2]) {
+ snd_soc_component_update_bits(component,
+ RT5682_I2S_M_CLK_CTRL_1, RT5682_I2S2_M_PD_MASK,
+ pre_div << RT5682_I2S2_M_PD_SFT);
+ }
+ if (params_channels(params) == 1) /* mono mode */
+ snd_soc_component_update_bits(component,
+ RT5682_I2S2_SDP, RT5682_I2S2_MONO_MASK,
+ RT5682_I2S2_MONO_EN);
+ else
+ snd_soc_component_update_bits(component,
+ RT5682_I2S2_SDP, RT5682_I2S2_MONO_MASK,
+ RT5682_I2S2_MONO_DIS);
+ break;
+ default:
+ dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt5682_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0, tdm_ctrl = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5682->master[dai->id] = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ rt5682->master[dai->id] = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ reg_val |= RT5682_I2S_BP_INV;
+ tdm_ctrl |= RT5682_TDM_S_BP_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ if (dai->id == RT5682_AIF1)
+ tdm_ctrl |= RT5682_TDM_S_LP_INV | RT5682_TDM_M_BP_INV;
+ else
+ return -EINVAL;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ if (dai->id == RT5682_AIF1)
+ tdm_ctrl |= RT5682_TDM_S_BP_INV | RT5682_TDM_S_LP_INV |
+ RT5682_TDM_M_BP_INV | RT5682_TDM_M_LP_INV;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ reg_val |= RT5682_I2S_DF_LEFT;
+ tdm_ctrl |= RT5682_TDM_DF_LEFT;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ reg_val |= RT5682_I2S_DF_PCM_A;
+ tdm_ctrl |= RT5682_TDM_DF_PCM_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ reg_val |= RT5682_I2S_DF_PCM_B;
+ tdm_ctrl |= RT5682_TDM_DF_PCM_B;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case RT5682_AIF1:
+ snd_soc_component_update_bits(component, RT5682_I2S1_SDP,
+ RT5682_I2S_DF_MASK, reg_val);
+ snd_soc_component_update_bits(component, RT5682_TDM_TCON_CTRL,
+ RT5682_TDM_MS_MASK | RT5682_TDM_S_BP_MASK |
+ RT5682_TDM_DF_MASK | RT5682_TDM_M_BP_MASK |
+ RT5682_TDM_M_LP_MASK | RT5682_TDM_S_LP_MASK,
+ tdm_ctrl | rt5682->master[dai->id]);
+ break;
+ case RT5682_AIF2:
+ if (rt5682->master[dai->id] == 0)
+ reg_val |= RT5682_I2S2_MS_S;
+ snd_soc_component_update_bits(component, RT5682_I2S2_SDP,
+ RT5682_I2S2_MS_MASK | RT5682_I2S_BP_MASK |
+ RT5682_I2S_DF_MASK, reg_val);
+ break;
+ default:
+ dev_err(component->dev, "Invalid dai->id: %d\n", dai->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int rt5682_set_component_sysclk(struct snd_soc_component *component,
+ int clk_id, int source, unsigned int freq, int dir)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ unsigned int reg_val = 0, src = 0;
+
+ if (freq == rt5682->sysclk && clk_id == rt5682->sysclk_src)
+ return 0;
+
+ switch (clk_id) {
+ case RT5682_SCLK_S_MCLK:
+ reg_val |= RT5682_SCLK_SRC_MCLK;
+ src = RT5682_CLK_SRC_MCLK;
+ break;
+ case RT5682_SCLK_S_PLL1:
+ reg_val |= RT5682_SCLK_SRC_PLL1;
+ src = RT5682_CLK_SRC_PLL1;
+ break;
+ case RT5682_SCLK_S_PLL2:
+ reg_val |= RT5682_SCLK_SRC_PLL2;
+ src = RT5682_CLK_SRC_PLL2;
+ break;
+ case RT5682_SCLK_S_RCCLK:
+ reg_val |= RT5682_SCLK_SRC_RCCLK;
+ src = RT5682_CLK_SRC_RCCLK;
+ break;
+ default:
+ dev_err(component->dev, "Invalid clock id (%d)\n", clk_id);
+ return -EINVAL;
+ }
+ snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+ RT5682_SCLK_SRC_MASK, reg_val);
+
+ if (rt5682->master[RT5682_AIF2]) {
+ snd_soc_component_update_bits(component,
+ RT5682_I2S_M_CLK_CTRL_1, RT5682_I2S2_SRC_MASK,
+ src << RT5682_I2S2_SRC_SFT);
+ }
+
+ rt5682->sysclk = freq;
+ rt5682->sysclk_src = clk_id;
+
+ dev_dbg(component->dev, "Sysclk is %dHz and clock id is %d\n",
+ freq, clk_id);
+
+ return 0;
+}
+
+static int rt5682_set_component_pll(struct snd_soc_component *component,
+ int pll_id, int source, unsigned int freq_in,
+ unsigned int freq_out)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+ struct rl6231_pll_code pll_code;
+ int ret;
+
+ if (source == rt5682->pll_src && freq_in == rt5682->pll_in &&
+ freq_out == rt5682->pll_out)
+ return 0;
+
+ if (!freq_in || !freq_out) {
+ dev_dbg(component->dev, "PLL disabled\n");
+
+ rt5682->pll_in = 0;
+ rt5682->pll_out = 0;
+ snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+ RT5682_SCLK_SRC_MASK, RT5682_SCLK_SRC_MCLK);
+ return 0;
+ }
+
+ switch (source) {
+ case RT5682_PLL1_S_MCLK:
+ snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+ RT5682_PLL1_SRC_MASK, RT5682_PLL1_SRC_MCLK);
+ break;
+ case RT5682_PLL1_S_BCLK1:
+ snd_soc_component_update_bits(component, RT5682_GLB_CLK,
+ RT5682_PLL1_SRC_MASK, RT5682_PLL1_SRC_BCLK1);
+ break;
+ default:
+ dev_err(component->dev, "Unknown PLL Source %d\n", source);
+ return -EINVAL;
+ }
+
+ ret = rl6231_pll_calc(freq_in, freq_out, &pll_code);
+ if (ret < 0) {
+ dev_err(component->dev, "Unsupport input clock %d\n", freq_in);
+ return ret;
+ }
+
+ dev_dbg(component->dev, "bypass=%d m=%d n=%d k=%d\n",
+ pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code),
+ pll_code.n_code, pll_code.k_code);
+
+ snd_soc_component_write(component, RT5682_PLL_CTRL_1,
+ pll_code.n_code << RT5682_PLL_N_SFT | pll_code.k_code);
+ snd_soc_component_write(component, RT5682_PLL_CTRL_2,
+ (pll_code.m_bp ? 0 : pll_code.m_code) << RT5682_PLL_M_SFT |
+ pll_code.m_bp << RT5682_PLL_M_BP_SFT | RT5682_PLL_RST);
+
+ rt5682->pll_in = freq_in;
+ rt5682->pll_out = freq_out;
+ rt5682->pll_src = source;
+
+ return 0;
+}
+
+static int rt5682_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ rt5682->bclk[dai->id] = ratio;
+
+ switch (ratio) {
+ case 64:
+ snd_soc_component_update_bits(component, RT5682_ADDA_CLK_2,
+ RT5682_I2S2_BCLK_MS2_MASK,
+ RT5682_I2S2_BCLK_MS2_64);
+ break;
+ case 32:
+ snd_soc_component_update_bits(component, RT5682_ADDA_CLK_2,
+ RT5682_I2S2_BCLK_MS2_MASK,
+ RT5682_I2S2_BCLK_MS2_32);
+ break;
+ default:
+ dev_err(dai->dev, "Invalid bclk ratio %d\n", ratio);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt5682_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+ RT5682_PWR_MB | RT5682_PWR_BG,
+ RT5682_PWR_MB | RT5682_PWR_BG);
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+ RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO,
+ RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+ RT5682_PWR_MB, RT5682_PWR_MB);
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+ RT5682_DIG_GATE_CTRL, RT5682_DIG_GATE_CTRL);
+ break;
+ case SND_SOC_BIAS_OFF:
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1,
+ RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, 0);
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+ RT5682_PWR_MB | RT5682_PWR_BG, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int rt5682_probe(struct snd_soc_component *component)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ rt5682->component = component;
+
+ return 0;
+}
+
+static void rt5682_remove(struct snd_soc_component *component)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ rt5682_reset(rt5682->regmap);
+}
+
+#ifdef CONFIG_PM
+static int rt5682_suspend(struct snd_soc_component *component)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
+ return 0;
+}
+
+static int rt5682_resume(struct snd_soc_component *component)
+{
+ struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
+
+ regcache_cache_only(rt5682->regmap, false);
+ regcache_sync(rt5682->regmap);
+
+ return 0;
+}
+#else
+#define rt5682_suspend NULL
+#define rt5682_resume NULL
+#endif
+
+#define RT5682_STEREO_RATES SNDRV_PCM_RATE_8000_192000
+#define RT5682_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
+
+static const struct snd_soc_dai_ops rt5682_aif1_dai_ops = {
+ .hw_params = rt5682_hw_params,
+ .set_fmt = rt5682_set_dai_fmt,
+ .set_tdm_slot = rt5682_set_tdm_slot,
+};
+
+static const struct snd_soc_dai_ops rt5682_aif2_dai_ops = {
+ .hw_params = rt5682_hw_params,
+ .set_fmt = rt5682_set_dai_fmt,
+ .set_bclk_ratio = rt5682_set_bclk_ratio,
+};
+
+static struct snd_soc_dai_driver rt5682_dai[] = {
+ {
+ .name = "rt5682-aif1",
+ .id = RT5682_AIF1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5682_STEREO_RATES,
+ .formats = RT5682_FORMATS,
+ },
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5682_STEREO_RATES,
+ .formats = RT5682_FORMATS,
+ },
+ .ops = &rt5682_aif1_dai_ops,
+ },
+ {
+ .name = "rt5682-aif2",
+ .id = RT5682_AIF2,
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5682_STEREO_RATES,
+ .formats = RT5682_FORMATS,
+ },
+ .ops = &rt5682_aif2_dai_ops,
+ },
+};
+
+static const struct snd_soc_component_driver soc_component_dev_rt5682 = {
+ .probe = rt5682_probe,
+ .remove = rt5682_remove,
+ .suspend = rt5682_suspend,
+ .resume = rt5682_resume,
+ .set_bias_level = rt5682_set_bias_level,
+ .controls = rt5682_snd_controls,
+ .num_controls = ARRAY_SIZE(rt5682_snd_controls),
+ .dapm_widgets = rt5682_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt5682_dapm_widgets),
+ .dapm_routes = rt5682_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(rt5682_dapm_routes),
+ .set_sysclk = rt5682_set_component_sysclk,
+ .set_pll = rt5682_set_component_pll,
+ .set_jack = rt5682_set_jack_detect,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+ .non_legacy_dai_naming = 1,
+};
+
+static const struct regmap_config rt5682_regmap = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = RT5682_I2C_MODE,
+ .volatile_reg = rt5682_volatile_register,
+ .readable_reg = rt5682_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = rt5682_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5682_reg),
+ .use_single_rw = true,
+};
+
+static const struct i2c_device_id rt5682_i2c_id[] = {
+ {"rt5682", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, rt5682_i2c_id);
+
+static int rt5682_parse_dt(struct rt5682_priv *rt5682, struct device *dev)
+{
+
+ device_property_read_u32(dev, "realtek,dmic1-data-pin",
+ &rt5682->pdata.dmic1_data_pin);
+ device_property_read_u32(dev, "realtek,dmic1-clk-pin",
+ &rt5682->pdata.dmic1_clk_pin);
+ device_property_read_u32(dev, "realtek,jd-src",
+ &rt5682->pdata.jd_src);
+
+ rt5682->pdata.ldo1_en = of_get_named_gpio(dev->of_node,
+ "realtek,ldo1-en-gpios", 0);
+
+ return 0;
+}
+
+static void rt5682_calibrate(struct rt5682_priv *rt5682)
+{
+ int value, count;
+
+ mutex_lock(&rt5682->calibrate_mutex);
+
+ rt5682_reset(rt5682->regmap);
+ regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xa2bf);
+ usleep_range(15000, 20000);
+ regmap_write(rt5682->regmap, RT5682_PWR_ANLG_1, 0xf2bf);
+ regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
+ regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8001);
+ regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
+ regmap_write(rt5682->regmap, RT5682_STO1_DAC_MIXER, 0x2080);
+ regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x4040);
+ regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0069);
+ regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
+ regmap_write(rt5682->regmap, RT5682_HP_CTRL_2, 0x6000);
+ regmap_write(rt5682->regmap, RT5682_HP_CHARGE_PUMP_1, 0x0f26);
+ regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7f05);
+ regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
+ regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
+ regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_9, 0x000f);
+ regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x8d01);
+ regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
+ regmap_write(rt5682->regmap, RT5682_HP_LOGIC_CTRL_2, 0x0004);
+ regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0x7c00);
+ regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_3, 0x06a1);
+ regmap_write(rt5682->regmap, RT5682_A_DAC1_MUX, 0x0311);
+ regmap_write(rt5682->regmap, RT5682_RESET_HPF_CTRL, 0x0000);
+ regmap_write(rt5682->regmap, RT5682_ADC_STO1_HP_CTRL_1, 0x3320);
+
+ regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_1, 0xfc00);
+
+ for (count = 0; count < 60; count++) {
+ regmap_read(rt5682->regmap, RT5682_HP_CALIB_STA_1, &value);
+ if (!(value & 0x8000))
+ break;
+
+ usleep_range(10000, 10005);
+ }
+
+ if (count >= 60)
+ pr_err("HP Calibration Failure\n");
+
+ /* restore settings */
+ regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
+ regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
+
+ mutex_unlock(&rt5682->calibrate_mutex);
+
+}
+
+static int rt5682_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5682_platform_data *pdata = dev_get_platdata(&i2c->dev);
+ struct rt5682_priv *rt5682;
+ int i, ret;
+ unsigned int val;
+
+ rt5682 = devm_kzalloc(&i2c->dev, sizeof(struct rt5682_priv),
+ GFP_KERNEL);
+
+ if (rt5682 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5682);
+
+ if (pdata)
+ rt5682->pdata = *pdata;
+ else
+ rt5682_parse_dt(rt5682, &i2c->dev);
+
+ rt5682->regmap = devm_regmap_init_i2c(i2c, &rt5682_regmap);
+ if (IS_ERR(rt5682->regmap)) {
+ ret = PTR_ERR(rt5682->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(rt5682->supplies); i++)
+ rt5682->supplies[i].supply = rt5682_supply_names[i];
+
+ ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5682->supplies),
+ rt5682->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(rt5682->supplies),
+ rt5682->supplies);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+ return ret;
+ }
+
+ if (gpio_is_valid(rt5682->pdata.ldo1_en)) {
+ if (devm_gpio_request_one(&i2c->dev, rt5682->pdata.ldo1_en,
+ GPIOF_OUT_INIT_HIGH, "rt5682"))
+ dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n");
+ }
+
+ /* Sleep for 300 ms miniumum */
+ usleep_range(300000, 350000);
+
+ regmap_write(rt5682->regmap, RT5682_I2C_MODE, 0x1);
+ usleep_range(10000, 15000);
+
+ regmap_read(rt5682->regmap, RT5682_DEVICE_ID, &val);
+ if (val != DEVICE_ID) {
+ pr_err("Device with ID register %x is not rt5682\n", val);
+ return -ENODEV;
+ }
+
+ rt5682_reset(rt5682->regmap);
+
+ rt5682_calibrate(rt5682);
+
+ ret = regmap_register_patch(rt5682->regmap, patch_list,
+ ARRAY_SIZE(patch_list));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ regmap_write(rt5682->regmap, RT5682_DEPOP_1, 0x0000);
+
+ /* DMIC pin*/
+ if (rt5682->pdata.dmic1_data_pin != RT5682_DMIC1_NULL) {
+ switch (rt5682->pdata.dmic1_data_pin) {
+ case RT5682_DMIC1_DATA_GPIO2: /* share with LRCK2 */
+ regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
+ RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO2);
+ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+ RT5682_GP2_PIN_MASK, RT5682_GP2_PIN_DMIC_SDA);
+ break;
+
+ case RT5682_DMIC1_DATA_GPIO5: /* share with DACDAT1 */
+ regmap_update_bits(rt5682->regmap, RT5682_DMIC_CTRL_1,
+ RT5682_DMIC_1_DP_MASK, RT5682_DMIC_1_DP_GPIO5);
+ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+ RT5682_GP5_PIN_MASK, RT5682_GP5_PIN_DMIC_SDA);
+ break;
+
+ default:
+ dev_warn(&i2c->dev, "invalid DMIC_DAT pin\n");
+ break;
+ }
+
+ switch (rt5682->pdata.dmic1_clk_pin) {
+ case RT5682_DMIC1_CLK_GPIO1: /* share with IRQ */
+ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+ RT5682_GP1_PIN_MASK, RT5682_GP1_PIN_DMIC_CLK);
+ break;
+
+ case RT5682_DMIC1_CLK_GPIO3: /* share with BCLK2 */
+ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+ RT5682_GP3_PIN_MASK, RT5682_GP3_PIN_DMIC_CLK);
+ break;
+
+ default:
+ dev_warn(&i2c->dev, "invalid DMIC_CLK pin\n");
+ break;
+ }
+ }
+
+ regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1,
+ RT5682_LDO1_DVO_MASK | RT5682_HP_DRIVER_MASK,
+ RT5682_LDO1_DVO_12 | RT5682_HP_DRIVER_5X);
+ regmap_write(rt5682->regmap, RT5682_MICBIAS_2, 0x0380);
+ regmap_update_bits(rt5682->regmap, RT5682_GPIO_CTRL_1,
+ RT5682_GP4_PIN_MASK | RT5682_GP5_PIN_MASK,
+ RT5682_GP4_PIN_ADCDAT1 | RT5682_GP5_PIN_DACDAT1);
+ regmap_write(rt5682->regmap, RT5682_TEST_MODE_CTRL_1, 0x0000);
+
+ INIT_DELAYED_WORK(&rt5682->jack_detect_work,
+ rt5682_jack_detect_handler);
+ INIT_DELAYED_WORK(&rt5682->jd_check_work,
+ rt5682_jd_check_handler);
+
+ mutex_init(&rt5682->calibrate_mutex);
+
+ if (i2c->irq) {
+ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
+ rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_ONESHOT, "rt5682", rt5682);
+ if (ret)
+ dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
+
+ }
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_component_dev_rt5682,
+ rt5682_dai, ARRAY_SIZE(rt5682_dai));
+}
+
+static void rt5682_i2c_shutdown(struct i2c_client *client)
+{
+ struct rt5682_priv *rt5682 = i2c_get_clientdata(client);
+
+ rt5682_reset(rt5682->regmap);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id rt5682_of_match[] = {
+ {.compatible = "realtek,rt5682i"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, rt5682_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id rt5682_acpi_match[] = {
+ {"10EC5682", 0,},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
+#endif
+
+static struct i2c_driver rt5682_i2c_driver = {
+ .driver = {
+ .name = "rt5682",
+ .of_match_table = of_match_ptr(rt5682_of_match),
+ .acpi_match_table = ACPI_PTR(rt5682_acpi_match),
+ },
+ .probe = rt5682_i2c_probe,
+ .shutdown = rt5682_i2c_shutdown,
+ .id_table = rt5682_i2c_id,
+};
+module_i2c_driver(rt5682_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC RT5682 driver");
+MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
new file mode 100644
index 000000000000..8068140ebe3f
--- /dev/null
+++ b/sound/soc/codecs/rt5682.h
@@ -0,0 +1,1324 @@
+/*
+ * rt5682.h -- RT5682/RT5658 ALSA SoC audio driver
+ *
+ * Copyright 2018 Realtek Microelectronics
+ * Author: Bard Liao <bardliao@realtek.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 __RT5682_H__
+#define __RT5682_H__
+
+#include <sound/rt5682.h>
+
+#define DEVICE_ID 0x6530
+
+/* Info */
+#define RT5682_RESET 0x0000
+#define RT5682_VERSION_ID 0x00fd
+#define RT5682_VENDOR_ID 0x00fe
+#define RT5682_DEVICE_ID 0x00ff
+/* I/O - Output */
+#define RT5682_HP_CTRL_1 0x0002
+#define RT5682_HP_CTRL_2 0x0003
+#define RT5682_HPL_GAIN 0x0005
+#define RT5682_HPR_GAIN 0x0006
+
+#define RT5682_I2C_CTRL 0x0008
+
+/* I/O - Input */
+#define RT5682_CBJ_BST_CTRL 0x000b
+#define RT5682_CBJ_CTRL_1 0x0010
+#define RT5682_CBJ_CTRL_2 0x0011
+#define RT5682_CBJ_CTRL_3 0x0012
+#define RT5682_CBJ_CTRL_4 0x0013
+#define RT5682_CBJ_CTRL_5 0x0014
+#define RT5682_CBJ_CTRL_6 0x0015
+#define RT5682_CBJ_CTRL_7 0x0016
+/* I/O - ADC/DAC/DMIC */
+#define RT5682_DAC1_DIG_VOL 0x0019
+#define RT5682_STO1_ADC_DIG_VOL 0x001c
+#define RT5682_STO1_ADC_BOOST 0x001f
+#define RT5682_HP_IMP_GAIN_1 0x0022
+#define RT5682_HP_IMP_GAIN_2 0x0023
+/* Mixer - D-D */
+#define RT5682_SIDETONE_CTRL 0x0024
+#define RT5682_STO1_ADC_MIXER 0x0026
+#define RT5682_AD_DA_MIXER 0x0029
+#define RT5682_STO1_DAC_MIXER 0x002a
+#define RT5682_A_DAC1_MUX 0x002b
+#define RT5682_DIG_INF2_DATA 0x0030
+/* Mixer - ADC */
+#define RT5682_REC_MIXER 0x003c
+#define RT5682_CAL_REC 0x0044
+#define RT5682_ALC_BACK_GAIN 0x0049
+/* Power */
+#define RT5682_PWR_DIG_1 0x0061
+#define RT5682_PWR_DIG_2 0x0062
+#define RT5682_PWR_ANLG_1 0x0063
+#define RT5682_PWR_ANLG_2 0x0064
+#define RT5682_PWR_ANLG_3 0x0065
+#define RT5682_PWR_MIXER 0x0066
+#define RT5682_PWR_VOL 0x0067
+/* Clock Detect */
+#define RT5682_CLK_DET 0x006b
+/* Filter Auto Reset */
+#define RT5682_RESET_LPF_CTRL 0x006c
+#define RT5682_RESET_HPF_CTRL 0x006d
+/* DMIC */
+#define RT5682_DMIC_CTRL_1 0x006e
+/* Format - ADC/DAC */
+#define RT5682_I2S1_SDP 0x0070
+#define RT5682_I2S2_SDP 0x0071
+#define RT5682_ADDA_CLK_1 0x0073
+#define RT5682_ADDA_CLK_2 0x0074
+#define RT5682_I2S1_F_DIV_CTRL_1 0x0075
+#define RT5682_I2S1_F_DIV_CTRL_2 0x0076
+/* Format - TDM Control */
+#define RT5682_TDM_CTRL 0x0079
+#define RT5682_TDM_ADDA_CTRL_1 0x007a
+#define RT5682_TDM_ADDA_CTRL_2 0x007b
+#define RT5682_DATA_SEL_CTRL_1 0x007c
+#define RT5682_TDM_TCON_CTRL 0x007e
+/* Function - Analog */
+#define RT5682_GLB_CLK 0x0080
+#define RT5682_PLL_CTRL_1 0x0081
+#define RT5682_PLL_CTRL_2 0x0082
+#define RT5682_PLL_TRACK_1 0x0083
+#define RT5682_PLL_TRACK_2 0x0084
+#define RT5682_PLL_TRACK_3 0x0085
+#define RT5682_PLL_TRACK_4 0x0086
+#define RT5682_PLL_TRACK_5 0x0087
+#define RT5682_PLL_TRACK_6 0x0088
+#define RT5682_PLL_TRACK_11 0x008c
+#define RT5682_SDW_REF_CLK 0x008d
+#define RT5682_DEPOP_1 0x008e
+#define RT5682_DEPOP_2 0x008f
+#define RT5682_HP_CHARGE_PUMP_1 0x0091
+#define RT5682_HP_CHARGE_PUMP_2 0x0092
+#define RT5682_MICBIAS_1 0x0093
+#define RT5682_MICBIAS_2 0x0094
+#define RT5682_PLL_TRACK_12 0x0098
+#define RT5682_PLL_TRACK_14 0x009a
+#define RT5682_PLL2_CTRL_1 0x009b
+#define RT5682_PLL2_CTRL_2 0x009c
+#define RT5682_PLL2_CTRL_3 0x009d
+#define RT5682_PLL2_CTRL_4 0x009e
+#define RT5682_RC_CLK_CTRL 0x009f
+#define RT5682_I2S_M_CLK_CTRL_1 0x00a0
+#define RT5682_I2S2_F_DIV_CTRL_1 0x00a3
+#define RT5682_I2S2_F_DIV_CTRL_2 0x00a4
+/* Function - Digital */
+#define RT5682_EQ_CTRL_1 0x00ae
+#define RT5682_EQ_CTRL_2 0x00af
+#define RT5682_IRQ_CTRL_1 0x00b6
+#define RT5682_IRQ_CTRL_2 0x00b7
+#define RT5682_IRQ_CTRL_3 0x00b8
+#define RT5682_IRQ_CTRL_4 0x00b9
+#define RT5682_INT_ST_1 0x00be
+#define RT5682_GPIO_CTRL_1 0x00c0
+#define RT5682_GPIO_CTRL_2 0x00c1
+#define RT5682_GPIO_CTRL_3 0x00c2
+#define RT5682_HP_AMP_DET_CTRL_1 0x00d0
+#define RT5682_HP_AMP_DET_CTRL_2 0x00d1
+#define RT5682_MID_HP_AMP_DET 0x00d2
+#define RT5682_LOW_HP_AMP_DET 0x00d3
+#define RT5682_DELAY_BUF_CTRL 0x00d4
+#define RT5682_SV_ZCD_1 0x00d9
+#define RT5682_SV_ZCD_2 0x00da
+#define RT5682_IL_CMD_1 0x00db
+#define RT5682_IL_CMD_2 0x00dc
+#define RT5682_IL_CMD_3 0x00dd
+#define RT5682_IL_CMD_4 0x00de
+#define RT5682_IL_CMD_5 0x00df
+#define RT5682_IL_CMD_6 0x00e0
+#define RT5682_4BTN_IL_CMD_1 0x00e2
+#define RT5682_4BTN_IL_CMD_2 0x00e3
+#define RT5682_4BTN_IL_CMD_3 0x00e4
+#define RT5682_4BTN_IL_CMD_4 0x00e5
+#define RT5682_4BTN_IL_CMD_5 0x00e6
+#define RT5682_4BTN_IL_CMD_6 0x00e7
+#define RT5682_4BTN_IL_CMD_7 0x00e8
+
+#define RT5682_ADC_STO1_HP_CTRL_1 0x00ea
+#define RT5682_ADC_STO1_HP_CTRL_2 0x00eb
+#define RT5682_AJD1_CTRL 0x00f0
+#define RT5682_JD1_THD 0x00f1
+#define RT5682_JD2_THD 0x00f2
+#define RT5682_JD_CTRL_1 0x00f6
+/* General Control */
+#define RT5682_DUMMY_1 0x00fa
+#define RT5682_DUMMY_2 0x00fb
+#define RT5682_DUMMY_3 0x00fc
+
+#define RT5682_DAC_ADC_DIG_VOL1 0x0100
+#define RT5682_BIAS_CUR_CTRL_2 0x010b
+#define RT5682_BIAS_CUR_CTRL_3 0x010c
+#define RT5682_BIAS_CUR_CTRL_4 0x010d
+#define RT5682_BIAS_CUR_CTRL_5 0x010e
+#define RT5682_BIAS_CUR_CTRL_6 0x010f
+#define RT5682_BIAS_CUR_CTRL_7 0x0110
+#define RT5682_BIAS_CUR_CTRL_8 0x0111
+#define RT5682_BIAS_CUR_CTRL_9 0x0112
+#define RT5682_BIAS_CUR_CTRL_10 0x0113
+#define RT5682_VREF_REC_OP_FB_CAP_CTRL 0x0117
+#define RT5682_CHARGE_PUMP_1 0x0125
+#define RT5682_DIG_IN_CTRL_1 0x0132
+#define RT5682_PAD_DRIVING_CTRL 0x0136
+#define RT5682_SOFT_RAMP_DEPOP 0x0138
+#define RT5682_CHOP_DAC 0x013a
+#define RT5682_CHOP_ADC 0x013b
+#define RT5682_CALIB_ADC_CTRL 0x013c
+#define RT5682_VOL_TEST 0x013f
+#define RT5682_SPKVDD_DET_STA 0x0142
+#define RT5682_TEST_MODE_CTRL_1 0x0145
+#define RT5682_TEST_MODE_CTRL_2 0x0146
+#define RT5682_TEST_MODE_CTRL_3 0x0147
+#define RT5682_TEST_MODE_CTRL_4 0x0148
+#define RT5682_TEST_MODE_CTRL_5 0x0149
+#define RT5682_PLL1_INTERNAL 0x0150
+#define RT5682_PLL2_INTERNAL 0x0151
+#define RT5682_STO_NG2_CTRL_1 0x0160
+#define RT5682_STO_NG2_CTRL_2 0x0161
+#define RT5682_STO_NG2_CTRL_3 0x0162
+#define RT5682_STO_NG2_CTRL_4 0x0163
+#define RT5682_STO_NG2_CTRL_5 0x0164
+#define RT5682_STO_NG2_CTRL_6 0x0165
+#define RT5682_STO_NG2_CTRL_7 0x0166
+#define RT5682_STO_NG2_CTRL_8 0x0167
+#define RT5682_STO_NG2_CTRL_9 0x0168
+#define RT5682_STO_NG2_CTRL_10 0x0169
+#define RT5682_STO1_DAC_SIL_DET 0x0190
+#define RT5682_SIL_PSV_CTRL1 0x0194
+#define RT5682_SIL_PSV_CTRL2 0x0195
+#define RT5682_SIL_PSV_CTRL3 0x0197
+#define RT5682_SIL_PSV_CTRL4 0x0198
+#define RT5682_SIL_PSV_CTRL5 0x0199
+#define RT5682_HP_IMP_SENS_CTRL_01 0x01af
+#define RT5682_HP_IMP_SENS_CTRL_02 0x01b0
+#define RT5682_HP_IMP_SENS_CTRL_03 0x01b1
+#define RT5682_HP_IMP_SENS_CTRL_04 0x01b2
+#define RT5682_HP_IMP_SENS_CTRL_05 0x01b3
+#define RT5682_HP_IMP_SENS_CTRL_06 0x01b4
+#define RT5682_HP_IMP_SENS_CTRL_07 0x01b5
+#define RT5682_HP_IMP_SENS_CTRL_08 0x01b6
+#define RT5682_HP_IMP_SENS_CTRL_09 0x01b7
+#define RT5682_HP_IMP_SENS_CTRL_10 0x01b8
+#define RT5682_HP_IMP_SENS_CTRL_11 0x01b9
+#define RT5682_HP_IMP_SENS_CTRL_12 0x01ba
+#define RT5682_HP_IMP_SENS_CTRL_13 0x01bb
+#define RT5682_HP_IMP_SENS_CTRL_14 0x01bc
+#define RT5682_HP_IMP_SENS_CTRL_15 0x01bd
+#define RT5682_HP_IMP_SENS_CTRL_16 0x01be
+#define RT5682_HP_IMP_SENS_CTRL_17 0x01bf
+#define RT5682_HP_IMP_SENS_CTRL_18 0x01c0
+#define RT5682_HP_IMP_SENS_CTRL_19 0x01c1
+#define RT5682_HP_IMP_SENS_CTRL_20 0x01c2
+#define RT5682_HP_IMP_SENS_CTRL_21 0x01c3
+#define RT5682_HP_IMP_SENS_CTRL_22 0x01c4
+#define RT5682_HP_IMP_SENS_CTRL_23 0x01c5
+#define RT5682_HP_IMP_SENS_CTRL_24 0x01c6
+#define RT5682_HP_IMP_SENS_CTRL_25 0x01c7
+#define RT5682_HP_IMP_SENS_CTRL_26 0x01c8
+#define RT5682_HP_IMP_SENS_CTRL_27 0x01c9
+#define RT5682_HP_IMP_SENS_CTRL_28 0x01ca
+#define RT5682_HP_IMP_SENS_CTRL_29 0x01cb
+#define RT5682_HP_IMP_SENS_CTRL_30 0x01cc
+#define RT5682_HP_IMP_SENS_CTRL_31 0x01cd
+#define RT5682_HP_IMP_SENS_CTRL_32 0x01ce
+#define RT5682_HP_IMP_SENS_CTRL_33 0x01cf
+#define RT5682_HP_IMP_SENS_CTRL_34 0x01d0
+#define RT5682_HP_IMP_SENS_CTRL_35 0x01d1
+#define RT5682_HP_IMP_SENS_CTRL_36 0x01d2
+#define RT5682_HP_IMP_SENS_CTRL_37 0x01d3
+#define RT5682_HP_IMP_SENS_CTRL_38 0x01d4
+#define RT5682_HP_IMP_SENS_CTRL_39 0x01d5
+#define RT5682_HP_IMP_SENS_CTRL_40 0x01d6
+#define RT5682_HP_IMP_SENS_CTRL_41 0x01d7
+#define RT5682_HP_IMP_SENS_CTRL_42 0x01d8
+#define RT5682_HP_IMP_SENS_CTRL_43 0x01d9
+#define RT5682_HP_LOGIC_CTRL_1 0x01da
+#define RT5682_HP_LOGIC_CTRL_2 0x01db
+#define RT5682_HP_LOGIC_CTRL_3 0x01dc
+#define RT5682_HP_CALIB_CTRL_1 0x01de
+#define RT5682_HP_CALIB_CTRL_2 0x01df
+#define RT5682_HP_CALIB_CTRL_3 0x01e0
+#define RT5682_HP_CALIB_CTRL_4 0x01e1
+#define RT5682_HP_CALIB_CTRL_5 0x01e2
+#define RT5682_HP_CALIB_CTRL_6 0x01e3
+#define RT5682_HP_CALIB_CTRL_7 0x01e4
+#define RT5682_HP_CALIB_CTRL_9 0x01e6
+#define RT5682_HP_CALIB_CTRL_10 0x01e7
+#define RT5682_HP_CALIB_CTRL_11 0x01e8
+#define RT5682_HP_CALIB_STA_1 0x01ea
+#define RT5682_HP_CALIB_STA_2 0x01eb
+#define RT5682_HP_CALIB_STA_3 0x01ec
+#define RT5682_HP_CALIB_STA_4 0x01ed
+#define RT5682_HP_CALIB_STA_5 0x01ee
+#define RT5682_HP_CALIB_STA_6 0x01ef
+#define RT5682_HP_CALIB_STA_7 0x01f0
+#define RT5682_HP_CALIB_STA_8 0x01f1
+#define RT5682_HP_CALIB_STA_9 0x01f2
+#define RT5682_HP_CALIB_STA_10 0x01f3
+#define RT5682_HP_CALIB_STA_11 0x01f4
+#define RT5682_SAR_IL_CMD_1 0x0210
+#define RT5682_SAR_IL_CMD_2 0x0211
+#define RT5682_SAR_IL_CMD_3 0x0212
+#define RT5682_SAR_IL_CMD_4 0x0213
+#define RT5682_SAR_IL_CMD_5 0x0214
+#define RT5682_SAR_IL_CMD_6 0x0215
+#define RT5682_SAR_IL_CMD_7 0x0216
+#define RT5682_SAR_IL_CMD_8 0x0217
+#define RT5682_SAR_IL_CMD_9 0x0218
+#define RT5682_SAR_IL_CMD_10 0x0219
+#define RT5682_SAR_IL_CMD_11 0x021a
+#define RT5682_SAR_IL_CMD_12 0x021b
+#define RT5682_SAR_IL_CMD_13 0x021c
+#define RT5682_EFUSE_CTRL_1 0x0250
+#define RT5682_EFUSE_CTRL_2 0x0251
+#define RT5682_EFUSE_CTRL_3 0x0252
+#define RT5682_EFUSE_CTRL_4 0x0253
+#define RT5682_EFUSE_CTRL_5 0x0254
+#define RT5682_EFUSE_CTRL_6 0x0255
+#define RT5682_EFUSE_CTRL_7 0x0256
+#define RT5682_EFUSE_CTRL_8 0x0257
+#define RT5682_EFUSE_CTRL_9 0x0258
+#define RT5682_EFUSE_CTRL_10 0x0259
+#define RT5682_EFUSE_CTRL_11 0x025a
+#define RT5682_JD_TOP_VC_VTRL 0x0270
+#define RT5682_DRC1_CTRL_0 0x02ff
+#define RT5682_DRC1_CTRL_1 0x0300
+#define RT5682_DRC1_CTRL_2 0x0301
+#define RT5682_DRC1_CTRL_3 0x0302
+#define RT5682_DRC1_CTRL_4 0x0303
+#define RT5682_DRC1_CTRL_5 0x0304
+#define RT5682_DRC1_CTRL_6 0x0305
+#define RT5682_DRC1_HARD_LMT_CTRL_1 0x0306
+#define RT5682_DRC1_HARD_LMT_CTRL_2 0x0307
+#define RT5682_DRC1_PRIV_1 0x0310
+#define RT5682_DRC1_PRIV_2 0x0311
+#define RT5682_DRC1_PRIV_3 0x0312
+#define RT5682_DRC1_PRIV_4 0x0313
+#define RT5682_DRC1_PRIV_5 0x0314
+#define RT5682_DRC1_PRIV_6 0x0315
+#define RT5682_DRC1_PRIV_7 0x0316
+#define RT5682_DRC1_PRIV_8 0x0317
+#define RT5682_EQ_AUTO_RCV_CTRL1 0x03c0
+#define RT5682_EQ_AUTO_RCV_CTRL2 0x03c1
+#define RT5682_EQ_AUTO_RCV_CTRL3 0x03c2
+#define RT5682_EQ_AUTO_RCV_CTRL4 0x03c3
+#define RT5682_EQ_AUTO_RCV_CTRL5 0x03c4
+#define RT5682_EQ_AUTO_RCV_CTRL6 0x03c5
+#define RT5682_EQ_AUTO_RCV_CTRL7 0x03c6
+#define RT5682_EQ_AUTO_RCV_CTRL8 0x03c7
+#define RT5682_EQ_AUTO_RCV_CTRL9 0x03c8
+#define RT5682_EQ_AUTO_RCV_CTRL10 0x03c9
+#define RT5682_EQ_AUTO_RCV_CTRL11 0x03ca
+#define RT5682_EQ_AUTO_RCV_CTRL12 0x03cb
+#define RT5682_EQ_AUTO_RCV_CTRL13 0x03cc
+#define RT5682_ADC_L_EQ_LPF1_A1 0x03d0
+#define RT5682_R_EQ_LPF1_A1 0x03d1
+#define RT5682_L_EQ_LPF1_H0 0x03d2
+#define RT5682_R_EQ_LPF1_H0 0x03d3
+#define RT5682_L_EQ_BPF1_A1 0x03d4
+#define RT5682_R_EQ_BPF1_A1 0x03d5
+#define RT5682_L_EQ_BPF1_A2 0x03d6
+#define RT5682_R_EQ_BPF1_A2 0x03d7
+#define RT5682_L_EQ_BPF1_H0 0x03d8
+#define RT5682_R_EQ_BPF1_H0 0x03d9
+#define RT5682_L_EQ_BPF2_A1 0x03da
+#define RT5682_R_EQ_BPF2_A1 0x03db
+#define RT5682_L_EQ_BPF2_A2 0x03dc
+#define RT5682_R_EQ_BPF2_A2 0x03dd
+#define RT5682_L_EQ_BPF2_H0 0x03de
+#define RT5682_R_EQ_BPF2_H0 0x03df
+#define RT5682_L_EQ_BPF3_A1 0x03e0
+#define RT5682_R_EQ_BPF3_A1 0x03e1
+#define RT5682_L_EQ_BPF3_A2 0x03e2
+#define RT5682_R_EQ_BPF3_A2 0x03e3
+#define RT5682_L_EQ_BPF3_H0 0x03e4
+#define RT5682_R_EQ_BPF3_H0 0x03e5
+#define RT5682_L_EQ_BPF4_A1 0x03e6
+#define RT5682_R_EQ_BPF4_A1 0x03e7
+#define RT5682_L_EQ_BPF4_A2 0x03e8
+#define RT5682_R_EQ_BPF4_A2 0x03e9
+#define RT5682_L_EQ_BPF4_H0 0x03ea
+#define RT5682_R_EQ_BPF4_H0 0x03eb
+#define RT5682_L_EQ_HPF1_A1 0x03ec
+#define RT5682_R_EQ_HPF1_A1 0x03ed
+#define RT5682_L_EQ_HPF1_H0 0x03ee
+#define RT5682_R_EQ_HPF1_H0 0x03ef
+#define RT5682_L_EQ_PRE_VOL 0x03f0
+#define RT5682_R_EQ_PRE_VOL 0x03f1
+#define RT5682_L_EQ_POST_VOL 0x03f2
+#define RT5682_R_EQ_POST_VOL 0x03f3
+#define RT5682_I2C_MODE 0xffff
+
+
+/* global definition */
+#define RT5682_L_MUTE (0x1 << 15)
+#define RT5682_L_MUTE_SFT 15
+#define RT5682_VOL_L_MUTE (0x1 << 14)
+#define RT5682_VOL_L_SFT 14
+#define RT5682_R_MUTE (0x1 << 7)
+#define RT5682_R_MUTE_SFT 7
+#define RT5682_VOL_R_MUTE (0x1 << 6)
+#define RT5682_VOL_R_SFT 6
+#define RT5682_L_VOL_MASK (0x3f << 8)
+#define RT5682_L_VOL_SFT 8
+#define RT5682_R_VOL_MASK (0x3f)
+#define RT5682_R_VOL_SFT 0
+
+/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/
+#define RT5682_G_HP (0xf << 8)
+#define RT5682_G_HP_SFT 8
+#define RT5682_G_STO_DA_DMIX (0xf)
+#define RT5682_G_STO_DA_SFT 0
+
+/* CBJ Control (0x000b) */
+#define RT5682_BST_CBJ_MASK (0xf << 8)
+#define RT5682_BST_CBJ_SFT 8
+
+/* Embeeded Jack and Type Detection Control 1 (0x0010) */
+#define RT5682_EMB_JD_EN (0x1 << 15)
+#define RT5682_EMB_JD_EN_SFT 15
+#define RT5682_EMB_JD_RST (0x1 << 14)
+#define RT5682_JD_MODE (0x1 << 13)
+#define RT5682_JD_MODE_SFT 13
+#define RT5682_DET_TYPE (0x1 << 12)
+#define RT5682_DET_TYPE_SFT 12
+#define RT5682_POLA_EXT_JD_MASK (0x1 << 11)
+#define RT5682_POLA_EXT_JD_LOW (0x1 << 11)
+#define RT5682_POLA_EXT_JD_HIGH (0x0 << 11)
+#define RT5682_EXT_JD_DIG (0x1 << 9)
+#define RT5682_POL_FAST_OFF_MASK (0x1 << 8)
+#define RT5682_POL_FAST_OFF_HIGH (0x1 << 8)
+#define RT5682_POL_FAST_OFF_LOW (0x0 << 8)
+#define RT5682_FAST_OFF_MASK (0x1 << 7)
+#define RT5682_FAST_OFF_EN (0x1 << 7)
+#define RT5682_FAST_OFF_DIS (0x0 << 7)
+#define RT5682_VREF_POW_MASK (0x1 << 6)
+#define RT5682_VREF_POW_FSM (0x0 << 6)
+#define RT5682_VREF_POW_REG (0x1 << 6)
+#define RT5682_MB1_PATH_MASK (0x1 << 5)
+#define RT5682_CTRL_MB1_REG (0x1 << 5)
+#define RT5682_CTRL_MB1_FSM (0x0 << 5)
+#define RT5682_MB2_PATH_MASK (0x1 << 4)
+#define RT5682_CTRL_MB2_REG (0x1 << 4)
+#define RT5682_CTRL_MB2_FSM (0x0 << 4)
+#define RT5682_TRIG_JD_MASK (0x1 << 3)
+#define RT5682_TRIG_JD_HIGH (0x1 << 3)
+#define RT5682_TRIG_JD_LOW (0x0 << 3)
+#define RT5682_MIC_CAP_MASK (0x1 << 1)
+#define RT5682_MIC_CAP_HS (0x1 << 1)
+#define RT5682_MIC_CAP_HP (0x0 << 1)
+#define RT5682_MIC_CAP_SRC_MASK (0x1)
+#define RT5682_MIC_CAP_SRC_REG (0x1)
+#define RT5682_MIC_CAP_SRC_ANA (0x0)
+
+/* Embeeded Jack and Type Detection Control 2 (0x0011) */
+#define RT5682_EXT_JD_SRC (0x7 << 4)
+#define RT5682_EXT_JD_SRC_SFT 4
+#define RT5682_EXT_JD_SRC_GPIO_JD1 (0x0 << 4)
+#define RT5682_EXT_JD_SRC_GPIO_JD2 (0x1 << 4)
+#define RT5682_EXT_JD_SRC_JDH (0x2 << 4)
+#define RT5682_EXT_JD_SRC_JDL (0x3 << 4)
+#define RT5682_EXT_JD_SRC_MANUAL (0x4 << 4)
+#define RT5682_JACK_TYPE_MASK (0x3)
+
+/* Combo Jack and Type Detection Control 3 (0x0012) */
+#define RT5682_CBJ_IN_BUF_EN (0x1 << 7)
+
+/* Combo Jack and Type Detection Control 4 (0x0013) */
+#define RT5682_SEL_SHT_MID_TON_MASK (0x3 << 12)
+#define RT5682_SEL_SHT_MID_TON_2 (0x0 << 12)
+#define RT5682_SEL_SHT_MID_TON_3 (0x1 << 12)
+#define RT5682_CBJ_JD_TEST_MASK (0x1 << 6)
+#define RT5682_CBJ_JD_TEST_NORM (0x0 << 6)
+#define RT5682_CBJ_JD_TEST_MODE (0x1 << 6)
+
+/* DAC1 Digital Volume (0x0019) */
+#define RT5682_DAC_L1_VOL_MASK (0xff << 8)
+#define RT5682_DAC_L1_VOL_SFT 8
+#define RT5682_DAC_R1_VOL_MASK (0xff)
+#define RT5682_DAC_R1_VOL_SFT 0
+
+/* ADC Digital Volume Control (0x001c) */
+#define RT5682_ADC_L_VOL_MASK (0x7f << 8)
+#define RT5682_ADC_L_VOL_SFT 8
+#define RT5682_ADC_R_VOL_MASK (0x7f)
+#define RT5682_ADC_R_VOL_SFT 0
+
+/* Stereo1 ADC Boost Gain Control (0x001f) */
+#define RT5682_STO1_ADC_L_BST_MASK (0x3 << 14)
+#define RT5682_STO1_ADC_L_BST_SFT 14
+#define RT5682_STO1_ADC_R_BST_MASK (0x3 << 12)
+#define RT5682_STO1_ADC_R_BST_SFT 12
+
+/* Sidetone Control (0x0024) */
+#define RT5682_ST_SRC_SEL (0x1 << 8)
+#define RT5682_ST_SRC_SFT 8
+#define RT5682_ST_EN_MASK (0x1 << 6)
+#define RT5682_ST_DIS (0x0 << 6)
+#define RT5682_ST_EN (0x1 << 6)
+#define RT5682_ST_EN_SFT 6
+
+/* Stereo1 ADC Mixer Control (0x0026) */
+#define RT5682_M_STO1_ADC_L1 (0x1 << 15)
+#define RT5682_M_STO1_ADC_L1_SFT 15
+#define RT5682_M_STO1_ADC_L2 (0x1 << 14)
+#define RT5682_M_STO1_ADC_L2_SFT 14
+#define RT5682_STO1_ADC1L_SRC_MASK (0x1 << 13)
+#define RT5682_STO1_ADC1L_SRC_SFT 13
+#define RT5682_STO1_ADC1_SRC_ADC (0x1 << 13)
+#define RT5682_STO1_ADC1_SRC_DACMIX (0x0 << 13)
+#define RT5682_STO1_ADC2L_SRC_MASK (0x1 << 12)
+#define RT5682_STO1_ADC2L_SRC_SFT 12
+#define RT5682_STO1_ADCL_SRC_MASK (0x3 << 10)
+#define RT5682_STO1_ADCL_SRC_SFT 10
+#define RT5682_STO1_DD_L_SRC_MASK (0x1 << 9)
+#define RT5682_STO1_DD_L_SRC_SFT 9
+#define RT5682_STO1_DMIC_SRC_MASK (0x1 << 8)
+#define RT5682_STO1_DMIC_SRC_SFT 8
+#define RT5682_STO1_DMIC_SRC_DMIC2 (0x1 << 8)
+#define RT5682_STO1_DMIC_SRC_DMIC1 (0x0 << 8)
+#define RT5682_M_STO1_ADC_R1 (0x1 << 7)
+#define RT5682_M_STO1_ADC_R1_SFT 7
+#define RT5682_M_STO1_ADC_R2 (0x1 << 6)
+#define RT5682_M_STO1_ADC_R2_SFT 6
+#define RT5682_STO1_ADC1R_SRC_MASK (0x1 << 5)
+#define RT5682_STO1_ADC1R_SRC_SFT 5
+#define RT5682_STO1_ADC2R_SRC_MASK (0x1 << 4)
+#define RT5682_STO1_ADC2R_SRC_SFT 4
+#define RT5682_STO1_ADCR_SRC_MASK (0x3 << 2)
+#define RT5682_STO1_ADCR_SRC_SFT 2
+
+/* ADC Mixer to DAC Mixer Control (0x0029) */
+#define RT5682_M_ADCMIX_L (0x1 << 15)
+#define RT5682_M_ADCMIX_L_SFT 15
+#define RT5682_M_DAC1_L (0x1 << 14)
+#define RT5682_M_DAC1_L_SFT 14
+#define RT5682_DAC1_R_SEL_MASK (0x1 << 10)
+#define RT5682_DAC1_R_SEL_SFT 10
+#define RT5682_DAC1_L_SEL_MASK (0x1 << 8)
+#define RT5682_DAC1_L_SEL_SFT 8
+#define RT5682_M_ADCMIX_R (0x1 << 7)
+#define RT5682_M_ADCMIX_R_SFT 7
+#define RT5682_M_DAC1_R (0x1 << 6)
+#define RT5682_M_DAC1_R_SFT 6
+
+/* Stereo1 DAC Mixer Control (0x002a) */
+#define RT5682_M_DAC_L1_STO_L (0x1 << 15)
+#define RT5682_M_DAC_L1_STO_L_SFT 15
+#define RT5682_G_DAC_L1_STO_L_MASK (0x1 << 14)
+#define RT5682_G_DAC_L1_STO_L_SFT 14
+#define RT5682_M_DAC_R1_STO_L (0x1 << 13)
+#define RT5682_M_DAC_R1_STO_L_SFT 13
+#define RT5682_G_DAC_R1_STO_L_MASK (0x1 << 12)
+#define RT5682_G_DAC_R1_STO_L_SFT 12
+#define RT5682_M_DAC_L1_STO_R (0x1 << 7)
+#define RT5682_M_DAC_L1_STO_R_SFT 7
+#define RT5682_G_DAC_L1_STO_R_MASK (0x1 << 6)
+#define RT5682_G_DAC_L1_STO_R_SFT 6
+#define RT5682_M_DAC_R1_STO_R (0x1 << 5)
+#define RT5682_M_DAC_R1_STO_R_SFT 5
+#define RT5682_G_DAC_R1_STO_R_MASK (0x1 << 4)
+#define RT5682_G_DAC_R1_STO_R_SFT 4
+
+/* Analog DAC1 Input Source Control (0x002b) */
+#define RT5682_M_ST_STO_L (0x1 << 9)
+#define RT5682_M_ST_STO_L_SFT 9
+#define RT5682_M_ST_STO_R (0x1 << 8)
+#define RT5682_M_ST_STO_R_SFT 8
+#define RT5682_DAC_L1_SRC_MASK (0x3 << 4)
+#define RT5682_A_DACL1_SFT 4
+#define RT5682_DAC_R1_SRC_MASK (0x3)
+#define RT5682_A_DACR1_SFT 0
+
+/* Digital Interface Data Control (0x0030) */
+#define RT5682_IF2_ADC_SEL_MASK (0x3 << 0)
+#define RT5682_IF2_ADC_SEL_SFT 0
+
+/* REC Left Mixer Control 2 (0x003c) */
+#define RT5682_G_CBJ_RM1_L (0x7 << 10)
+#define RT5682_G_CBJ_RM1_L_SFT 10
+#define RT5682_M_CBJ_RM1_L (0x1 << 7)
+#define RT5682_M_CBJ_RM1_L_SFT 7
+
+/* Power Management for Digital 1 (0x0061) */
+#define RT5682_PWR_I2S1 (0x1 << 15)
+#define RT5682_PWR_I2S1_BIT 15
+#define RT5682_PWR_I2S2 (0x1 << 14)
+#define RT5682_PWR_I2S2_BIT 14
+#define RT5682_PWR_DAC_L1 (0x1 << 11)
+#define RT5682_PWR_DAC_L1_BIT 11
+#define RT5682_PWR_DAC_R1 (0x1 << 10)
+#define RT5682_PWR_DAC_R1_BIT 10
+#define RT5682_PWR_LDO (0x1 << 8)
+#define RT5682_PWR_LDO_BIT 8
+#define RT5682_PWR_ADC_L1 (0x1 << 4)
+#define RT5682_PWR_ADC_L1_BIT 4
+#define RT5682_PWR_ADC_R1 (0x1 << 3)
+#define RT5682_PWR_ADC_R1_BIT 3
+#define RT5682_DIG_GATE_CTRL (0x1 << 0)
+#define RT5682_DIG_GATE_CTRL_SFT 0
+
+
+/* Power Management for Digital 2 (0x0062) */
+#define RT5682_PWR_ADC_S1F (0x1 << 15)
+#define RT5682_PWR_ADC_S1F_BIT 15
+#define RT5682_PWR_DAC_S1F (0x1 << 10)
+#define RT5682_PWR_DAC_S1F_BIT 10
+
+/* Power Management for Analog 1 (0x0063) */
+#define RT5682_PWR_VREF1 (0x1 << 15)
+#define RT5682_PWR_VREF1_BIT 15
+#define RT5682_PWR_FV1 (0x1 << 14)
+#define RT5682_PWR_FV1_BIT 14
+#define RT5682_PWR_VREF2 (0x1 << 13)
+#define RT5682_PWR_VREF2_BIT 13
+#define RT5682_PWR_FV2 (0x1 << 12)
+#define RT5682_PWR_FV2_BIT 12
+#define RT5682_LDO1_DBG_MASK (0x3 << 10)
+#define RT5682_PWR_MB (0x1 << 9)
+#define RT5682_PWR_MB_BIT 9
+#define RT5682_PWR_BG (0x1 << 7)
+#define RT5682_PWR_BG_BIT 7
+#define RT5682_LDO1_BYPASS_MASK (0x1 << 6)
+#define RT5682_LDO1_BYPASS (0x1 << 6)
+#define RT5682_LDO1_NOT_BYPASS (0x0 << 6)
+#define RT5682_PWR_MA_BIT 6
+#define RT5682_LDO1_DVO_MASK (0x3 << 4)
+#define RT5682_LDO1_DVO_09 (0x0 << 4)
+#define RT5682_LDO1_DVO_10 (0x1 << 4)
+#define RT5682_LDO1_DVO_12 (0x2 << 4)
+#define RT5682_LDO1_DVO_14 (0x3 << 4)
+#define RT5682_HP_DRIVER_MASK (0x3 << 2)
+#define RT5682_HP_DRIVER_1X (0x0 << 2)
+#define RT5682_HP_DRIVER_3X (0x1 << 2)
+#define RT5682_HP_DRIVER_5X (0x3 << 2)
+#define RT5682_PWR_HA_L (0x1 << 1)
+#define RT5682_PWR_HA_L_BIT 1
+#define RT5682_PWR_HA_R (0x1 << 0)
+#define RT5682_PWR_HA_R_BIT 0
+
+/* Power Management for Analog 2 (0x0064) */
+#define RT5682_PWR_MB1 (0x1 << 11)
+#define RT5682_PWR_MB1_PWR_DOWN (0x0 << 11)
+#define RT5682_PWR_MB1_BIT 11
+#define RT5682_PWR_MB2 (0x1 << 10)
+#define RT5682_PWR_MB2_PWR_DOWN (0x0 << 10)
+#define RT5682_PWR_MB2_BIT 10
+#define RT5682_PWR_JDH (0x1 << 3)
+#define RT5682_PWR_JDH_BIT 3
+#define RT5682_PWR_JDL (0x1 << 2)
+#define RT5682_PWR_JDL_BIT 2
+#define RT5682_PWR_RM1_L (0x1 << 1)
+#define RT5682_PWR_RM1_L_BIT 1
+
+/* Power Management for Analog 3 (0x0065) */
+#define RT5682_PWR_CBJ (0x1 << 9)
+#define RT5682_PWR_CBJ_BIT 9
+#define RT5682_PWR_PLL (0x1 << 6)
+#define RT5682_PWR_PLL_BIT 6
+#define RT5682_PWR_PLL2B (0x1 << 5)
+#define RT5682_PWR_PLL2B_BIT 5
+#define RT5682_PWR_PLL2F (0x1 << 4)
+#define RT5682_PWR_PLL2F_BIT 4
+#define RT5682_PWR_LDO2 (0x1 << 2)
+#define RT5682_PWR_LDO2_BIT 2
+#define RT5682_PWR_DET_SPKVDD (0x1 << 1)
+#define RT5682_PWR_DET_SPKVDD_BIT 1
+
+/* Power Management for Mixer (0x0066) */
+#define RT5682_PWR_STO1_DAC_L (0x1 << 5)
+#define RT5682_PWR_STO1_DAC_L_BIT 5
+#define RT5682_PWR_STO1_DAC_R (0x1 << 4)
+#define RT5682_PWR_STO1_DAC_R_BIT 4
+
+/* MCLK and System Clock Detection Control (0x006b) */
+#define RT5682_SYS_CLK_DET (0x1 << 15)
+#define RT5682_SYS_CLK_DET_SFT 15
+#define RT5682_PLL1_CLK_DET (0x1 << 14)
+#define RT5682_PLL1_CLK_DET_SFT 14
+#define RT5682_PLL2_CLK_DET (0x1 << 13)
+#define RT5682_PLL2_CLK_DET_SFT 13
+#define RT5682_POW_CLK_DET2_SFT 8
+#define RT5682_POW_CLK_DET_SFT 0
+
+/* Digital Microphone Control 1 (0x006e) */
+#define RT5682_DMIC_1_EN_MASK (0x1 << 15)
+#define RT5682_DMIC_1_EN_SFT 15
+#define RT5682_DMIC_1_DIS (0x0 << 15)
+#define RT5682_DMIC_1_EN (0x1 << 15)
+#define RT5682_DMIC_1_DP_MASK (0x3 << 4)
+#define RT5682_DMIC_1_DP_SFT 4
+#define RT5682_DMIC_1_DP_GPIO2 (0x0 << 4)
+#define RT5682_DMIC_1_DP_GPIO5 (0x1 << 4)
+#define RT5682_DMIC_CLK_MASK (0xf << 0)
+#define RT5682_DMIC_CLK_SFT 0
+
+/* I2S1 Audio Serial Data Port Control (0x0070) */
+#define RT5682_SEL_ADCDAT_MASK (0x1 << 15)
+#define RT5682_SEL_ADCDAT_OUT (0x0 << 15)
+#define RT5682_SEL_ADCDAT_IN (0x1 << 15)
+#define RT5682_SEL_ADCDAT_SFT 15
+#define RT5682_I2S1_TX_CHL_MASK (0x7 << 12)
+#define RT5682_I2S1_TX_CHL_SFT 12
+#define RT5682_I2S1_TX_CHL_16 (0x0 << 12)
+#define RT5682_I2S1_TX_CHL_20 (0x1 << 12)
+#define RT5682_I2S1_TX_CHL_24 (0x2 << 12)
+#define RT5682_I2S1_TX_CHL_32 (0x3 << 12)
+#define RT5682_I2S1_TX_CHL_8 (0x4 << 12)
+#define RT5682_I2S1_RX_CHL_MASK (0x7 << 8)
+#define RT5682_I2S1_RX_CHL_SFT 8
+#define RT5682_I2S1_RX_CHL_16 (0x0 << 8)
+#define RT5682_I2S1_RX_CHL_20 (0x1 << 8)
+#define RT5682_I2S1_RX_CHL_24 (0x2 << 8)
+#define RT5682_I2S1_RX_CHL_32 (0x3 << 8)
+#define RT5682_I2S1_RX_CHL_8 (0x4 << 8)
+#define RT5682_I2S1_MONO_MASK (0x1 << 7)
+#define RT5682_I2S1_MONO_EN (0x1 << 7)
+#define RT5682_I2S1_MONO_DIS (0x0 << 7)
+#define RT5682_I2S2_MONO_MASK (0x1 << 6)
+#define RT5682_I2S2_MONO_EN (0x1 << 6)
+#define RT5682_I2S2_MONO_DIS (0x0 << 6)
+#define RT5682_I2S1_DL_MASK (0x7 << 4)
+#define RT5682_I2S1_DL_SFT 4
+#define RT5682_I2S1_DL_16 (0x0 << 4)
+#define RT5682_I2S1_DL_20 (0x1 << 4)
+#define RT5682_I2S1_DL_24 (0x2 << 4)
+#define RT5682_I2S1_DL_32 (0x3 << 4)
+#define RT5682_I2S1_DL_8 (0x4 << 4)
+
+/* I2S1/2 Audio Serial Data Port Control (0x0070)(0x0071) */
+#define RT5682_I2S2_MS_MASK (0x1 << 15)
+#define RT5682_I2S2_MS_SFT 15
+#define RT5682_I2S2_MS_M (0x0 << 15)
+#define RT5682_I2S2_MS_S (0x1 << 15)
+#define RT5682_I2S2_PIN_CFG_MASK (0x1 << 14)
+#define RT5682_I2S2_PIN_CFG_SFT 14
+#define RT5682_I2S2_CLK_SEL_MASK (0x1 << 11)
+#define RT5682_I2S2_CLK_SEL_SFT 11
+#define RT5682_I2S2_OUT_MASK (0x1 << 9)
+#define RT5682_I2S2_OUT_SFT 9
+#define RT5682_I2S2_OUT_UM (0x0 << 9)
+#define RT5682_I2S2_OUT_M (0x1 << 9)
+#define RT5682_I2S_BP_MASK (0x1 << 8)
+#define RT5682_I2S_BP_SFT 8
+#define RT5682_I2S_BP_NOR (0x0 << 8)
+#define RT5682_I2S_BP_INV (0x1 << 8)
+#define RT5682_I2S2_MONO_EN (0x1 << 6)
+#define RT5682_I2S2_MONO_DIS (0x0 << 6)
+#define RT5682_I2S2_DL_MASK (0x3 << 4)
+#define RT5682_I2S2_DL_SFT 4
+#define RT5682_I2S2_DL_16 (0x0 << 4)
+#define RT5682_I2S2_DL_20 (0x1 << 4)
+#define RT5682_I2S2_DL_24 (0x2 << 4)
+#define RT5682_I2S2_DL_8 (0x3 << 4)
+#define RT5682_I2S_DF_MASK (0x7)
+#define RT5682_I2S_DF_SFT 0
+#define RT5682_I2S_DF_I2S (0x0)
+#define RT5682_I2S_DF_LEFT (0x1)
+#define RT5682_I2S_DF_PCM_A (0x2)
+#define RT5682_I2S_DF_PCM_B (0x3)
+#define RT5682_I2S_DF_PCM_A_N (0x6)
+#define RT5682_I2S_DF_PCM_B_N (0x7)
+
+/* ADC/DAC Clock Control 1 (0x0073) */
+#define RT5682_ADC_OSR_MASK (0xf << 12)
+#define RT5682_ADC_OSR_SFT 12
+#define RT5682_ADC_OSR_D_1 (0x0 << 12)
+#define RT5682_ADC_OSR_D_2 (0x1 << 12)
+#define RT5682_ADC_OSR_D_4 (0x2 << 12)
+#define RT5682_ADC_OSR_D_6 (0x3 << 12)
+#define RT5682_ADC_OSR_D_8 (0x4 << 12)
+#define RT5682_ADC_OSR_D_12 (0x5 << 12)
+#define RT5682_ADC_OSR_D_16 (0x6 << 12)
+#define RT5682_ADC_OSR_D_24 (0x7 << 12)
+#define RT5682_ADC_OSR_D_32 (0x8 << 12)
+#define RT5682_ADC_OSR_D_48 (0x9 << 12)
+#define RT5682_I2S_M_DIV_MASK (0xf << 12)
+#define RT5682_I2S_M_DIV_SFT 8
+#define RT5682_I2S_M_D_1 (0x0 << 8)
+#define RT5682_I2S_M_D_2 (0x1 << 8)
+#define RT5682_I2S_M_D_3 (0x2 << 8)
+#define RT5682_I2S_M_D_4 (0x3 << 8)
+#define RT5682_I2S_M_D_6 (0x4 << 8)
+#define RT5682_I2S_M_D_8 (0x5 << 8)
+#define RT5682_I2S_M_D_12 (0x6 << 8)
+#define RT5682_I2S_M_D_16 (0x7 << 8)
+#define RT5682_I2S_M_D_24 (0x8 << 8)
+#define RT5682_I2S_M_D_32 (0x9 << 8)
+#define RT5682_I2S_M_D_48 (0x10 << 8)
+#define RT5682_I2S_CLK_SRC_MASK (0x7 << 4)
+#define RT5682_I2S_CLK_SRC_SFT 4
+#define RT5682_I2S_CLK_SRC_MCLK (0x0 << 4)
+#define RT5682_I2S_CLK_SRC_PLL1 (0x1 << 4)
+#define RT5682_I2S_CLK_SRC_PLL2 (0x2 << 4)
+#define RT5682_I2S_CLK_SRC_SDW (0x3 << 4)
+#define RT5682_I2S_CLK_SRC_RCCLK (0x4 << 4) /* 25M */
+#define RT5682_DAC_OSR_MASK (0xf << 0)
+#define RT5682_DAC_OSR_SFT 0
+#define RT5682_DAC_OSR_D_1 (0x0 << 0)
+#define RT5682_DAC_OSR_D_2 (0x1 << 0)
+#define RT5682_DAC_OSR_D_4 (0x2 << 0)
+#define RT5682_DAC_OSR_D_6 (0x3 << 0)
+#define RT5682_DAC_OSR_D_8 (0x4 << 0)
+#define RT5682_DAC_OSR_D_12 (0x5 << 0)
+#define RT5682_DAC_OSR_D_16 (0x6 << 0)
+#define RT5682_DAC_OSR_D_24 (0x7 << 0)
+#define RT5682_DAC_OSR_D_32 (0x8 << 0)
+#define RT5682_DAC_OSR_D_48 (0x9 << 0)
+
+/* ADC/DAC Clock Control 2 (0x0074) */
+#define RT5682_I2S2_BCLK_MS2_MASK (0x1 << 11)
+#define RT5682_I2S2_BCLK_MS2_SFT 11
+#define RT5682_I2S2_BCLK_MS2_32 (0x0 << 11)
+#define RT5682_I2S2_BCLK_MS2_64 (0x1 << 11)
+
+
+/* TDM control 1 (0x0079) */
+#define RT5682_TDM_TX_CH_MASK (0x3 << 12)
+#define RT5682_TDM_TX_CH_2 (0x0 << 12)
+#define RT5682_TDM_TX_CH_4 (0x1 << 12)
+#define RT5682_TDM_TX_CH_6 (0x2 << 12)
+#define RT5682_TDM_TX_CH_8 (0x3 << 12)
+#define RT5682_TDM_RX_CH_MASK (0x3 << 8)
+#define RT5682_TDM_RX_CH_2 (0x0 << 8)
+#define RT5682_TDM_RX_CH_4 (0x1 << 8)
+#define RT5682_TDM_RX_CH_6 (0x2 << 8)
+#define RT5682_TDM_RX_CH_8 (0x3 << 8)
+#define RT5682_TDM_ADC_LCA_MASK (0xf << 4)
+#define RT5682_TDM_ADC_LCA_SFT 4
+#define RT5682_TDM_ADC_DL_SFT 0
+
+/* TDM control 2 (0x007a) */
+#define RT5682_IF1_ADC1_SEL_SFT 14
+#define RT5682_IF1_ADC2_SEL_SFT 12
+#define RT5682_IF1_ADC3_SEL_SFT 10
+#define RT5682_IF1_ADC4_SEL_SFT 8
+#define RT5682_TDM_ADC_SEL_SFT 4
+
+/* TDM control 3 (0x007b) */
+#define RT5682_TDM_EN (0x1 << 7)
+
+/* TDM/I2S control (0x007e) */
+#define RT5682_TDM_S_BP_MASK (0x1 << 15)
+#define RT5682_TDM_S_BP_SFT 15
+#define RT5682_TDM_S_BP_NOR (0x0 << 15)
+#define RT5682_TDM_S_BP_INV (0x1 << 15)
+#define RT5682_TDM_S_LP_MASK (0x1 << 14)
+#define RT5682_TDM_S_LP_SFT 14
+#define RT5682_TDM_S_LP_NOR (0x0 << 14)
+#define RT5682_TDM_S_LP_INV (0x1 << 14)
+#define RT5682_TDM_DF_MASK (0x7 << 11)
+#define RT5682_TDM_DF_SFT 11
+#define RT5682_TDM_DF_I2S (0x0 << 11)
+#define RT5682_TDM_DF_LEFT (0x1 << 11)
+#define RT5682_TDM_DF_PCM_A (0x2 << 11)
+#define RT5682_TDM_DF_PCM_B (0x3 << 11)
+#define RT5682_TDM_DF_PCM_A_N (0x6 << 11)
+#define RT5682_TDM_DF_PCM_B_N (0x7 << 11)
+#define RT5682_TDM_CL_MASK (0x3 << 4)
+#define RT5682_TDM_CL_16 (0x0 << 4)
+#define RT5682_TDM_CL_20 (0x1 << 4)
+#define RT5682_TDM_CL_24 (0x2 << 4)
+#define RT5682_TDM_CL_32 (0x3 << 4)
+#define RT5682_TDM_M_BP_MASK (0x1 << 2)
+#define RT5682_TDM_M_BP_SFT 2
+#define RT5682_TDM_M_BP_NOR (0x0 << 2)
+#define RT5682_TDM_M_BP_INV (0x1 << 2)
+#define RT5682_TDM_M_LP_MASK (0x1 << 1)
+#define RT5682_TDM_M_LP_SFT 1
+#define RT5682_TDM_M_LP_NOR (0x0 << 1)
+#define RT5682_TDM_M_LP_INV (0x1 << 1)
+#define RT5682_TDM_MS_MASK (0x1 << 0)
+#define RT5682_TDM_MS_SFT 0
+#define RT5682_TDM_MS_M (0x0 << 0)
+#define RT5682_TDM_MS_S (0x1 << 0)
+
+/* Global Clock Control (0x0080) */
+#define RT5682_SCLK_SRC_MASK (0x7 << 13)
+#define RT5682_SCLK_SRC_SFT 13
+#define RT5682_SCLK_SRC_MCLK (0x0 << 13)
+#define RT5682_SCLK_SRC_PLL1 (0x1 << 13)
+#define RT5682_SCLK_SRC_PLL2 (0x2 << 13)
+#define RT5682_SCLK_SRC_SDW (0x3 << 13)
+#define RT5682_SCLK_SRC_RCCLK (0x4 << 13)
+#define RT5682_PLL1_SRC_MASK (0x3 << 10)
+#define RT5682_PLL1_SRC_SFT 10
+#define RT5682_PLL1_SRC_MCLK (0x0 << 10)
+#define RT5682_PLL1_SRC_BCLK1 (0x1 << 10)
+#define RT5682_PLL1_SRC_SDW (0x2 << 10)
+#define RT5682_PLL1_SRC_RC (0x3 << 10)
+#define RT5682_PLL2_SRC_MASK (0x3 << 8)
+#define RT5682_PLL2_SRC_SFT 8
+#define RT5682_PLL2_SRC_MCLK (0x0 << 8)
+#define RT5682_PLL2_SRC_BCLK1 (0x1 << 8)
+#define RT5682_PLL2_SRC_SDW (0x2 << 8)
+#define RT5682_PLL2_SRC_RC (0x3 << 8)
+
+
+
+#define RT5682_PLL_INP_MAX 40000000
+#define RT5682_PLL_INP_MIN 256000
+/* PLL M/N/K Code Control 1 (0x0081) */
+#define RT5682_PLL_N_MAX 0x001ff
+#define RT5682_PLL_N_MASK (RT5682_PLL_N_MAX << 7)
+#define RT5682_PLL_N_SFT 7
+#define RT5682_PLL_K_MAX 0x001f
+#define RT5682_PLL_K_MASK (RT5682_PLL_K_MAX)
+#define RT5682_PLL_K_SFT 0
+
+/* PLL M/N/K Code Control 2 (0x0082) */
+#define RT5682_PLL_M_MAX 0x00f
+#define RT5682_PLL_M_MASK (RT5682_PLL_M_MAX << 12)
+#define RT5682_PLL_M_SFT 12
+#define RT5682_PLL_M_BP (0x1 << 11)
+#define RT5682_PLL_M_BP_SFT 11
+#define RT5682_PLL_K_BP (0x1 << 10)
+#define RT5682_PLL_K_BP_SFT 10
+#define RT5682_PLL_RST (0x1 << 1)
+
+/* PLL tracking mode 1 (0x0083) */
+#define RT5682_DA_ASRC_MASK (0x1 << 13)
+#define RT5682_DA_ASRC_SFT 13
+#define RT5682_DAC_STO1_ASRC_MASK (0x1 << 12)
+#define RT5682_DAC_STO1_ASRC_SFT 12
+#define RT5682_AD_ASRC_MASK (0x1 << 8)
+#define RT5682_AD_ASRC_SFT 8
+#define RT5682_AD_ASRC_SEL_MASK (0x1 << 4)
+#define RT5682_AD_ASRC_SEL_SFT 4
+#define RT5682_DMIC_ASRC_MASK (0x1 << 3)
+#define RT5682_DMIC_ASRC_SFT 3
+#define RT5682_ADC_STO1_ASRC_MASK (0x1 << 2)
+#define RT5682_ADC_STO1_ASRC_SFT 2
+#define RT5682_DA_ASRC_SEL_MASK (0x1 << 0)
+#define RT5682_DA_ASRC_SEL_SFT 0
+
+/* PLL tracking mode 2 3 (0x0084)(0x0085)*/
+#define RT5682_FILTER_CLK_SEL_MASK (0x7 << 12)
+#define RT5682_FILTER_CLK_SEL_SFT 12
+#define RT5682_FILTER_CLK_DIV_MASK (0xf << 8)
+#define RT5682_FILTER_CLK_DIV_SFT 8
+
+/* ASRC Control 4 (0x0086) */
+#define RT5682_ASRCIN_FTK_N1_MASK (0x3 << 14)
+#define RT5682_ASRCIN_FTK_N1_SFT 14
+#define RT5682_ASRCIN_FTK_N2_MASK (0x3 << 12)
+#define RT5682_ASRCIN_FTK_N2_SFT 12
+#define RT5682_ASRCIN_FTK_M1_MASK (0x7 << 8)
+#define RT5682_ASRCIN_FTK_M1_SFT 8
+#define RT5682_ASRCIN_FTK_M2_MASK (0x7 << 4)
+#define RT5682_ASRCIN_FTK_M2_SFT 4
+
+/* SoundWire reference clk (0x008d) */
+#define RT5682_PLL2_OUT_MASK (0x1 << 8)
+#define RT5682_PLL2_OUT_98M (0x0 << 8)
+#define RT5682_PLL2_OUT_49M (0x1 << 8)
+#define RT5682_SDW_REF_2_MASK (0xf << 4)
+#define RT5682_SDW_REF_2_SFT 4
+#define RT5682_SDW_REF_2_48K (0x0 << 4)
+#define RT5682_SDW_REF_2_96K (0x1 << 4)
+#define RT5682_SDW_REF_2_192K (0x2 << 4)
+#define RT5682_SDW_REF_2_32K (0x3 << 4)
+#define RT5682_SDW_REF_2_24K (0x4 << 4)
+#define RT5682_SDW_REF_2_16K (0x5 << 4)
+#define RT5682_SDW_REF_2_12K (0x6 << 4)
+#define RT5682_SDW_REF_2_8K (0x7 << 4)
+#define RT5682_SDW_REF_2_44K (0x8 << 4)
+#define RT5682_SDW_REF_2_88K (0x9 << 4)
+#define RT5682_SDW_REF_2_176K (0xa << 4)
+#define RT5682_SDW_REF_2_353K (0xb << 4)
+#define RT5682_SDW_REF_2_22K (0xc << 4)
+#define RT5682_SDW_REF_2_384K (0xd << 4)
+#define RT5682_SDW_REF_2_11K (0xe << 4)
+#define RT5682_SDW_REF_1_MASK (0xf << 0)
+#define RT5682_SDW_REF_1_SFT 0
+#define RT5682_SDW_REF_1_48K (0x0 << 0)
+#define RT5682_SDW_REF_1_96K (0x1 << 0)
+#define RT5682_SDW_REF_1_192K (0x2 << 0)
+#define RT5682_SDW_REF_1_32K (0x3 << 0)
+#define RT5682_SDW_REF_1_24K (0x4 << 0)
+#define RT5682_SDW_REF_1_16K (0x5 << 0)
+#define RT5682_SDW_REF_1_12K (0x6 << 0)
+#define RT5682_SDW_REF_1_8K (0x7 << 0)
+#define RT5682_SDW_REF_1_44K (0x8 << 0)
+#define RT5682_SDW_REF_1_88K (0x9 << 0)
+#define RT5682_SDW_REF_1_176K (0xa << 0)
+#define RT5682_SDW_REF_1_353K (0xb << 0)
+#define RT5682_SDW_REF_1_22K (0xc << 0)
+#define RT5682_SDW_REF_1_384K (0xd << 0)
+#define RT5682_SDW_REF_1_11K (0xe << 0)
+
+/* Depop Mode Control 1 (0x008e) */
+#define RT5682_PUMP_EN (0x1 << 3)
+#define RT5682_PUMP_EN_SFT 3
+#define RT5682_CAPLESS_EN (0x1 << 0)
+#define RT5682_CAPLESS_EN_SFT 0
+
+/* Depop Mode Control 2 (0x8f) */
+#define RT5682_RAMP_MASK (0x1 << 12)
+#define RT5682_RAMP_SFT 12
+#define RT5682_RAMP_DIS (0x0 << 12)
+#define RT5682_RAMP_EN (0x1 << 12)
+#define RT5682_BPS_MASK (0x1 << 11)
+#define RT5682_BPS_SFT 11
+#define RT5682_BPS_DIS (0x0 << 11)
+#define RT5682_BPS_EN (0x1 << 11)
+#define RT5682_FAST_UPDN_MASK (0x1 << 10)
+#define RT5682_FAST_UPDN_SFT 10
+#define RT5682_FAST_UPDN_DIS (0x0 << 10)
+#define RT5682_FAST_UPDN_EN (0x1 << 10)
+#define RT5682_VLO_MASK (0x1 << 7)
+#define RT5682_VLO_SFT 7
+#define RT5682_VLO_3V (0x0 << 7)
+#define RT5682_VLO_33V (0x1 << 7)
+
+/* HPOUT charge pump 1 (0x0091) */
+#define RT5682_OSW_L_MASK (0x1 << 11)
+#define RT5682_OSW_L_SFT 11
+#define RT5682_OSW_L_DIS (0x0 << 11)
+#define RT5682_OSW_L_EN (0x1 << 11)
+#define RT5682_OSW_R_MASK (0x1 << 10)
+#define RT5682_OSW_R_SFT 10
+#define RT5682_OSW_R_DIS (0x0 << 10)
+#define RT5682_OSW_R_EN (0x1 << 10)
+#define RT5682_PM_HP_MASK (0x3 << 8)
+#define RT5682_PM_HP_SFT 8
+#define RT5682_PM_HP_LV (0x0 << 8)
+#define RT5682_PM_HP_MV (0x1 << 8)
+#define RT5682_PM_HP_HV (0x2 << 8)
+#define RT5682_IB_HP_MASK (0x3 << 6)
+#define RT5682_IB_HP_SFT 6
+#define RT5682_IB_HP_125IL (0x0 << 6)
+#define RT5682_IB_HP_25IL (0x1 << 6)
+#define RT5682_IB_HP_5IL (0x2 << 6)
+#define RT5682_IB_HP_1IL (0x3 << 6)
+
+/* Micbias Control1 (0x93) */
+#define RT5682_MIC1_OV_MASK (0x3 << 14)
+#define RT5682_MIC1_OV_SFT 14
+#define RT5682_MIC1_OV_2V7 (0x0 << 14)
+#define RT5682_MIC1_OV_2V4 (0x1 << 14)
+#define RT5682_MIC1_OV_2V25 (0x3 << 14)
+#define RT5682_MIC1_OV_1V8 (0x4 << 14)
+#define RT5682_MIC1_CLK_MASK (0x1 << 13)
+#define RT5682_MIC1_CLK_SFT 13
+#define RT5682_MIC1_CLK_DIS (0x0 << 13)
+#define RT5682_MIC1_CLK_EN (0x1 << 13)
+#define RT5682_MIC1_OVCD_MASK (0x1 << 12)
+#define RT5682_MIC1_OVCD_SFT 12
+#define RT5682_MIC1_OVCD_DIS (0x0 << 12)
+#define RT5682_MIC1_OVCD_EN (0x1 << 12)
+#define RT5682_MIC1_OVTH_MASK (0x3 << 10)
+#define RT5682_MIC1_OVTH_SFT 10
+#define RT5682_MIC1_OVTH_768UA (0x0 << 10)
+#define RT5682_MIC1_OVTH_960UA (0x1 << 10)
+#define RT5682_MIC1_OVTH_1152UA (0x2 << 10)
+#define RT5682_MIC1_OVTH_1960UA (0x3 << 10)
+#define RT5682_MIC2_OV_MASK (0x3 << 8)
+#define RT5682_MIC2_OV_SFT 8
+#define RT5682_MIC2_OV_2V7 (0x0 << 8)
+#define RT5682_MIC2_OV_2V4 (0x1 << 8)
+#define RT5682_MIC2_OV_2V25 (0x3 << 8)
+#define RT5682_MIC2_OV_1V8 (0x4 << 8)
+#define RT5682_MIC2_CLK_MASK (0x1 << 7)
+#define RT5682_MIC2_CLK_SFT 7
+#define RT5682_MIC2_CLK_DIS (0x0 << 7)
+#define RT5682_MIC2_CLK_EN (0x1 << 7)
+#define RT5682_MIC2_OVTH_MASK (0x3 << 4)
+#define RT5682_MIC2_OVTH_SFT 4
+#define RT5682_MIC2_OVTH_768UA (0x0 << 4)
+#define RT5682_MIC2_OVTH_960UA (0x1 << 4)
+#define RT5682_MIC2_OVTH_1152UA (0x2 << 4)
+#define RT5682_MIC2_OVTH_1960UA (0x3 << 4)
+#define RT5682_PWR_MB_MASK (0x1 << 3)
+#define RT5682_PWR_MB_SFT 3
+#define RT5682_PWR_MB_PD (0x0 << 3)
+#define RT5682_PWR_MB_PU (0x1 << 3)
+
+/* Micbias Control2 (0x0094) */
+#define RT5682_PWR_CLK25M_MASK (0x1 << 9)
+#define RT5682_PWR_CLK25M_SFT 9
+#define RT5682_PWR_CLK25M_PD (0x0 << 9)
+#define RT5682_PWR_CLK25M_PU (0x1 << 9)
+#define RT5682_PWR_CLK1M_MASK (0x1 << 8)
+#define RT5682_PWR_CLK1M_SFT 8
+#define RT5682_PWR_CLK1M_PD (0x0 << 8)
+#define RT5682_PWR_CLK1M_PU (0x1 << 8)
+
+/* RC Clock Control (0x009f) */
+#define RT5682_POW_IRQ (0x1 << 15)
+#define RT5682_POW_JDH (0x1 << 14)
+#define RT5682_POW_JDL (0x1 << 13)
+#define RT5682_POW_ANA (0x1 << 12)
+
+/* I2S Master Mode Clock Control 1 (0x00a0) */
+#define RT5682_CLK_SRC_MCLK (0x0)
+#define RT5682_CLK_SRC_PLL1 (0x1)
+#define RT5682_CLK_SRC_PLL2 (0x2)
+#define RT5682_CLK_SRC_SDW (0x3)
+#define RT5682_CLK_SRC_RCCLK (0x4)
+#define RT5682_I2S_PD_1 (0x0)
+#define RT5682_I2S_PD_2 (0x1)
+#define RT5682_I2S_PD_3 (0x2)
+#define RT5682_I2S_PD_4 (0x3)
+#define RT5682_I2S_PD_6 (0x4)
+#define RT5682_I2S_PD_8 (0x5)
+#define RT5682_I2S_PD_12 (0x6)
+#define RT5682_I2S_PD_16 (0x7)
+#define RT5682_I2S_PD_24 (0x8)
+#define RT5682_I2S_PD_32 (0x9)
+#define RT5682_I2S_PD_48 (0xa)
+#define RT5682_I2S2_SRC_MASK (0x3 << 4)
+#define RT5682_I2S2_SRC_SFT 4
+#define RT5682_I2S2_M_PD_MASK (0xf << 0)
+#define RT5682_I2S2_M_PD_SFT 0
+
+/* IRQ Control 1 (0x00b6) */
+#define RT5682_JD1_PULSE_EN_MASK (0x1 << 10)
+#define RT5682_JD1_PULSE_EN_SFT 10
+#define RT5682_JD1_PULSE_DIS (0x0 << 10)
+#define RT5682_JD1_PULSE_EN (0x1 << 10)
+
+/* IRQ Control 2 (0x00b7) */
+#define RT5682_JD1_EN_MASK (0x1 << 15)
+#define RT5682_JD1_EN_SFT 15
+#define RT5682_JD1_DIS (0x0 << 15)
+#define RT5682_JD1_EN (0x1 << 15)
+#define RT5682_JD1_POL_MASK (0x1 << 13)
+#define RT5682_JD1_POL_NOR (0x0 << 13)
+#define RT5682_JD1_POL_INV (0x1 << 13)
+
+/* IRQ Control 3 (0x00b8) */
+#define RT5682_IL_IRQ_MASK (0x1 << 7)
+#define RT5682_IL_IRQ_DIS (0x0 << 7)
+#define RT5682_IL_IRQ_EN (0x1 << 7)
+
+/* GPIO Control 1 (0x00c0) */
+#define RT5682_GP1_PIN_MASK (0x3 << 14)
+#define RT5682_GP1_PIN_SFT 14
+#define RT5682_GP1_PIN_GPIO1 (0x0 << 14)
+#define RT5682_GP1_PIN_IRQ (0x1 << 14)
+#define RT5682_GP1_PIN_DMIC_CLK (0x2 << 14)
+#define RT5682_GP2_PIN_MASK (0x3 << 12)
+#define RT5682_GP2_PIN_SFT 12
+#define RT5682_GP2_PIN_GPIO2 (0x0 << 12)
+#define RT5682_GP2_PIN_LRCK2 (0x1 << 12)
+#define RT5682_GP2_PIN_DMIC_SDA (0x2 << 12)
+#define RT5682_GP3_PIN_MASK (0x3 << 10)
+#define RT5682_GP3_PIN_SFT 10
+#define RT5682_GP3_PIN_GPIO3 (0x0 << 10)
+#define RT5682_GP3_PIN_BCLK2 (0x1 << 10)
+#define RT5682_GP3_PIN_DMIC_CLK (0x2 << 10)
+#define RT5682_GP4_PIN_MASK (0x3 << 8)
+#define RT5682_GP4_PIN_SFT 8
+#define RT5682_GP4_PIN_GPIO4 (0x0 << 8)
+#define RT5682_GP4_PIN_ADCDAT1 (0x1 << 8)
+#define RT5682_GP4_PIN_DMIC_CLK (0x2 << 8)
+#define RT5682_GP4_PIN_ADCDAT2 (0x3 << 8)
+#define RT5682_GP5_PIN_MASK (0x3 << 6)
+#define RT5682_GP5_PIN_SFT 6
+#define RT5682_GP5_PIN_GPIO5 (0x0 << 6)
+#define RT5682_GP5_PIN_DACDAT1 (0x1 << 6)
+#define RT5682_GP5_PIN_DMIC_SDA (0x2 << 6)
+#define RT5682_GP6_PIN_MASK (0x1 << 5)
+#define RT5682_GP6_PIN_SFT 5
+#define RT5682_GP6_PIN_GPIO6 (0x0 << 5)
+#define RT5682_GP6_PIN_LRCK1 (0x1 << 5)
+
+/* GPIO Control 2 (0x00c1)*/
+#define RT5682_GP1_PF_MASK (0x1 << 15)
+#define RT5682_GP1_PF_IN (0x0 << 15)
+#define RT5682_GP1_PF_OUT (0x1 << 15)
+#define RT5682_GP1_OUT_MASK (0x1 << 14)
+#define RT5682_GP1_OUT_L (0x0 << 14)
+#define RT5682_GP1_OUT_H (0x1 << 14)
+#define RT5682_GP2_PF_MASK (0x1 << 13)
+#define RT5682_GP2_PF_IN (0x0 << 13)
+#define RT5682_GP2_PF_OUT (0x1 << 13)
+#define RT5682_GP2_OUT_MASK (0x1 << 12)
+#define RT5682_GP2_OUT_L (0x0 << 12)
+#define RT5682_GP2_OUT_H (0x1 << 12)
+#define RT5682_GP3_PF_MASK (0x1 << 11)
+#define RT5682_GP3_PF_IN (0x0 << 11)
+#define RT5682_GP3_PF_OUT (0x1 << 11)
+#define RT5682_GP3_OUT_MASK (0x1 << 10)
+#define RT5682_GP3_OUT_L (0x0 << 10)
+#define RT5682_GP3_OUT_H (0x1 << 10)
+#define RT5682_GP4_PF_MASK (0x1 << 9)
+#define RT5682_GP4_PF_IN (0x0 << 9)
+#define RT5682_GP4_PF_OUT (0x1 << 9)
+#define RT5682_GP4_OUT_MASK (0x1 << 8)
+#define RT5682_GP4_OUT_L (0x0 << 8)
+#define RT5682_GP4_OUT_H (0x1 << 8)
+#define RT5682_GP5_PF_MASK (0x1 << 7)
+#define RT5682_GP5_PF_IN (0x0 << 7)
+#define RT5682_GP5_PF_OUT (0x1 << 7)
+#define RT5682_GP5_OUT_MASK (0x1 << 6)
+#define RT5682_GP5_OUT_L (0x0 << 6)
+#define RT5682_GP5_OUT_H (0x1 << 6)
+#define RT5682_GP6_PF_MASK (0x1 << 5)
+#define RT5682_GP6_PF_IN (0x0 << 5)
+#define RT5682_GP6_PF_OUT (0x1 << 5)
+#define RT5682_GP6_OUT_MASK (0x1 << 4)
+#define RT5682_GP6_OUT_L (0x0 << 4)
+#define RT5682_GP6_OUT_H (0x1 << 4)
+
+
+/* GPIO Status (0x00c2) */
+#define RT5682_GP6_STA (0x1 << 6)
+#define RT5682_GP5_STA (0x1 << 5)
+#define RT5682_GP4_STA (0x1 << 4)
+#define RT5682_GP3_STA (0x1 << 3)
+#define RT5682_GP2_STA (0x1 << 2)
+#define RT5682_GP1_STA (0x1 << 1)
+
+/* Soft volume and zero cross control 1 (0x00d9) */
+#define RT5682_SV_MASK (0x1 << 15)
+#define RT5682_SV_SFT 15
+#define RT5682_SV_DIS (0x0 << 15)
+#define RT5682_SV_EN (0x1 << 15)
+#define RT5682_ZCD_MASK (0x1 << 10)
+#define RT5682_ZCD_SFT 10
+#define RT5682_ZCD_PD (0x0 << 10)
+#define RT5682_ZCD_PU (0x1 << 10)
+#define RT5682_SV_DLY_MASK (0xf)
+#define RT5682_SV_DLY_SFT 0
+
+/* Soft volume and zero cross control 2 (0x00da) */
+#define RT5682_ZCD_BST1_CBJ_MASK (0x1 << 7)
+#define RT5682_ZCD_BST1_CBJ_SFT 7
+#define RT5682_ZCD_BST1_CBJ_DIS (0x0 << 7)
+#define RT5682_ZCD_BST1_CBJ_EN (0x1 << 7)
+#define RT5682_ZCD_RECMIX_MASK (0x1)
+#define RT5682_ZCD_RECMIX_SFT 0
+#define RT5682_ZCD_RECMIX_DIS (0x0)
+#define RT5682_ZCD_RECMIX_EN (0x1)
+
+/* 4 Button Inline Command Control 2 (0x00e3) */
+#define RT5682_4BTN_IL_MASK (0x1 << 15)
+#define RT5682_4BTN_IL_EN (0x1 << 15)
+#define RT5682_4BTN_IL_DIS (0x0 << 15)
+#define RT5682_4BTN_IL_RST_MASK (0x1 << 14)
+#define RT5682_4BTN_IL_NOR (0x1 << 14)
+#define RT5682_4BTN_IL_RST (0x0 << 14)
+
+/* Analog JD Control (0x00f0) */
+#define RT5682_JDH_RS_MASK (0x1 << 4)
+#define RT5682_JDH_NO_PLUG (0x1 << 4)
+#define RT5682_JDH_PLUG (0x0 << 4)
+
+/* Chopper and Clock control for DAC (0x013a)*/
+#define RT5682_CKXEN_DAC1_MASK (0x1 << 13)
+#define RT5682_CKXEN_DAC1_SFT 13
+#define RT5682_CKGEN_DAC1_MASK (0x1 << 12)
+#define RT5682_CKGEN_DAC1_SFT 12
+
+/* Chopper and Clock control for ADC (0x013b)*/
+#define RT5682_CKXEN_ADC1_MASK (0x1 << 13)
+#define RT5682_CKXEN_ADC1_SFT 13
+#define RT5682_CKGEN_ADC1_MASK (0x1 << 12)
+#define RT5682_CKGEN_ADC1_SFT 12
+
+/* Volume test (0x013f)*/
+#define RT5682_SEL_CLK_VOL_MASK (0x1 << 15)
+#define RT5682_SEL_CLK_VOL_EN (0x1 << 15)
+#define RT5682_SEL_CLK_VOL_DIS (0x0 << 15)
+
+/* Test Mode Control 1 (0x0145) */
+#define RT5682_AD2DA_LB_MASK (0x1 << 10)
+#define RT5682_AD2DA_LB_SFT 10
+
+/* Stereo Noise Gate Control 1 (0x0160) */
+#define RT5682_NG2_EN_MASK (0x1 << 15)
+#define RT5682_NG2_EN (0x1 << 15)
+#define RT5682_NG2_DIS (0x0 << 15)
+
+/* Stereo1 DAC Silence Detection Control (0x0190) */
+#define RT5682_DEB_STO_DAC_MASK (0x7 << 4)
+#define RT5682_DEB_80_MS (0x0 << 4)
+
+/* SAR ADC Inline Command Control 1 (0x0210) */
+#define RT5682_SAR_BUTT_DET_MASK (0x1 << 15)
+#define RT5682_SAR_BUTT_DET_EN (0x1 << 15)
+#define RT5682_SAR_BUTT_DET_DIS (0x0 << 15)
+#define RT5682_SAR_BUTDET_MODE_MASK (0x1 << 14)
+#define RT5682_SAR_BUTDET_POW_SAV (0x1 << 14)
+#define RT5682_SAR_BUTDET_POW_NORM (0x0 << 14)
+#define RT5682_SAR_BUTDET_RST_MASK (0x1 << 13)
+#define RT5682_SAR_BUTDET_RST_NORMAL (0x1 << 13)
+#define RT5682_SAR_BUTDET_RST (0x0 << 13)
+#define RT5682_SAR_POW_MASK (0x1 << 12)
+#define RT5682_SAR_POW_EN (0x1 << 12)
+#define RT5682_SAR_POW_DIS (0x0 << 12)
+#define RT5682_SAR_RST_MASK (0x1 << 11)
+#define RT5682_SAR_RST_NORMAL (0x1 << 11)
+#define RT5682_SAR_RST (0x0 << 11)
+#define RT5682_SAR_BYPASS_MASK (0x1 << 10)
+#define RT5682_SAR_BYPASS_EN (0x1 << 10)
+#define RT5682_SAR_BYPASS_DIS (0x0 << 10)
+#define RT5682_SAR_SEL_MB1_MASK (0x1 << 9)
+#define RT5682_SAR_SEL_MB1_SEL (0x1 << 9)
+#define RT5682_SAR_SEL_MB1_NOSEL (0x0 << 9)
+#define RT5682_SAR_SEL_MB2_MASK (0x1 << 8)
+#define RT5682_SAR_SEL_MB2_SEL (0x1 << 8)
+#define RT5682_SAR_SEL_MB2_NOSEL (0x0 << 8)
+#define RT5682_SAR_SEL_MODE_MASK (0x1 << 7)
+#define RT5682_SAR_SEL_MODE_CMP (0x1 << 7)
+#define RT5682_SAR_SEL_MODE_ADC (0x0 << 7)
+#define RT5682_SAR_SEL_MB1_MB2_MASK (0x1 << 5)
+#define RT5682_SAR_SEL_MB1_MB2_AUTO (0x1 << 5)
+#define RT5682_SAR_SEL_MB1_MB2_MANU (0x0 << 5)
+#define RT5682_SAR_SEL_SIGNAL_MASK (0x1 << 4)
+#define RT5682_SAR_SEL_SIGNAL_AUTO (0x1 << 4)
+#define RT5682_SAR_SEL_SIGNAL_MANU (0x0 << 4)
+
+/* SAR ADC Inline Command Control 13 (0x021c) */
+#define RT5682_SAR_SOUR_MASK (0x3f)
+#define RT5682_SAR_SOUR_BTN (0x3f)
+#define RT5682_SAR_SOUR_TYPE (0x0)
+
+
+/* System Clock Source */
+enum {
+ RT5682_SCLK_S_MCLK,
+ RT5682_SCLK_S_PLL1,
+ RT5682_SCLK_S_PLL2,
+ RT5682_SCLK_S_RCCLK,
+};
+
+/* PLL Source */
+enum {
+ RT5682_PLL1_S_MCLK,
+ RT5682_PLL1_S_BCLK1,
+ RT5682_PLL1_S_RCCLK,
+};
+
+enum {
+ RT5682_AIF1,
+ RT5682_AIF2,
+ RT5682_AIFS
+};
+
+/* filter mask */
+enum {
+ RT5682_DA_STEREO1_FILTER = 0x1,
+ RT5682_AD_STEREO1_FILTER = (0x1 << 1),
+};
+
+enum {
+ RT5682_CLK_SEL_SYS,
+ RT5682_CLK_SEL_I2S1_ASRC,
+ RT5682_CLK_SEL_I2S2_ASRC,
+};
+
+int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
+ unsigned int filter_mask, unsigned int clk_src);
+
+#endif /* __RT5682_H__ */
diff --git a/sound/soc/codecs/dio2125.c b/sound/soc/codecs/simple-amplifier.c
index 09451cd44f9b..85524acf3e9c 100644
--- a/sound/soc/codecs/dio2125.c
+++ b/sound/soc/codecs/simple-amplifier.c
@@ -21,9 +21,9 @@
#include <linux/module.h>
#include <sound/soc.h>
-#define DRV_NAME "dio2125"
+#define DRV_NAME "simple-amplifier"
-struct dio2125 {
+struct simple_amp {
struct gpio_desc *gpiod_enable;
};
@@ -31,7 +31,7 @@ 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);
+ struct simple_amp *priv = snd_soc_component_get_drvdata(c);
int val;
switch (event) {
@@ -51,7 +51,7 @@ static int drv_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
+static const struct snd_soc_dapm_widget simple_amp_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,
@@ -60,24 +60,24 @@ static const struct snd_soc_dapm_widget dio2125_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("OUTR"),
};
-static const struct snd_soc_dapm_route dio2125_dapm_routes[] = {
+static const struct snd_soc_dapm_route simple_amp_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 const struct snd_soc_component_driver simple_amp_component_driver = {
+ .dapm_widgets = simple_amp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(simple_amp_dapm_widgets),
+ .dapm_routes = simple_amp_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(simple_amp_dapm_routes),
};
-static int dio2125_probe(struct platform_device *pdev)
+static int simple_amp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct dio2125 *priv;
+ struct simple_amp *priv;
int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -93,28 +93,30 @@ static int dio2125_probe(struct platform_device *pdev)
return err;
}
- return devm_snd_soc_register_component(dev, &dio2125_component_driver,
+ return devm_snd_soc_register_component(dev,
+ &simple_amp_component_driver,
NULL, 0);
}
#ifdef CONFIG_OF
-static const struct of_device_id dio2125_ids[] = {
+static const struct of_device_id simple_amp_ids[] = {
{ .compatible = "dioo,dio2125", },
+ { .compatible = "simple-audio-amplifier", },
{ }
};
-MODULE_DEVICE_TABLE(of, dio2125_ids);
+MODULE_DEVICE_TABLE(of, simple_amp_ids);
#endif
-static struct platform_driver dio2125_driver = {
+static struct platform_driver simple_amp_driver = {
.driver = {
.name = DRV_NAME,
- .of_match_table = of_match_ptr(dio2125_ids),
+ .of_match_table = of_match_ptr(simple_amp_ids),
},
- .probe = dio2125_probe,
+ .probe = simple_amp_probe,
};
-module_platform_driver(dio2125_driver);
+module_platform_driver(simple_amp_driver);
-MODULE_DESCRIPTION("ASoC DIO2125 output driver");
+MODULE_DESCRIPTION("ASoC Simple Audio Amplifier driver");
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c
index 52f34c94ec25..ca2dfe12344e 100644
--- a/sound/soc/codecs/tas571x.c
+++ b/sound/soc/codecs/tas571x.c
@@ -7,6 +7,9 @@
* TAS5721 support:
* Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com>
*
+ * TAS5707 support:
+ * Copyright (C) 2018 Jerome Brunet, Baylibre SAS <jbrunet@baylibre.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
@@ -444,6 +447,111 @@ static const struct tas571x_chip tas5711_chip = {
.vol_reg_size = 1,
};
+static const struct regmap_range tas5707_volatile_regs_range[] = {
+ regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_ERR_STATUS_REG),
+ regmap_reg_range(TAS571X_OSC_TRIM_REG, TAS571X_OSC_TRIM_REG),
+ regmap_reg_range(TAS5707_CH1_BQ0_REG, TAS5707_CH2_BQ6_REG),
+};
+
+static const struct regmap_access_table tas5707_volatile_regs = {
+ .yes_ranges = tas5707_volatile_regs_range,
+ .n_yes_ranges = ARRAY_SIZE(tas5707_volatile_regs_range),
+
+};
+
+static const DECLARE_TLV_DB_SCALE(tas5707_volume_tlv, -7900, 50, 1);
+
+static const char * const tas5707_volume_slew_step_txt[] = {
+ "256", "512", "1024", "2048",
+};
+
+static const unsigned int tas5707_volume_slew_step_values[] = {
+ 3, 0, 1, 2,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(tas5707_volume_slew_step_enum,
+ TAS571X_VOL_CFG_REG, 0, 0x3,
+ tas5707_volume_slew_step_txt,
+ tas5707_volume_slew_step_values);
+
+static const struct snd_kcontrol_new tas5707_controls[] = {
+ SOC_SINGLE_TLV("Master Volume",
+ TAS571X_MVOL_REG,
+ 0, 0xff, 1, tas5707_volume_tlv),
+ SOC_DOUBLE_R_TLV("Speaker Volume",
+ TAS571X_CH1_VOL_REG,
+ TAS571X_CH2_VOL_REG,
+ 0, 0xff, 1, tas5707_volume_tlv),
+ SOC_DOUBLE("Speaker Switch",
+ TAS571X_SOFT_MUTE_REG,
+ TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT,
+ 1, 1),
+
+ SOC_ENUM("Slew Rate Steps", tas5707_volume_slew_step_enum),
+
+ BIQUAD_COEFS("CH1 - Biquad 0", TAS5707_CH1_BQ0_REG),
+ BIQUAD_COEFS("CH1 - Biquad 1", TAS5707_CH1_BQ1_REG),
+ BIQUAD_COEFS("CH1 - Biquad 2", TAS5707_CH1_BQ2_REG),
+ BIQUAD_COEFS("CH1 - Biquad 3", TAS5707_CH1_BQ3_REG),
+ BIQUAD_COEFS("CH1 - Biquad 4", TAS5707_CH1_BQ4_REG),
+ BIQUAD_COEFS("CH1 - Biquad 5", TAS5707_CH1_BQ5_REG),
+ BIQUAD_COEFS("CH1 - Biquad 6", TAS5707_CH1_BQ6_REG),
+
+ BIQUAD_COEFS("CH2 - Biquad 0", TAS5707_CH2_BQ0_REG),
+ BIQUAD_COEFS("CH2 - Biquad 1", TAS5707_CH2_BQ1_REG),
+ BIQUAD_COEFS("CH2 - Biquad 2", TAS5707_CH2_BQ2_REG),
+ BIQUAD_COEFS("CH2 - Biquad 3", TAS5707_CH2_BQ3_REG),
+ BIQUAD_COEFS("CH2 - Biquad 4", TAS5707_CH2_BQ4_REG),
+ BIQUAD_COEFS("CH2 - Biquad 5", TAS5707_CH2_BQ5_REG),
+ BIQUAD_COEFS("CH2 - Biquad 6", TAS5707_CH2_BQ6_REG),
+};
+
+static const struct reg_default tas5707_reg_defaults[] = {
+ {TAS571X_CLK_CTRL_REG, 0x6c},
+ {TAS571X_DEV_ID_REG, 0x70},
+ {TAS571X_ERR_STATUS_REG, 0x00},
+ {TAS571X_SYS_CTRL_1_REG, 0xa0},
+ {TAS571X_SDI_REG, 0x05},
+ {TAS571X_SYS_CTRL_2_REG, 0x40},
+ {TAS571X_SOFT_MUTE_REG, 0x00},
+ {TAS571X_MVOL_REG, 0xff},
+ {TAS571X_CH1_VOL_REG, 0x30},
+ {TAS571X_CH2_VOL_REG, 0x30},
+ {TAS571X_VOL_CFG_REG, 0x91},
+ {TAS571X_MODULATION_LIMIT_REG, 0x02},
+ {TAS571X_IC_DELAY_CH1_REG, 0xac},
+ {TAS571X_IC_DELAY_CH2_REG, 0x54},
+ {TAS571X_IC_DELAY_CH3_REG, 0xac},
+ {TAS571X_IC_DELAY_CH4_REG, 0x54},
+ {TAS571X_START_STOP_PERIOD_REG, 0x0f},
+ {TAS571X_OSC_TRIM_REG, 0x82},
+ {TAS571X_BKND_ERR_REG, 0x02},
+ {TAS571X_INPUT_MUX_REG, 0x17772},
+ {TAS571X_PWM_MUX_REG, 0x1021345},
+};
+
+static const struct regmap_config tas5707_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .max_register = 0xff,
+ .reg_read = tas571x_reg_read,
+ .reg_write = tas571x_reg_write,
+ .reg_defaults = tas5707_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5707_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .wr_table = &tas571x_write_regs,
+ .volatile_table = &tas5707_volatile_regs,
+};
+
+static const struct tas571x_chip tas5707_chip = {
+ .supply_names = tas5711_supply_names,
+ .num_supply_names = ARRAY_SIZE(tas5711_supply_names),
+ .controls = tas5707_controls,
+ .num_controls = ARRAY_SIZE(tas5707_controls),
+ .regmap_config = &tas5707_regmap_config,
+ .vol_reg_size = 1,
+};
+
static const char *const tas5717_supply_names[] = {
"AVDD",
"DVDD",
@@ -775,6 +883,7 @@ static int tas571x_i2c_remove(struct i2c_client *client)
}
static const struct of_device_id tas571x_of_match[] = {
+ { .compatible = "ti,tas5707", .data = &tas5707_chip, },
{ .compatible = "ti,tas5711", .data = &tas5711_chip, },
{ .compatible = "ti,tas5717", .data = &tas5717_chip, },
{ .compatible = "ti,tas5719", .data = &tas5717_chip, },
@@ -784,6 +893,7 @@ static const struct of_device_id tas571x_of_match[] = {
MODULE_DEVICE_TABLE(of, tas571x_of_match);
static const struct i2c_device_id tas571x_i2c_id[] = {
+ { "tas5707", (kernel_ulong_t) &tas5707_chip },
{ "tas5711", (kernel_ulong_t) &tas5711_chip },
{ "tas5717", (kernel_ulong_t) &tas5717_chip },
{ "tas5719", (kernel_ulong_t) &tas5717_chip },
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h
index c45677bc26ad..bd23e89cfe79 100644
--- a/sound/soc/codecs/tas571x.h
+++ b/sound/soc/codecs/tas571x.h
@@ -53,6 +53,22 @@
#define TAS571X_PWM_MUX_REG 0x25
/* 20-byte biquad registers */
+#define TAS5707_CH1_BQ0_REG 0x29
+#define TAS5707_CH1_BQ1_REG 0x2a
+#define TAS5707_CH1_BQ2_REG 0x2b
+#define TAS5707_CH1_BQ3_REG 0x2c
+#define TAS5707_CH1_BQ4_REG 0x2d
+#define TAS5707_CH1_BQ5_REG 0x2e
+#define TAS5707_CH1_BQ6_REG 0x2f
+
+#define TAS5707_CH2_BQ0_REG 0x30
+#define TAS5707_CH2_BQ1_REG 0x31
+#define TAS5707_CH2_BQ2_REG 0x32
+#define TAS5707_CH2_BQ3_REG 0x33
+#define TAS5707_CH2_BQ4_REG 0x34
+#define TAS5707_CH2_BQ5_REG 0x35
+#define TAS5707_CH2_BQ6_REG 0x36
+
#define TAS5717_CH1_BQ0_REG 0x26
#define TAS5717_CH1_BQ1_REG 0x27
#define TAS5717_CH1_BQ2_REG 0x28
diff --git a/sound/soc/codecs/tda7419.c b/sound/soc/codecs/tda7419.c
index 225c210ac38f..7f3b79c5a563 100644
--- a/sound/soc/codecs/tda7419.c
+++ b/sound/soc/codecs/tda7419.c
@@ -142,9 +142,9 @@ struct tda7419_vol_control {
static inline bool tda7419_vol_is_stereo(struct tda7419_vol_control *tvc)
{
if (tvc->reg == tvc->rreg)
- return 0;
+ return false;
- return 1;
+ return true;
}
static int tda7419_vol_info(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index d18ff17719cc..7396a6e5277e 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -625,25 +625,34 @@ static int bytes_info_ext(struct snd_kcontrol *kcontrol,
static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
/* Volumes */
- SOC_DOUBLE_R_TLV("Headphone Playback Volume", R_HPVOLL, R_HPVOLR,
+ SOC_DOUBLE_R_TLV("Headphone Volume", R_HPVOLL, R_HPVOLR,
FB_HPVOLL, 0x7F, 0, hpvol_scale),
- SOC_DOUBLE_R_TLV("Speaker Playback Volume", R_SPKVOLL, R_SPKVOLR,
+ SOC_DOUBLE_R_TLV("Speaker Volume", R_SPKVOLL, R_SPKVOLR,
FB_SPKVOLL, 0x7F, 0, spkvol_scale),
- SOC_DOUBLE_R_TLV("Master Playback Volume", R_DACVOLL, R_DACVOLR,
+ SOC_DOUBLE_R_TLV("Master Volume", R_DACVOLL, R_DACVOLR,
FB_DACVOLL, 0xFF, 0, dacvol_scale),
- SOC_DOUBLE_R_TLV("PCM Capture Volume", R_ADCVOLL, R_ADCVOLR,
+ SOC_DOUBLE_R_TLV("PCM Volume", R_ADCVOLL, R_ADCVOLR,
FB_ADCVOLL, 0xFF, 0, adcvol_scale),
- SOC_DOUBLE_R_TLV("Master Capture Volume", R_INVOLL, R_INVOLR,
+ SOC_DOUBLE_R_TLV("Input Volume", R_INVOLL, R_INVOLR,
FB_INVOLL, 0x3F, 0, invol_scale),
/* INSEL */
- SOC_DOUBLE_R_TLV("Mic Boost Capture Volume", R_INSELL, R_INSELR,
+ SOC_DOUBLE_R_TLV("Mic Boost Volume", R_INSELL, R_INSELR,
FB_INSELL_MICBSTL, FV_INSELL_MICBSTL_30DB,
0, mic_boost_scale),
/* Input Channel Map */
SOC_ENUM("Input Channel Map", ch_map_select_enum),
+ /* Mic Bias */
+ SOC_SINGLE("Mic Bias Boost Switch", 0x71, 0x07, 1, 0),
+
+ /* Headphone Auto Switching */
+ SOC_SINGLE("Headphone Auto Switching Switch",
+ R_CTL, FB_CTL_HPSWEN, 1, 0),
+ SOC_SINGLE("Headphone Detect Polarity Toggle Switch",
+ R_CTL, FB_CTL_HPSWPOL, 1, 0),
+
/* Coefficient Ram */
COEFF_RAM_CTL("Cascade1L BiQuad1", BIQUAD_SIZE, 0x00),
COEFF_RAM_CTL("Cascade1L BiQuad2", BIQUAD_SIZE, 0x05),
@@ -733,9 +742,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
R_CLECTL, FB_CLECTL_LIMIT_EN, 1, 0),
SOC_SINGLE("Comp Switch",
R_CLECTL, FB_CLECTL_COMP_EN, 1, 0),
- SOC_SINGLE_TLV("CLE Make-Up Gain Playback Volume",
+ SOC_SINGLE_TLV("CLE Make-Up Gain Volume",
R_MUGAIN, FB_MUGAIN_CLEMUG, 0x1f, 0, mugain_scale),
- SOC_SINGLE_TLV("Comp Thresh Playback Volume",
+ SOC_SINGLE_TLV("Comp Thresh Volume",
R_COMPTH, FB_COMPTH, 0xff, 0, compth_scale),
SOC_ENUM("Comp Ratio", compressor_ratio_enum),
SND_SOC_BYTES("Comp Atk Time", R_CATKTCL, 2),
@@ -766,9 +775,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
SOC_SINGLE("MBC1 Phase Invert Switch",
R_DACMBCMUG1, FB_DACMBCMUG1_PHASE, 1, 0),
- SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Playback Volume",
+ SOC_SINGLE_TLV("DAC MBC1 Make-Up Gain Volume",
R_DACMBCMUG1, FB_DACMBCMUG1_MUGAIN, 0x1f, 0, mugain_scale),
- SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Playback Volume",
+ SOC_SINGLE_TLV("DAC MBC1 Comp Thresh Volume",
R_DACMBCTHR1, FB_DACMBCTHR1_THRESH, 0xff, 0, compth_scale),
SOC_ENUM("DAC MBC1 Comp Ratio",
dac_mbc1_compressor_ratio_enum),
@@ -778,9 +787,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
SOC_SINGLE("MBC2 Phase Invert Switch",
R_DACMBCMUG2, FB_DACMBCMUG2_PHASE, 1, 0),
- SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Playback Volume",
+ SOC_SINGLE_TLV("DAC MBC2 Make-Up Gain Volume",
R_DACMBCMUG2, FB_DACMBCMUG2_MUGAIN, 0x1f, 0, mugain_scale),
- SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Playback Volume",
+ SOC_SINGLE_TLV("DAC MBC2 Comp Thresh Volume",
R_DACMBCTHR2, FB_DACMBCTHR2_THRESH, 0xff, 0, compth_scale),
SOC_ENUM("DAC MBC2 Comp Ratio",
dac_mbc2_compressor_ratio_enum),
@@ -790,9 +799,9 @@ static const struct snd_kcontrol_new tscs42xx_snd_controls[] = {
SOC_SINGLE("MBC3 Phase Invert Switch",
R_DACMBCMUG3, FB_DACMBCMUG3_PHASE, 1, 0),
- SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Playback Volume",
+ SOC_SINGLE_TLV("DAC MBC3 Make-Up Gain Volume",
R_DACMBCMUG3, FB_DACMBCMUG3_MUGAIN, 0x1f, 0, mugain_scale),
- SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Playback Volume",
+ SOC_SINGLE_TLV("DAC MBC3 Comp Thresh Volume",
R_DACMBCTHR3, FB_DACMBCTHR3_THRESH, 0xff, 0, compth_scale),
SOC_ENUM("DAC MBC3 Comp Ratio",
dac_mbc3_compressor_ratio_enum),
diff --git a/sound/soc/codecs/tscs42xx.h b/sound/soc/codecs/tscs42xx.h
index 814c8f3c4a68..6b3a21081635 100644
--- a/sound/soc/codecs/tscs42xx.h
+++ b/sound/soc/codecs/tscs42xx.h
@@ -34,6 +34,7 @@ enum {
#define R_DACSR 0x19
#define R_PWRM1 0x1A
#define R_PWRM2 0x1B
+#define R_CTL 0x1C
#define R_CONFIG0 0x1F
#define R_CONFIG1 0x20
#define R_DMICCTL 0x24
@@ -1110,6 +1111,13 @@ enum {
#define RV_PWRM2_VREF_DISABLE \
RV(FV_PWRM2_VREF_DISABLE, FB_PWRM2_VREF)
+/******************************
+ * R_CTL (0x1C) *
+ ******************************/
+
+/* Fiel Offsets */
+#define FB_CTL_HPSWEN 7
+#define FB_CTL_HPSWPOL 6
/******************************
* R_CONFIG0 (0x1F) *
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index bfd1abd72253..94675da514c8 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -148,7 +148,7 @@ static bool twl6040_can_write_to_chip(struct snd_soc_component *component,
case TWL6040_REG_HFRCTL:
return priv->dl2_unmuted;
default:
- return 1;
+ return true;
}
}
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 3663b9fd4d65..deff65161504 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1180,6 +1180,9 @@ SOC_DOUBLE_R_TLV("OUT2 Digital Volume", WM2200_DAC_DIGITAL_VOLUME_2L,
SOC_DOUBLE("OUT2 Switch", WM2200_PDM_1, WM2200_SPK1L_MUTE_SHIFT,
WM2200_SPK1R_MUTE_SHIFT, 1, 1),
SOC_ENUM("RxANC Src", wm2200_rxanc_input_sel),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+WM_ADSP_FW_CONTROL("DSP2", 1),
};
WM2200_MIXER_ENUMS(OUT1L, WM2200_OUT1LMIX_INPUT_1_SOURCE);
@@ -1553,15 +1556,10 @@ static const struct snd_soc_dapm_route wm2200_dapm_routes[] = {
static int wm2200_probe(struct snd_soc_component *component)
{
struct wm2200_priv *wm2200 = snd_soc_component_get_drvdata(component);
- int ret;
wm2200->component = component;
- ret = snd_soc_add_component_controls(component, wm_adsp_fw_controls, 2);
- if (ret != 0)
- return ret;
-
- return ret;
+ return 0;
}
static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c
index e239f4bf2460..9e987cf07450 100644
--- a/sound/soc/codecs/wm5100-tables.c
+++ b/sound/soc/codecs/wm5100-tables.c
@@ -30,7 +30,7 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
case WM5100_OUTPUT_STATUS_2:
case WM5100_INPUT_ENABLES_STATUS:
case WM5100_MIC_DETECT_3:
- return 1;
+ return true;
default:
if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
(reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
@@ -41,9 +41,9 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
(reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
(reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
(reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
- return 1;
+ return true;
else
- return 0;
+ return false;
}
}
@@ -798,7 +798,7 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
case WM5100_DSP3_CONTROL_28:
case WM5100_DSP3_CONTROL_29:
case WM5100_DSP3_CONTROL_30:
- return 1;
+ return true;
default:
if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
(reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
@@ -809,9 +809,9 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
(reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
(reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
(reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
- return 1;
+ return true;
else
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 1ac83388d1b8..7e817e1877c2 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -985,6 +985,8 @@ ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
};
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -2094,6 +2096,12 @@ static int wm5102_probe(struct platform_device *pdev)
return ret;
}
+ ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
+ if (ret != 0)
+ dev_warn(&pdev->dev,
+ "Failed to set compressed IRQ as a wake source: %d\n",
+ ret);
+
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
@@ -2117,6 +2125,7 @@ static int wm5102_probe(struct platform_device *pdev)
err_spk_irqs:
arizona_free_spk_irqs(arizona);
err_dsp_irq:
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
return ret;
@@ -2133,6 +2142,7 @@ static int wm5102_remove(struct platform_device *pdev)
arizona_free_spk_irqs(arizona);
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102);
return 0;
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index fb9835dcd836..b0789a03d699 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -927,6 +927,11 @@ ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+
+WM_ADSP_FW_CONTROL("DSP1", 0),
+WM_ADSP_FW_CONTROL("DSP2", 1),
+WM_ADSP_FW_CONTROL("DSP3", 2),
+WM_ADSP_FW_CONTROL("DSP4", 3),
};
ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
@@ -2455,6 +2460,12 @@ static int wm5110_probe(struct platform_device *pdev)
return ret;
}
+ ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 1);
+ if (ret != 0)
+ dev_warn(&pdev->dev,
+ "Failed to set compressed IRQ as a wake source: %d\n",
+ ret);
+
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
@@ -2478,6 +2489,7 @@ static int wm5110_probe(struct platform_device *pdev)
err_spk_irqs:
arizona_free_spk_irqs(arizona);
err_dsp_irq:
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
return ret;
@@ -2496,6 +2508,7 @@ static int wm5110_remove(struct platform_device *pdev)
arizona_free_spk_irqs(arizona);
+ arizona_set_irq_wake(arizona, ARIZONA_IRQ_DSP_IRQ1, 0);
arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110);
return 0;
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 7b8b6ef2f632..6cb3c153ba19 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -251,10 +251,10 @@ static bool wm8903_volatile_register(struct device *dev, unsigned int reg)
case WM8903_DC_SERVO_READBACK_2:
case WM8903_DC_SERVO_READBACK_3:
case WM8903_DC_SERVO_READBACK_4:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 9037a35b931d..1965635ec07c 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -1455,6 +1455,7 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif1 |= 0x3 | WM8904_AIF_LRCLK_INV;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif1 |= 0x3;
break;
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index ba44e3d6c1e0..cd204f79647d 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -686,6 +686,7 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif |= WM8955_LRP;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif |= 0x3;
break;
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index c30f5aa392c6..8dc1f3d6a988 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -839,6 +839,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
iface |= 0x000c;
break;
}
+ /* fall through */
default:
dev_err(component->dev, "unsupported width %d\n",
params_width(params));
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index f70f563d59f3..68b4cadc308f 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -653,6 +653,7 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
case SND_SOC_DAIFMT_DSP_B:
aif |= WM8961_LRP;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif |= 3;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index a11e9d6bf950..efd8910b1ff7 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2649,6 +2649,7 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif0 |= WM8962_LRCLK_INV | 3;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif0 |= 3;
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 62200117444b..6e52c6a8bab3 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -522,7 +522,7 @@ static inline int get_coeff(int mclk, int rate)
/* The set of rates we can generate from the above for each SYSCLK */
static const unsigned int rates_12288[] = {
- 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
+ 8000, 12000, 16000, 24000, 32000, 48000, 96000,
};
static const struct snd_pcm_hw_constraint_list constraints_12288 = {
@@ -540,7 +540,7 @@ static const struct snd_pcm_hw_constraint_list constraints_112896 = {
};
static const unsigned int rates_12[] = {
- 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
+ 8000, 11025, 12000, 16000, 22050, 24000, 32000, 41100, 48000,
48000, 88235, 96000,
};
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 411b9eee88c2..457bc437ce54 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -40,9 +40,9 @@ static bool wm8990_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WM8990_RESET:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 7fdfdf3f6e67..14f1b0c0d286 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2432,6 +2432,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
snd_soc_component_update_bits(component, WM8994_POWER_MANAGEMENT_2,
WM8994_OPCLK_ENA, 0);
}
+ break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 60e227832331..68c99fe37097 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -1465,6 +1465,7 @@ static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif |= WM8995_AIF1_LRCLK_INV;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif |= (0x3 << WM8995_AIF1_FMT_SHIFT);
break;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index d9d206046f8c..91711f8958c5 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1498,9 +1498,9 @@ static bool wm8996_readable_register(struct device *dev, unsigned int reg)
case WM8996_RIGHT_PDM_SPEAKER:
case WM8996_PDM_SPEAKER_MUTE_SEQUENCE:
case WM8996_PDM_SPEAKER_VOLUME:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
@@ -1522,9 +1522,9 @@ static bool wm8996_volatile_register(struct device *dev, unsigned int reg)
case WM8996_MIC_DETECT_3:
case WM8996_HEADPHONE_DETECT_1:
case WM8996_HEADPHONE_DETECT_2:
- return 1;
+ return true;
default:
- return 0;
+ return false;
}
}
@@ -1858,6 +1858,7 @@ static int wm8996_set_sysclk(struct snd_soc_dai *dai,
case 24576000:
ratediv = WM8996_SYSCLK_DIV;
wm8996->sysclk /= 2;
+ /* fall through */
case 11289600:
case 12288000:
snd_soc_component_update_bits(component, WM8996_AIF_RATE,
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 5a0ea7b3c149..399255d1f78a 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -933,6 +933,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_B:
aif2 |= WM9081_AIF_LRCLK_INV;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
aif2 |= 0x3;
break;
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 2fcdd84021a5..f61656070225 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -35,15 +36,15 @@
#include "wm_adsp.h"
#define adsp_crit(_dsp, fmt, ...) \
- dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+ dev_crit(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define adsp_err(_dsp, fmt, ...) \
- dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+ dev_err(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define adsp_warn(_dsp, fmt, ...) \
- dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+ dev_warn(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define adsp_info(_dsp, fmt, ...) \
- dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+ dev_info(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define adsp_dbg(_dsp, fmt, ...) \
- dev_dbg(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__)
+ dev_dbg(_dsp->dev, "%s: " fmt, _dsp->name, ##__VA_ARGS__)
#define ADSP1_CONTROL_1 0x00
#define ADSP1_CONTROL_2 0x02
@@ -418,7 +419,7 @@ static const struct wm_adsp_fw_caps ctrl_caps[] = {
{
.id = SND_AUDIOCODEC_BESPOKE,
.desc = {
- .max_ch = 1,
+ .max_ch = 8,
.sample_rates = { 16000 },
.num_sample_rates = 1,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -608,7 +609,6 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
struct snd_soc_component *component)
{
struct dentry *root = NULL;
- char *root_name;
int i;
if (!component->debugfs_root) {
@@ -616,13 +616,7 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp,
goto err;
}
- root_name = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!root_name)
- goto err;
-
- snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num);
- root = debugfs_create_dir(root_name, component->debugfs_root);
- kfree(root_name);
+ root = debugfs_create_dir(dsp->name, component->debugfs_root);
if (!root)
goto err;
@@ -684,8 +678,8 @@ static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp)
}
#endif
-static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -695,9 +689,10 @@ static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
return 0;
}
+EXPORT_SYMBOL_GPL(wm_adsp_fw_get);
-static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -721,8 +716,9 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
return ret;
}
+EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
-static const struct soc_enum wm_adsp_fw_enum[] = {
+const struct soc_enum wm_adsp_fw_enum[] = {
SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
@@ -731,24 +727,7 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
};
-
-const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
- SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
- wm_adsp_fw_get, wm_adsp_fw_put),
- SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
- wm_adsp_fw_get, wm_adsp_fw_put),
- SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
- wm_adsp_fw_get, wm_adsp_fw_put),
- SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
- wm_adsp_fw_get, wm_adsp_fw_put),
- SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4],
- wm_adsp_fw_get, wm_adsp_fw_put),
- SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5],
- wm_adsp_fw_get, wm_adsp_fw_put),
- SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6],
- wm_adsp_fw_get, wm_adsp_fw_put),
-};
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp_fw_enum);
static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
int type)
@@ -1330,12 +1309,12 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
switch (dsp->fw_ver) {
case 0:
case 1:
- snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x",
- dsp->num, region_name, alg_region->alg);
+ snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
+ dsp->name, region_name, alg_region->alg);
break;
default:
ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
- "DSP%d%c %.12s %x", dsp->num, *region_name,
+ "%s%c %.12s %x", dsp->name, *region_name,
wm_adsp_fw_text[dsp->fw], alg_region->alg);
/* Truncate the subname from the start if it is too long */
@@ -1343,6 +1322,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp,
int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2;
int skip = 0;
+ if (dsp->component->name_prefix)
+ avail -= strlen(dsp->component->name_prefix) + 1;
+
if (subname_len > avail)
skip = subname_len - avail;
@@ -1604,6 +1586,15 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp,
if (ret)
return -EINVAL;
break;
+ case WMFW_CTL_TYPE_HOST_BUFFER:
+ ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk,
+ WMFW_CTL_FLAG_SYS |
+ WMFW_CTL_FLAG_VOLATILE |
+ WMFW_CTL_FLAG_READABLE,
+ 0);
+ if (ret)
+ return -EINVAL;
+ break;
default:
adsp_err(dsp, "Unknown control type: %d\n",
coeff_blk.ctl_type);
@@ -1651,7 +1642,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
if (file == NULL)
return -ENOMEM;
- snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num,
+ snprintf(file, PAGE_SIZE, "%s-%s-%s.wmfw", dsp->part, dsp->fwf_name,
wm_adsp_fw[dsp->fw].file);
file[PAGE_SIZE - 1] = '\0';
@@ -1871,9 +1862,11 @@ static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp,
}
static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
+ const struct wm_adsp_region *mem,
unsigned int pos, unsigned int len)
{
void *alg;
+ unsigned int reg;
int ret;
__be32 val;
@@ -1888,7 +1881,9 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
}
/* Read the terminator first to validate the length */
- ret = regmap_raw_read(dsp->regmap, pos + len, &val, sizeof(val));
+ reg = wm_adsp_region_to_reg(mem, pos + len);
+
+ ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list end: %d\n",
ret);
@@ -1897,13 +1892,18 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs,
if (be32_to_cpu(val) != 0xbedead)
adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n",
- pos + len, be32_to_cpu(val));
+ reg, be32_to_cpu(val));
+
+ /* Convert length from DSP words to bytes */
+ len *= sizeof(u32);
- alg = kcalloc(len, 2, GFP_KERNEL | GFP_DMA);
+ alg = kzalloc(len, GFP_KERNEL | GFP_DMA);
if (!alg)
return ERR_PTR(-ENOMEM);
- ret = regmap_raw_read(dsp->regmap, pos, alg, len * 2);
+ reg = wm_adsp_region_to_reg(mem, pos);
+
+ ret = regmap_raw_read(dsp->regmap, reg, alg, len);
if (ret != 0) {
adsp_err(dsp, "Failed to read algorithm list: %d\n", ret);
kfree(alg);
@@ -2002,10 +2002,11 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp)
if (IS_ERR(alg_region))
return PTR_ERR(alg_region);
- pos = sizeof(adsp1_id) / 2;
- len = (sizeof(*adsp1_alg) * n_algs) / 2;
+ /* Calculate offset and length in DSP words */
+ pos = sizeof(adsp1_id) / sizeof(u32);
+ len = (sizeof(*adsp1_alg) * n_algs) / sizeof(u32);
- adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+ adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
if (IS_ERR(adsp1_alg))
return PTR_ERR(adsp1_alg);
@@ -2113,10 +2114,11 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp)
if (IS_ERR(alg_region))
return PTR_ERR(alg_region);
- pos = sizeof(adsp2_id) / 2;
- len = (sizeof(*adsp2_alg) * n_algs) / 2;
+ /* Calculate offset and length in DSP words */
+ pos = sizeof(adsp2_id) / sizeof(u32);
+ len = (sizeof(*adsp2_alg) * n_algs) / sizeof(u32);
- adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len);
+ adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem, pos, len);
if (IS_ERR(adsp2_alg))
return PTR_ERR(adsp2_alg);
@@ -2218,7 +2220,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
if (file == NULL)
return -ENOMEM;
- snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num,
+ snprintf(file, PAGE_SIZE, "%s-%s-%s.bin", dsp->part, dsp->fwf_name,
wm_adsp_fw[dsp->fw].file);
file[PAGE_SIZE - 1] = '\0';
@@ -2390,8 +2392,38 @@ out:
return ret;
}
+static int wm_adsp_create_name(struct wm_adsp *dsp)
+{
+ char *p;
+
+ if (!dsp->name) {
+ dsp->name = devm_kasprintf(dsp->dev, GFP_KERNEL, "DSP%d",
+ dsp->num);
+ if (!dsp->name)
+ return -ENOMEM;
+ }
+
+ if (!dsp->fwf_name) {
+ p = devm_kstrdup(dsp->dev, dsp->name, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ dsp->fwf_name = p;
+ for (; *p != 0; ++p)
+ *p = tolower(*p);
+ }
+
+ return 0;
+}
+
int wm_adsp1_init(struct wm_adsp *dsp)
{
+ int ret;
+
+ ret = wm_adsp_create_name(dsp);
+ if (ret)
+ return ret;
+
INIT_LIST_HEAD(&dsp->alg_regions);
mutex_init(&dsp->pwr_lock);
@@ -2642,7 +2674,10 @@ int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
+ struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct wm_adsp *dsp = &dsps[mc->shift - 1];
ucontrol->value.integer.value[0] = dsp->preloaded;
@@ -2654,13 +2689,14 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
+ struct wm_adsp *dsps = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ struct wm_adsp *dsp = &dsps[mc->shift - 1];
char preload[32];
- snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift);
+ snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
dsp->preloaded = ucontrol->value.integer.value[0];
@@ -2671,6 +2707,8 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
snd_soc_dapm_sync(dapm);
+ flush_work(&dsp->boot_work);
+
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
@@ -2853,17 +2891,14 @@ int wm_adsp2_component_probe(struct wm_adsp *dsp, struct snd_soc_component *comp
{
char preload[32];
- snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num);
-
+ snprintf(preload, ARRAY_SIZE(preload), "%s Preload", dsp->name);
snd_soc_component_disable_pin(component, preload);
wm_adsp2_init_debugfs(dsp, component);
dsp->component = component;
- return snd_soc_add_component_controls(component,
- &wm_adsp_fw_controls[dsp->num - 1],
- 1);
+ return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp2_component_probe);
@@ -2879,6 +2914,10 @@ int wm_adsp2_init(struct wm_adsp *dsp)
{
int ret;
+ ret = wm_adsp_create_name(dsp);
+ if (ret)
+ return ret;
+
switch (dsp->rev) {
case 0:
/*
@@ -3186,7 +3225,7 @@ static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf,
buf->host_buf_ptr + field_offset, data);
}
-static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+static int wm_adsp_legacy_host_buf_addr(struct wm_adsp_compr_buf *buf)
{
struct wm_adsp_alg_region *alg_region;
struct wm_adsp *dsp = buf->dsp;
@@ -3225,6 +3264,61 @@ static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
return 0;
}
+static struct wm_coeff_ctl *
+wm_adsp_find_host_buffer_ctrl(struct wm_adsp_compr_buf *buf)
+{
+ struct wm_adsp *dsp = buf->dsp;
+ struct wm_coeff_ctl *ctl;
+
+ list_for_each_entry(ctl, &dsp->ctl_list, list) {
+ if (ctl->type != WMFW_CTL_TYPE_HOST_BUFFER)
+ continue;
+
+ if (!ctl->enabled)
+ continue;
+
+ return ctl;
+ }
+
+ return NULL;
+}
+
+static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf)
+{
+ struct wm_adsp *dsp = buf->dsp;
+ struct wm_coeff_ctl *ctl;
+ unsigned int reg;
+ u32 val;
+ int i, ret;
+
+ ctl = wm_adsp_find_host_buffer_ctrl(buf);
+ if (!ctl)
+ return wm_adsp_legacy_host_buf_addr(buf);
+
+ ret = wm_coeff_base_reg(ctl, &reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 5; ++i) {
+ ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val));
+ if (ret < 0)
+ return ret;
+
+ if (val)
+ break;
+
+ usleep_range(1000, 2000);
+ }
+
+ if (!val)
+ return -EIO;
+
+ buf->host_buf_ptr = be32_to_cpu(val);
+ adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr);
+
+ return 0;
+}
+
static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
{
const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps;
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h
index bc6d359f0533..4b8778b0b06c 100644
--- a/sound/soc/codecs/wm_adsp.h
+++ b/sound/soc/codecs/wm_adsp.h
@@ -57,6 +57,8 @@ struct wm_adsp_compr_buf;
struct wm_adsp {
const char *part;
+ const char *name;
+ const char *fwf_name;
int rev;
int num;
int type;
@@ -121,7 +123,11 @@ struct wm_adsp {
.reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
-extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
+#define WM_ADSP_FW_CONTROL(dspname, num) \
+ SOC_ENUM_EXT(dspname " Firmware", wm_adsp_fw_enum[num], \
+ wm_adsp_fw_get, wm_adsp_fw_put)
+
+extern const struct soc_enum wm_adsp_fw_enum[];
int wm_adsp1_init(struct wm_adsp *dsp);
int wm_adsp2_init(struct wm_adsp *dsp);
@@ -144,6 +150,10 @@ int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
+int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream);
int wm_adsp_compr_free(struct snd_compr_stream *stream);
diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h
index ec78b9da020f..0c3f50acb8b1 100644
--- a/sound/soc/codecs/wmfw.h
+++ b/sound/soc/codecs/wmfw.h
@@ -29,6 +29,7 @@
/* Non-ALSA coefficient types start at 0x1000 */
#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */
#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */
+#define WMFW_CTL_TYPE_HOST_BUFFER 0x1002 /* host buffer pointer */
struct wmfw_header {
char magic[4];
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index 807040bb3921..a3206e65e5e5 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -340,6 +340,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
* rate is lowered.
*/
inv_fs = true;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_A:
dev->mode = MOD_DSP_A;
break;
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 47c0c821d325..f70db8412c7c 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -320,12 +320,8 @@ static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
handled_mask |= XUNDRN;
substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
- if (substream) {
- snd_pcm_stream_lock_irq(substream);
- if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irq(substream);
- }
+ if (substream)
+ snd_pcm_stop_xrun(substream);
}
if (!handled_mask)
@@ -355,12 +351,8 @@ static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
handled_mask |= ROVRN;
substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
- if (substream) {
- snd_pcm_stream_lock_irq(substream);
- if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irq(substream);
- }
+ if (substream)
+ snd_pcm_stop_xrun(substream);
}
if (!handled_mask)
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 4a6750aa3637..44433b20435c 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -1,14 +1,10 @@
-/*
- * Freescale Generic ASoC Sound Card driver with ASRC
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale Generic ASoC Sound Card driver with ASRC
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+//
+// Author: Nicolin Chen <nicoleotsuka@gmail.com>
#include <linux/clk.h>
#include <linux/i2c.h>
@@ -199,7 +195,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
snd_mask_none(mask);
- snd_mask_set(mask, (__force int)priv->asrc_format);
+ snd_mask_set_format(mask, priv->asrc_format);
return 0;
}
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index adfb8135d739..528e8b108422 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1,14 +1,10 @@
-/*
- * Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+//
+// Author: Nicolin Chen <nicoleotsuka@gmail.com>
#include <linux/clk.h>
#include <linux/delay.h>
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index d558dd5499a5..c60075112570 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* fsl_asrc.h - Freescale ASRC ALSA SoC header file
*
* Copyright (C) 2014 Freescale Semiconductor, Inc.
*
* Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#ifndef _FSL_ASRC_H
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 565e16d8fe85..1033ac6631b0 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -1,14 +1,10 @@
-/*
- * Freescale ASRC ALSA SoC Platform (DMA) driver
- *
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * Author: Nicolin Chen <nicoleotsuka@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ASRC ALSA SoC Platform (DMA) driver
+//
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
+//
+// Author: Nicolin Chen <nicoleotsuka@gmail.com>
#include <linux/dma-mapping.h>
#include <linux/module.h>
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 8f43110373b8..c1d1d06783e5 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -249,6 +249,7 @@ static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
break;
case ESAI_HCKT_EXTAL:
ecr |= ESAI_ECR_ETI;
+ /* fall through */
case ESAI_HCKR_EXTAL:
ecr |= ESAI_ECR_ERI;
break;
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 9b59d87b61bf..740b90df44bb 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -1118,7 +1118,7 @@ static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
- rate_ideal = rate[index] * txclk_df * 64;
+ rate_ideal = rate[index] * txclk_df * 64ULL;
if (round)
rate_actual = clk_round_rate(clk, rate_ideal);
else
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index 7592b0406370..7f0fa4b52223 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -1,14 +1,10 @@
-/**
- * Freescale ALSA SoC Machine driver utility
- *
- * Author: Timur Tabi <timur@freescale.com>
- *
- * Copyright 2010 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale ALSA SoC Machine driver utility
+//
+// Author: Timur Tabi <timur@freescale.com>
+//
+// Copyright 2010 Freescale Semiconductor, Inc.
#include <linux/module.h>
#include <linux/of_address.h>
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
index 1687b66ef18e..c5dc2a14b492 100644
--- a/sound/soc/fsl/fsl_utils.h
+++ b/sound/soc/fsl/fsl_utils.h
@@ -1,13 +1,10 @@
-/**
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
* Freescale ALSA SoC Machine driver utility
*
* Author: Timur Tabi <timur@freescale.com>
*
* Copyright 2010 Freescale Semiconductor, Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
*/
#ifndef _FSL_UTILS_H
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index b99e0b5e00e9..c29200cf755a 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -1,14 +1,7 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- * Copyright 2012 Linaro Ltd.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2012 Freescale Semiconductor, Inc.
+// Copyright 2012 Linaro Ltd.
#include <linux/module.h>
#include <linux/of.h>
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index d93bacacbd5b..2094d2c8919f 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -1,15 +1,12 @@
-/*
- * ASoC audio graph sound card support
- *
- * Copyright (C) 2016 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on ${LINUX}/sound/soc/generic/simple-card.c
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC audio graph sound card support
+//
+// Copyright (C) 2016 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// based on ${LINUX}/sound/soc/generic/simple-card.c
+
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio.h>
@@ -21,7 +18,6 @@
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/string.h>
-#include <sound/jack.h>
#include <sound/simple_card_utils.h>
struct graph_card_data {
@@ -32,6 +28,8 @@ struct graph_card_data {
unsigned int mclk_fs;
} *dai_props;
unsigned int mclk_fs;
+ struct asoc_simple_jack hp_jack;
+ struct asoc_simple_jack mic_jack;
struct snd_soc_dai_link *dai_link;
struct gpio_desc *pa_gpio;
};
@@ -278,6 +276,22 @@ static int asoc_graph_get_dais_count(struct device *dev)
return count;
}
+static int asoc_graph_soc_card_probe(struct snd_soc_card *card)
+{
+ struct graph_card_data *priv = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = asoc_simple_card_init_hp(card, &priv->hp_jack, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_init_mic(card, &priv->mic_jack, NULL);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int asoc_graph_card_probe(struct platform_device *pdev)
{
struct graph_card_data *priv;
@@ -319,6 +333,7 @@ static int asoc_graph_card_probe(struct platform_device *pdev)
card->num_links = num;
card->dapm_widgets = asoc_graph_card_dapm_widgets;
card->num_dapm_widgets = ARRAY_SIZE(asoc_graph_card_dapm_widgets);
+ card->probe = asoc_graph_soc_card_probe;
ret = asoc_graph_card_parse_of(priv);
if (ret < 0) {
diff --git a/sound/soc/generic/audio-graph-scu-card.c b/sound/soc/generic/audio-graph-scu-card.c
index 095ef6426d42..92882e392d6c 100644
--- a/sound/soc/generic/audio-graph-scu-card.c
+++ b/sound/soc/generic/audio-graph-scu-card.c
@@ -1,17 +1,14 @@
-/*
- * ASoC audio graph SCU sound card support
- *
- * Copyright (C) 2017 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on
- * ${LINUX}/sound/soc/generic/simple-scu-card.c
- * ${LINUX}/sound/soc/generic/audio-graph-card.c
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC audio graph SCU sound card support
+//
+// Copyright (C) 2017 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// based on
+// ${LINUX}/sound/soc/generic/simple-scu-card.c
+// ${LINUX}/sound/soc/generic/audio-graph-card.c
+
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/gpio.h>
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 3751a07de6aa..d3f3f0fec74c 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -1,16 +1,17 @@
-/*
- * simple-card-utils.c
- *
- * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// simple-card-utils.c
+//
+// Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/of_graph.h>
+#include <sound/jack.h>
#include <sound/simple_card_utils.h>
void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
@@ -419,6 +420,61 @@ int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
+int asoc_simple_card_init_jack(struct snd_soc_card *card,
+ struct asoc_simple_jack *sjack,
+ int is_hp, char *prefix)
+{
+ struct device *dev = card->dev;
+ enum of_gpio_flags flags;
+ char prop[128];
+ char *pin_name;
+ char *gpio_name;
+ int mask;
+ int det;
+
+ if (!prefix)
+ prefix = "";
+
+ sjack->gpio.gpio = -ENOENT;
+
+ if (is_hp) {
+ snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
+ pin_name = "Headphones";
+ gpio_name = "Headphone detection";
+ mask = SND_JACK_HEADPHONE;
+ } else {
+ snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
+ pin_name = "Mic Jack";
+ gpio_name = "Mic detection";
+ mask = SND_JACK_MICROPHONE;
+ }
+
+ det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
+ if (det == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ if (gpio_is_valid(det)) {
+ sjack->pin.pin = pin_name;
+ sjack->pin.mask = mask;
+
+ sjack->gpio.name = gpio_name;
+ sjack->gpio.report = mask;
+ sjack->gpio.gpio = det;
+ sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
+ sjack->gpio.debounce_time = 150;
+
+ snd_soc_card_jack_new(card, pin_name, mask,
+ &sjack->jack,
+ &sjack->pin, 1);
+
+ snd_soc_jack_add_gpios(&sjack->jack, 1,
+ &sjack->gpio);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(asoc_simple_card_init_jack);
+
/* Module information */
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 8b374af86a6e..64bf3560c1d1 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -1,32 +1,20 @@
-/*
- * ASoC simple sound card support
- *
- * Copyright (C) 2012 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC simple sound card support
+//
+// Copyright (C) 2012 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include <linux/clk.h>
#include <linux/device.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/string.h>
-#include <sound/jack.h>
#include <sound/simple_card.h>
#include <sound/soc-dai.h>
#include <sound/soc.h>
-struct asoc_simple_jack {
- struct snd_soc_jack jack;
- struct snd_soc_jack_pin pin;
- struct snd_soc_jack_gpio gpio;
-};
-
struct simple_card_data {
struct snd_soc_card snd_card;
struct simple_dai_props {
@@ -49,61 +37,6 @@ struct simple_card_data {
#define CELL "#sound-dai-cells"
#define PREFIX "simple-audio-card,"
-#define asoc_simple_card_init_hp(card, sjack, prefix)\
- asoc_simple_card_init_jack(card, sjack, 1, prefix)
-#define asoc_simple_card_init_mic(card, sjack, prefix)\
- asoc_simple_card_init_jack(card, sjack, 0, prefix)
-static int asoc_simple_card_init_jack(struct snd_soc_card *card,
- struct asoc_simple_jack *sjack,
- int is_hp, char *prefix)
-{
- struct device *dev = card->dev;
- enum of_gpio_flags flags;
- char prop[128];
- char *pin_name;
- char *gpio_name;
- int mask;
- int det;
-
- sjack->gpio.gpio = -ENOENT;
-
- if (is_hp) {
- snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
- pin_name = "Headphones";
- gpio_name = "Headphone detection";
- mask = SND_JACK_HEADPHONE;
- } else {
- snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
- pin_name = "Mic Jack";
- gpio_name = "Mic detection";
- mask = SND_JACK_MICROPHONE;
- }
-
- det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
- if (det == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-
- if (gpio_is_valid(det)) {
- sjack->pin.pin = pin_name;
- sjack->pin.mask = mask;
-
- sjack->gpio.name = gpio_name;
- sjack->gpio.report = mask;
- sjack->gpio.gpio = det;
- sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW);
- sjack->gpio.debounce_time = 150;
-
- snd_soc_card_jack_new(card, pin_name, mask,
- &sjack->jack,
- &sjack->pin, 1);
-
- snd_soc_jack_add_gpios(&sjack->jack, 1,
- &sjack->gpio);
- }
-
- return 0;
-}
-
static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -213,14 +146,6 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
if (ret < 0)
return ret;
- ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX);
- if (ret < 0)
- return ret;
-
- ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -414,6 +339,22 @@ card_parse_end:
return ret;
}
+static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
+{
+ struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
+ if (ret < 0)
+ return ret;
+
+ ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int asoc_simple_card_probe(struct platform_device *pdev)
{
struct simple_card_data *priv;
@@ -449,6 +390,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
card->dev = dev;
card->dai_link = priv->dai_link;
card->num_links = num;
+ card->probe = asoc_simple_soc_card_probe;
if (np && of_device_is_available(np)) {
diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c
index 487716559deb..16a83bc51e0e 100644
--- a/sound/soc/generic/simple-scu-card.c
+++ b/sound/soc/generic/simple-scu-card.c
@@ -1,15 +1,12 @@
-/*
- * ASoC simple SCU sound card support
- *
- * Copyright (C) 2015 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on ${LINUX}/sound/soc/generic/simple-card.c
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ASoC simple SCU sound card support
+//
+// Copyright (C) 2015 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// based on ${LINUX}/sound/soc/generic/simple-card.c
+
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/module.h>
diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c
index 6a8b253c58d2..5455d6e0ab53 100644
--- a/sound/soc/intel/atom/sst/sst_drv_interface.c
+++ b/sound/soc/intel/atom/sst/sst_drv_interface.c
@@ -266,17 +266,15 @@ static int sst_cdev_ack(struct device *dev, unsigned int str_id,
stream->cumm_bytes += bytes;
dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
- memcpy_fromio(&fw_tstamp,
- ((void *)(ctx->mailbox + ctx->tstamp)
- +(str_id * sizeof(fw_tstamp))),
- sizeof(fw_tstamp));
+ addr = ((void __iomem *)(ctx->mailbox + ctx->tstamp)) +
+ (str_id * sizeof(fw_tstamp));
+
+ memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
fw_tstamp.bytes_copied = stream->cumm_bytes;
dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
fw_tstamp.bytes_copied, bytes);
- addr = ((void *)(ctx->mailbox + ctx->tstamp)) +
- (str_id * sizeof(fw_tstamp));
offset = offsetof(struct snd_sst_tstamp, bytes_copied);
sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
return 0;
@@ -360,11 +358,12 @@ static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
struct snd_sst_tstamp fw_tstamp = {0,};
struct stream_info *stream;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+ void __iomem *addr;
+
+ addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) +
+ (str_id * sizeof(fw_tstamp));
- memcpy_fromio(&fw_tstamp,
- ((void *)(ctx->mailbox + ctx->tstamp)
- +(str_id * sizeof(fw_tstamp))),
- sizeof(fw_tstamp));
+ memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
stream = get_stream_info(ctx, str_id);
if (!stream)
@@ -530,6 +529,7 @@ static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
struct snd_sst_tstamp fw_tstamp;
unsigned int str_id;
struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+ void __iomem *addr;
str_id = info->str_id;
stream = get_stream_info(ctx, str_id);
@@ -540,10 +540,11 @@ static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
return -EINVAL;
substream = stream->pcm_substream;
- memcpy_fromio(&fw_tstamp,
- ((void *)(ctx->mailbox + ctx->tstamp)
- + (str_id * sizeof(fw_tstamp))),
- sizeof(fw_tstamp));
+ addr = (void __iomem *)(ctx->mailbox + ctx->tstamp) +
+ (str_id * sizeof(fw_tstamp));
+
+ memcpy_fromio(&fw_tstamp, addr, sizeof(fw_tstamp));
+
return sst_calc_tstamp(ctx, info, substream, &fw_tstamp);
}
diff --git a/sound/soc/intel/atom/sst/sst_loader.c b/sound/soc/intel/atom/sst/sst_loader.c
index a686eef2cf7f..27413ebae956 100644
--- a/sound/soc/intel/atom/sst/sst_loader.c
+++ b/sound/soc/intel/atom/sst/sst_loader.c
@@ -44,15 +44,15 @@ void memcpy32_toio(void __iomem *dst, const void *src, int count)
/* __iowrite32_copy uses 32-bit count values so divide by 4 for
* right count in words
*/
- __iowrite32_copy(dst, src, count/4);
+ __iowrite32_copy(dst, src, count / 4);
}
void memcpy32_fromio(void *dst, const void __iomem *src, int count)
{
- /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+ /* __ioread32_copy uses 32-bit count values so divide by 4 for
* right count in words
*/
- __iowrite32_copy(dst, src, count/4);
+ __ioread32_copy(dst, src, count / 4);
}
/**
diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig
index 24797482a3d2..cccda87f4b34 100644
--- a/sound/soc/intel/boards/Kconfig
+++ b/sound/soc/intel/boards/Kconfig
@@ -281,6 +281,20 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
+ tristate "GLK with RT5682 and MAX98357A in I2S Mode"
+ depends on MFD_INTEL_LPSS && I2C && ACPI
+ select SND_SOC_RT5682
+ select SND_SOC_MAX98357A
+ select SND_SOC_DMIC
+ select SND_SOC_HDAC_HDMI
+ select SND_HDA_DSP_LOADER
+ help
+ This adds support for ASoC machine driver for Geminilake platforms
+ with RT5682 + MAX98357A I2S audio codec.
+ Say Y if you have such a device.
+ If unsure select "N".
+
endif ## SND_SOC_INTEL_SKYLAKE
endif ## SND_SOC_INTEL_MACH
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile
index 92b5507291af..87ef8b4058e5 100644
--- a/sound/soc/intel/boards/Makefile
+++ b/sound/soc/intel/boards/Makefile
@@ -6,6 +6,7 @@ snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o
snd-soc-sst-broadwell-objs := broadwell.o
snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o
snd-soc-sst-bxt-rt298-objs := bxt_rt298.o
+snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o
snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o
snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o
snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o
+obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o
diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c
index 6ea360f33575..efcfd906c856 100644
--- a/sound/soc/intel/boards/bdw-rt5677.c
+++ b/sound/soc/intel/boards/bdw-rt5677.c
@@ -154,9 +154,7 @@ static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = 2;
/* set SSP0 to 16 bit */
- snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
- SNDRV_PCM_HW_PARAM_FIRST_MASK],
- SNDRV_PCM_FORMAT_S16_LE);
+ params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c
index 40eb979d5ac1..6f052fc8d1e2 100644
--- a/sound/soc/intel/boards/bxt_da7219_max98357a.c
+++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c
@@ -160,7 +160,7 @@ static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP to 24 bit */
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
@@ -324,8 +324,22 @@ static const struct snd_pcm_hw_constraint_list constraints_16000 = {
.list = rates_16000,
};
+static const unsigned int ch_mono[] = {
+ 1,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_refcap = {
+ .count = ARRAY_SIZE(ch_mono),
+ .list = ch_mono,
+};
+
static int broxton_refcap_startup(struct snd_pcm_substream *substream)
{
+ substream->runtime->hw.channels_max = 1;
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_refcap);
+
return snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_16000);
@@ -586,7 +600,7 @@ static int broxton_audio_probe(struct platform_device *pdev)
static struct platform_driver broxton_audio = {
.probe = broxton_audio_probe,
.driver = {
- .name = "bxt_da7219_max98357a_i2s",
+ .name = "bxt_da7219_max98357a",
.pm = &snd_soc_pm_ops,
},
};
@@ -599,4 +613,4 @@ MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>");
MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>");
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bxt_da7219_max98357a_i2s");
+MODULE_ALIAS("platform:bxt_da7219_max98357a");
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c
index b68c289558a8..27308337ab12 100644
--- a/sound/soc/intel/boards/bxt_rt298.c
+++ b/sound/soc/intel/boards/bxt_rt298.c
@@ -221,7 +221,7 @@ static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP5 to 24 bit */
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 33065ba294a9..d32844f94d74 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -404,7 +404,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
BYT_RT5640_JD_SRC_JD1_IN4P |
- BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_TH_1500UA |
BYT_RT5640_OVCD_SF_0P75 |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
@@ -464,12 +464,38 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_MCLK_EN),
},
{
+ /* Chuwi Vi10 (CWI505) */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"),
+ DMI_MATCH(DMI_BOARD_NAME, "BYT-PF02"),
+ DMI_MATCH(DMI_SYS_VENDOR, "ilife"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S165"),
+ },
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
+ {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
},
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP),
},
+ { /* Connect Tablet 9 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Connect"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Tablet 9"),
+ },
+ .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+ BYT_RT5640_MONO_SPEAKER |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -536,6 +562,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
+ { /* Lenovo Miix 2 8 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "20326"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "Hiking"),
+ },
+ .driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_MONO_SPEAKER |
+ BYT_RT5640_MCLK_EN),
+ },
{ /* MSI S100 tablet */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
@@ -549,6 +588,20 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_DIFF_MIC |
BYT_RT5640_MCLK_EN),
},
+ { /* Nuvison/TMax TM800W560 */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TMAX"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "TM800W560L"),
+ },
+ .driver_data = (void *)(BYT_RT5640_IN1_MAP |
+ BYT_RT5640_JD_SRC_JD2_IN4N |
+ BYT_RT5640_OVCD_TH_2000UA |
+ BYT_RT5640_OVCD_SF_0P75 |
+ BYT_RT5640_JD_NOT_INV |
+ BYT_RT5640_DIFF_MIC |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
{ /* Pipo W4 */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c
index 987720e203f9..f8a68bdb3885 100644
--- a/sound/soc/intel/boards/bytcr_rt5651.c
+++ b/sound/soc/intel/boards/bytcr_rt5651.c
@@ -26,8 +26,12 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/dmi.h>
+#include <linux/input.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/slab.h>
#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
#include <asm/platform_sst_audio.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -42,8 +46,6 @@ enum {
BYT_RT5651_IN1_MAP,
BYT_RT5651_IN2_MAP,
BYT_RT5651_IN1_IN2_MAP,
- BYT_RT5651_IN1_HS_IN3_MAP,
- BYT_RT5651_IN2_HS_IN3_MAP,
};
enum {
@@ -76,21 +78,26 @@ enum {
#define BYT_RT5651_SSP2_AIF2 BIT(19) /* default is using AIF1 */
#define BYT_RT5651_SSP0_AIF1 BIT(20)
#define BYT_RT5651_SSP0_AIF2 BIT(21)
+#define BYT_RT5651_HP_LR_SWAPPED BIT(22)
+#define BYT_RT5651_MONO_SPEAKER BIT(23)
+
+#define BYT_RT5651_DEFAULT_QUIRKS (BYT_RT5651_MCLK_EN | \
+ BYT_RT5651_JD1_1 | \
+ BYT_RT5651_OVCD_TH_2000UA | \
+ BYT_RT5651_OVCD_SF_0P75)
/* jack-detect-source + dmic-en + ovcd-th + -sf + terminating empty entry */
#define MAX_NO_PROPS 5
struct byt_rt5651_private {
struct clk *mclk;
+ struct gpio_desc *ext_amp_gpio;
struct snd_soc_jack jack;
};
/* Default: jack-detect on JD1_1, internal mic on in2, headsetmic on in3 */
-static unsigned long byt_rt5651_quirk = BYT_RT5651_MCLK_EN |
- BYT_RT5651_JD1_1 |
- BYT_RT5651_OVCD_TH_2000UA |
- BYT_RT5651_OVCD_SF_0P75 |
- BYT_RT5651_IN2_HS_IN3_MAP;
+static unsigned long byt_rt5651_quirk = BYT_RT5651_DEFAULT_QUIRKS |
+ BYT_RT5651_IN2_MAP;
static void log_quirks(struct device *dev)
{
@@ -100,10 +107,8 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk IN1_MAP enabled");
if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_MAP)
dev_info(dev, "quirk IN2_MAP enabled");
- if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_HS_IN3_MAP)
- dev_info(dev, "quirk IN1_HS_IN3_MAP enabled");
- if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN2_HS_IN3_MAP)
- dev_info(dev, "quirk IN2_HS_IN3_MAP enabled");
+ if (BYT_RT5651_MAP(byt_rt5651_quirk) == BYT_RT5651_IN1_IN2_MAP)
+ dev_info(dev, "quirk IN1_IN2_MAP enabled");
if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) {
dev_info(dev, "quirk realtek,jack-detect-source %ld\n",
BYT_RT5651_JDSRC(byt_rt5651_quirk));
@@ -124,6 +129,8 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk SSP0_AIF1 enabled\n");
if (byt_rt5651_quirk & BYT_RT5651_SSP0_AIF2)
dev_info(dev, "quirk SSP0_AIF2 enabled\n");
+ if (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER)
+ dev_info(dev, "quirk MONO_SPEAKER enabled\n");
}
#define BYT_CODEC_DAI1 "rt5651-aif1"
@@ -211,6 +218,20 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5651_ext_amp_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_card *card = w->dapm->card;
+ struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ gpiod_set_value_cansleep(priv->ext_amp_gpio, 1);
+ else
+ gpiod_set_value_cansleep(priv->ext_amp_gpio, 0);
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -220,7 +241,9 @@ static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = {
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
-
+ SND_SOC_DAPM_SUPPLY("Ext Amp Power", SND_SOC_NOPM, 0, 0,
+ rt5651_ext_amp_power_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
};
static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
@@ -228,6 +251,7 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
{"Headset Mic", NULL, "Platform Clock"},
{"Internal Mic", NULL, "Platform Clock"},
{"Speaker", NULL, "Platform Clock"},
+ {"Speaker", NULL, "Ext Amp Power"},
{"Line In", NULL, "Platform Clock"},
{"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */
@@ -241,38 +265,26 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = {
};
static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic_map[] = {
- {"IN2P", NULL, "Headset Mic"},
{"DMIC L1", NULL, "Internal Mic"},
{"DMIC R1", NULL, "Internal Mic"},
+ {"IN3P", NULL, "Headset Mic"},
};
static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = {
{"Internal Mic", NULL, "micbias1"},
{"IN1P", NULL, "Internal Mic"},
- {"IN2P", NULL, "Headset Mic"},
+ {"IN3P", NULL, "Headset Mic"},
};
static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_map[] = {
{"Internal Mic", NULL, "micbias1"},
- {"IN1P", NULL, "Headset Mic"},
- {"IN2P", NULL, "Internal Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
- {"Internal Mic", NULL, "micbias1"},
- {"IN1P", NULL, "Internal Mic"},
{"IN2P", NULL, "Internal Mic"},
{"IN3P", NULL, "Headset Mic"},
};
-static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_hs_in3_map[] = {
+static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_in2_map[] = {
{"Internal Mic", NULL, "micbias1"},
{"IN1P", NULL, "Internal Mic"},
- {"IN3P", NULL, "Headset Mic"},
-};
-
-static const struct snd_soc_dapm_route byt_rt5651_intmic_in2_hs_in3_map[] = {
- {"Internal Mic", NULL, "micbias1"},
{"IN2P", NULL, "Internal Mic"},
{"IN3P", NULL, "Headset Mic"},
};
@@ -357,46 +369,72 @@ static int byt_rt5651_quirk_cb(const struct dmi_system_id *id)
static const struct dmi_system_id byt_rt5651_quirk_table[] = {
{
+ /* Chuwi Hi8 Pro (CWI513) */
.callback = byt_rt5651_quirk_cb,
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"),
},
- .driver_data = (void *)(BYT_RT5651_IN1_HS_IN3_MAP),
+ .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+ BYT_RT5651_IN2_MAP |
+ BYT_RT5651_HP_LR_SWAPPED |
+ BYT_RT5651_MONO_SPEAKER),
},
{
+ /* Chuwi Vi8 Plus (CWI519) */
.callback = byt_rt5651_quirk_cb,
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ADI"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"),
},
- .driver_data = (void *)(BYT_RT5651_MCLK_EN |
- BYT_RT5651_IN1_HS_IN3_MAP),
+ .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+ BYT_RT5651_IN2_MAP |
+ BYT_RT5651_HP_LR_SWAPPED |
+ BYT_RT5651_MONO_SPEAKER),
+ },
+ {
+ /* I.T.Works TW701, Ployer Momo7w and Trekstor ST70416-6
+ * (these all use the same mainboard) */
+ .callback = byt_rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "INSYDE Corp."),
+ /* Partial match for all of itWORKS.G.WI71C.JGBMRBA,
+ * TREK.G.WI71C.JGBMRBA0x and MOMO.G.WI71C.MABMRBA02 */
+ DMI_MATCH(DMI_BIOS_VERSION, ".G.WI71C."),
+ },
+ .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+ BYT_RT5651_IN2_MAP |
+ BYT_RT5651_SSP0_AIF1 |
+ BYT_RT5651_MONO_SPEAKER),
},
{
+ /* KIANO SlimNote 14.2 */
.callback = byt_rt5651_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "KIANO"),
DMI_MATCH(DMI_PRODUCT_NAME, "KIANO SlimNote 14.2"),
},
- .driver_data = (void *)(BYT_RT5651_MCLK_EN |
- BYT_RT5651_JD1_1 |
- BYT_RT5651_OVCD_TH_2000UA |
- BYT_RT5651_OVCD_SF_0P75 |
+ .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
BYT_RT5651_IN1_IN2_MAP),
},
{
- /* Chuwi Vi8 Plus (CWI519) */
+ /* Minnowboard Max B3 */
.callback = byt_rt5651_quirk_cb,
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
- DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"),
+ DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
+ },
+ .driver_data = (void *)(BYT_RT5651_IN1_MAP),
+ },
+ {
+ /* Minnowboard Turbot */
+ .callback = byt_rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ADI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Turbot"),
},
.driver_data = (void *)(BYT_RT5651_MCLK_EN |
- BYT_RT5651_JD1_1 |
- BYT_RT5651_OVCD_TH_2000UA |
- BYT_RT5651_OVCD_SF_0P75 |
- BYT_RT5651_IN2_HS_IN3_MAP),
+ BYT_RT5651_IN1_MAP),
},
{
/* VIOS LTH17 */
@@ -405,11 +443,24 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "VIOS"),
DMI_MATCH(DMI_PRODUCT_NAME, "LTH17"),
},
- .driver_data = (void *)(BYT_RT5651_MCLK_EN |
+ .driver_data = (void *)(BYT_RT5651_IN1_IN2_MAP |
BYT_RT5651_JD1_1 |
BYT_RT5651_OVCD_TH_2000UA |
BYT_RT5651_OVCD_SF_1P0 |
- BYT_RT5651_IN1_IN2_MAP),
+ BYT_RT5651_MCLK_EN),
+ },
+ {
+ /* Yours Y8W81 (and others using the same mainboard) */
+ .callback = byt_rt5651_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "INSYDE Corp."),
+ /* Partial match for all devs with a W86C mainboard */
+ DMI_MATCH(DMI_BIOS_VERSION, ".F.W86C."),
+ },
+ .driver_data = (void *)(BYT_RT5651_DEFAULT_QUIRKS |
+ BYT_RT5651_IN2_MAP |
+ BYT_RT5651_SSP0_AIF1 |
+ BYT_RT5651_MONO_SPEAKER),
},
{}
};
@@ -418,15 +469,10 @@ static const struct dmi_system_id byt_rt5651_quirk_table[] = {
* Note this MUST be called before snd_soc_register_card(), so that the props
* are in place before the codec component driver's probe function parses them.
*/
-static int byt_rt5651_add_codec_device_props(const char *i2c_dev_name)
+static int byt_rt5651_add_codec_device_props(struct device *i2c_dev)
{
struct property_entry props[MAX_NO_PROPS] = {};
- struct device *i2c_dev;
- int ret, cnt = 0;
-
- i2c_dev = bus_find_device_by_name(&i2c_bus_type, NULL, i2c_dev_name);
- if (!i2c_dev)
- return -EPROBE_DEFER;
+ int cnt = 0;
props[cnt++] = PROPERTY_ENTRY_U32("realtek,jack-detect-source",
BYT_RT5651_JDSRC(byt_rt5651_quirk));
@@ -440,10 +486,7 @@ static int byt_rt5651_add_codec_device_props(const char *i2c_dev_name)
if (byt_rt5651_quirk & BYT_RT5651_DMIC_EN)
props[cnt++] = PROPERTY_ENTRY_BOOL("realtek,dmic-en");
- ret = device_add_properties(i2c_dev, props);
- put_device(i2c_dev);
-
- return ret;
+ return device_add_properties(i2c_dev, props);
}
static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
@@ -475,14 +518,6 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
custom_map = byt_rt5651_intmic_in1_in2_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_in2_map);
break;
- case BYT_RT5651_IN1_HS_IN3_MAP:
- custom_map = byt_rt5651_intmic_in1_hs_in3_map;
- num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_hs_in3_map);
- break;
- case BYT_RT5651_IN2_HS_IN3_MAP:
- custom_map = byt_rt5651_intmic_in2_hs_in3_map;
- num_routes = ARRAY_SIZE(byt_rt5651_intmic_in2_hs_in3_map);
- break;
default:
custom_map = byt_rt5651_intmic_dmic_map;
num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic_map);
@@ -546,13 +581,17 @@ static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime)
if (BYT_RT5651_JDSRC(byt_rt5651_quirk)) {
ret = snd_soc_card_jack_new(runtime->card, "Headset",
- SND_JACK_HEADSET, &priv->jack,
- bytcr_jack_pins, ARRAY_SIZE(bytcr_jack_pins));
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &priv->jack, bytcr_jack_pins,
+ ARRAY_SIZE(bytcr_jack_pins));
if (ret) {
dev_err(runtime->dev, "jack creation failed %d\n", ret);
return ret;
}
+ snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0,
+ KEY_PLAYPAUSE);
+
ret = snd_soc_component_set_jack(codec, &priv->jack, NULL);
if (ret)
return ret;
@@ -691,6 +730,48 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = {
};
/* SoC card */
+static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
+static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */
+static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
+static char byt_rt5651_long_name[50]; /* = "bytcr-rt5651-*-spk-*-mic[-swapped-hp]" */
+
+static int byt_rt5651_suspend(struct snd_soc_card *card)
+{
+ struct snd_soc_component *component;
+
+ if (!BYT_RT5651_JDSRC(byt_rt5651_quirk))
+ return 0;
+
+ list_for_each_entry(component, &card->component_dev_list, card_list) {
+ if (!strcmp(component->name, byt_rt5651_codec_name)) {
+ dev_dbg(component->dev, "disabling jack detect before suspend\n");
+ snd_soc_component_set_jack(component, NULL, NULL);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int byt_rt5651_resume(struct snd_soc_card *card)
+{
+ struct byt_rt5651_private *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component;
+
+ if (!BYT_RT5651_JDSRC(byt_rt5651_quirk))
+ return 0;
+
+ list_for_each_entry(component, &card->component_dev_list, card_list) {
+ if (!strcmp(component->name, byt_rt5651_codec_name)) {
+ dev_dbg(component->dev, "re-enabling jack detect after resume\n");
+ snd_soc_component_set_jack(component, &priv->jack, NULL);
+ break;
+ }
+ }
+
+ return 0;
+}
+
static struct snd_soc_card byt_rt5651_card = {
.name = "bytcr-rt5651",
.owner = THIS_MODULE,
@@ -701,23 +782,86 @@ static struct snd_soc_card byt_rt5651_card = {
.dapm_routes = byt_rt5651_audio_map,
.num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map),
.fully_routed = true,
+ .suspend_pre = byt_rt5651_suspend,
+ .resume_post = byt_rt5651_resume,
};
-static char byt_rt5651_codec_name[SND_ACPI_I2C_ID_LEN];
-static char byt_rt5651_codec_aif_name[12]; /* = "rt5651-aif[1|2]" */
-static char byt_rt5651_cpu_dai_name[10]; /* = "ssp[0|2]-port" */
-static char byt_rt5651_long_name[40]; /* = "bytcr-rt5651-*-spk-*-mic" */
+static const struct x86_cpu_id baytrail_cpu_ids[] = {
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 }, /* Valleyview */
+ {}
+};
+
+static const struct x86_cpu_id cherrytrail_cpu_ids[] = {
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, /* Braswell */
+ {}
+};
+
+static const struct acpi_gpio_params first_gpio = { 0, 0, false };
+static const struct acpi_gpio_params second_gpio = { 1, 0, false };
+
+static const struct acpi_gpio_mapping byt_rt5651_amp_en_first[] = {
+ { "ext-amp-enable-gpios", &first_gpio, 1 },
+ { },
+};
-static bool is_valleyview(void)
+static const struct acpi_gpio_mapping byt_rt5651_amp_en_second[] = {
+ { "ext-amp-enable-gpios", &second_gpio, 1 },
+ { },
+};
+
+/*
+ * Some boards have I2cSerialBusV2, GpioIo, GpioInt as ACPI resources, other
+ * boards may have I2cSerialBusV2, GpioInt, GpioIo instead. We want the
+ * GpioIo one for the ext-amp-enable-gpio and both count for the index in
+ * acpi_gpio_params index. So we have 2 different mappings and the code
+ * below figures out which one to use.
+ */
+struct byt_rt5651_acpi_resource_data {
+ int gpio_count;
+ int gpio_int_idx;
+};
+
+static int snd_byt_rt5651_acpi_resource(struct acpi_resource *ares, void *arg)
{
- static const struct x86_cpu_id cpu_ids[] = {
- { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
- {}
- };
-
- if (!x86_match_cpu(cpu_ids))
- return false;
- return true;
+ struct byt_rt5651_acpi_resource_data *data = arg;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
+ return 0;
+
+ if (ares->data.gpio.connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
+ data->gpio_int_idx = data->gpio_count;
+
+ data->gpio_count++;
+ return 0;
+}
+
+static void snd_byt_rt5651_mc_add_amp_en_gpio_mapping(struct device *codec)
+{
+ struct byt_rt5651_acpi_resource_data data = { 0, -1 };
+ LIST_HEAD(resources);
+ int ret;
+
+ ret = acpi_dev_get_resources(ACPI_COMPANION(codec), &resources,
+ snd_byt_rt5651_acpi_resource, &data);
+ if (ret < 0) {
+ dev_warn(codec, "Failed to get ACPI resources, not adding external amplifier GPIO mapping\n");
+ return;
+ }
+
+ /* All info we need is gathered during the walk */
+ acpi_dev_free_resource_list(&resources);
+
+ switch (data.gpio_int_idx) {
+ case 0:
+ devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_second);
+ break;
+ case 1:
+ devm_acpi_dev_add_driver_gpios(codec, byt_rt5651_amp_en_first);
+ break;
+ default:
+ dev_warn(codec, "Unknown GpioInt index %d, not adding external amplifier GPIO mapping\n",
+ data.gpio_int_idx);
+ }
}
struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
@@ -727,13 +871,12 @@ struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */
static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
{
- const char * const intmic_name[] =
- { "dmic", "in1", "in2", "in12", "in1", "in2" };
- const char * const hsmic_name[] =
- { "in2", "in2", "in1", "in3", "in3", "in3" };
+ const char * const mic_name[] = { "dmic", "in1", "in2", "in12" };
struct byt_rt5651_private *priv;
struct snd_soc_acpi_mach *mach;
+ struct device *codec_dev;
const char *i2c_name = NULL;
+ const char *hp_swapped;
bool is_bytcr = false;
int ret_val = 0;
int dai_index = 0;
@@ -767,11 +910,16 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
"%s%s", "i2c-", i2c_name);
byt_rt5651_dais[dai_index].codec_name = byt_rt5651_codec_name;
+ codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL,
+ byt_rt5651_codec_name);
+ if (!codec_dev)
+ return -EPROBE_DEFER;
+
/*
* swap SSP0 if bytcr is detected
* (will be overridden if DMI quirk is detected)
*/
- if (is_valleyview()) {
+ if (x86_match_cpu(baytrail_cpu_ids)) {
struct sst_platform_info *p_info = mach->pdata;
const struct sst_res_info *res_info = p_info->res_info;
@@ -830,9 +978,37 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
dmi_check_system(byt_rt5651_quirk_table);
/* Must be called before register_card, also see declaration comment. */
- ret_val = byt_rt5651_add_codec_device_props(byt_rt5651_codec_name);
- if (ret_val)
+ ret_val = byt_rt5651_add_codec_device_props(codec_dev);
+ if (ret_val) {
+ put_device(codec_dev);
return ret_val;
+ }
+
+ /* Cherry Trail devices use an external amplifier enable gpio */
+ if (x86_match_cpu(cherrytrail_cpu_ids)) {
+ snd_byt_rt5651_mc_add_amp_en_gpio_mapping(codec_dev);
+ priv->ext_amp_gpio = devm_fwnode_get_index_gpiod_from_child(
+ &pdev->dev, "ext-amp-enable", 0,
+ codec_dev->fwnode,
+ GPIOD_OUT_LOW, "speaker-amp");
+ if (IS_ERR(priv->ext_amp_gpio)) {
+ ret_val = PTR_ERR(priv->ext_amp_gpio);
+ switch (ret_val) {
+ case -ENOENT:
+ priv->ext_amp_gpio = NULL;
+ break;
+ default:
+ dev_err(&pdev->dev, "Failed to get ext-amp-enable GPIO: %d\n",
+ ret_val);
+ /* fall through */
+ case -EPROBE_DEFER:
+ put_device(codec_dev);
+ return ret_val;
+ }
+ }
+ }
+
+ put_device(codec_dev);
log_quirks(&pdev->dev);
@@ -876,10 +1052,16 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev)
}
}
+ if (byt_rt5651_quirk & BYT_RT5651_HP_LR_SWAPPED)
+ hp_swapped = "-hp-swapped";
+ else
+ hp_swapped = "";
+
snprintf(byt_rt5651_long_name, sizeof(byt_rt5651_long_name),
- "bytcr-rt5651-%s-intmic-%s-hsmic",
- intmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)],
- hsmic_name[BYT_RT5651_MAP(byt_rt5651_quirk)]);
+ "bytcr-rt5651-%s-spk-%s-mic%s",
+ (byt_rt5651_quirk & BYT_RT5651_MONO_SPEAKER) ?
+ "mono" : "stereo",
+ mic_name[BYT_RT5651_MAP(byt_rt5651_quirk)], hp_swapped);
byt_rt5651_card.long_name = byt_rt5651_long_name;
ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card);
diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c
new file mode 100644
index 000000000000..c4b94e2617c5
--- /dev/null
+++ b/sound/soc/intel/boards/glk_rt5682_max98357a.c
@@ -0,0 +1,643 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2018 Intel Corporation.
+
+/*
+ * Intel Geminilake I2S Machine Driver with MAX98357A & RT5682 Codecs
+ *
+ * Modified from:
+ * Intel Apollolake I2S Machine driver
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../skylake/skl.h"
+#include "../../codecs/rt5682.h"
+#include "../../codecs/hdac_hdmi.h"
+
+/* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */
+#define GLK_PLAT_CLK_FREQ 19200000
+#define RT5682_PLL_FREQ (48000 * 512)
+#define GLK_REALTEK_CODEC_DAI "rt5682-aif1"
+#define GLK_MAXIM_CODEC_DAI "HiFi"
+#define MAXIM_DEV0_NAME "MX98357A:00"
+#define DUAL_CHANNEL 2
+#define QUAD_CHANNEL 4
+#define NAME_SIZE 32
+
+static struct snd_soc_jack geminilake_hdmi[3];
+
+struct glk_hdmi_pcm {
+ struct list_head head;
+ struct snd_soc_dai *codec_dai;
+ int device;
+};
+
+struct glk_card_private {
+ struct snd_soc_jack geminilake_headset;
+ struct list_head hdmi_pcm_list;
+};
+
+enum {
+ GLK_DPCM_AUDIO_PB = 0,
+ GLK_DPCM_AUDIO_CP,
+ GLK_DPCM_AUDIO_HS_PB,
+ GLK_DPCM_AUDIO_ECHO_REF_CP,
+ GLK_DPCM_AUDIO_REF_CP,
+ GLK_DPCM_AUDIO_DMIC_CP,
+ GLK_DPCM_AUDIO_HDMI1_PB,
+ GLK_DPCM_AUDIO_HDMI2_PB,
+ GLK_DPCM_AUDIO_HDMI3_PB,
+};
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+ int ret = 0;
+
+ codec_dai = snd_soc_card_get_codec_dai(card, GLK_REALTEK_CODEC_DAI);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n");
+ return -EIO;
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
+ if (ret)
+ dev_err(card->dev, "failed to stop sysclk: %d\n", ret);
+ } else if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5682_PLL1_S_MCLK,
+ GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ);
+ if (ret < 0) {
+ dev_err(card->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (ret)
+ dev_err(card->dev, "failed to start internal clk: %d\n", ret);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new geminilake_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Spk"),
+};
+
+static const struct snd_soc_dapm_widget geminilake_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Spk", NULL),
+ SND_SOC_DAPM_MIC("SoC DMIC", NULL),
+ SND_SOC_DAPM_SPK("HDMI1", NULL),
+ SND_SOC_DAPM_SPK("HDMI2", NULL),
+ SND_SOC_DAPM_SPK("HDMI3", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route geminilake_map[] = {
+ /* HP jack connectors - unknown if we have jack detection */
+ { "Headphone Jack", NULL, "Platform Clock" },
+ { "Headphone Jack", NULL, "HPOL" },
+ { "Headphone Jack", NULL, "HPOR" },
+
+ /* speaker */
+ { "Spk", NULL, "Speaker" },
+
+ /* other jacks */
+ { "Headset Mic", NULL, "Platform Clock" },
+ { "IN1P", NULL, "Headset Mic" },
+
+ /* digital mics */
+ { "DMic", NULL, "SoC DMIC" },
+
+ /* CODEC BE connections */
+ { "HiFi Playback", NULL, "ssp1 Tx" },
+ { "ssp1 Tx", NULL, "codec0_out" },
+
+ { "AIF1 Playback", NULL, "ssp2 Tx" },
+ { "ssp2 Tx", NULL, "codec1_out" },
+
+ { "codec0_in", NULL, "ssp2 Rx" },
+ { "ssp2 Rx", NULL, "AIF1 Capture" },
+
+ { "HDMI1", NULL, "hif5-0 Output" },
+ { "HDMI2", NULL, "hif6-0 Output" },
+ { "HDMI2", NULL, "hif7-0 Output" },
+
+ { "hifi3", NULL, "iDisp3 Tx" },
+ { "iDisp3 Tx", NULL, "iDisp3_out" },
+ { "hifi2", NULL, "iDisp2 Tx" },
+ { "iDisp2 Tx", NULL, "iDisp2_out" },
+ { "hifi1", NULL, "iDisp1 Tx" },
+ { "iDisp1 Tx", NULL, "iDisp1_out" },
+
+ /* DMIC */
+ { "dmic01_hifi", NULL, "DMIC01 Rx" },
+ { "DMIC01 Rx", NULL, "DMIC AIF" },
+};
+
+static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* The ADSP will convert the FE rate to 48k, stereo */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = DUAL_CHANNEL;
+
+ /* set SSP to 24 bit */
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_component *component = rtd->codec_dai->component;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_jack *jack;
+ int ret;
+
+ /* Configure sysclk for codec */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
+ RT5682_PLL_FREQ, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ /*
+ * Headset buttons map to the google Reference headset.
+ * These can be configured by userspace.
+ */
+ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT,
+ &ctx->geminilake_headset, NULL, 0);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ jack = &ctx->geminilake_headset;
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+ ret = snd_soc_component_set_jack(component, jack, NULL);
+
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+};
+
+static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ /* Set valid bitmask & configuration for I2S in 24 bit */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 24);
+ if (ret < 0) {
+ dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static struct snd_soc_ops geminilake_rt5682_ops = {
+ .hw_params = geminilake_rt5682_hw_params,
+};
+
+static int geminilake_hdmi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *dai = rtd->codec_dai;
+ struct glk_hdmi_pcm *pcm;
+
+ pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+
+ pcm->device = GLK_DPCM_AUDIO_HDMI1_PB + dai->id;
+ pcm->codec_dai = dai;
+
+ list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+ return 0;
+}
+
+static int geminilake_rt5682_fe_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component = rtd->cpu_dai->component;
+ struct snd_soc_dapm_context *dapm;
+ int ret;
+
+ dapm = snd_soc_component_get_dapm(component);
+ ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture");
+ if (ret) {
+ dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static const unsigned int rates[] = {
+ 48000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+ .mask = 0,
+};
+
+static const unsigned int channels[] = {
+ DUAL_CHANNEL,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_channels = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+ .mask = 0,
+};
+
+static unsigned int channels_quad[] = {
+ QUAD_CHANNEL,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_channels_quad = {
+ .count = ARRAY_SIZE(channels_quad),
+ .list = channels_quad,
+ .mask = 0,
+};
+
+static int geminilake_dmic_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /*
+ * set BE channel constraint as user FE channels
+ */
+ channels->min = channels->max = 4;
+
+ return 0;
+}
+
+static int geminilake_dmic_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL;
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_channels_quad);
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &constraints_rates);
+}
+
+static const struct snd_soc_ops geminilake_dmic_ops = {
+ .startup = geminilake_dmic_startup,
+};
+
+static const unsigned int rates_16000[] = {
+ 16000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_16000 = {
+ .count = ARRAY_SIZE(rates_16000),
+ .list = rates_16000,
+};
+
+static int geminilake_refcap_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_16000);
+};
+
+static const struct snd_soc_ops geminilake_refcap_ops = {
+ .startup = geminilake_refcap_startup,
+};
+
+/* geminilake digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link geminilake_dais[] = {
+ /* Front End DAI links */
+ [GLK_DPCM_AUDIO_PB] = {
+ .name = "Glk Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:0e.0",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .init = geminilake_rt5682_fe_init,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ },
+ [GLK_DPCM_AUDIO_CP] = {
+ .name = "Glk Audio Capture Port",
+ .stream_name = "Audio Record",
+ .cpu_dai_name = "System Pin",
+ .platform_name = "0000:00:0e.0",
+ .dynamic = 1,
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .nonatomic = 1,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_capture = 1,
+ },
+ [GLK_DPCM_AUDIO_HS_PB] = {
+ .name = "Glk Audio Headset Playback",
+ .stream_name = "Headset Audio",
+ .cpu_dai_name = "System Pin2",
+ .platform_name = "0000:00:0e.0",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .dpcm_playback = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [GLK_DPCM_AUDIO_ECHO_REF_CP] = {
+ .name = "Glk Audio Echo Reference cap",
+ .stream_name = "Echoreference Capture",
+ .cpu_dai_name = "Echoref Pin",
+ .platform_name = "0000:00:0e.0",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .init = NULL,
+ .capture_only = 1,
+ .nonatomic = 1,
+ },
+ [GLK_DPCM_AUDIO_REF_CP] = {
+ .name = "Glk Audio Reference cap",
+ .stream_name = "Refcap",
+ .cpu_dai_name = "Reference Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:0e.0",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &geminilake_refcap_ops,
+ },
+ [GLK_DPCM_AUDIO_DMIC_CP] = {
+ .name = "Glk Audio DMIC cap",
+ .stream_name = "dmiccap",
+ .cpu_dai_name = "DMIC Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:0e.0",
+ .init = NULL,
+ .dpcm_capture = 1,
+ .nonatomic = 1,
+ .dynamic = 1,
+ .ops = &geminilake_dmic_ops,
+ },
+ [GLK_DPCM_AUDIO_HDMI1_PB] = {
+ .name = "Glk HDMI Port1",
+ .stream_name = "Hdmi1",
+ .cpu_dai_name = "HDMI1 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:0e.0",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [GLK_DPCM_AUDIO_HDMI2_PB] = {
+ .name = "Glk HDMI Port2",
+ .stream_name = "Hdmi2",
+ .cpu_dai_name = "HDMI2 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:0e.0",
+ .dpcm_playback = 1,
+ .init = NULL,
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ [GLK_DPCM_AUDIO_HDMI3_PB] = {
+ .name = "Glk HDMI Port3",
+ .stream_name = "Hdmi3",
+ .cpu_dai_name = "HDMI3 Pin",
+ .codec_name = "snd-soc-dummy",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .platform_name = "0000:00:0e.0",
+ .trigger = {
+ SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+ .dpcm_playback = 1,
+ .init = NULL,
+ .nonatomic = 1,
+ .dynamic = 1,
+ },
+ /* Back End DAI links */
+ {
+ /* SSP1 - Codec */
+ .name = "SSP1-Codec",
+ .id = 0,
+ .cpu_dai_name = "SSP1 Pin",
+ .platform_name = "0000:00:0e.0",
+ .no_pcm = 1,
+ .codec_name = MAXIM_DEV0_NAME,
+ .codec_dai_name = GLK_MAXIM_CODEC_DAI,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = geminilake_ssp_fixup,
+ .dpcm_playback = 1,
+ },
+ {
+ /* SSP2 - Codec */
+ .name = "SSP2-Codec",
+ .id = 1,
+ .cpu_dai_name = "SSP2 Pin",
+ .platform_name = "0000:00:0e.0",
+ .no_pcm = 1,
+ .codec_name = "i2c-10EC5682:00",
+ .codec_dai_name = GLK_REALTEK_CODEC_DAI,
+ .init = geminilake_rt5682_codec_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ignore_pmdown_time = 1,
+ .be_hw_params_fixup = geminilake_ssp_fixup,
+ .ops = &geminilake_rt5682_ops,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ },
+ {
+ .name = "dmic01",
+ .id = 2,
+ .cpu_dai_name = "DMIC01 Pin",
+ .codec_name = "dmic-codec",
+ .codec_dai_name = "dmic-hifi",
+ .platform_name = "0000:00:0e.0",
+ .ignore_suspend = 1,
+ .be_hw_params_fixup = geminilake_dmic_fixup,
+ .dpcm_capture = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp1",
+ .id = 3,
+ .cpu_dai_name = "iDisp1 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi1",
+ .platform_name = "0000:00:0e.0",
+ .init = geminilake_hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp2",
+ .id = 4,
+ .cpu_dai_name = "iDisp2 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi2",
+ .platform_name = "0000:00:0e.0",
+ .init = geminilake_hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+ {
+ .name = "iDisp3",
+ .id = 5,
+ .cpu_dai_name = "iDisp3 Pin",
+ .codec_name = "ehdaudio0D2",
+ .codec_dai_name = "intel-hdmi-hifi3",
+ .platform_name = "0000:00:0e.0",
+ .init = geminilake_hdmi_init,
+ .dpcm_playback = 1,
+ .no_pcm = 1,
+ },
+};
+
+static int glk_card_late_probe(struct snd_soc_card *card)
+{
+ struct glk_card_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_component *component = NULL;
+ char jack_name[NAME_SIZE];
+ struct glk_hdmi_pcm *pcm;
+ int err = 0;
+ int i = 0;
+
+ list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+ component = pcm->codec_dai->component;
+ snprintf(jack_name, sizeof(jack_name),
+ "HDMI/DP, pcm=%d Jack", pcm->device);
+ err = snd_soc_card_jack_new(card, jack_name,
+ SND_JACK_AVOUT, &geminilake_hdmi[i],
+ NULL, 0);
+
+ if (err)
+ return err;
+
+ err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+ &geminilake_hdmi[i]);
+ if (err < 0)
+ return err;
+
+ i++;
+ }
+
+ if (!component)
+ return -EINVAL;
+
+ return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
+
+/* geminilake audio machine driver for SPT + RT5682 */
+static struct snd_soc_card glk_audio_card_rt5682_m98357a = {
+ .name = "glkrt5682max",
+ .owner = THIS_MODULE,
+ .dai_link = geminilake_dais,
+ .num_links = ARRAY_SIZE(geminilake_dais),
+ .controls = geminilake_controls,
+ .num_controls = ARRAY_SIZE(geminilake_controls),
+ .dapm_widgets = geminilake_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(geminilake_widgets),
+ .dapm_routes = geminilake_map,
+ .num_dapm_routes = ARRAY_SIZE(geminilake_map),
+ .fully_routed = true,
+ .late_probe = glk_card_late_probe,
+};
+
+static int geminilake_audio_probe(struct platform_device *pdev)
+{
+ struct glk_card_private *ctx;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+ if (!ctx)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+ glk_audio_card_rt5682_m98357a.dev = &pdev->dev;
+ snd_soc_card_set_drvdata(&glk_audio_card_rt5682_m98357a, ctx);
+
+ return devm_snd_soc_register_card(&pdev->dev,
+ &glk_audio_card_rt5682_m98357a);
+}
+
+static const struct platform_device_id glk_board_ids[] = {
+ {
+ .name = "glk_rt5682_max98357a",
+ .driver_data =
+ (kernel_ulong_t)&glk_audio_card_rt5682_m98357a,
+ },
+ { }
+};
+
+static struct platform_driver geminilake_audio = {
+ .probe = geminilake_audio_probe,
+ .driver = {
+ .name = "glk_rt5682_max98357a",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = glk_board_ids,
+};
+module_platform_driver(geminilake_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mode");
+MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>");
+MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:glk_rt5682_max98357a");
diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c
index 94294c27d1db..38f6ab74709d 100644
--- a/sound/soc/intel/boards/kbl_da7219_max98357a.c
+++ b/sound/soc/intel/boards/kbl_da7219_max98357a.c
@@ -152,7 +152,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP to 24 bit */
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
@@ -380,6 +380,7 @@ static struct snd_soc_dai_link kabylake_dais[] = {
.trigger = {
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
+ .ops = &kabylake_da7219_fe_ops,
},
[KBL_DPCM_AUDIO_DMIC_CP] = {
.name = "Kbl Audio DMIC cap",
diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c
index 3a61252fe450..21a6490746a6 100644
--- a/sound/soc/intel/boards/kbl_rt5663_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_max98927.c
@@ -434,14 +434,14 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
}
/*
* The speaker on the SSP0 supports S16_LE and not S24_LE.
* thus changing the mask here
*/
if (!strcmp(be_dai_link->name, "SSP0-Codec"))
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
index 92f5fb2ae0a3..a892b37eab7c 100644
--- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
+++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c
@@ -307,7 +307,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
} else if (!strcmp(fe_dai_link->name, "Kbl Audio DMIC cap")) {
if (params_channels(params) == 2 ||
DMIC_CH(dmic_constraints) == 2)
@@ -320,7 +320,7 @@ static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
* thus changing the mask here
*/
if (!strcmp(be_dai_link->name, "SSP0-Codec"))
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S16_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
index 3ff6646cfa21..d31482b8c9bb 100644
--- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c
+++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c
@@ -157,7 +157,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP0 to 24 bit */
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
index b0610bba3cfa..e877bb60beb1 100644
--- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
+++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c
@@ -346,7 +346,7 @@ static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP0 to 24 bit */
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c
index 38a1495c29cf..0e1818dd4cc6 100644
--- a/sound/soc/intel/boards/skl_rt286.c
+++ b/sound/soc/intel/boards/skl_rt286.c
@@ -229,7 +229,7 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
/* set SSP0 to 24 bit */
snd_mask_none(fmt);
- snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
return 0;
}
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile
index 7379d8830c39..915a34cdc8ac 100644
--- a/sound/soc/intel/common/Makefile
+++ b/sound/soc/intel/common/Makefile
@@ -3,7 +3,11 @@ snd-soc-sst-dsp-objs := sst-dsp.o
snd-soc-sst-acpi-objs := sst-acpi.o
snd-soc-sst-ipc-objs := sst-ipc.o
snd-soc-sst-firmware-objs := sst-firmware.o
-snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o soc-acpi-intel-hsw-bdw-match.o
+snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \
+ soc-acpi-intel-hsw-bdw-match.o \
+ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \
+ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \
+ soc-acpi-intel-cnl-match.o
obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o
obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o
diff --git a/sound/soc/intel/common/soc-acpi-intel-bxt-match.c b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
new file mode 100644
index 000000000000..f39386e540d3
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-bxt-match.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-bxt-match.c - tables and support for BXT ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static struct snd_soc_acpi_codecs bxt_codecs = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[] = {
+ {
+ .id = "INT343A",
+ .drv_name = "bxt_alc298s_i2s",
+ .fw_filename = "intel/dsp_fw_bxtn.bin",
+ },
+ {
+ .id = "DLGS7219",
+ .drv_name = "bxt_da7219_max98357a",
+ .fw_filename = "intel/dsp_fw_bxtn.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &bxt_codecs,
+ .sof_fw_filename = "intel/sof-apl.ri",
+ .sof_tplg_filename = "intel/sof-apl-da7219.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
+ },
+ {
+ .id = "104C5122",
+ .drv_name = "bxt-pcm512x",
+ .sof_fw_filename = "intel/sof-apl.ri",
+ .sof_tplg_filename = "intel/sof-apl-pcm512x.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
+ },
+ {
+ .id = "1AEC8804",
+ .drv_name = "bxt-wm8804",
+ .sof_fw_filename = "intel/sof-apl.ri",
+ .sof_tplg_filename = "intel/sof-apl-wm8804.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
+ },
+ {
+ .id = "INT34C3",
+ .drv_name = "bxt_tdf8532",
+ .sof_fw_filename = "intel/sof-apl.ri",
+ .sof_tplg_filename = "intel/sof-apl-tdf8532.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_bxt_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-byt-match.c b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
index bfe1ca68a542..4daa8a4f0c0c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-byt-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-byt-match.c
@@ -59,8 +59,8 @@ static struct snd_soc_acpi_mach byt_thinkpad_10 = {
.drv_name = "cht-bsw-rt5672",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5670.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5670.tplg",
.asoc_plat_name = "sst-mfld-platform",
};
@@ -98,8 +98,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "bytcr_rt5640",
.machine_quirk = byt_quirk,
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5640.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -107,8 +107,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "bytcr_rt5640",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "bytcr_rt5640",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5640.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -116,8 +116,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "bytcr_rt5640",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "bytcr_rt5640",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5640.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5640.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -125,8 +125,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "bytcr_rt5651",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "bytcr_rt5651",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5651.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5651.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -134,8 +134,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "bytcht_da7213",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "bytcht_da7213",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-da7213.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-da7213.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -143,8 +143,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "bytcht_da7213",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "bytcht_da7213",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-da7213.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-da7213.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
/* some Baytrail platforms rely on RT5645, use CHT machine driver */
@@ -153,8 +153,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "cht-bsw-rt5645",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5645.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5645.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -162,8 +162,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "cht-bsw-rt5645",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-rt5645.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-rt5645.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
/* use CHT driver to Baytrail Chromebooks */
@@ -172,8 +172,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_baytrail_machines[] = {
.drv_name = "cht-bsw-max98090",
.fw_filename = "intel/fw_sst_0f28.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-byt.ri",
- .sof_tplg_filename = "intel/reef-byt-max98090.tplg",
+ .sof_fw_filename = "intel/sof-byt.ri",
+ .sof_tplg_filename = "intel/sof-byt-max98090.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
index ad1eb2d644be..91bb99b69601 100644
--- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c
@@ -44,8 +44,8 @@ static struct snd_soc_acpi_mach cht_surface_mach = {
.drv_name = "cht-bsw-rt5645",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
.asoc_plat_name = "sst-mfld-platform",
};
@@ -68,8 +68,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-rt5672",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5670.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5670.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -77,8 +77,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-rt5672",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5670.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5670.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -86,8 +86,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-rt5645",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -95,8 +95,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-rt5645",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -104,8 +104,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-rt5645",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5645.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5645.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -113,8 +113,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-max98090",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-max98090.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-max98090.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -122,8 +122,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "cht-bsw-nau8824",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "cht-bsw",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-nau8824.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-nau8824.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -131,8 +131,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "bytcht_da7213",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "bytcht_da7213",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-da7213.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-da7213.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -140,8 +140,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "bytcht_da7213",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "bytcht_da7213",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-da7213.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-da7213.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -149,8 +149,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "bytcht_es8316",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "bytcht_es8316",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-es8316.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-es8316.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
/* some CHT-T platforms rely on RT5640, use Baytrail machine driver */
@@ -160,8 +160,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "bytcr_rt5640",
.machine_quirk = cht_quirk,
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5640.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5640.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
{
@@ -169,8 +169,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "bytcr_rt5640",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "bytcr_rt5640",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5640.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5640.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
/* some CHT-T platforms rely on RT5651, use Baytrail machine driver */
@@ -179,8 +179,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cherrytrail_machines[] = {
.drv_name = "bytcr_rt5651",
.fw_filename = "intel/fw_sst_22a8.bin",
.board = "bytcr_rt5651",
- .sof_fw_filename = "intel/reef-cht.ri",
- .sof_tplg_filename = "intel/reef-cht-rt5651.tplg",
+ .sof_fw_filename = "intel/sof-cht.ri",
+ .sof_tplg_filename = "intel/sof-cht-rt5651.tplg",
.asoc_plat_name = "sst-mfld-platform",
},
#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
new file mode 100644
index 000000000000..ec8e28e7b937
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-cnl-match.c - tables and support for CNL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata cnl_pdata = {
+ .use_tplg_pcm = true,
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = {
+ {
+ .id = "INT34C2",
+ .drv_name = "cnl_rt274",
+ .fw_filename = "intel/dsp_fw_cnl.bin",
+ .pdata = &cnl_pdata,
+ .sof_fw_filename = "intel/sof-cnl.ri",
+ .sof_tplg_filename = "intel/sof-cnl-rt274.tplg",
+ .asoc_plat_name = "0000:00:1f.3",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
new file mode 100644
index 000000000000..305875af71ca
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-glk-match.c - tables and support for GLK ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+
+static struct snd_soc_acpi_codecs glk_codecs = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = {
+ {
+ .id = "INT343A",
+ .drv_name = "glk_alc298s_i2s",
+ .fw_filename = "intel/dsp_fw_glk.bin",
+ .sof_fw_filename = "intel/sof-glk.ri",
+ .sof_tplg_filename = "intel/sof-glk-alc298.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
+ },
+ {
+ .id = "DLGS7219",
+ .drv_name = "glk_da7219_max98357a",
+ .fw_filename = "intel/dsp_fw_glk.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &glk_codecs,
+ .sof_fw_filename = "intel/sof-glk.ri",
+ .sof_tplg_filename = "intel/sof-glk-da7219.tplg",
+ .asoc_plat_name = "0000:00:0e.0",
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_glk_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
index e0e8c8c27528..494a0ea9b029 100644
--- a/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-hsw-bdw-match.c
@@ -23,8 +23,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_haswell_machines[] = {
.id = "INT33CA",
.drv_name = "haswell-audio",
.fw_filename = "intel/IntcSST1.bin",
- .sof_fw_filename = "intel/reef-hsw.ri",
- .sof_tplg_filename = "intel/reef-hsw.tplg",
+ .sof_fw_filename = "intel/sof-hsw.ri",
+ .sof_tplg_filename = "intel/sof-hsw.tplg",
.asoc_plat_name = "haswell-pcm-audio",
},
{}
@@ -36,24 +36,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_broadwell_machines[] = {
.id = "INT343A",
.drv_name = "broadwell-audio",
.fw_filename = "intel/IntcSST2.bin",
- .sof_fw_filename = "intel/reef-bdw.ri",
- .sof_tplg_filename = "intel/reef-bdw-rt286.tplg",
+ .sof_fw_filename = "intel/sof-bdw.ri",
+ .sof_tplg_filename = "intel/sof-bdw-rt286.tplg",
.asoc_plat_name = "haswell-pcm-audio",
},
{
.id = "RT5677CE",
.drv_name = "bdw-rt5677",
.fw_filename = "intel/IntcSST2.bin",
- .sof_fw_filename = "intel/reef-bdw.ri",
- .sof_tplg_filename = "intel/reef-bdw-rt286.tplg",
+ .sof_fw_filename = "intel/sof-bdw.ri",
+ .sof_tplg_filename = "intel/sof-bdw-rt5677.tplg",
.asoc_plat_name = "haswell-pcm-audio",
},
{
.id = "INT33CA",
.drv_name = "haswell-audio",
.fw_filename = "intel/IntcSST2.bin",
- .sof_fw_filename = "intel/reef-bdw.ri",
- .sof_tplg_filename = "intel/reef-bdw-rt5640.tplg",
+ .sof_fw_filename = "intel/sof-bdw.ri",
+ .sof_tplg_filename = "intel/sof-bdw-rt5640.tplg",
.asoc_plat_name = "haswell-pcm-audio",
},
{}
diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
new file mode 100644
index 000000000000..0ee173ca437d
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-kbl-match.c - tables and support for KBL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata skl_dmic_data;
+
+static struct snd_soc_acpi_codecs kbl_codecs = {
+ .num_codecs = 1,
+ .codecs = {"10508825"}
+};
+
+static struct snd_soc_acpi_codecs kbl_poppy_codecs = {
+ .num_codecs = 1,
+ .codecs = {"10EC5663"}
+};
+
+static struct snd_soc_acpi_codecs kbl_5663_5514_codecs = {
+ .num_codecs = 2,
+ .codecs = {"10EC5663", "10EC5514"}
+};
+
+static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = {
+ .num_codecs = 1,
+ .codecs = {"MX98357A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = {
+ {
+ .id = "INT343A",
+ .drv_name = "kbl_alc286s_i2s",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
+ {
+ .id = "INT343B",
+ .drv_name = "kbl_n88l25_s4567",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &kbl_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {
+ .id = "MX98357A",
+ .drv_name = "kbl_n88l25_m98357a",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &kbl_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {
+ .id = "MX98927",
+ .drv_name = "kbl_r5514_5663_max",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &kbl_5663_5514_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {
+ .id = "MX98927",
+ .drv_name = "kbl_rt5663_m98927",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &kbl_poppy_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {
+ .id = "10EC5663",
+ .drv_name = "kbl_rt5663",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ },
+ {
+ .id = "DLGS7219",
+ .drv_name = "kbl_da7219_max98357a",
+ .fw_filename = "intel/dsp_fw_kbl.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &kbl_7219_98357_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_kbl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/soc-acpi-intel-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
new file mode 100644
index 000000000000..0c9c0edd35b3
--- /dev/null
+++ b/sound/soc/intel/common/soc-acpi-intel-skl-match.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * soc-apci-intel-skl-match.c - tables and support for SKL ACPI enumeration.
+ *
+ * Copyright (c) 2018, Intel Corporation.
+ *
+ */
+
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include "../skylake/skl.h"
+
+static struct skl_machine_pdata skl_dmic_data;
+
+static struct snd_soc_acpi_codecs skl_codecs = {
+ .num_codecs = 1,
+ .codecs = {"10508825"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = {
+ {
+ .id = "INT343A",
+ .drv_name = "skl_alc286s_i2s",
+ .fw_filename = "intel/dsp_fw_release.bin",
+ },
+ {
+ .id = "INT343B",
+ .drv_name = "skl_n88l25_s4567",
+ .fw_filename = "intel/dsp_fw_release.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &skl_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {
+ .id = "MX98357A",
+ .drv_name = "skl_n88l25_m98357a",
+ .fw_filename = "intel/dsp_fw_release.bin",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &skl_codecs,
+ .pdata = &skl_dmic_data,
+ },
+ {},
+};
+EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_skl_machines);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Common ACPI Match module");
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c
index 657afc02f1c4..11041aedea31 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -270,7 +270,7 @@ void sst_dsp_dma_put_channel(struct sst_dsp *dsp)
}
EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel);
-int sst_dma_new(struct sst_dsp *sst)
+static int sst_dma_new(struct sst_dsp *sst)
{
struct sst_pdata *sst_pdata = sst->pdata;
struct sst_dma *dma;
@@ -320,9 +320,8 @@ err_dma_dev:
devm_kfree(sst->dev, dma);
return ret;
}
-EXPORT_SYMBOL(sst_dma_new);
-void sst_dma_free(struct sst_dma *dma)
+static void sst_dma_free(struct sst_dma *dma)
{
if (dma == NULL)
@@ -335,7 +334,6 @@ void sst_dma_free(struct sst_dma *dma)
dw_remove(dma->chip);
}
-EXPORT_SYMBOL(sst_dma_free);
/* create new generic firmware object */
struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c
index b2bec36d074c..a28220e67cdf 100644
--- a/sound/soc/intel/haswell/sst-haswell-dsp.c
+++ b/sound/soc/intel/haswell/sst-haswell-dsp.c
@@ -93,29 +93,31 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
struct sst_module_template template;
int count, ret;
void __iomem *ram;
+ int type = le16_to_cpu(module->type);
+ int entry_point = le32_to_cpu(module->entry_point);
/* TODO: allowed module types need to be configurable */
- if (module->type != SST_HSW_MODULE_BASE_FW
- && module->type != SST_HSW_MODULE_PCM_SYSTEM
- && module->type != SST_HSW_MODULE_PCM
- && module->type != SST_HSW_MODULE_PCM_REFERENCE
- && module->type != SST_HSW_MODULE_PCM_CAPTURE
- && module->type != SST_HSW_MODULE_WAVES
- && module->type != SST_HSW_MODULE_LPAL)
+ if (type != SST_HSW_MODULE_BASE_FW &&
+ type != SST_HSW_MODULE_PCM_SYSTEM &&
+ type != SST_HSW_MODULE_PCM &&
+ type != SST_HSW_MODULE_PCM_REFERENCE &&
+ type != SST_HSW_MODULE_PCM_CAPTURE &&
+ type != SST_HSW_MODULE_WAVES &&
+ type != SST_HSW_MODULE_LPAL)
return 0;
dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n",
module->signature, module->mod_size,
- module->blocks, module->type);
- dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point);
+ module->blocks, type);
+ dev_dbg(dsp->dev, " entrypoint 0x%x\n", entry_point);
dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n",
module->info.persistent_size, module->info.scratch_size);
memset(&template, 0, sizeof(template));
- template.id = module->type;
- template.entry = module->entry_point - 4;
- template.persistent_size = module->info.persistent_size;
- template.scratch_size = module->info.scratch_size;
+ template.id = type;
+ template.entry = entry_point - 4;
+ template.persistent_size = le32_to_cpu(module->info.persistent_size);
+ template.scratch_size = le32_to_cpu(module->info.scratch_size);
mod = sst_module_new(fw, &template, NULL);
if (mod == NULL)
@@ -123,26 +125,26 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
block = (void *)module + sizeof(*module);
- for (count = 0; count < module->blocks; count++) {
+ for (count = 0; count < le32_to_cpu(module->blocks); count++) {
- if (block->size <= 0) {
+ if (le32_to_cpu(block->size) <= 0) {
dev_err(dsp->dev,
"error: block %d size invalid\n", count);
sst_module_free(mod);
return -EINVAL;
}
- switch (block->type) {
+ switch (le32_to_cpu(block->type)) {
case SST_HSW_IRAM:
ram = dsp->addr.lpe;
- mod->offset =
- block->ram_offset + dsp->addr.iram_offset;
+ mod->offset = le32_to_cpu(block->ram_offset) +
+ dsp->addr.iram_offset;
mod->type = SST_MEM_IRAM;
break;
case SST_HSW_DRAM:
case SST_HSW_REGS:
ram = dsp->addr.lpe;
- mod->offset = block->ram_offset;
+ mod->offset = le32_to_cpu(block->ram_offset);
mod->type = SST_MEM_DRAM;
break;
default:
@@ -152,7 +154,7 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
return -EINVAL;
}
- mod->size = block->size;
+ mod->size = le32_to_cpu(block->size);
mod->data = (void *)block + sizeof(*block);
mod->data_offset = mod->data - fw->dma_buf;
@@ -169,7 +171,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
return ret;
}
- block = (void *)block + sizeof(*block) + block->size;
+ block = (void *)block + sizeof(*block) +
+ le32_to_cpu(block->size);
}
mod->state = SST_MODULE_STATE_LOADED;
@@ -188,7 +191,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
/* verify FW */
if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) ||
- (sst_fw->size != header->file_size + sizeof(*header))) {
+ (sst_fw->size !=
+ le32_to_cpu(header->file_size) + sizeof(*header))) {
dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n");
return -EINVAL;
}
@@ -199,7 +203,7 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
/* parse each module */
module = (void *)sst_fw->dma_buf + sizeof(*header);
- for (count = 0; count < header->modules; count++) {
+ for (count = 0; count < le32_to_cpu(header->modules); count++) {
/* module */
ret = hsw_parse_module(dsp, sst_fw, module);
@@ -207,7 +211,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
dev_err(dsp->dev, "error: invalid module %d\n", count);
return ret;
}
- module = (void *)module + sizeof(*module) + module->mod_size;
+ module = (void *)module + sizeof(*module) +
+ le32_to_cpu(module->mod_size);
}
return 0;
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index d5f9c30eba32..8bfb8b0fa3d5 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -33,8 +33,7 @@
static int skl_alloc_dma_buf(struct device *dev,
struct snd_dma_buffer *dmab, size_t size)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
if (!bus)
return -ENODEV;
@@ -44,8 +43,7 @@ static int skl_alloc_dma_buf(struct device *dev,
static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
if (!bus)
return -ENODEV;
@@ -89,8 +87,7 @@ void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable)
static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
int stream_tag, int enable)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_stream *stream = snd_hdac_get_stream(bus,
SNDRV_PCM_STREAM_PLAYBACK, stream_tag);
struct hdac_ext_stream *estream;
@@ -100,10 +97,10 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
estream = stream_to_hdac_ext_stream(stream);
/* enable/disable SPIB for this hdac stream */
- snd_hdac_ext_stream_spbcap_enable(ebus, enable, stream->index);
+ snd_hdac_ext_stream_spbcap_enable(bus, enable, stream->index);
/* set the spib value */
- snd_hdac_ext_stream_set_spib(ebus, estream, size);
+ snd_hdac_ext_stream_set_spib(bus, estream, size);
return 0;
}
@@ -111,8 +108,7 @@ static int skl_dsp_setup_spib(struct device *dev, unsigned int size,
static int skl_dsp_prepare(struct device *dev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_ext_stream *estream;
struct hdac_stream *stream;
struct snd_pcm_substream substream;
@@ -124,7 +120,7 @@ static int skl_dsp_prepare(struct device *dev, unsigned int format,
memset(&substream, 0, sizeof(substream));
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- estream = snd_hdac_ext_stream_assign(ebus, &substream,
+ estream = snd_hdac_ext_stream_assign(bus, &substream,
HDAC_EXT_STREAM_TYPE_HOST);
if (!estream)
return -ENODEV;
@@ -143,9 +139,8 @@ static int skl_dsp_prepare(struct device *dev, unsigned int format,
static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_stream *stream;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
if (!bus)
return -ENODEV;
@@ -163,10 +158,9 @@ static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag)
static int skl_dsp_cleanup(struct device *dev,
struct snd_dma_buffer *dmab, int stream_tag)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
struct hdac_stream *stream;
struct hdac_ext_stream *estream;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
if (!bus)
return -ENODEV;
@@ -270,8 +264,7 @@ const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id)
int skl_init_dsp(struct skl *skl)
{
void __iomem *mmio_base;
- struct hdac_ext_bus *ebus = &skl->ebus;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct skl_dsp_loader_ops loader_ops;
int irq = bus->irq;
const struct skl_dsp_ops *ops;
@@ -279,8 +272,8 @@ int skl_init_dsp(struct skl *skl)
int ret;
/* enable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
- snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
+ snd_hdac_ext_bus_ppcap_enable(bus, true);
+ snd_hdac_ext_bus_ppcap_int_enable(bus, true);
/* read the BAR of the ADSP MMIO */
mmio_base = pci_ioremap_bar(skl->pci, 4);
@@ -335,12 +328,11 @@ unmap_mmio:
int skl_free_dsp(struct skl *skl)
{
- struct hdac_ext_bus *ebus = &skl->ebus;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct skl_sst *ctx = skl->skl_sst;
/* disable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
+ snd_hdac_ext_bus_ppcap_int_enable(bus, false);
ctx->dsp_ops->cleanup(bus->dev, ctx);
@@ -383,10 +375,11 @@ int skl_suspend_late_dsp(struct skl *skl)
int skl_suspend_dsp(struct skl *skl)
{
struct skl_sst *ctx = skl->skl_sst;
+ struct hdac_bus *bus = skl_to_bus(skl);
int ret;
/* if ppcap is not supported return 0 */
- if (!skl->ebus.bus.ppcap)
+ if (!bus->ppcap)
return 0;
ret = skl_dsp_sleep(ctx->dsp);
@@ -394,8 +387,8 @@ int skl_suspend_dsp(struct skl *skl)
return ret;
/* disable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false);
- snd_hdac_ext_bus_ppcap_enable(&skl->ebus, false);
+ snd_hdac_ext_bus_ppcap_int_enable(bus, false);
+ snd_hdac_ext_bus_ppcap_enable(bus, false);
return 0;
}
@@ -403,15 +396,16 @@ int skl_suspend_dsp(struct skl *skl)
int skl_resume_dsp(struct skl *skl)
{
struct skl_sst *ctx = skl->skl_sst;
+ struct hdac_bus *bus = skl_to_bus(skl);
int ret;
/* if ppcap is not supported return 0 */
- if (!skl->ebus.bus.ppcap)
+ if (!bus->ppcap)
return 0;
/* enable ppcap interrupt */
- snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true);
- snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true);
+ snd_hdac_ext_bus_ppcap_enable(bus, true);
+ snd_hdac_ext_bus_ppcap_int_enable(bus, true);
/* check if DSP 1st boot is done */
if (skl->skl_sst->is_first_boot == true)
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c
index b9b140275be0..01a050cf8775 100644
--- a/sound/soc/intel/skylake/skl-nhlt.c
+++ b/sound/soc/intel/skylake/skl-nhlt.c
@@ -141,7 +141,7 @@ struct nhlt_specific_cfg
{
struct nhlt_fmt *fmt;
struct nhlt_endpoint *epnt;
- struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct device *dev = bus->dev;
struct nhlt_specific_cfg *sp_config;
struct nhlt_acpi_table *nhlt = skl->nhlt;
@@ -228,7 +228,7 @@ static void skl_nhlt_trim_space(char *trim)
int skl_nhlt_update_topology_bin(struct skl *skl)
{
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
- struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct device *dev = bus->dev;
dev_dbg(dev, "oem_id %.6s, oem_table_id %8s oem_revision %d\n",
@@ -248,8 +248,8 @@ static ssize_t skl_nhlt_platform_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
+ struct skl *skl = bus_to_skl(bus);
struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt;
char platform_id[32];
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index afa86b9e4dcf..823e39103edd 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -67,16 +67,15 @@ struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream)
return substream->runtime->private_data;
}
-static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream)
+static struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct hdac_stream *hstream = hdac_stream(stream);
struct hdac_bus *bus = hstream->bus;
-
- return hbus_to_ebus(bus);
+ return bus;
}
-static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus,
+static int skl_substream_alloc_pages(struct hdac_bus *bus,
struct snd_pcm_substream *substream,
size_t size)
{
@@ -95,7 +94,7 @@ static int skl_substream_free_pages(struct hdac_bus *bus,
return snd_pcm_lib_free_pages(substream);
}
-static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
+static void skl_set_pcm_constrains(struct hdac_bus *bus,
struct snd_pcm_runtime *runtime)
{
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
@@ -105,9 +104,9 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus,
20, 178000000);
}
-static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus)
+static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus)
{
- if ((ebus_to_hbus(ebus))->ppcap)
+ if (bus->ppcap)
return HDAC_EXT_STREAM_TYPE_HOST;
else
return HDAC_EXT_STREAM_TYPE_COUPLED;
@@ -123,9 +122,9 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e
static void skl_set_suspend_active(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai, bool enable)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct snd_soc_dapm_widget *w;
- struct skl *skl = ebus_to_skl(ebus);
+ struct skl *skl = bus_to_skl(bus);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
w = dai->playback_widget;
@@ -140,8 +139,7 @@ static void skl_set_suspend_active(struct snd_pcm_substream *substream,
int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
unsigned int format_val;
struct hdac_stream *hstream;
struct hdac_ext_stream *stream;
@@ -153,7 +151,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
return -EINVAL;
stream = stream_to_hdac_ext_stream(hstream);
- snd_hdac_ext_stream_decouple(ebus, stream, true);
+ snd_hdac_ext_stream_decouple(bus, stream, true);
format_val = snd_hdac_calc_stream_format(params->s_freq,
params->ch, params->format, params->host_bps, 0);
@@ -177,8 +175,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
unsigned int format_val;
struct hdac_stream *hstream;
struct hdac_ext_stream *stream;
@@ -190,7 +187,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
return -EINVAL;
stream = stream_to_hdac_ext_stream(hstream);
- snd_hdac_ext_stream_decouple(ebus, stream, true);
+ snd_hdac_ext_stream_decouple(bus, stream, true);
format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
params->format, params->link_bps, 0);
@@ -201,7 +198,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
snd_hdac_ext_link_stream_setup(stream, format_val);
- list_for_each_entry(link, &ebus->hlink_list, list) {
+ list_for_each_entry(link, &bus->hlink_list, list) {
if (link->index == params->link_index)
snd_hdac_ext_link_set_stream_id(link,
hstream->stream_tag);
@@ -215,7 +212,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params)
static int skl_pcm_open(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct skl_dma_params *dma_params;
@@ -224,12 +221,12 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- stream = snd_hdac_ext_stream_assign(ebus, substream,
- skl_get_host_stream_type(ebus));
+ stream = snd_hdac_ext_stream_assign(bus, substream,
+ skl_get_host_stream_type(bus));
if (stream == NULL)
return -EBUSY;
- skl_set_pcm_constrains(ebus, runtime);
+ skl_set_pcm_constrains(bus, runtime);
/*
* disable WALLCLOCK timestamps for capture streams
@@ -301,7 +298,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct skl_pipe_params p_params = {0};
@@ -309,7 +306,7 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream,
int ret, dma_id;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- ret = skl_substream_alloc_pages(ebus, substream,
+ ret = skl_substream_alloc_pages(bus, substream,
params_buffer_bytes(params));
if (ret < 0)
return ret;
@@ -343,14 +340,14 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct skl_dma_params *dma_params = NULL;
- struct skl *skl = ebus_to_skl(ebus);
+ struct skl *skl = bus_to_skl(bus);
struct skl_module_cfg *mconfig;
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
- snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus));
+ snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus));
dma_params = snd_soc_dai_get_dma_data(dai, substream);
/*
@@ -380,7 +377,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig;
@@ -400,7 +397,7 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
snd_hdac_stream_cleanup(hdac_stream(stream));
hdac_stream(stream)->prepared = 0;
- return skl_substream_free_pages(ebus_to_hbus(ebus), substream);
+ return skl_substream_free_pages(bus, substream);
}
static int skl_be_hw_params(struct snd_pcm_substream *substream,
@@ -420,8 +417,7 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream,
static int skl_decoupled_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream;
int start;
unsigned long cookie;
@@ -470,7 +466,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_sst *ctx = skl->skl_sst;
struct skl_module_cfg *mconfig;
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
struct snd_soc_dapm_widget *w;
int ret;
@@ -492,9 +488,9 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
* dpib & lpib position to resume before starting the
* DMA
*/
- snd_hdac_ext_stream_drsm_enable(ebus, true,
+ snd_hdac_ext_stream_drsm_enable(bus, true,
hdac_stream(stream)->index);
- snd_hdac_ext_stream_set_dpibr(ebus, stream,
+ snd_hdac_ext_stream_set_dpibr(bus, stream,
stream->lpib);
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
}
@@ -528,14 +524,14 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
ret = skl_decoupled_trigger(substream, cmd);
if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) {
/* save the dpib and lpib positions */
- stream->dpib = readl(ebus->bus.remap_addr +
+ stream->dpib = readl(bus->remap_addr +
AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL *
hdac_stream(stream)->index));
stream->lpib = snd_hdac_stream_get_pos_lpib(
hdac_stream(stream));
- snd_hdac_ext_stream_decouple(ebus, stream, false);
+ snd_hdac_ext_stream_decouple(bus, stream, false);
}
break;
@@ -546,11 +542,12 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
+
static int skl_link_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *link_dev;
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct snd_soc_dai *codec_dai = rtd->codec_dai;
@@ -558,14 +555,14 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream,
struct hdac_ext_link *link;
int stream_tag;
- link_dev = snd_hdac_ext_stream_assign(ebus, substream,
+ link_dev = snd_hdac_ext_stream_assign(bus, substream,
HDAC_EXT_STREAM_TYPE_LINK);
if (!link_dev)
return -EBUSY;
snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
- link = snd_hdac_ext_bus_get_link(ebus, codec_dai->component->name);
+ link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -610,7 +607,7 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
{
struct hdac_ext_stream *link_dev =
snd_soc_dai_get_dma_data(dai, substream);
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
@@ -626,7 +623,7 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_STOP:
snd_hdac_ext_link_stream_clear(link_dev);
if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
- snd_hdac_ext_stream_decouple(ebus, stream, false);
+ snd_hdac_ext_stream_decouple(bus, stream, false);
break;
default:
@@ -638,7 +635,7 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
static int skl_link_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
struct hdac_ext_stream *link_dev =
snd_soc_dai_get_dma_data(dai, substream);
@@ -648,7 +645,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream,
link_dev->link_prepared = 0;
- link = snd_hdac_ext_bus_get_link(ebus, rtd->codec_dai->component->name);
+ link = snd_hdac_ext_bus_get_link(bus, rtd->codec_dai->component->name);
if (!link)
return -EINVAL;
@@ -1017,10 +1014,11 @@ static struct snd_soc_dai_driver skl_platform_dai[] = {
},
};
-int skl_dai_load(struct snd_soc_component *cmp,
- struct snd_soc_dai_driver *pcm_dai)
+int skl_dai_load(struct snd_soc_component *cmp, int index,
+ struct snd_soc_dai_driver *dai_drv,
+ struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
{
- pcm_dai->ops = &skl_pcm_dai_ops;
+ dai_drv->ops = &skl_pcm_dai_ops;
return 0;
}
@@ -1041,8 +1039,7 @@ static int skl_platform_open(struct snd_pcm_substream *substream)
static int skl_coupled_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream;
struct snd_pcm_substream *s;
bool start;
@@ -1115,9 +1112,9 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream,
static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
int cmd)
{
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = get_bus_ctx(substream);
- if (!(ebus_to_hbus(ebus))->ppcap)
+ if (!bus->ppcap)
return skl_coupled_trigger(substream, cmd);
return 0;
@@ -1127,7 +1124,7 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
(struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream);
- struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_bus *bus = get_bus_ctx(substream);
unsigned int pos;
/*
@@ -1152,12 +1149,12 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
+ pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL *
hdac_stream(hstream)->index));
} else {
udelay(20);
- readl(ebus->bus.remap_addr +
+ readl(bus->remap_addr +
AZX_REG_VS_SDXDPIB_XBASE +
(AZX_REG_VS_SDXDPIB_XINTERVAL *
hdac_stream(hstream)->index));
@@ -1242,11 +1239,11 @@ static void skl_pcm_free(struct snd_pcm *pcm)
static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *dai = rtd->cpu_dai;
- struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+ struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct snd_pcm *pcm = rtd->pcm;
unsigned int size;
int retval = 0;
- struct skl *skl = ebus_to_skl(ebus);
+ struct skl *skl = bus_to_skl(bus);
if (dai->driver->playback.channels_min ||
dai->driver->capture.channels_min) {
@@ -1356,19 +1353,19 @@ static int skl_populate_modules(struct skl *skl)
static int skl_platform_soc_probe(struct snd_soc_component *component)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(component->dev);
- struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(component->dev);
+ struct skl *skl = bus_to_skl(bus);
const struct skl_dsp_ops *ops;
int ret;
pm_runtime_get_sync(component->dev);
- if ((ebus_to_hbus(ebus))->ppcap) {
+ if (bus->ppcap) {
skl->component = component;
/* init debugfs */
skl->debugfs = skl_debugfs_init(skl);
- ret = skl_tplg_init(component, ebus);
+ ret = skl_tplg_init(component, bus);
if (ret < 0) {
dev_err(component->dev, "Failed to init topology!\n");
return ret;
@@ -1425,10 +1422,10 @@ static const struct snd_soc_component_driver skl_component = {
int skl_platform_register(struct device *dev)
{
int ret;
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct skl *skl = ebus_to_skl(ebus);
struct snd_soc_dai_driver *dais;
int num_dais = ARRAY_SIZE(skl_platform_dai);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
+ struct skl *skl = bus_to_skl(bus);
INIT_LIST_HEAD(&skl->ppl_list);
INIT_LIST_HEAD(&skl->bind_list);
@@ -1464,8 +1461,8 @@ err:
int skl_platform_unregister(struct device *dev)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
- struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
+ struct skl *skl = bus_to_skl(bus);
struct skl_module_deferred_bind *modules, *tmp;
if (!list_empty(&skl->bind_list)) {
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c
index d2b1d60fec02..5bc0d38da7e3 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.c
+++ b/sound/soc/intel/skylake/skl-sst-cldma.c
@@ -83,9 +83,9 @@ static void skl_cldma_stream_clear(struct sst_dsp *ctx)
/* Code loader helper APIs */
static void skl_cldma_setup_bdle(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_data,
- u32 **bdlp, int size, int with_ioc)
+ __le32 **bdlp, int size, int with_ioc)
{
- u32 *bdl = *bdlp;
+ __le32 *bdl = *bdlp;
ctx->cl_dev.frags = 0;
while (size > 0) {
@@ -330,7 +330,7 @@ void skl_cldma_process_intr(struct sst_dsp *ctx)
int skl_cldma_prepare(struct sst_dsp *ctx)
{
int ret;
- u32 *bdl;
+ __le32 *bdl;
ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE;
@@ -359,7 +359,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx)
ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data);
return ret;
}
- bdl = (u32 *)ctx->cl_dev.dmab_bdl.area;
+ bdl = (__le32 *)ctx->cl_dev.dmab_bdl.area;
/* Allocate BDLs */
ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data,
diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h
index 5b730a1a0ae4..ec736921a083 100644
--- a/sound/soc/intel/skylake/skl-sst-cldma.h
+++ b/sound/soc/intel/skylake/skl-sst-cldma.h
@@ -203,7 +203,7 @@ struct sst_dsp;
struct skl_cl_dev_ops {
void (*cl_setup_bdle)(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_data,
- u32 **bdlp, int size, int with_ioc);
+ __le32 **bdlp, int size, int with_ioc);
void (*cl_setup_controller)(struct sst_dsp *ctx,
struct snd_dma_buffer *dmab_bdl,
unsigned int max_size, u32 page_count);
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index fcdc716754b6..2620d77729c5 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -108,6 +108,9 @@ static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai_out:
case snd_soc_dapm_switch:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_mux:
+
return false;
default:
return true;
@@ -934,7 +937,7 @@ static int skl_tplg_find_moduleid_from_uuid(struct skl *skl,
struct soc_bytes_ext *sb = (void *) k->private_value;
struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private;
struct skl_kpb_params *uuid_params, *params;
- struct hdac_bus *bus = ebus_to_hbus(skl_to_ebus(skl));
+ struct hdac_bus *bus = skl_to_bus(skl);
int i, size, module_id;
if (bc->set_params == SKL_PARAM_BIND && bc->max) {
@@ -3024,14 +3027,13 @@ void skl_cleanup_resources(struct skl *skl)
* information to the driver about module and pipeline parameters which DSP
* FW expects like ids, resource values, formats etc
*/
-static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
+static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index,
struct snd_soc_dapm_widget *w,
struct snd_soc_tplg_dapm_widget *tplg_w)
{
int ret;
- struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
+ struct skl *skl = bus_to_skl(bus);
struct skl_module_cfg *mconfig;
if (!tplg_w->priv.size)
@@ -3131,14 +3133,14 @@ static int skl_init_enum_data(struct device *dev, struct soc_enum *se,
}
static int skl_tplg_control_load(struct snd_soc_component *cmpnt,
+ int index,
struct snd_kcontrol_new *kctl,
struct snd_soc_tplg_ctl_hdr *hdr)
{
struct soc_bytes_ext *sb;
struct snd_soc_tplg_bytes_control *tplg_bc;
struct snd_soc_tplg_enum_control *tplg_ec;
- struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
struct soc_enum *se;
switch (hdr->ops.info) {
@@ -3619,12 +3621,11 @@ static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest,
return 0;
}
-static int skl_manifest_load(struct snd_soc_component *cmpnt,
+static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
struct snd_soc_tplg_manifest *manifest)
{
- struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt);
+ struct skl *skl = bus_to_skl(bus);
/* proceed only if we have private data defined */
if (manifest->priv.size == 0)
@@ -3713,12 +3714,11 @@ static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe)
/*
* SKL topology init routine
*/
-int skl_tplg_init(struct snd_soc_component *component, struct hdac_ext_bus *ebus)
+int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus)
{
int ret;
const struct firmware *fw;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
- struct skl *skl = ebus_to_skl(ebus);
+ struct skl *skl = bus_to_skl(bus);
struct skl_pipeline *ppl;
ret = request_firmware(&fw, skl->tplg_name, bus->dev);
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 6d7e0569695f..82282cac9751 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -458,9 +458,9 @@ enum skl_channel {
static inline struct skl *get_skl_ctx(struct device *dev)
{
- struct hdac_ext_bus *ebus = dev_get_drvdata(dev);
+ struct hdac_bus *bus = dev_get_drvdata(dev);
- return ebus_to_skl(ebus);
+ return bus_to_skl(bus);
}
int skl_tplg_be_update_params(struct snd_soc_dai *dai,
@@ -470,7 +470,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, u32 *caps,
void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai,
struct skl_pipe_params *params, int stream);
int skl_tplg_init(struct snd_soc_component *component,
- struct hdac_ext_bus *ebus);
+ struct hdac_bus *ebus);
struct skl_module_cfg *skl_tplg_fe_get_cpr_module(
struct snd_soc_dai *dai, int stream);
int skl_tplg_update_pipe_params(struct device *dev,
@@ -512,8 +512,9 @@ int skl_pcm_host_dma_prepare(struct device *dev,
int skl_pcm_link_dma_prepare(struct device *dev,
struct skl_pipe_params *params);
-int skl_dai_load(struct snd_soc_component *cmp,
- struct snd_soc_dai_driver *pcm_dai);
+int skl_dai_load(struct snd_soc_component *cmp, int index,
+ struct snd_soc_dai_driver *dai_drv,
+ struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai);
void skl_tplg_add_moduleid_in_bind_params(struct skl *skl,
struct snd_soc_dapm_widget *w);
#endif
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index f0d9793f872a..dce649485649 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
#include <sound/hda_register.h>
#include <sound/hdaudio.h>
#include <sound/hda_i915.h>
@@ -36,8 +37,6 @@
#include "skl-sst-dsp.h"
#include "skl-sst-ipc.h"
-static struct skl_machine_pdata skl_dmic_data;
-
/*
* initialize the PCI registers
*/
@@ -54,7 +53,7 @@ static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg,
static void skl_init_pci(struct skl *skl)
{
- struct hdac_ext_bus *ebus = &skl->ebus;
+ struct hdac_bus *bus = skl_to_bus(skl);
/*
* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
@@ -63,7 +62,7 @@ static void skl_init_pci(struct skl *skl)
* codecs.
* The PCI register TCSEL is defined in the Intel manuals.
*/
- dev_dbg(ebus_to_hbus(ebus)->dev, "Clearing TCSEL\n");
+ dev_dbg(bus->dev, "Clearing TCSEL\n");
skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0);
}
@@ -103,8 +102,7 @@ static void skl_enable_miscbdcge(struct device *dev, bool enable)
static void skl_clock_power_gating(struct device *dev, bool enable)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
u32 val;
/* Update PDCGE bit of CGCTL register */
@@ -127,7 +125,6 @@ static void skl_clock_power_gating(struct device *dev, bool enable)
*/
static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
{
- struct hdac_ext_bus *ebus = hbus_to_ebus(bus);
struct hdac_ext_link *hlink;
int ret;
@@ -135,7 +132,7 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
ret = snd_hdac_bus_init_chip(bus, full_reset);
/* Reset stream-to-link mapping */
- list_for_each_entry(hlink, &ebus->hlink_list, list)
+ list_for_each_entry(hlink, &bus->hlink_list, list)
bus->io_ops->reg_writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
skl_enable_miscbdcge(bus->dev, true);
@@ -146,8 +143,7 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset)
void skl_update_d0i3c(struct device *dev, bool enable)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
u8 reg;
int timeout = 50;
@@ -197,8 +193,7 @@ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr)
static irqreturn_t skl_interrupt(int irq, void *dev_id)
{
- struct hdac_ext_bus *ebus = dev_id;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_id;
u32 status;
if (!pm_runtime_active(bus->dev))
@@ -227,8 +222,7 @@ static irqreturn_t skl_interrupt(int irq, void *dev_id)
static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
{
- struct hdac_ext_bus *ebus = dev_id;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = dev_id;
u32 status;
status = snd_hdac_chip_readl(bus, INTSTS);
@@ -238,16 +232,15 @@ static irqreturn_t skl_threaded_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
+static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect)
{
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *skl = bus_to_skl(bus);
int ret;
ret = request_threaded_irq(skl->pci->irq, skl_interrupt,
skl_threaded_handler,
IRQF_SHARED,
- KBUILD_MODNAME, ebus);
+ KBUILD_MODNAME, bus);
if (ret) {
dev_err(bus->dev,
"unable to grab IRQ %d, disabling device\n",
@@ -264,21 +257,20 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect)
static int skl_suspend_late(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
+ struct skl *skl = bus_to_skl(bus);
return skl_suspend_late_dsp(skl);
}
#ifdef CONFIG_PM
-static int _skl_suspend(struct hdac_ext_bus *ebus)
+static int _skl_suspend(struct hdac_bus *bus)
{
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *skl = bus_to_skl(bus);
struct pci_dev *pci = to_pci_dev(bus->dev);
int ret;
- snd_hdac_ext_bus_link_power_down_all(ebus);
+ snd_hdac_ext_bus_link_power_down_all(bus);
ret = skl_suspend_dsp(skl);
if (ret < 0)
@@ -295,10 +287,9 @@ static int _skl_suspend(struct hdac_ext_bus *ebus)
return 0;
}
-static int _skl_resume(struct hdac_ext_bus *ebus)
+static int _skl_resume(struct hdac_bus *bus)
{
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *skl = bus_to_skl(bus);
skl_init_pci(skl);
skl_init_chip(bus, true);
@@ -314,9 +305,8 @@ static int _skl_resume(struct hdac_ext_bus *ebus)
static int skl_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
+ struct skl *skl = bus_to_skl(bus);
int ret = 0;
/*
@@ -325,15 +315,15 @@ static int skl_suspend(struct device *dev)
*/
if (skl->supend_active) {
/* turn off the links and stop the CORB/RIRB DMA if it is On */
- snd_hdac_ext_bus_link_power_down_all(ebus);
+ snd_hdac_ext_bus_link_power_down_all(bus);
- if (ebus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(&ebus->bus);
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_stop_cmd_io(bus);
enable_irq_wake(bus->irq);
pci_save_state(pci);
} else {
- ret = _skl_suspend(ebus);
+ ret = _skl_suspend(bus);
if (ret < 0)
return ret;
skl->skl_sst->fw_loaded = false;
@@ -352,9 +342,8 @@ static int skl_suspend(struct device *dev)
static int skl_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
+ struct skl *skl = bus_to_skl(bus);
struct hdac_ext_link *hlink = NULL;
int ret;
@@ -374,32 +363,32 @@ static int skl_resume(struct device *dev)
*/
if (skl->supend_active) {
pci_restore_state(pci);
- snd_hdac_ext_bus_link_power_up_all(ebus);
+ snd_hdac_ext_bus_link_power_up_all(bus);
disable_irq_wake(bus->irq);
/*
* turn On the links which are On before active suspend
* and start the CORB/RIRB DMA if On before
* active suspend.
*/
- list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
if (hlink->ref_count)
snd_hdac_ext_bus_link_power_up(hlink);
}
- if (ebus->cmd_dma_state)
- snd_hdac_bus_init_cmd_io(&ebus->bus);
ret = 0;
+ if (bus->cmd_dma_state)
+ snd_hdac_bus_init_cmd_io(bus);
} else {
- ret = _skl_resume(ebus);
+ ret = _skl_resume(bus);
/* turn off the links which are off before suspend */
- list_for_each_entry(hlink, &ebus->hlink_list, list) {
+ list_for_each_entry(hlink, &bus->hlink_list, list) {
if (!hlink->ref_count)
snd_hdac_ext_bus_link_power_down(hlink);
}
- if (!ebus->cmd_dma_state)
- snd_hdac_bus_stop_cmd_io(&ebus->bus);
+ if (!bus->cmd_dma_state)
+ snd_hdac_bus_stop_cmd_io(bus);
}
return ret;
@@ -410,23 +399,21 @@ static int skl_resume(struct device *dev)
static int skl_runtime_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
dev_dbg(bus->dev, "in %s\n", __func__);
- return _skl_suspend(ebus);
+ return _skl_suspend(bus);
}
static int skl_runtime_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
dev_dbg(bus->dev, "in %s\n", __func__);
- return _skl_resume(ebus);
+ return _skl_resume(bus);
}
#endif /* CONFIG_PM */
@@ -439,20 +426,19 @@ static const struct dev_pm_ops skl_pm = {
/*
* destructor
*/
-static int skl_free(struct hdac_ext_bus *ebus)
+static int skl_free(struct hdac_bus *bus)
{
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *skl = bus_to_skl(bus);
skl->init_done = 0; /* to be sure */
- snd_hdac_ext_stop_streams(ebus);
+ snd_hdac_ext_stop_streams(bus);
if (bus->irq >= 0)
- free_irq(bus->irq, (void *)ebus);
+ free_irq(bus->irq, (void *)bus);
snd_hdac_bus_free_stream_pages(bus);
- snd_hdac_stream_free_all(ebus);
- snd_hdac_link_free_all(ebus);
+ snd_hdac_stream_free_all(bus);
+ snd_hdac_link_free_all(bus);
if (bus->remap_addr)
iounmap(bus->remap_addr);
@@ -460,11 +446,11 @@ static int skl_free(struct hdac_ext_bus *ebus)
pci_release_regions(skl->pci);
pci_disable_device(skl->pci);
- snd_hdac_ext_bus_exit(ebus);
+ snd_hdac_ext_bus_exit(bus);
cancel_work_sync(&skl->probe_work);
if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI))
- snd_hdac_i915_exit(&ebus->bus);
+ snd_hdac_i915_exit(bus);
return 0;
}
@@ -488,8 +474,8 @@ static struct skl_ssp_clk skl_ssp_clks[] = {
static int skl_find_machine(struct skl *skl, void *driver_data)
{
+ struct hdac_bus *bus = skl_to_bus(skl);
struct snd_soc_acpi_mach *mach = driver_data;
- struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
struct skl_machine_pdata *pdata;
mach = snd_soc_acpi_find_machine(mach);
@@ -500,17 +486,19 @@ static int skl_find_machine(struct skl *skl, void *driver_data)
skl->mach = mach;
skl->fw_name = mach->fw_filename;
- pdata = skl->mach->pdata;
+ pdata = mach->pdata;
- if (mach->pdata)
+ if (pdata) {
skl->use_tplg_pcm = pdata->use_tplg_pcm;
+ pdata->dmic_num = skl_get_dmic_geo(skl);
+ }
return 0;
}
static int skl_machine_device_register(struct skl *skl)
{
- struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct snd_soc_acpi_mach *mach = skl->mach;
struct platform_device *pdev;
int ret;
@@ -544,7 +532,7 @@ static void skl_machine_device_unregister(struct skl *skl)
static int skl_dmic_device_register(struct skl *skl)
{
- struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct platform_device *pdev;
int ret;
@@ -643,12 +631,13 @@ static void skl_clock_device_unregister(struct skl *skl)
/*
* Probe the given codec address
*/
-static int probe_codec(struct hdac_ext_bus *ebus, int addr)
+static int probe_codec(struct hdac_bus *bus, int addr)
{
- struct hdac_bus *bus = ebus_to_hbus(ebus);
unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) |
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
unsigned int res = -1;
+ struct skl *skl = bus_to_skl(bus);
+ struct hdac_device *hdev;
mutex_lock(&bus->cmd_mutex);
snd_hdac_bus_send_cmd(bus, cmd);
@@ -658,13 +647,16 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr)
return -EIO;
dev_dbg(bus->dev, "codec #%d probed OK\n", addr);
- return snd_hdac_ext_bus_device_init(ebus, addr);
+ hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL);
+ if (!hdev)
+ return -ENOMEM;
+
+ return snd_hdac_ext_bus_device_init(bus, addr, hdev);
}
/* Codec initialization */
-static void skl_codec_create(struct hdac_ext_bus *ebus)
+static void skl_codec_create(struct hdac_bus *bus)
{
- struct hdac_bus *bus = ebus_to_hbus(ebus);
int c, max_slots;
max_slots = HDA_MAX_CODECS;
@@ -672,7 +664,7 @@ static void skl_codec_create(struct hdac_ext_bus *ebus)
/* First try to probe all given codec slots */
for (c = 0; c < max_slots; c++) {
if ((bus->codec_mask & (1 << c))) {
- if (probe_codec(ebus, c) < 0) {
+ if (probe_codec(bus, c) < 0) {
/*
* Some BIOSen give you wrong codec addresses
* that don't exist
@@ -722,8 +714,7 @@ static int skl_i915_init(struct hdac_bus *bus)
static void skl_probe_work(struct work_struct *work)
{
struct skl *skl = container_of(work, struct skl, probe_work);
- struct hdac_ext_bus *ebus = &skl->ebus;
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = skl_to_bus(skl);
struct hdac_ext_link *hlink = NULL;
int err;
@@ -744,7 +735,7 @@ static void skl_probe_work(struct work_struct *work)
dev_info(bus->dev, "no hda codecs found!\n");
/* create codec instances */
- skl_codec_create(ebus);
+ skl_codec_create(bus);
/* register platform dai and controls */
err = skl_platform_register(bus->dev);
@@ -773,8 +764,8 @@ static void skl_probe_work(struct work_struct *work)
/*
* we are done probing so decrement link counts
*/
- list_for_each_entry(hlink, &ebus->hlink_list, list)
- snd_hdac_ext_bus_link_put(ebus, hlink);
+ list_for_each_entry(hlink, &bus->hlink_list, list)
+ snd_hdac_ext_bus_link_put(bus, hlink);
/* configure PM */
pm_runtime_put_noidle(bus->dev);
@@ -796,7 +787,7 @@ static int skl_create(struct pci_dev *pci,
struct skl **rskl)
{
struct skl *skl;
- struct hdac_ext_bus *ebus;
+ struct hdac_bus *bus;
int err;
@@ -811,23 +802,22 @@ static int skl_create(struct pci_dev *pci,
pci_disable_device(pci);
return -ENOMEM;
}
- ebus = &skl->ebus;
- snd_hdac_ext_bus_init(ebus, &pci->dev, &bus_core_ops, io_ops);
- ebus->bus.use_posbuf = 1;
+
+ bus = skl_to_bus(skl);
+ snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL);
+ bus->use_posbuf = 1;
skl->pci = pci;
INIT_WORK(&skl->probe_work, skl_probe_work);
-
- ebus->bus.bdl_pos_adj = 0;
+ bus->bdl_pos_adj = 0;
*rskl = skl;
return 0;
}
-static int skl_first_init(struct hdac_ext_bus *ebus)
+static int skl_first_init(struct hdac_bus *bus)
{
- struct skl *skl = ebus_to_skl(ebus);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct skl *skl = bus_to_skl(bus);
struct pci_dev *pci = skl->pci;
int err;
unsigned short gcap;
@@ -848,7 +838,7 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
snd_hdac_bus_parse_capabilities(bus);
- if (skl_acquire_irq(ebus, 0) < 0)
+ if (skl_acquire_irq(bus, 0) < 0)
return -EBUSY;
pci_set_master(pci);
@@ -872,14 +862,14 @@ static int skl_first_init(struct hdac_ext_bus *ebus)
if (!pb_streams && !cp_streams)
return -EIO;
- ebus->num_streams = cp_streams + pb_streams;
+ bus->num_streams = cp_streams + pb_streams;
/* initialize streams */
snd_hdac_ext_stream_init_all
- (ebus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
+ (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE);
start_idx = cp_streams;
snd_hdac_ext_stream_init_all
- (ebus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
+ (bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK);
err = snd_hdac_bus_alloc_stream_pages(bus);
if (err < 0)
@@ -895,7 +885,6 @@ static int skl_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
struct skl *skl;
- struct hdac_ext_bus *ebus = NULL;
struct hdac_bus *bus = NULL;
int err;
@@ -904,10 +893,9 @@ static int skl_probe(struct pci_dev *pci,
if (err < 0)
return err;
- ebus = &skl->ebus;
- bus = ebus_to_hbus(ebus);
+ bus = skl_to_bus(skl);
- err = skl_first_init(ebus);
+ err = skl_first_init(bus);
if (err < 0)
goto out_free;
@@ -928,9 +916,7 @@ static int skl_probe(struct pci_dev *pci,
skl_nhlt_update_topology_bin(skl);
- pci_set_drvdata(skl->pci, ebus);
-
- skl_dmic_data.dmic_num = skl_get_dmic_geo(skl);
+ pci_set_drvdata(skl->pci, bus);
/* check if dsp is there */
if (bus->ppcap) {
@@ -952,7 +938,7 @@ static int skl_probe(struct pci_dev *pci,
skl->skl_sst->clock_power_gating = skl_clock_power_gating;
}
if (bus->mlcap)
- snd_hdac_ext_bus_get_ml_capabilities(ebus);
+ snd_hdac_ext_bus_get_ml_capabilities(bus);
snd_hdac_bus_stop_chip(bus);
@@ -972,31 +958,30 @@ out_clk_free:
out_nhlt_free:
skl_nhlt_free(skl->nhlt);
out_free:
- skl_free(ebus);
+ skl_free(bus);
return err;
}
static void skl_shutdown(struct pci_dev *pci)
{
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct hdac_bus *bus = ebus_to_hbus(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
struct hdac_stream *s;
struct hdac_ext_stream *stream;
struct skl *skl;
- if (ebus == NULL)
+ if (!bus)
return;
- skl = ebus_to_skl(ebus);
+ skl = bus_to_skl(bus);
if (!skl->init_done)
return;
- snd_hdac_ext_stop_streams(ebus);
+ snd_hdac_ext_stop_streams(bus);
list_for_each_entry(s, &bus->stream_list, list) {
stream = stream_to_hdac_ext_stream(s);
- snd_hdac_ext_stream_decouple(ebus, stream, false);
+ snd_hdac_ext_stream_decouple(bus, stream, false);
}
snd_hdac_bus_stop_chip(bus);
@@ -1004,15 +989,15 @@ static void skl_shutdown(struct pci_dev *pci)
static void skl_remove(struct pci_dev *pci)
{
- struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
- struct skl *skl = ebus_to_skl(ebus);
+ struct hdac_bus *bus = pci_get_drvdata(pci);
+ struct skl *skl = bus_to_skl(bus);
release_firmware(skl->tplg);
pm_runtime_get_noresume(&pci->dev);
/* codec removal, invoke bus_device_remove */
- snd_hdac_ext_bus_device_remove(ebus);
+ snd_hdac_ext_bus_device_remove(bus);
skl->debugfs = NULL;
skl_platform_unregister(&pci->dev);
@@ -1022,176 +1007,27 @@ static void skl_remove(struct pci_dev *pci)
skl_clock_device_unregister(skl);
skl_nhlt_remove_sysfs(skl);
skl_nhlt_free(skl->nhlt);
- skl_free(ebus);
+ skl_free(bus);
dev_set_drvdata(&pci->dev, NULL);
}
-static struct snd_soc_acpi_codecs skl_codecs = {
- .num_codecs = 1,
- .codecs = {"10508825"}
-};
-
-static struct snd_soc_acpi_codecs kbl_codecs = {
- .num_codecs = 1,
- .codecs = {"10508825"}
-};
-
-static struct snd_soc_acpi_codecs bxt_codecs = {
- .num_codecs = 1,
- .codecs = {"MX98357A"}
-};
-
-static struct snd_soc_acpi_codecs kbl_poppy_codecs = {
- .num_codecs = 1,
- .codecs = {"10EC5663"}
-};
-
-static struct snd_soc_acpi_codecs kbl_5663_5514_codecs = {
- .num_codecs = 2,
- .codecs = {"10EC5663", "10EC5514"}
-};
-
-static struct snd_soc_acpi_codecs kbl_7219_98357_codecs = {
- .num_codecs = 1,
- .codecs = {"MX98357A"}
-};
-
-static struct skl_machine_pdata cnl_pdata = {
- .use_tplg_pcm = true,
-};
-
-static struct snd_soc_acpi_mach sst_skl_devdata[] = {
- {
- .id = "INT343A",
- .drv_name = "skl_alc286s_i2s",
- .fw_filename = "intel/dsp_fw_release.bin",
- },
- {
- .id = "INT343B",
- .drv_name = "skl_n88l25_s4567",
- .fw_filename = "intel/dsp_fw_release.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &skl_codecs,
- .pdata = &skl_dmic_data
- },
- {
- .id = "MX98357A",
- .drv_name = "skl_n88l25_m98357a",
- .fw_filename = "intel/dsp_fw_release.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &skl_codecs,
- .pdata = &skl_dmic_data
- },
- {}
-};
-
-static struct snd_soc_acpi_mach sst_bxtp_devdata[] = {
- {
- .id = "INT343A",
- .drv_name = "bxt_alc298s_i2s",
- .fw_filename = "intel/dsp_fw_bxtn.bin",
- },
- {
- .id = "DLGS7219",
- .drv_name = "bxt_da7219_max98357a_i2s",
- .fw_filename = "intel/dsp_fw_bxtn.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &bxt_codecs,
- },
- {}
-};
-
-static struct snd_soc_acpi_mach sst_kbl_devdata[] = {
- {
- .id = "INT343A",
- .drv_name = "kbl_alc286s_i2s",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- },
- {
- .id = "INT343B",
- .drv_name = "kbl_n88l25_s4567",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &kbl_codecs,
- .pdata = &skl_dmic_data
- },
- {
- .id = "MX98357A",
- .drv_name = "kbl_n88l25_m98357a",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &kbl_codecs,
- .pdata = &skl_dmic_data
- },
- {
- .id = "MX98927",
- .drv_name = "kbl_r5514_5663_max",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &kbl_5663_5514_codecs,
- .pdata = &skl_dmic_data
- },
- {
- .id = "MX98927",
- .drv_name = "kbl_rt5663_m98927",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &kbl_poppy_codecs,
- .pdata = &skl_dmic_data
- },
- {
- .id = "10EC5663",
- .drv_name = "kbl_rt5663",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- },
- {
- .id = "DLGS7219",
- .drv_name = "kbl_da7219_max98357a",
- .fw_filename = "intel/dsp_fw_kbl.bin",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &kbl_7219_98357_codecs,
- .pdata = &skl_dmic_data
- },
-
- {}
-};
-
-static struct snd_soc_acpi_mach sst_glk_devdata[] = {
- {
- .id = "INT343A",
- .drv_name = "glk_alc298s_i2s",
- .fw_filename = "intel/dsp_fw_glk.bin",
- },
- {}
-};
-
-static const struct snd_soc_acpi_mach sst_cnl_devdata[] = {
- {
- .id = "INT34C2",
- .drv_name = "cnl_rt274",
- .fw_filename = "intel/dsp_fw_cnl.bin",
- .pdata = &cnl_pdata,
- },
- {}
-};
-
/* PCI IDs */
static const struct pci_device_id skl_ids[] = {
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
- .driver_data = (unsigned long)&sst_skl_devdata},
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_skl_machines},
/* BXT-P */
{ PCI_DEVICE(0x8086, 0x5a98),
- .driver_data = (unsigned long)&sst_bxtp_devdata},
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_bxt_machines},
/* KBL */
{ PCI_DEVICE(0x8086, 0x9D71),
- .driver_data = (unsigned long)&sst_kbl_devdata},
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_kbl_machines},
/* GLK */
{ PCI_DEVICE(0x8086, 0x3198),
- .driver_data = (unsigned long)&sst_glk_devdata},
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_glk_machines},
/* CNL */
{ PCI_DEVICE(0x8086, 0x9dc8),
- .driver_data = (unsigned long)&sst_cnl_devdata},
+ .driver_data = (unsigned long)&snd_soc_acpi_intel_cnl_machines},
{ 0, }
};
MODULE_DEVICE_TABLE(pci, skl_ids);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index 0d5375cbcf6e..78aa8bdcb619 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -71,7 +71,7 @@ struct skl_fw_config {
};
struct skl {
- struct hdac_ext_bus ebus;
+ struct hdac_bus hbus;
struct pci_dev *pci;
unsigned int init_done:1; /* delayed init status */
@@ -105,9 +105,8 @@ struct skl {
struct snd_soc_acpi_mach *mach;
};
-#define skl_to_ebus(s) (&(s)->ebus)
-#define ebus_to_skl(sbus) \
- container_of(sbus, struct skl, sbus)
+#define skl_to_bus(s) (&(s)->hbus)
+#define bus_to_skl(bus) container_of(bus, struct skl, hbus)
/* to pass dai dma data */
struct skl_dma_params {
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
index 51ec4ff6ed95..697aa50aff9a 100644
--- a/sound/soc/mediatek/common/mtk-afe-platform-driver.c
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -15,20 +15,12 @@
int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
{
- struct snd_soc_dai_driver *sub_dai_drivers;
+ struct mtk_base_afe_dai *dai;
size_t num_dai_drivers = 0, dai_idx = 0;
- int i;
-
- if (!afe->sub_dais) {
- dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
- return -EINVAL;
- }
/* calcualte total dai driver size */
- for (i = 0; i < afe->num_sub_dais; i++) {
- if (afe->sub_dais[i].dai_drivers &&
- afe->sub_dais[i].num_dai_drivers != 0)
- num_dai_drivers += afe->sub_dais[i].num_dai_drivers;
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ num_dai_drivers += dai->num_dai_drivers;
}
dev_info(afe->dev, "%s(), num of dai %zd\n", __func__, num_dai_drivers);
@@ -42,19 +34,14 @@ int mtk_afe_combine_sub_dai(struct mtk_base_afe *afe)
if (!afe->dai_drivers)
return -ENOMEM;
- for (i = 0; i < afe->num_sub_dais; i++) {
- if (afe->sub_dais[i].dai_drivers &&
- afe->sub_dais[i].num_dai_drivers != 0) {
- sub_dai_drivers = afe->sub_dais[i].dai_drivers;
- /* dai driver */
- memcpy(&afe->dai_drivers[dai_idx],
- sub_dai_drivers,
- afe->sub_dais[i].num_dai_drivers *
- sizeof(struct snd_soc_dai_driver));
- dai_idx += afe->sub_dais[i].num_dai_drivers;
- }
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ /* dai driver */
+ memcpy(&afe->dai_drivers[dai_idx],
+ dai->dai_drivers,
+ dai->num_dai_drivers *
+ sizeof(struct snd_soc_dai_driver));
+ dai_idx += dai->num_dai_drivers;
}
-
return 0;
}
EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
@@ -62,28 +49,25 @@ EXPORT_SYMBOL_GPL(mtk_afe_combine_sub_dai);
int mtk_afe_add_sub_dai_control(struct snd_soc_component *component)
{
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
- int i;
+ struct mtk_base_afe_dai *dai;
- if (!afe->sub_dais) {
- dev_err(afe->dev, "%s(), sub_dais == NULL\n", __func__);
- return -EINVAL;
- }
-
- for (i = 0; i < afe->num_sub_dais; i++) {
- if (afe->sub_dais[i].controls)
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ if (dai->controls)
snd_soc_add_component_controls(component,
- afe->sub_dais[i].controls,
- afe->sub_dais[i].num_controls);
+ dai->controls,
+ dai->num_controls);
- if (afe->sub_dais[i].dapm_widgets)
+ if (dai->dapm_widgets)
snd_soc_dapm_new_controls(&component->dapm,
- afe->sub_dais[i].dapm_widgets,
- afe->sub_dais[i].num_dapm_widgets);
-
- if (afe->sub_dais[i].dapm_routes)
+ dai->dapm_widgets,
+ dai->num_dapm_widgets);
+ }
+ /* add routes after all widgets are added */
+ list_for_each_entry(dai, &afe->sub_dais, list) {
+ if (dai->dapm_routes)
snd_soc_dapm_add_routes(&component->dapm,
- afe->sub_dais[i].dapm_routes,
- afe->sub_dais[i].num_dapm_routes);
+ dai->dapm_routes,
+ dai->num_dapm_routes);
}
snd_soc_dapm_new_widgets(component->dapm.card);
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
index bcf562f029b6..bd8d5e0c6843 100644
--- a/sound/soc/mediatek/common/mtk-base-afe.h
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -46,6 +46,7 @@ struct mtk_base_irq_data {
};
struct device;
+struct list_head;
struct mtk_base_afe_memif;
struct mtk_base_afe_irq;
struct mtk_base_afe_dai;
@@ -72,8 +73,7 @@ struct mtk_base_afe {
struct mtk_base_afe_irq *irqs;
int irqs_size;
- struct mtk_base_afe_dai *sub_dais;
- int num_sub_dais;
+ struct list_head sub_dais;
struct snd_soc_dai_driver *dai_drivers;
unsigned int num_dai_drivers;
@@ -110,6 +110,8 @@ struct mtk_base_afe_dai {
unsigned int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
unsigned int num_dapm_routes;
+
+ struct list_head list;
};
#endif
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-common.h b/sound/soc/mediatek/mt6797/mt6797-afe-common.h
index 22eb7b455cf1..4eac9977b2b0 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-common.h
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-common.h
@@ -10,6 +10,7 @@
#define _MT_6797_AFE_COMMON_H_
#include <sound/soc.h>
+#include <linux/list.h>
#include <linux/regmap.h>
#include "../common/mtk-base-afe.h"
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 6c5dd9fc9976..192f4d7b37b6 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -733,6 +733,34 @@ static const struct snd_soc_component_driver mt6797_afe_component = {
.probe = mt6797_afe_component_probe,
};
+static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mt6797_memif_dai_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mt6797_memif_dai_driver);
+
+ dai->dapm_widgets = mt6797_memif_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mt6797_memif_widgets);
+ dai->dapm_routes = mt6797_memif_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mt6797_memif_routes);
+ return 0;
+}
+
+typedef int (*dai_register_cb)(struct mtk_base_afe *);
+static const dai_register_cb dai_register_cbs[] = {
+ mt6797_dai_adda_register,
+ mt6797_dai_pcm_register,
+ mt6797_dai_hostless_register,
+ mt6797_dai_memif_register,
+};
+
static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
{
struct mtk_base_afe *afe;
@@ -811,29 +839,24 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
}
/* init sub_dais */
- afe->num_sub_dais = MT6797_DAI_NUM;
- afe->sub_dais = devm_kcalloc(dev, afe->num_sub_dais,
- sizeof(*afe->sub_dais),
- GFP_KERNEL);
- if (!afe->sub_dais)
- return -ENOMEM;
-
- mt6797_dai_adda_register(afe);
- mt6797_dai_pcm_register(afe);
- mt6797_dai_hostless_register(afe);
-
- afe->sub_dais[MT6797_MEMIF_DL1].dai_drivers = mt6797_memif_dai_driver;
- afe->sub_dais[MT6797_MEMIF_DL1].num_dai_drivers =
- ARRAY_SIZE(mt6797_memif_dai_driver);
- afe->sub_dais[MT6797_MEMIF_DL1].dapm_widgets = mt6797_memif_widgets;
- afe->sub_dais[MT6797_MEMIF_DL1].num_dapm_widgets =
- ARRAY_SIZE(mt6797_memif_widgets);
- afe->sub_dais[MT6797_MEMIF_DL1].dapm_routes = mt6797_memif_routes;
- afe->sub_dais[MT6797_MEMIF_DL1].num_dapm_routes =
- ARRAY_SIZE(mt6797_memif_routes);
+ INIT_LIST_HEAD(&afe->sub_dais);
+
+ for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ ret = dai_register_cbs[i](afe);
+ if (ret) {
+ dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+ i, ret);
+ return ret;
+ }
+ }
/* init dai_driver and component_driver */
- mtk_afe_combine_sub_dai(afe);
+ ret = mtk_afe_combine_sub_dai(afe);
+ if (ret) {
+ dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+ ret);
+ return ret;
+ }
afe->mtk_afe_hardware = &mt6797_afe_hardware;
afe->memif_fs = mt6797_memif_fs;
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
index ad083265ce94..0ac6409c6d61 100644
--- a/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-adda.c
@@ -383,14 +383,20 @@ static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
int mt6797_dai_adda_register(struct mtk_base_afe *afe)
{
- int id = MT6797_DAI_ADDA;
+ struct mtk_base_afe_dai *dai;
- afe->sub_dais[id].dai_drivers = mtk_dai_adda_driver;
- afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
- afe->sub_dais[id].dapm_widgets = mtk_dai_adda_widgets;
- afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
- afe->sub_dais[id].dapm_routes = mtk_dai_adda_routes;
- afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_adda_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
+
+ dai->dapm_widgets = mtk_dai_adda_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
+ dai->dapm_routes = mtk_dai_adda_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
return 0;
}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c b/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
index 4cf985b15a11..ed23e6a53b08 100644
--- a/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-hostless.c
@@ -100,13 +100,19 @@ static struct snd_soc_dai_driver mtk_dai_hostless_driver[] = {
int mt6797_dai_hostless_register(struct mtk_base_afe *afe)
{
- int id = MT6797_DAI_HOSTLESS_LPBK;
+ struct mtk_base_afe_dai *dai;
- afe->sub_dais[id].dai_drivers = mtk_dai_hostless_driver;
- afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
- afe->sub_dais[id].dapm_routes = mtk_dai_hostless_routes;
- afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_hostless_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_hostless_driver);
+
+ dai->dapm_routes = mtk_dai_hostless_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_hostless_routes);
return 0;
}
diff --git a/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
index 16d5b5067204..3136f0bc7827 100644
--- a/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-dai-pcm.c
@@ -298,15 +298,20 @@ static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
int mt6797_dai_pcm_register(struct mtk_base_afe *afe)
{
- int id = MT6797_DAI_PCM_1;
+ struct mtk_base_afe_dai *dai;
- afe->sub_dais[id].dai_drivers = mtk_dai_pcm_driver;
- afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
- afe->sub_dais[id].dapm_widgets = mtk_dai_pcm_widgets;
- afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
- afe->sub_dais[id].dapm_routes = mtk_dai_pcm_routes;
- afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
+ list_add(&dai->list, &afe->sub_dais);
+ dai->dai_drivers = mtk_dai_pcm_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
+
+ dai->dapm_widgets = mtk_dai_pcm_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
+ dai->dapm_routes = mtk_dai_pcm_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
return 0;
}
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
new file mode 100644
index 000000000000..8af8bc358a90
--- /dev/null
+++ b/sound/soc/meson/Kconfig
@@ -0,0 +1,65 @@
+menu "ASoC support for Amlogic platforms"
+ depends on ARCH_MESON || COMPILE_TEST
+
+config SND_MESON_AXG_FIFO
+ tristate
+ select REGMAP_MMIO
+
+config SND_MESON_AXG_FRDDR
+ tristate "Amlogic AXG Playback FIFO support"
+ select SND_MESON_AXG_FIFO
+ help
+ Select Y or M to add support for the frontend playback interfaces
+ embedded in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_TODDR
+ tristate "Amlogic AXG Capture FIFO support"
+ select SND_MESON_AXG_FIFO
+ help
+ Select Y or M to add support for the frontend capture interfaces
+ embedded in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_TDM_FORMATTER
+ tristate
+ select REGMAP_MMIO
+
+config SND_MESON_AXG_TDM_INTERFACE
+ tristate
+ select SND_MESON_AXG_TDM_FORMATTER
+
+config SND_MESON_AXG_TDMIN
+ tristate "Amlogic AXG TDM Input Support"
+ select SND_MESON_AXG_TDM_FORMATTER
+ select SND_MESON_AXG_TDM_INTERFACE
+ help
+ Select Y or M to add support for TDM input formatter embedded
+ in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_TDMOUT
+ tristate "Amlogic AXG TDM Output Support"
+ select SND_MESON_AXG_TDM_FORMATTER
+ select SND_MESON_AXG_TDM_INTERFACE
+ help
+ Select Y or M to add support for TDM output formatter embedded
+ in the Amlogic AXG SoC family
+
+config SND_MESON_AXG_SOUND_CARD
+ tristate "Amlogic AXG Sound Card Support"
+ select SND_MESON_AXG_TDM_INTERFACE
+ imply SND_MESON_AXG_FRDDR
+ imply SND_MESON_AXG_TODDR
+ imply SND_MESON_AXG_TDMIN
+ imply SND_MESON_AXG_TDMOUT
+ imply SND_MESON_AXG_SPDIFOUT
+ help
+ Select Y or M to add support for the AXG SoC sound card
+
+config SND_MESON_AXG_SPDIFOUT
+ tristate "Amlogic AXG SPDIF Output Support"
+ select SND_PCM_IEC958
+ imply SND_SOC_SPDIF
+ help
+ Select Y or M to add support for SPDIF output serializer embedded
+ in the Amlogic AXG SoC family
+
+endmenu
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
new file mode 100644
index 000000000000..c5e003b093db
--- /dev/null
+++ b/sound/soc/meson/Makefile
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+snd-soc-meson-axg-fifo-objs := axg-fifo.o
+snd-soc-meson-axg-frddr-objs := axg-frddr.o
+snd-soc-meson-axg-toddr-objs := axg-toddr.o
+snd-soc-meson-axg-tdm-formatter-objs := axg-tdm-formatter.o
+snd-soc-meson-axg-tdm-interface-objs := axg-tdm-interface.o
+snd-soc-meson-axg-tdmin-objs := axg-tdmin.o
+snd-soc-meson-axg-tdmout-objs := axg-tdmout.o
+snd-soc-meson-axg-sound-card-objs := axg-card.o
+snd-soc-meson-axg-spdifout-objs := axg-spdifout.o
+
+obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o
+obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o
+obj-$(CONFIG_SND_MESON_AXG_TODDR) += snd-soc-meson-axg-toddr.o
+obj-$(CONFIG_SND_MESON_AXG_TDM_FORMATTER) += snd-soc-meson-axg-tdm-formatter.o
+obj-$(CONFIG_SND_MESON_AXG_TDM_INTERFACE) += snd-soc-meson-axg-tdm-interface.o
+obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
+obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
+obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
new file mode 100644
index 000000000000..2914ba0d965b
--- /dev/null
+++ b/sound/soc/meson/axg-card.c
@@ -0,0 +1,671 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm.h"
+
+struct axg_card {
+ struct snd_soc_card card;
+ void **link_data;
+};
+
+struct axg_dai_link_tdm_mask {
+ u32 tx;
+ u32 rx;
+};
+
+struct axg_dai_link_tdm_data {
+ unsigned int mclk_fs;
+ unsigned int slots;
+ unsigned int slot_width;
+ u32 *tx_mask;
+ u32 *rx_mask;
+ struct axg_dai_link_tdm_mask *codec_masks;
+};
+
+#define PREFIX "amlogic,"
+
+static int axg_card_reallocate_links(struct axg_card *priv,
+ unsigned int num_links)
+{
+ struct snd_soc_dai_link *links;
+ void **ldata;
+
+ links = krealloc(priv->card.dai_link,
+ num_links * sizeof(*priv->card.dai_link),
+ GFP_KERNEL | __GFP_ZERO);
+ ldata = krealloc(priv->link_data,
+ num_links * sizeof(*priv->link_data),
+ GFP_KERNEL | __GFP_ZERO);
+
+ if (!links || !ldata) {
+ dev_err(priv->card.dev, "failed to allocate links\n");
+ return -ENOMEM;
+ }
+
+ priv->card.dai_link = links;
+ priv->link_data = ldata;
+ priv->card.num_links = num_links;
+ return 0;
+}
+
+static int axg_card_parse_dai(struct snd_soc_card *card,
+ struct device_node *node,
+ struct device_node **dai_of_node,
+ const char **dai_name)
+{
+ struct of_phandle_args args;
+ int ret;
+
+ if (!dai_name || !dai_of_node || !node)
+ return -EINVAL;
+
+ ret = of_parse_phandle_with_args(node, "sound-dai",
+ "#sound-dai-cells", 0, &args);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(card->dev, "can't parse dai %d\n", ret);
+ return ret;
+ }
+ *dai_of_node = args.np;
+
+ return snd_soc_get_dai_name(&args, dai_name);
+}
+
+static int axg_card_set_link_name(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link,
+ const char *prefix)
+{
+ char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
+ prefix, link->cpu_of_node->full_name);
+ if (!name)
+ return -ENOMEM;
+
+ link->name = name;
+ link->stream_name = name;
+
+ return 0;
+}
+
+static void axg_card_clean_references(struct axg_card *priv)
+{
+ struct snd_soc_card *card = &priv->card;
+ struct snd_soc_dai_link *link;
+ int i, j;
+
+ if (card->dai_link) {
+ for (i = 0; i < card->num_links; i++) {
+ link = &card->dai_link[i];
+ of_node_put(link->cpu_of_node);
+ for (j = 0; j < link->num_codecs; j++)
+ of_node_put(link->codecs[j].of_node);
+ }
+ }
+
+ if (card->aux_dev) {
+ for (i = 0; i < card->num_aux_devs; i++)
+ of_node_put(card->aux_dev[i].codec_of_node);
+ }
+
+ kfree(card->dai_link);
+ kfree(priv->link_data);
+}
+
+static int axg_card_add_aux_devices(struct snd_soc_card *card)
+{
+ struct device_node *node = card->dev->of_node;
+ struct snd_soc_aux_dev *aux;
+ int num, i;
+
+ num = of_count_phandle_with_args(node, "audio-aux-devs", NULL);
+ if (num == -ENOENT) {
+ /*
+ * It is ok to have no auxiliary devices but for this card it
+ * is a strange situtation. Let's warn the about it.
+ */
+ dev_warn(card->dev, "card has no auxiliary devices\n");
+ return 0;
+ } else if (num < 0) {
+ dev_err(card->dev, "error getting auxiliary devices: %d\n",
+ num);
+ return num;
+ }
+
+ aux = devm_kcalloc(card->dev, num, sizeof(*aux), GFP_KERNEL);
+ if (!aux)
+ return -ENOMEM;
+ card->aux_dev = aux;
+ card->num_aux_devs = num;
+
+ for (i = 0; i < card->num_aux_devs; i++, aux++) {
+ aux->codec_of_node =
+ of_parse_phandle(node, "audio-aux-devs", i);
+ if (!aux->codec_of_node)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int axg_card_tdm_be_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct axg_dai_link_tdm_data *be =
+ (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+ struct snd_soc_dai *codec_dai;
+ unsigned int mclk;
+ int ret, i;
+
+ if (be->mclk_fs) {
+ mclk = params_rate(params) * be->mclk_fs;
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ codec_dai = rtd->codec_dais[i];
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk,
+ SND_SOC_CLOCK_OUT);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_ops axg_card_tdm_be_ops = {
+ .hw_params = axg_card_tdm_be_hw_params,
+};
+
+static int axg_card_tdm_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct axg_dai_link_tdm_data *be =
+ (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+ struct snd_soc_dai *codec_dai;
+ int ret, i;
+
+ for (i = 0; i < rtd->num_codecs; i++) {
+ codec_dai = rtd->codec_dais[i];
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ be->codec_masks[i].tx,
+ be->codec_masks[i].rx,
+ be->slots, be->slot_width);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(codec_dai->dev,
+ "setting tdm link slots failed\n");
+ return ret;
+ }
+ }
+
+ ret = axg_tdm_set_tdm_slots(rtd->cpu_dai, be->tx_mask, be->rx_mask,
+ be->slots, be->slot_width);
+ if (ret) {
+ dev_err(rtd->cpu_dai->dev, "setting tdm link slots failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_card_tdm_dai_lb_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct axg_card *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct axg_dai_link_tdm_data *be =
+ (struct axg_dai_link_tdm_data *)priv->link_data[rtd->num];
+ int ret;
+
+ /* The loopback rx_mask is the pad tx_mask */
+ ret = axg_tdm_set_tdm_slots(rtd->cpu_dai, NULL, be->tx_mask,
+ be->slots, be->slot_width);
+ if (ret) {
+ dev_err(rtd->cpu_dai->dev, "setting tdm link slots failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
+ int *index)
+{
+ struct axg_card *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai_link *pad = &card->dai_link[*index];
+ struct snd_soc_dai_link *lb;
+ int ret;
+
+ /* extend links */
+ ret = axg_card_reallocate_links(priv, card->num_links + 1);
+ if (ret)
+ return ret;
+
+ lb = &card->dai_link[*index + 1];
+
+ lb->name = kasprintf(GFP_KERNEL, "%s-lb", pad->name);
+ if (!lb->name)
+ return -ENOMEM;
+
+ lb->stream_name = lb->name;
+ lb->cpu_of_node = pad->cpu_of_node;
+ lb->cpu_dai_name = "TDM Loopback";
+ lb->codec_name = "snd-soc-dummy";
+ lb->codec_dai_name = "snd-soc-dummy-dai";
+ lb->dpcm_capture = 1;
+ lb->no_pcm = 1;
+ lb->ops = &axg_card_tdm_be_ops;
+ lb->init = axg_card_tdm_dai_lb_init;
+
+ /* Provide the same link data to the loopback */
+ priv->link_data[*index + 1] = priv->link_data[*index];
+
+ /*
+ * axg_card_clean_references() will iterate over this link,
+ * make sure the node count is balanced
+ */
+ of_node_get(lb->cpu_of_node);
+
+ /* Let add_links continue where it should */
+ *index += 1;
+
+ return 0;
+}
+
+static unsigned int axg_card_parse_daifmt(struct device_node *node,
+ struct device_node *cpu_node)
+{
+ struct device_node *bitclkmaster = NULL;
+ struct device_node *framemaster = NULL;
+ unsigned int daifmt;
+
+ daifmt = snd_soc_of_parse_daifmt(node, PREFIX,
+ &bitclkmaster, &framemaster);
+ daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+ /* If no master is provided, default to cpu master */
+ if (!bitclkmaster || bitclkmaster == cpu_node) {
+ daifmt |= (!framemaster || framemaster == cpu_node) ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
+ } else {
+ daifmt |= (!framemaster || framemaster == cpu_node) ?
+ SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
+ }
+
+ of_node_put(bitclkmaster);
+ of_node_put(framemaster);
+
+ return daifmt;
+}
+
+static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link,
+ struct device_node *node,
+ struct axg_dai_link_tdm_data *be)
+{
+ char propname[32];
+ u32 tx, rx;
+ int i;
+
+ be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+ sizeof(*be->tx_mask), GFP_KERNEL);
+ be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+ sizeof(*be->rx_mask), GFP_KERNEL);
+ if (!be->tx_mask || !be->rx_mask)
+ return -ENOMEM;
+
+ for (i = 0, tx = 0; i < AXG_TDM_NUM_LANES; i++) {
+ snprintf(propname, 32, "dai-tdm-slot-tx-mask-%d", i);
+ snd_soc_of_get_slot_mask(node, propname, &be->tx_mask[i]);
+ tx = max(tx, be->tx_mask[i]);
+ }
+
+ /* Disable playback is the interface has no tx slots */
+ if (!tx)
+ link->dpcm_playback = 0;
+
+ for (i = 0, rx = 0; i < AXG_TDM_NUM_LANES; i++) {
+ snprintf(propname, 32, "dai-tdm-slot-rx-mask-%d", i);
+ snd_soc_of_get_slot_mask(node, propname, &be->rx_mask[i]);
+ rx = max(rx, be->rx_mask[i]);
+ }
+
+ /* Disable capture is the interface has no rx slots */
+ if (!rx)
+ link->dpcm_capture = 0;
+
+ /* ... but the interface should at least have one of them */
+ if (!tx && !rx) {
+ dev_err(card->dev, "tdm link has no cpu slots\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32(node, "dai-tdm-slot-num", &be->slots);
+ if (!be->slots) {
+ /*
+ * If the slot number is not provided, set it such as it
+ * accommodates the largest mask
+ */
+ be->slots = fls(max(tx, rx));
+ } else if (be->slots < fls(max(tx, rx)) || be->slots > 32) {
+ /*
+ * Error if the slots can't accommodate the largest mask or
+ * if it is just too big
+ */
+ dev_err(card->dev, "bad slot number\n");
+ return -EINVAL;
+ }
+
+ of_property_read_u32(node, "dai-tdm-slot-width", &be->slot_width);
+
+ return 0;
+}
+
+static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link,
+ struct device_node *node,
+ struct axg_dai_link_tdm_data *be)
+{
+ struct axg_dai_link_tdm_mask *codec_mask;
+ struct device_node *np;
+
+ codec_mask = devm_kcalloc(card->dev, link->num_codecs,
+ sizeof(*codec_mask), GFP_KERNEL);
+ if (!codec_mask)
+ return -ENOMEM;
+
+ be->codec_masks = codec_mask;
+
+ for_each_child_of_node(node, np) {
+ snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask",
+ &codec_mask->rx);
+ snd_soc_of_get_slot_mask(np, "dai-tdm-slot-tx-mask",
+ &codec_mask->tx);
+
+ codec_mask++;
+ }
+
+ return 0;
+}
+
+static int axg_card_parse_tdm(struct snd_soc_card *card,
+ struct device_node *node,
+ int *index)
+{
+ struct axg_card *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai_link *link = &card->dai_link[*index];
+ struct axg_dai_link_tdm_data *be;
+ int ret;
+
+ /* Allocate tdm link parameters */
+ be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
+ if (!be)
+ return -ENOMEM;
+ priv->link_data[*index] = be;
+
+ /* Setup tdm link */
+ link->ops = &axg_card_tdm_be_ops;
+ link->init = axg_card_tdm_dai_init;
+ link->dai_fmt = axg_card_parse_daifmt(node, link->cpu_of_node);
+
+ of_property_read_u32(node, "mclk-fs", &be->mclk_fs);
+
+ ret = axg_card_parse_cpu_tdm_slots(card, link, node, be);
+ if (ret) {
+ dev_err(card->dev, "error parsing tdm link slots\n");
+ return ret;
+ }
+
+ ret = axg_card_parse_codecs_masks(card, link, node, be);
+ if (ret)
+ return ret;
+
+ /* Add loopback if the pad dai has playback */
+ if (link->dpcm_playback) {
+ ret = axg_card_add_tdm_loopback(card, index);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_card_set_be_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link,
+ struct device_node *node)
+{
+ struct snd_soc_dai_link_component *codec;
+ struct device_node *np;
+ int ret, num_codecs;
+
+ link->no_pcm = 1;
+ link->dpcm_playback = 1;
+ link->dpcm_capture = 1;
+
+ num_codecs = of_get_child_count(node);
+ if (!num_codecs) {
+ dev_err(card->dev, "be link %s has no codec\n",
+ node->full_name);
+ return -EINVAL;
+ }
+
+ codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
+ if (!codec)
+ return -ENOMEM;
+
+ link->codecs = codec;
+ link->num_codecs = num_codecs;
+
+ for_each_child_of_node(node, np) {
+ ret = axg_card_parse_dai(card, np, &codec->of_node,
+ &codec->dai_name);
+ if (ret) {
+ of_node_put(np);
+ return ret;
+ }
+
+ codec++;
+ }
+
+ ret = axg_card_set_link_name(card, link, "be");
+ if (ret)
+ dev_err(card->dev, "error setting %s link name\n", np->name);
+
+ return ret;
+}
+
+static int axg_card_set_fe_link(struct snd_soc_card *card,
+ struct snd_soc_dai_link *link,
+ bool is_playback)
+{
+ link->dynamic = 1;
+ link->dpcm_merged_format = 1;
+ link->dpcm_merged_chan = 1;
+ link->dpcm_merged_rate = 1;
+ link->codec_dai_name = "snd-soc-dummy-dai";
+ link->codec_name = "snd-soc-dummy";
+
+ if (is_playback)
+ link->dpcm_playback = 1;
+ else
+ link->dpcm_capture = 1;
+
+ return axg_card_set_link_name(card, link, "fe");
+}
+
+static int axg_card_cpu_is_capture_fe(struct device_node *np)
+{
+ return of_device_is_compatible(np, PREFIX "axg-toddr");
+}
+
+static int axg_card_cpu_is_playback_fe(struct device_node *np)
+{
+ return of_device_is_compatible(np, PREFIX "axg-frddr");
+}
+
+static int axg_card_cpu_is_tdm_iface(struct device_node *np)
+{
+ return of_device_is_compatible(np, PREFIX "axg-tdm-iface");
+}
+
+static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
+ int *index)
+{
+ struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
+ int ret;
+
+ ret = axg_card_parse_dai(card, np, &dai_link->cpu_of_node,
+ &dai_link->cpu_dai_name);
+ if (ret)
+ return ret;
+
+ if (axg_card_cpu_is_playback_fe(dai_link->cpu_of_node))
+ ret = axg_card_set_fe_link(card, dai_link, true);
+ else if (axg_card_cpu_is_capture_fe(dai_link->cpu_of_node))
+ ret = axg_card_set_fe_link(card, dai_link, false);
+ else
+ ret = axg_card_set_be_link(card, dai_link, np);
+
+ if (ret)
+ return ret;
+
+ if (axg_card_cpu_is_tdm_iface(dai_link->cpu_of_node))
+ ret = axg_card_parse_tdm(card, np, index);
+
+ return ret;
+}
+
+static int axg_card_add_links(struct snd_soc_card *card)
+{
+ struct axg_card *priv = snd_soc_card_get_drvdata(card);
+ struct device_node *node = card->dev->of_node;
+ struct device_node *np;
+ int num, i, ret;
+
+ num = of_get_child_count(node);
+ if (!num) {
+ dev_err(card->dev, "card has no links\n");
+ return -EINVAL;
+ }
+
+ ret = axg_card_reallocate_links(priv, num);
+ if (ret)
+ return ret;
+
+ i = 0;
+ for_each_child_of_node(node, np) {
+ ret = axg_card_add_link(card, np, &i);
+ if (ret) {
+ of_node_put(np);
+ return ret;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+static int axg_card_parse_of_optional(struct snd_soc_card *card,
+ const char *propname,
+ int (*func)(struct snd_soc_card *c,
+ const char *p))
+{
+ /* If property is not provided, don't fail ... */
+ if (!of_property_read_bool(card->dev->of_node, propname))
+ return 0;
+
+ /* ... but do fail if it is provided and the parsing fails */
+ return func(card, propname);
+}
+
+static const struct of_device_id axg_card_of_match[] = {
+ { .compatible = "amlogic,axg-sound-card", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, axg_card_of_match);
+
+static int axg_card_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct axg_card *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, priv);
+ snd_soc_card_set_drvdata(&priv->card, priv);
+
+ priv->card.owner = THIS_MODULE;
+ priv->card.dev = dev;
+
+ ret = snd_soc_of_parse_card_name(&priv->card, "model");
+ if (ret < 0)
+ return ret;
+
+ ret = axg_card_parse_of_optional(&priv->card, "audio-routing",
+ snd_soc_of_parse_audio_routing);
+ if (ret) {
+ dev_err(dev, "error while parsing routing\n");
+ return ret;
+ }
+
+ ret = axg_card_parse_of_optional(&priv->card, "audio-widgets",
+ snd_soc_of_parse_audio_simple_widgets);
+ if (ret) {
+ dev_err(dev, "error while parsing widgets\n");
+ return ret;
+ }
+
+ ret = axg_card_add_links(&priv->card);
+ if (ret)
+ goto out_err;
+
+ ret = axg_card_add_aux_devices(&priv->card);
+ if (ret)
+ goto out_err;
+
+ ret = devm_snd_soc_register_card(dev, &priv->card);
+ if (ret)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ axg_card_clean_references(priv);
+ return ret;
+}
+
+static int axg_card_remove(struct platform_device *pdev)
+{
+ struct axg_card *priv = platform_get_drvdata(pdev);
+
+ axg_card_clean_references(priv);
+
+ return 0;
+}
+
+static struct platform_driver axg_card_pdrv = {
+ .probe = axg_card_probe,
+ .remove = axg_card_remove,
+ .driver = {
+ .name = "axg-sound-card",
+ .of_match_table = axg_card_of_match,
+ },
+};
+module_platform_driver(axg_card_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG ALSA machine driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
new file mode 100644
index 000000000000..30262550e37b
--- /dev/null
+++ b/sound/soc/meson/axg-fifo.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-fifo.h"
+
+/*
+ * This file implements the platform operations common to the playback and
+ * capture frontend DAI. The logic behind this two types of fifo is very
+ * similar but some difference exist.
+ * These differences the respective DAI drivers
+ */
+
+static struct snd_pcm_hardware axg_fifo_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE),
+
+ .formats = AXG_FIFO_FORMATS,
+ .rate_min = 5512,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = AXG_FIFO_CH_MAX,
+ .period_bytes_min = AXG_FIFO_MIN_DEPTH,
+ .period_bytes_max = UINT_MAX,
+ .periods_min = 2,
+ .periods_max = UINT_MAX,
+
+ /* No real justification for this */
+ .buffer_bytes_max = 1 * 1024 * 1024,
+};
+
+static struct snd_soc_dai *axg_fifo_dai(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+
+ return rtd->cpu_dai;
+}
+
+static struct axg_fifo *axg_fifo_data(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_dai *dai = axg_fifo_dai(ss);
+
+ return snd_soc_dai_get_drvdata(dai);
+}
+
+static struct device *axg_fifo_dev(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_dai *dai = axg_fifo_dai(ss);
+
+ return dai->dev;
+}
+
+static void __dma_enable(struct axg_fifo *fifo, bool enable)
+{
+ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_DMA_EN,
+ enable ? CTRL0_DMA_EN : 0);
+}
+
+static int axg_fifo_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
+{
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ __dma_enable(fifo, true);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ __dma_enable(fifo, false);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t axg_fifo_pcm_pointer(struct snd_pcm_substream *ss)
+{
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+ struct snd_pcm_runtime *runtime = ss->runtime;
+ unsigned int addr;
+
+ regmap_read(fifo->map, FIFO_STATUS2, &addr);
+
+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
+}
+
+static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = ss->runtime;
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+ dma_addr_t end_ptr;
+ unsigned int burst_num;
+ int ret;
+
+ ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(params));
+ if (ret < 0)
+ return ret;
+
+ /* Setup dma memory pointers */
+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
+ regmap_write(fifo->map, FIFO_START_ADDR, runtime->dma_addr);
+ regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
+
+ /* Setup interrupt periodicity */
+ burst_num = params_period_bytes(params) / AXG_FIFO_BURST;
+ regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
+
+ /* Enable block count irq */
+ regmap_update_bits(fifo->map, FIFO_CTRL0,
+ CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
+ CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT));
+
+ return 0;
+}
+
+static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss)
+{
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+
+ /* Disable the block count irq */
+ regmap_update_bits(fifo->map, FIFO_CTRL0,
+ CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
+
+ return snd_pcm_lib_free_pages(ss);
+}
+
+static void axg_fifo_ack_irq(struct axg_fifo *fifo, u8 mask)
+{
+ regmap_update_bits(fifo->map, FIFO_CTRL1,
+ CTRL1_INT_CLR(FIFO_INT_MASK),
+ CTRL1_INT_CLR(mask));
+
+ /* Clear must also be cleared */
+ regmap_update_bits(fifo->map, FIFO_CTRL1,
+ CTRL1_INT_CLR(FIFO_INT_MASK),
+ 0);
+}
+
+static irqreturn_t axg_fifo_pcm_irq_block(int irq, void *dev_id)
+{
+ struct snd_pcm_substream *ss = dev_id;
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+ unsigned int status;
+
+ regmap_read(fifo->map, FIFO_STATUS1, &status);
+
+ status = STATUS1_INT_STS(status) & FIFO_INT_MASK;
+ if (status & FIFO_INT_COUNT_REPEAT)
+ snd_pcm_period_elapsed(ss);
+ else
+ dev_dbg(axg_fifo_dev(ss), "unexpected irq - STS 0x%02x\n",
+ status);
+
+ /* Ack irqs */
+ axg_fifo_ack_irq(fifo, status);
+
+ return IRQ_RETVAL(status);
+}
+
+static int axg_fifo_pcm_open(struct snd_pcm_substream *ss)
+{
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+ struct device *dev = axg_fifo_dev(ss);
+ int ret;
+
+ snd_soc_set_runtime_hwparams(ss, &axg_fifo_hw);
+
+ /*
+ * Make sure the buffer and period size are multiple of the FIFO
+ * minimum depth size
+ */
+ ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ AXG_FIFO_MIN_DEPTH);
+ if (ret)
+ return ret;
+
+ ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ AXG_FIFO_MIN_DEPTH);
+ if (ret)
+ return ret;
+
+ ret = request_irq(fifo->irq, axg_fifo_pcm_irq_block, 0,
+ dev_name(dev), ss);
+
+ /* Enable pclk to access registers and clock the fifo ip */
+ ret = clk_prepare_enable(fifo->pclk);
+ if (ret)
+ return ret;
+
+ /* Setup status2 so it reports the memory pointer */
+ regmap_update_bits(fifo->map, FIFO_CTRL1,
+ CTRL1_STATUS2_SEL_MASK,
+ CTRL1_STATUS2_SEL(STATUS2_SEL_DDR_READ));
+
+ /* Make sure the dma is initially disabled */
+ __dma_enable(fifo, false);
+
+ /* Disable irqs until params are ready */
+ regmap_update_bits(fifo->map, FIFO_CTRL0,
+ CTRL0_INT_EN(FIFO_INT_MASK), 0);
+
+ /* Clear any pending interrupt */
+ axg_fifo_ack_irq(fifo, FIFO_INT_MASK);
+
+ /* Take memory arbitror out of reset */
+ ret = reset_control_deassert(fifo->arb);
+ if (ret)
+ clk_disable_unprepare(fifo->pclk);
+
+ return ret;
+}
+
+static int axg_fifo_pcm_close(struct snd_pcm_substream *ss)
+{
+ struct axg_fifo *fifo = axg_fifo_data(ss);
+ int ret;
+
+ /* Put the memory arbitror back in reset */
+ ret = reset_control_assert(fifo->arb);
+
+ /* Disable fifo ip and register access */
+ clk_disable_unprepare(fifo->pclk);
+
+ /* remove IRQ */
+ free_irq(fifo->irq, ss);
+
+ return ret;
+}
+
+const struct snd_pcm_ops axg_fifo_pcm_ops = {
+ .open = axg_fifo_pcm_open,
+ .close = axg_fifo_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = axg_fifo_pcm_hw_params,
+ .hw_free = axg_fifo_pcm_hw_free,
+ .pointer = axg_fifo_pcm_pointer,
+ .trigger = axg_fifo_pcm_trigger,
+};
+EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops);
+
+int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
+{
+ struct snd_card *card = rtd->card->snd_card;
+ size_t size = axg_fifo_hw.buffer_bytes_max;
+
+ return snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream,
+ SNDRV_DMA_TYPE_DEV, card->dev,
+ size, size);
+}
+EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
+
+static const struct regmap_config axg_fifo_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = FIFO_STATUS2,
+};
+
+int axg_fifo_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct axg_fifo_match_data *data;
+ struct axg_fifo *fifo;
+ struct resource *res;
+ void __iomem *regs;
+
+ data = of_device_get_match_data(dev);
+ if (!data) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ fifo = devm_kzalloc(dev, sizeof(*fifo), GFP_KERNEL);
+ if (!fifo)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, fifo);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ fifo->map = devm_regmap_init_mmio(dev, regs, &axg_fifo_regmap_cfg);
+ if (IS_ERR(fifo->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(fifo->map));
+ return PTR_ERR(fifo->map);
+ }
+
+ fifo->pclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(fifo->pclk)) {
+ if (PTR_ERR(fifo->pclk) != -EPROBE_DEFER)
+ dev_err(dev, "failed to get pclk: %ld\n",
+ PTR_ERR(fifo->pclk));
+ return PTR_ERR(fifo->pclk);
+ }
+
+ fifo->arb = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(fifo->arb)) {
+ if (PTR_ERR(fifo->arb) != -EPROBE_DEFER)
+ dev_err(dev, "failed to get arb reset: %ld\n",
+ PTR_ERR(fifo->arb));
+ return PTR_ERR(fifo->arb);
+ }
+
+ fifo->irq = of_irq_get(dev->of_node, 0);
+ if (fifo->irq <= 0) {
+ dev_err(dev, "failed to get irq: %d\n", fifo->irq);
+ return fifo->irq;
+ }
+
+ return devm_snd_soc_register_component(dev, data->component_drv,
+ data->dai_drv, 1);
+}
+EXPORT_SYMBOL_GPL(axg_fifo_probe);
+
+MODULE_DESCRIPTION("Amlogic AXG fifo driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h
new file mode 100644
index 000000000000..cb6c4013ca33
--- /dev/null
+++ b/sound/soc/meson/axg-fifo.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef _MESON_AXG_FIFO_H
+#define _MESON_AXG_FIFO_H
+
+struct clk;
+struct platform_device;
+struct regmap;
+struct reset_control;
+
+struct snd_soc_component_driver;
+struct snd_soc_dai;
+struct snd_soc_dai_driver;
+struct snd_pcm_ops;
+struct snd_soc_pcm_runtime;
+
+#define AXG_FIFO_CH_MAX 128
+#define AXG_FIFO_RATES (SNDRV_PCM_RATE_5512 | \
+ SNDRV_PCM_RATE_8000_192000)
+#define AXG_FIFO_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AXG_FIFO_BURST 8
+#define AXG_FIFO_MIN_CNT 64
+#define AXG_FIFO_MIN_DEPTH (AXG_FIFO_BURST * AXG_FIFO_MIN_CNT)
+
+#define FIFO_INT_ADDR_FINISH BIT(0)
+#define FIFO_INT_ADDR_INT BIT(1)
+#define FIFO_INT_COUNT_REPEAT BIT(2)
+#define FIFO_INT_COUNT_ONCE BIT(3)
+#define FIFO_INT_FIFO_ZERO BIT(4)
+#define FIFO_INT_FIFO_DEPTH BIT(5)
+#define FIFO_INT_MASK GENMASK(7, 0)
+
+#define FIFO_CTRL0 0x00
+#define CTRL0_DMA_EN BIT(31)
+#define CTRL0_INT_EN(x) ((x) << 16)
+#define CTRL0_SEL_MASK GENMASK(2, 0)
+#define CTRL0_SEL_SHIFT 0
+#define FIFO_CTRL1 0x04
+#define CTRL1_INT_CLR(x) ((x) << 0)
+#define CTRL1_STATUS2_SEL_MASK GENMASK(11, 8)
+#define CTRL1_STATUS2_SEL(x) ((x) << 8)
+#define STATUS2_SEL_DDR_READ 0
+#define CTRL1_THRESHOLD_MASK GENMASK(23, 16)
+#define CTRL1_THRESHOLD(x) ((x) << 16)
+#define CTRL1_FRDDR_DEPTH_MASK GENMASK(31, 24)
+#define CTRL1_FRDDR_DEPTH(x) ((x) << 24)
+#define FIFO_START_ADDR 0x08
+#define FIFO_FINISH_ADDR 0x0c
+#define FIFO_INT_ADDR 0x10
+#define FIFO_STATUS1 0x14
+#define STATUS1_INT_STS(x) ((x) << 0)
+#define FIFO_STATUS2 0x18
+
+struct axg_fifo {
+ struct regmap *map;
+ struct clk *pclk;
+ struct reset_control *arb;
+ int irq;
+};
+
+struct axg_fifo_match_data {
+ const struct snd_soc_component_driver *component_drv;
+ struct snd_soc_dai_driver *dai_drv;
+};
+
+extern const struct snd_pcm_ops axg_fifo_pcm_ops;
+
+int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type);
+int axg_fifo_probe(struct platform_device *pdev);
+
+#endif /* _MESON_AXG_FIFO_H */
diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c
new file mode 100644
index 000000000000..a6f6f6a2eca8
--- /dev/null
+++ b/sound/soc/meson/axg-frddr.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+/* This driver implements the frontend playback DAI of AXG based SoCs */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-fifo.h"
+
+#define CTRL0_FRDDR_PP_MODE BIT(30)
+
+static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+ unsigned int fifo_depth, fifo_threshold;
+ int ret;
+
+ /* Enable pclk to access registers and clock the fifo ip */
+ ret = clk_prepare_enable(fifo->pclk);
+ if (ret)
+ return ret;
+
+ /* Apply single buffer mode to the interface */
+ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
+
+ /*
+ * TODO: We could adapt the fifo depth and the fifo threshold
+ * depending on the expected memory throughput and lantencies
+ * For now, we'll just use the same values as the vendor kernel
+ * Depth and threshold are zero based.
+ */
+ fifo_depth = AXG_FIFO_MIN_CNT - 1;
+ fifo_threshold = (AXG_FIFO_MIN_CNT / 2) - 1;
+ regmap_update_bits(fifo->map, FIFO_CTRL1,
+ CTRL1_FRDDR_DEPTH_MASK | CTRL1_THRESHOLD_MASK,
+ CTRL1_FRDDR_DEPTH(fifo_depth) |
+ CTRL1_THRESHOLD(fifo_threshold));
+
+ return 0;
+}
+
+static void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(fifo->pclk);
+}
+
+static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *dai)
+{
+ return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static const struct snd_soc_dai_ops axg_frddr_ops = {
+ .startup = axg_frddr_dai_startup,
+ .shutdown = axg_frddr_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver axg_frddr_dai_drv = {
+ .name = "FRDDR",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = AXG_FIFO_CH_MAX,
+ .rates = AXG_FIFO_RATES,
+ .formats = AXG_FIFO_FORMATS,
+ },
+ .ops = &axg_frddr_ops,
+ .pcm_new = axg_frddr_pcm_new,
+};
+
+static const char * const axg_frddr_sel_texts[] = {
+ "OUT 0", "OUT 1", "OUT 2", "OUT 3"
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
+ axg_frddr_sel_texts);
+
+static const struct snd_kcontrol_new axg_frddr_out_demux =
+ SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum);
+
+static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = {
+ SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0,
+ &axg_frddr_out_demux),
+ SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = {
+ { "SINK SEL", NULL, "Playback" },
+ { "OUT 0", "OUT 0", "SINK SEL" },
+ { "OUT 1", "OUT 1", "SINK SEL" },
+ { "OUT 2", "OUT 2", "SINK SEL" },
+ { "OUT 3", "OUT 3", "SINK SEL" },
+};
+
+static const struct snd_soc_component_driver axg_frddr_component_drv = {
+ .dapm_widgets = axg_frddr_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(axg_frddr_dapm_widgets),
+ .dapm_routes = axg_frddr_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes),
+ .ops = &axg_fifo_pcm_ops
+};
+
+static const struct axg_fifo_match_data axg_frddr_match_data = {
+ .component_drv = &axg_frddr_component_drv,
+ .dai_drv = &axg_frddr_dai_drv
+};
+
+static const struct of_device_id axg_frddr_of_match[] = {
+ {
+ .compatible = "amlogic,axg-frddr",
+ .data = &axg_frddr_match_data,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
+
+static struct platform_driver axg_frddr_pdrv = {
+ .probe = axg_fifo_probe,
+ .driver = {
+ .name = "axg-frddr",
+ .of_match_table = axg_frddr_of_match,
+ },
+};
+module_platform_driver(axg_frddr_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG playback fifo driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-spdifout.c b/sound/soc/meson/axg-spdifout.c
new file mode 100644
index 000000000000..9dea528053ad
--- /dev/null
+++ b/sound/soc/meson/axg-spdifout.c
@@ -0,0 +1,456 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm_iec958.h>
+
+/*
+ * NOTE:
+ * The meaning of bits SPDIFOUT_CTRL0_XXX_SEL is actually the opposite
+ * of what the documentation says. Manual control on V, U and C bits is
+ * applied when the related sel bits are cleared
+ */
+
+#define SPDIFOUT_STAT 0x00
+#define SPDIFOUT_GAIN0 0x04
+#define SPDIFOUT_GAIN1 0x08
+#define SPDIFOUT_CTRL0 0x0c
+#define SPDIFOUT_CTRL0_EN BIT(31)
+#define SPDIFOUT_CTRL0_RST_OUT BIT(29)
+#define SPDIFOUT_CTRL0_RST_IN BIT(28)
+#define SPDIFOUT_CTRL0_USEL BIT(26)
+#define SPDIFOUT_CTRL0_USET BIT(25)
+#define SPDIFOUT_CTRL0_CHSTS_SEL BIT(24)
+#define SPDIFOUT_CTRL0_DATA_SEL BIT(20)
+#define SPDIFOUT_CTRL0_MSB_FIRST BIT(19)
+#define SPDIFOUT_CTRL0_VSEL BIT(18)
+#define SPDIFOUT_CTRL0_VSET BIT(17)
+#define SPDIFOUT_CTRL0_MASK_MASK GENMASK(11, 4)
+#define SPDIFOUT_CTRL0_MASK(x) ((x) << 4)
+#define SPDIFOUT_CTRL1 0x10
+#define SPDIFOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8)
+#define SPDIFOUT_CTRL1_MSB_POS(x) ((x) << 8)
+#define SPDIFOUT_CTRL1_TYPE_MASK GENMASK(6, 4)
+#define SPDIFOUT_CTRL1_TYPE(x) ((x) << 4)
+#define SPDIFOUT_PREAMB 0x14
+#define SPDIFOUT_SWAP 0x18
+#define SPDIFOUT_CHSTS0 0x1c
+#define SPDIFOUT_CHSTS1 0x20
+#define SPDIFOUT_CHSTS2 0x24
+#define SPDIFOUT_CHSTS3 0x28
+#define SPDIFOUT_CHSTS4 0x2c
+#define SPDIFOUT_CHSTS5 0x30
+#define SPDIFOUT_CHSTS6 0x34
+#define SPDIFOUT_CHSTS7 0x38
+#define SPDIFOUT_CHSTS8 0x3c
+#define SPDIFOUT_CHSTS9 0x40
+#define SPDIFOUT_CHSTSA 0x44
+#define SPDIFOUT_CHSTSB 0x48
+#define SPDIFOUT_MUTE_VAL 0x4c
+
+struct axg_spdifout {
+ struct regmap *map;
+ struct clk *mclk;
+ struct clk *pclk;
+};
+
+static void axg_spdifout_enable(struct regmap *map)
+{
+ /* Apply both reset */
+ regmap_update_bits(map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_RST_OUT | SPDIFOUT_CTRL0_RST_IN,
+ 0);
+
+ /* Clear out reset before in reset */
+ regmap_update_bits(map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_RST_OUT, SPDIFOUT_CTRL0_RST_OUT);
+ regmap_update_bits(map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_RST_IN, SPDIFOUT_CTRL0_RST_IN);
+
+ /* Enable spdifout */
+ regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN,
+ SPDIFOUT_CTRL0_EN);
+}
+
+static void axg_spdifout_disable(struct regmap *map)
+{
+ regmap_update_bits(map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_EN, 0);
+}
+
+static int axg_spdifout_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ axg_spdifout_enable(priv->map);
+ return 0;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ axg_spdifout_disable(priv->map);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int axg_spdifout_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+
+ /* Use spdif valid bit to perform digital mute */
+ regmap_update_bits(priv->map, SPDIFOUT_CTRL0, SPDIFOUT_CTRL0_VSET,
+ mute ? SPDIFOUT_CTRL0_VSET : 0);
+
+ return 0;
+}
+
+static int axg_spdifout_sample_fmt(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int val;
+
+ /* Set the samples spdifout will pull from the FIFO */
+ switch (params_channels(params)) {
+ case 1:
+ val = SPDIFOUT_CTRL0_MASK(0x1);
+ break;
+ case 2:
+ val = SPDIFOUT_CTRL0_MASK(0x3);
+ break;
+ default:
+ dev_err(dai->dev, "too many channels for spdif dai: %u\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_MASK_MASK, val);
+
+ /* FIFO data are arranged in chunks of 64bits */
+ switch (params_physical_width(params)) {
+ case 8:
+ /* 8 samples of 8 bits */
+ val = SPDIFOUT_CTRL1_TYPE(0);
+ break;
+ case 16:
+ /* 4 samples of 16 bits - right justified */
+ val = SPDIFOUT_CTRL1_TYPE(2);
+ break;
+ case 32:
+ /* 2 samples of 32 bits - right justified */
+ val = SPDIFOUT_CTRL1_TYPE(4);
+ break;
+ default:
+ dev_err(dai->dev, "Unsupported physical width: %u\n",
+ params_physical_width(params));
+ return -EINVAL;
+ }
+
+ /* Position of the MSB in FIFO samples */
+ val |= SPDIFOUT_CTRL1_MSB_POS(params_width(params) - 1);
+
+ regmap_update_bits(priv->map, SPDIFOUT_CTRL1,
+ SPDIFOUT_CTRL1_MSB_POS_MASK |
+ SPDIFOUT_CTRL1_TYPE_MASK, val);
+
+ regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
+ 0);
+
+ return 0;
+}
+
+static int axg_spdifout_set_chsts(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int offset;
+ int ret;
+ u8 cs[4];
+ u32 val;
+
+ ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, 4);
+ if (ret < 0) {
+ dev_err(dai->dev, "Creating IEC958 channel status failed %d\n",
+ ret);
+ return ret;
+ }
+ val = cs[0] | cs[1] << 8 | cs[2] << 16 | cs[3] << 24;
+
+ /* Setup channel status A bits [31 - 0]*/
+ regmap_write(priv->map, SPDIFOUT_CHSTS0, val);
+
+ /* Clear channel status A bits [191 - 32] */
+ for (offset = SPDIFOUT_CHSTS1; offset <= SPDIFOUT_CHSTS5;
+ offset += regmap_get_reg_stride(priv->map))
+ regmap_write(priv->map, offset, 0);
+
+ /* Setup channel status B bits [31 - 0]*/
+ regmap_write(priv->map, SPDIFOUT_CHSTS6, val);
+
+ /* Clear channel status B bits [191 - 32] */
+ for (offset = SPDIFOUT_CHSTS7; offset <= SPDIFOUT_CHSTSB;
+ offset += regmap_get_reg_stride(priv->map))
+ regmap_write(priv->map, offset, 0);
+
+ return 0;
+}
+
+static int axg_spdifout_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+ unsigned int rate = params_rate(params);
+ int ret;
+
+ /* 2 * 32bits per subframe * 2 channels = 128 */
+ ret = clk_set_rate(priv->mclk, rate * 128);
+ if (ret) {
+ dev_err(dai->dev, "failed to set spdif clock\n");
+ return ret;
+ }
+
+ ret = axg_spdifout_sample_fmt(params, dai);
+ if (ret) {
+ dev_err(dai->dev, "failed to setup sample format\n");
+ return ret;
+ }
+
+ ret = axg_spdifout_set_chsts(params, dai);
+ if (ret) {
+ dev_err(dai->dev, "failed to setup channel status words\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_spdifout_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ /* Clock the spdif output block */
+ ret = clk_prepare_enable(priv->pclk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable pclk\n");
+ return ret;
+ }
+
+ /* Make sure the block is initially stopped */
+ axg_spdifout_disable(priv->map);
+
+ /* Insert data from bit 27 lsb first */
+ regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_MSB_FIRST | SPDIFOUT_CTRL0_DATA_SEL,
+ 0);
+
+ /* Manual control of V, C and U, U = 0 */
+ regmap_update_bits(priv->map, SPDIFOUT_CTRL0,
+ SPDIFOUT_CTRL0_CHSTS_SEL | SPDIFOUT_CTRL0_VSEL |
+ SPDIFOUT_CTRL0_USEL | SPDIFOUT_CTRL0_USET,
+ 0);
+
+ /* Static SWAP configuration ATM */
+ regmap_write(priv->map, SPDIFOUT_SWAP, 0x10);
+
+ return 0;
+}
+
+static void axg_spdifout_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_spdifout *priv = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(priv->pclk);
+}
+
+static const struct snd_soc_dai_ops axg_spdifout_ops = {
+ .trigger = axg_spdifout_trigger,
+ .digital_mute = axg_spdifout_digital_mute,
+ .hw_params = axg_spdifout_hw_params,
+ .startup = axg_spdifout_startup,
+ .shutdown = axg_spdifout_shutdown,
+};
+
+static struct snd_soc_dai_driver axg_spdifout_dai_drv[] = {
+ {
+ .name = "SPDIF Output",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = (SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000),
+ .formats = (SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S20_LE |
+ SNDRV_PCM_FMTBIT_S24_LE),
+ },
+ .ops = &axg_spdifout_ops,
+ },
+};
+
+static const char * const spdifout_sel_texts[] = {
+ "IN 0", "IN 1", "IN 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_spdifout_sel_enum, SPDIFOUT_CTRL1, 24,
+ spdifout_sel_texts);
+
+static const struct snd_kcontrol_new axg_spdifout_in_mux =
+ SOC_DAPM_ENUM("Input Source", axg_spdifout_sel_enum);
+
+static const struct snd_soc_dapm_widget axg_spdifout_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_spdifout_in_mux),
+};
+
+static const struct snd_soc_dapm_route axg_spdifout_dapm_routes[] = {
+ { "SRC SEL", "IN 0", "IN 0" },
+ { "SRC SEL", "IN 1", "IN 1" },
+ { "SRC SEL", "IN 2", "IN 2" },
+ { "Playback", NULL, "SRC SEL" },
+};
+
+static const struct snd_kcontrol_new axg_spdifout_controls[] = {
+ SOC_DOUBLE("Playback Volume", SPDIFOUT_GAIN0, 0, 8, 255, 0),
+ SOC_DOUBLE("Playback Switch", SPDIFOUT_CTRL0, 22, 21, 1, 1),
+ SOC_SINGLE("Playback Gain Enable Switch",
+ SPDIFOUT_CTRL1, 26, 1, 0),
+ SOC_SINGLE("Playback Channels Mix Switch",
+ SPDIFOUT_CTRL0, 23, 1, 0),
+};
+
+static int axg_spdifout_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct axg_spdifout *priv = snd_soc_component_get_drvdata(component);
+ enum snd_soc_bias_level now =
+ snd_soc_component_get_bias_level(component);
+ int ret = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (now == SND_SOC_BIAS_STANDBY)
+ ret = clk_prepare_enable(priv->mclk);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (now == SND_SOC_BIAS_PREPARE)
+ clk_disable_unprepare(priv->mclk);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ case SND_SOC_BIAS_ON:
+ break;
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_component_driver axg_spdifout_component_drv = {
+ .controls = axg_spdifout_controls,
+ .num_controls = ARRAY_SIZE(axg_spdifout_controls),
+ .dapm_widgets = axg_spdifout_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(axg_spdifout_dapm_widgets),
+ .dapm_routes = axg_spdifout_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(axg_spdifout_dapm_routes),
+ .set_bias_level = axg_spdifout_set_bias_level,
+};
+
+static const struct regmap_config axg_spdifout_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPDIFOUT_MUTE_VAL,
+};
+
+static const struct of_device_id axg_spdifout_of_match[] = {
+ { .compatible = "amlogic,axg-spdifout", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, axg_spdifout_of_match);
+
+static int axg_spdifout_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct axg_spdifout *priv;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifout_regmap_cfg);
+ if (IS_ERR(priv->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(priv->map));
+ return PTR_ERR(priv->map);
+ }
+
+ priv->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(priv->pclk)) {
+ ret = PTR_ERR(priv->pclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get pclk: %d\n", ret);
+ return ret;
+ }
+
+ priv->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(priv->mclk)) {
+ ret = PTR_ERR(priv->mclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get mclk: %d\n", ret);
+ return ret;
+ }
+
+ return devm_snd_soc_register_component(dev, &axg_spdifout_component_drv,
+ axg_spdifout_dai_drv, ARRAY_SIZE(axg_spdifout_dai_drv));
+}
+
+static struct platform_driver axg_spdifout_pdrv = {
+ .probe = axg_spdifout_probe,
+ .driver = {
+ .name = "axg-spdifout",
+ .of_match_table = axg_spdifout_of_match,
+ },
+};
+module_platform_driver(axg_spdifout_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG SPDIF Output driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
new file mode 100644
index 000000000000..43e390f9358a
--- /dev/null
+++ b/sound/soc/meson/axg-tdm-formatter.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "axg-tdm-formatter.h"
+
+struct axg_tdm_formatter {
+ struct list_head list;
+ struct axg_tdm_stream *stream;
+ const struct axg_tdm_formatter_driver *drv;
+ struct clk *pclk;
+ struct clk *sclk;
+ struct clk *lrclk;
+ struct clk *sclk_sel;
+ struct clk *lrclk_sel;
+ bool enabled;
+ struct regmap *map;
+};
+
+int axg_tdm_formatter_set_channel_masks(struct regmap *map,
+ struct axg_tdm_stream *ts,
+ unsigned int offset)
+{
+ unsigned int val, ch = ts->channels;
+ unsigned long mask;
+ int i, j;
+
+ /*
+ * Distribute the channels of the stream over the available slots
+ * of each TDM lane
+ */
+ for (i = 0; i < AXG_TDM_NUM_LANES; i++) {
+ val = 0;
+ mask = ts->mask[i];
+
+ for (j = find_first_bit(&mask, 32);
+ (j < 32) && ch;
+ j = find_next_bit(&mask, 32, j + 1)) {
+ val |= 1 << j;
+ ch -= 1;
+ }
+
+ regmap_write(map, offset, val);
+ offset += regmap_get_reg_stride(map);
+ }
+
+ /*
+ * If we still have channel left at the end of the process, it means
+ * the stream has more channels than we can accommodate and we should
+ * have caught this earlier.
+ */
+ if (WARN_ON(ch != 0)) {
+ pr_err("channel mask error\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks);
+
+static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter)
+{
+ struct axg_tdm_stream *ts = formatter->stream;
+ bool invert = formatter->drv->invert_sclk;
+ int ret;
+
+ /* Do nothing if the formatter is already enabled */
+ if (formatter->enabled)
+ return 0;
+
+ /*
+ * If sclk is inverted, invert it back and provide the inversion
+ * required by the formatter
+ */
+ invert ^= axg_tdm_sclk_invert(ts->iface->fmt);
+ ret = clk_set_phase(formatter->sclk, invert ? 180 : 0);
+ if (ret)
+ return ret;
+
+ /* Setup the stream parameter in the formatter */
+ ret = formatter->drv->ops->prepare(formatter->map, formatter->stream);
+ if (ret)
+ return ret;
+
+ /* Enable the signal clocks feeding the formatter */
+ ret = clk_prepare_enable(formatter->sclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(formatter->lrclk);
+ if (ret) {
+ clk_disable_unprepare(formatter->sclk);
+ return ret;
+ }
+
+ /* Finally, actually enable the formatter */
+ formatter->drv->ops->enable(formatter->map);
+ formatter->enabled = true;
+
+ return 0;
+}
+
+static void axg_tdm_formatter_disable(struct axg_tdm_formatter *formatter)
+{
+ /* Do nothing if the formatter is already disabled */
+ if (!formatter->enabled)
+ return;
+
+ formatter->drv->ops->disable(formatter->map);
+ clk_disable_unprepare(formatter->lrclk);
+ clk_disable_unprepare(formatter->sclk);
+ formatter->enabled = false;
+}
+
+static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
+{
+ struct axg_tdm_stream *ts = formatter->stream;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+
+ /* Catch up if the stream is already running when we attach */
+ if (ts->ready) {
+ ret = axg_tdm_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to enable formatter\n");
+ goto out;
+ }
+ }
+
+ list_add_tail(&formatter->list, &ts->formatter_list);
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+
+static void axg_tdm_formatter_dettach(struct axg_tdm_formatter *formatter)
+{
+ struct axg_tdm_stream *ts = formatter->stream;
+
+ mutex_lock(&ts->lock);
+ list_del(&formatter->list);
+ mutex_unlock(&ts->lock);
+
+ axg_tdm_formatter_disable(formatter);
+}
+
+static int axg_tdm_formatter_power_up(struct axg_tdm_formatter *formatter,
+ struct snd_soc_dapm_widget *w)
+{
+ struct axg_tdm_stream *ts = formatter->drv->ops->get_stream(w);
+ int ret;
+
+ /*
+ * If we don't get a stream at this stage, it would mean that the
+ * widget is powering up but is not attached to any backend DAI.
+ * It should not happen, ever !
+ */
+ if (WARN_ON(!ts))
+ return -ENODEV;
+
+ /* Clock our device */
+ ret = clk_prepare_enable(formatter->pclk);
+ if (ret)
+ return ret;
+
+ /* Reparent the bit clock to the TDM interface */
+ ret = clk_set_parent(formatter->sclk_sel, ts->iface->sclk);
+ if (ret)
+ goto disable_pclk;
+
+ /* Reparent the sample clock to the TDM interface */
+ ret = clk_set_parent(formatter->lrclk_sel, ts->iface->lrclk);
+ if (ret)
+ goto disable_pclk;
+
+ formatter->stream = ts;
+ ret = axg_tdm_formatter_attach(formatter);
+ if (ret)
+ goto disable_pclk;
+
+ return 0;
+
+disable_pclk:
+ clk_disable_unprepare(formatter->pclk);
+ return ret;
+}
+
+static void axg_tdm_formatter_power_down(struct axg_tdm_formatter *formatter)
+{
+ axg_tdm_formatter_dettach(formatter);
+ clk_disable_unprepare(formatter->pclk);
+ formatter->stream = NULL;
+}
+
+int axg_tdm_formatter_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 axg_tdm_formatter *formatter = snd_soc_component_get_drvdata(c);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = axg_tdm_formatter_power_up(formatter, w);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ axg_tdm_formatter_power_down(formatter);
+ break;
+
+ default:
+ dev_err(c->dev, "Unexpected event %d\n", event);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_formatter_event);
+
+int axg_tdm_formatter_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct axg_tdm_formatter_driver *drv;
+ struct axg_tdm_formatter *formatter;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ drv = of_device_get_match_data(dev);
+ if (!drv) {
+ dev_err(dev, "failed to match device\n");
+ return -ENODEV;
+ }
+
+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+ if (!formatter)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, formatter);
+ formatter->drv = drv;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ formatter->map = devm_regmap_init_mmio(dev, regs, drv->regmap_cfg);
+ if (IS_ERR(formatter->map)) {
+ dev_err(dev, "failed to init regmap: %ld\n",
+ PTR_ERR(formatter->map));
+ return PTR_ERR(formatter->map);
+ }
+
+ /* Peripharal clock */
+ formatter->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(formatter->pclk)) {
+ ret = PTR_ERR(formatter->pclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get pclk: %d\n", ret);
+ return ret;
+ }
+
+ /* Formatter bit clock */
+ formatter->sclk = devm_clk_get(dev, "sclk");
+ if (IS_ERR(formatter->sclk)) {
+ ret = PTR_ERR(formatter->sclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get sclk: %d\n", ret);
+ return ret;
+ }
+
+ /* Formatter sample clock */
+ formatter->lrclk = devm_clk_get(dev, "lrclk");
+ if (IS_ERR(formatter->lrclk)) {
+ ret = PTR_ERR(formatter->lrclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get lrclk: %d\n", ret);
+ return ret;
+ }
+
+ /* Formatter bit clock input multiplexer */
+ formatter->sclk_sel = devm_clk_get(dev, "sclk_sel");
+ if (IS_ERR(formatter->sclk_sel)) {
+ ret = PTR_ERR(formatter->sclk_sel);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get sclk_sel: %d\n", ret);
+ return ret;
+ }
+
+ /* Formatter sample clock input multiplexer */
+ formatter->lrclk_sel = devm_clk_get(dev, "lrclk_sel");
+ if (IS_ERR(formatter->lrclk_sel)) {
+ ret = PTR_ERR(formatter->lrclk_sel);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get lrclk_sel: %d\n", ret);
+ return ret;
+ }
+
+ return devm_snd_soc_register_component(dev, drv->component_drv,
+ NULL, 0);
+}
+EXPORT_SYMBOL_GPL(axg_tdm_formatter_probe);
+
+int axg_tdm_stream_start(struct axg_tdm_stream *ts)
+{
+ struct axg_tdm_formatter *formatter;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+ ts->ready = true;
+
+ /* Start all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ ret = axg_tdm_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to start tdm stream\n");
+ goto out;
+ }
+ }
+
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_start);
+
+void axg_tdm_stream_stop(struct axg_tdm_stream *ts)
+{
+ struct axg_tdm_formatter *formatter;
+
+ mutex_lock(&ts->lock);
+ ts->ready = false;
+
+ /* Stop all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ axg_tdm_formatter_disable(formatter);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_stop);
+
+struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface)
+{
+ struct axg_tdm_stream *ts;
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts) {
+ INIT_LIST_HEAD(&ts->formatter_list);
+ mutex_init(&ts->lock);
+ ts->iface = iface;
+ }
+
+ return ts;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_alloc);
+
+void axg_tdm_stream_free(struct axg_tdm_stream *ts)
+{
+ /*
+ * If the list is not empty, it would mean that one of the formatter
+ * widget is still powered and attached to the interface while we
+ * we are removing the TDM DAI. It should not be possible
+ */
+ WARN_ON(!list_empty(&ts->formatter_list));
+ mutex_destroy(&ts->lock);
+ kfree(ts);
+}
+EXPORT_SYMBOL_GPL(axg_tdm_stream_free);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm-formatter.h b/sound/soc/meson/axg-tdm-formatter.h
new file mode 100644
index 000000000000..cf947caf3cb1
--- /dev/null
+++ b/sound/soc/meson/axg-tdm-formatter.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ *
+ * Copyright (c) 2018 Baylibre SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef _MESON_AXG_TDM_FORMATTER_H
+#define _MESON_AXG_TDM_FORMATTER_H
+
+#include "axg-tdm.h"
+
+struct platform_device;
+struct regmap;
+struct snd_soc_dapm_widget;
+struct snd_kcontrol;
+
+struct axg_tdm_formatter_ops {
+ struct axg_tdm_stream *(*get_stream)(struct snd_soc_dapm_widget *w);
+ void (*enable)(struct regmap *map);
+ void (*disable)(struct regmap *map);
+ int (*prepare)(struct regmap *map, struct axg_tdm_stream *ts);
+};
+
+struct axg_tdm_formatter_driver {
+ const struct snd_soc_component_driver *component_drv;
+ const struct regmap_config *regmap_cfg;
+ const struct axg_tdm_formatter_ops *ops;
+ bool invert_sclk;
+};
+
+int axg_tdm_formatter_set_channel_masks(struct regmap *map,
+ struct axg_tdm_stream *ts,
+ unsigned int offset);
+int axg_tdm_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event);
+int axg_tdm_formatter_probe(struct platform_device *pdev);
+
+#endif /* _MESON_AXG_TDM_FORMATTER_H */
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
new file mode 100644
index 000000000000..7b8baf46d968
--- /dev/null
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm.h"
+
+enum {
+ TDM_IFACE_PAD,
+ TDM_IFACE_LOOPBACK,
+};
+
+static unsigned int axg_tdm_slots_total(u32 *mask)
+{
+ unsigned int slots = 0;
+ int i;
+
+ if (!mask)
+ return 0;
+
+ /* Count the total number of slots provided by all 4 lanes */
+ for (i = 0; i < AXG_TDM_NUM_LANES; i++)
+ slots += hweight32(mask[i]);
+
+ return slots;
+}
+
+int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
+ u32 *rx_mask, unsigned int slots,
+ unsigned int slot_width)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ struct axg_tdm_stream *tx = (struct axg_tdm_stream *)
+ dai->playback_dma_data;
+ struct axg_tdm_stream *rx = (struct axg_tdm_stream *)
+ dai->capture_dma_data;
+ unsigned int tx_slots, rx_slots;
+
+ tx_slots = axg_tdm_slots_total(tx_mask);
+ rx_slots = axg_tdm_slots_total(rx_mask);
+
+ /* We should at least have a slot for a valid interface */
+ if (!tx_slots && !rx_slots) {
+ dev_err(dai->dev, "interface has no slot\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Amend the dai driver channel number and let dpcm channel merge do
+ * its job
+ */
+ if (tx) {
+ tx->mask = tx_mask;
+ dai->driver->playback.channels_max = tx_slots;
+ }
+
+ if (rx) {
+ rx->mask = rx_mask;
+ dai->driver->capture.channels_max = rx_slots;
+ }
+
+ iface->slots = slots;
+
+ switch (slot_width) {
+ case 0:
+ /* defaults width to 32 if not provided */
+ iface->slot_width = 32;
+ break;
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ iface->slot_width = slot_width;
+ break;
+ default:
+ dev_err(dai->dev, "unsupported slot width: %d\n", slot_width);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(axg_tdm_set_tdm_slots);
+
+static int axg_tdm_iface_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ int ret = -ENOTSUPP;
+
+ if (dir == SND_SOC_CLOCK_OUT && clk_id == 0) {
+ if (!iface->mclk) {
+ dev_warn(dai->dev, "master clock not provided\n");
+ } else {
+ ret = clk_set_rate(iface->mclk, freq);
+ if (!ret)
+ iface->mclk_rate = freq;
+ }
+ }
+
+ return ret;
+}
+
+static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+
+ /* These modes are not supported */
+ if (fmt & (SND_SOC_DAIFMT_CBS_CFM | SND_SOC_DAIFMT_CBM_CFS)) {
+ dev_err(dai->dev, "only CBS_CFS and CBM_CFM are supported\n");
+ return -EINVAL;
+ }
+
+ /* If the TDM interface is the clock master, it requires mclk */
+ if (!iface->mclk && (fmt & SND_SOC_DAIFMT_CBS_CFS)) {
+ dev_err(dai->dev, "cpu clock master: mclk missing\n");
+ return -ENODEV;
+ }
+
+ iface->fmt = fmt;
+ return 0;
+}
+
+static int axg_tdm_iface_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ struct axg_tdm_stream *ts =
+ snd_soc_dai_get_dma_data(dai, substream);
+ int ret;
+
+ if (!axg_tdm_slots_total(ts->mask)) {
+ dev_err(dai->dev, "interface has not slots\n");
+ return -EINVAL;
+ }
+
+ /* Apply component wide rate symmetry */
+ if (dai->component->active) {
+ ret = snd_pcm_hw_constraint_single(substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ iface->rate);
+ if (ret < 0) {
+ dev_err(dai->dev,
+ "can't set iface rate constraint\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int axg_tdm_iface_set_stream(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ unsigned int channels = params_channels(params);
+ unsigned int width = params_width(params);
+
+ /* Save rate and sample_bits for component symmetry */
+ iface->rate = params_rate(params);
+
+ /* Make sure this interface can cope with the stream */
+ if (axg_tdm_slots_total(ts->mask) < channels) {
+ dev_err(dai->dev, "not enough slots for channels\n");
+ return -EINVAL;
+ }
+
+ if (iface->slot_width < width) {
+ dev_err(dai->dev, "incompatible slots width for stream\n");
+ return -EINVAL;
+ }
+
+ /* Save the parameter for tdmout/tdmin widgets */
+ ts->physical_width = params_physical_width(params);
+ ts->width = params_width(params);
+ ts->channels = params_channels(params);
+
+ return 0;
+}
+
+static int axg_tdm_iface_set_lrclk(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ unsigned int ratio_num;
+ int ret;
+
+ ret = clk_set_rate(iface->lrclk, params_rate(params));
+ if (ret) {
+ dev_err(dai->dev, "setting sample clock failed: %d\n", ret);
+ return ret;
+ }
+
+ switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* 50% duty cycle ratio */
+ ratio_num = 1;
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ /*
+ * A zero duty cycle ratio will result in setting the mininum
+ * ratio possible which, for this clock, is 1 cycle of the
+ * parent bclk clock high and the rest low, This is exactly
+ * what we want here.
+ */
+ ratio_num = 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = clk_set_duty_cycle(iface->lrclk, ratio_num, 2);
+ if (ret) {
+ dev_err(dai->dev,
+ "setting sample clock duty cycle failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Set sample clock inversion */
+ ret = clk_set_phase(iface->lrclk,
+ axg_tdm_lrclk_invert(iface->fmt) ? 180 : 0);
+ if (ret) {
+ dev_err(dai->dev,
+ "setting sample clock phase failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ unsigned long srate;
+ int ret;
+
+ srate = iface->slots * iface->slot_width * params_rate(params);
+
+ if (!iface->mclk_rate) {
+ /* If no specific mclk is requested, default to bit clock * 4 */
+ clk_set_rate(iface->mclk, 4 * srate);
+ } else {
+ /* Check if we can actually get the bit clock from mclk */
+ if (iface->mclk_rate % srate) {
+ dev_err(dai->dev,
+ "can't derive sclk %lu from mclk %lu\n",
+ srate, iface->mclk_rate);
+ return -EINVAL;
+ }
+ }
+
+ ret = clk_set_rate(iface->sclk, srate);
+ if (ret) {
+ dev_err(dai->dev, "setting bit clock failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Set the bit clock inversion */
+ ret = clk_set_phase(iface->sclk,
+ axg_tdm_sclk_invert(iface->fmt) ? 0 : 180);
+ if (ret) {
+ dev_err(dai->dev, "setting bit clock phase failed: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ if (iface->slots > 2) {
+ dev_err(dai->dev, "bad slot number for format: %d\n",
+ iface->slots);
+ return -EINVAL;
+ }
+ break;
+
+ case SND_SOC_DAI_FORMAT_DSP_A:
+ case SND_SOC_DAI_FORMAT_DSP_B:
+ break;
+
+ default:
+ dev_err(dai->dev, "unsupported dai format\n");
+ return -EINVAL;
+ }
+
+ ret = axg_tdm_iface_set_stream(substream, params, dai);
+ if (ret)
+ return ret;
+
+ if (iface->fmt & SND_SOC_DAIFMT_CBS_CFS) {
+ ret = axg_tdm_iface_set_sclk(dai, params);
+ if (ret)
+ return ret;
+
+ ret = axg_tdm_iface_set_lrclk(dai, params);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+
+ /* Stop all attached formatters */
+ axg_tdm_stream_stop(ts);
+
+ return 0;
+}
+
+static int axg_tdm_iface_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+
+ /* Force all attached formatters to update */
+ return axg_tdm_stream_reset(ts);
+}
+
+static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai)
+{
+ if (dai->capture_dma_data)
+ axg_tdm_stream_free(dai->capture_dma_data);
+
+ if (dai->playback_dma_data)
+ axg_tdm_stream_free(dai->playback_dma_data);
+
+ return 0;
+}
+
+static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai)
+{
+ struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
+
+ if (dai->capture_widget) {
+ dai->capture_dma_data = axg_tdm_stream_alloc(iface);
+ if (!dai->capture_dma_data)
+ return -ENOMEM;
+ }
+
+ if (dai->playback_widget) {
+ dai->playback_dma_data = axg_tdm_stream_alloc(iface);
+ if (!dai->playback_dma_data) {
+ axg_tdm_iface_remove_dai(dai);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
+ .set_sysclk = axg_tdm_iface_set_sysclk,
+ .set_fmt = axg_tdm_iface_set_fmt,
+ .startup = axg_tdm_iface_startup,
+ .hw_params = axg_tdm_iface_hw_params,
+ .prepare = axg_tdm_iface_prepare,
+ .hw_free = axg_tdm_iface_hw_free,
+};
+
+/* TDM Backend DAIs */
+static const struct snd_soc_dai_driver axg_tdm_iface_dai_drv[] = {
+ [TDM_IFACE_PAD] = {
+ .name = "TDM Pad",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = AXG_TDM_CHANNEL_MAX,
+ .rates = AXG_TDM_RATES,
+ .formats = AXG_TDM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = AXG_TDM_CHANNEL_MAX,
+ .rates = AXG_TDM_RATES,
+ .formats = AXG_TDM_FORMATS,
+ },
+ .id = TDM_IFACE_PAD,
+ .ops = &axg_tdm_iface_ops,
+ .probe = axg_tdm_iface_probe_dai,
+ .remove = axg_tdm_iface_remove_dai,
+ },
+ [TDM_IFACE_LOOPBACK] = {
+ .name = "TDM Loopback",
+ .capture = {
+ .stream_name = "Loopback",
+ .channels_min = 1,
+ .channels_max = AXG_TDM_CHANNEL_MAX,
+ .rates = AXG_TDM_RATES,
+ .formats = AXG_TDM_FORMATS,
+ },
+ .id = TDM_IFACE_LOOPBACK,
+ .ops = &axg_tdm_iface_ops,
+ .probe = axg_tdm_iface_probe_dai,
+ .remove = axg_tdm_iface_remove_dai,
+ },
+};
+
+static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct axg_tdm_iface *iface = snd_soc_component_get_drvdata(component);
+ enum snd_soc_bias_level now =
+ snd_soc_component_get_bias_level(component);
+ int ret = 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (now == SND_SOC_BIAS_STANDBY)
+ ret = clk_prepare_enable(iface->mclk);
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (now == SND_SOC_BIAS_PREPARE)
+ clk_disable_unprepare(iface->mclk);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ case SND_SOC_BIAS_ON:
+ break;
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_component_driver axg_tdm_iface_component_drv = {
+ .set_bias_level = axg_tdm_iface_set_bias_level,
+};
+
+static const struct of_device_id axg_tdm_iface_of_match[] = {
+ { .compatible = "amlogic,axg-tdm-iface", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, axg_tdm_iface_of_match);
+
+static int axg_tdm_iface_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct snd_soc_dai_driver *dai_drv;
+ struct axg_tdm_iface *iface;
+ int ret, i;
+
+ iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL);
+ if (!iface)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, iface);
+
+ /*
+ * Duplicate dai driver: depending on the slot masks configuration
+ * We'll change the number of channel provided by DAI stream, so dpcm
+ * channel merge can be done properly
+ */
+ dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv),
+ sizeof(*dai_drv), GFP_KERNEL);
+ if (!dai_drv)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++)
+ memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i],
+ sizeof(*dai_drv));
+
+ /* Bit clock provided on the pad */
+ iface->sclk = devm_clk_get(dev, "sclk");
+ if (IS_ERR(iface->sclk)) {
+ ret = PTR_ERR(iface->sclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get sclk: %d\n", ret);
+ return ret;
+ }
+
+ /* Sample clock provided on the pad */
+ iface->lrclk = devm_clk_get(dev, "lrclk");
+ if (IS_ERR(iface->lrclk)) {
+ ret = PTR_ERR(iface->lrclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get lrclk: %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * mclk maybe be missing when the cpu dai is in slave mode and
+ * the codec does not require it to provide a master clock.
+ * At this point, ignore the error if mclk is missing. We'll
+ * throw an error if the cpu dai is master and mclk is missing
+ */
+ iface->mclk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(iface->mclk)) {
+ ret = PTR_ERR(iface->mclk);
+ if (ret == -ENOENT) {
+ iface->mclk = NULL;
+ } else {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get mclk: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return devm_snd_soc_register_component(dev,
+ &axg_tdm_iface_component_drv, dai_drv,
+ ARRAY_SIZE(axg_tdm_iface_dai_drv));
+}
+
+static struct platform_driver axg_tdm_iface_pdrv = {
+ .probe = axg_tdm_iface_probe,
+ .driver = {
+ .name = "axg-tdm-iface",
+ .of_match_table = axg_tdm_iface_of_match,
+ },
+};
+module_platform_driver(axg_tdm_iface_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM interface driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdm.h b/sound/soc/meson/axg-tdm.h
new file mode 100644
index 000000000000..e578b6f40a07
--- /dev/null
+++ b/sound/soc/meson/axg-tdm.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
+ *
+ * Copyright (c) 2018 Baylibre SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef _MESON_AXG_TDM_H
+#define _MESON_AXG_TDM_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#define AXG_TDM_NUM_LANES 4
+#define AXG_TDM_CHANNEL_MAX 128
+#define AXG_TDM_RATES (SNDRV_PCM_RATE_5512 | \
+ SNDRV_PCM_RATE_8000_192000)
+#define AXG_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct axg_tdm_iface {
+ struct clk *sclk;
+ struct clk *lrclk;
+ struct clk *mclk;
+ unsigned long mclk_rate;
+
+ /* format is common to all the DAIs of the iface */
+ unsigned int fmt;
+ unsigned int slots;
+ unsigned int slot_width;
+
+ /* For component wide symmetry */
+ int rate;
+};
+
+static inline bool axg_tdm_lrclk_invert(unsigned int fmt)
+{
+ return (fmt & SND_SOC_DAIFMT_I2S) ^
+ !!(fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_NB_IF));
+}
+
+static inline bool axg_tdm_sclk_invert(unsigned int fmt)
+{
+ return fmt & (SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_IB_NF);
+}
+
+struct axg_tdm_stream {
+ struct axg_tdm_iface *iface;
+ struct list_head formatter_list;
+ struct mutex lock;
+ unsigned int channels;
+ unsigned int width;
+ unsigned int physical_width;
+ u32 *mask;
+ bool ready;
+};
+
+struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
+void axg_tdm_stream_free(struct axg_tdm_stream *ts);
+int axg_tdm_stream_start(struct axg_tdm_stream *ts);
+void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
+
+static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
+{
+ axg_tdm_stream_stop(ts);
+ return axg_tdm_stream_start(ts);
+}
+
+int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask,
+ u32 *rx_mask, unsigned int slots,
+ unsigned int slot_width);
+
+#endif /* _MESON_AXG_TDM_H */
diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c
new file mode 100644
index 000000000000..bbac44c81688
--- /dev/null
+++ b/sound/soc/meson/axg-tdmin.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm-formatter.h"
+
+#define TDMIN_CTRL 0x00
+#define TDMIN_CTRL_ENABLE BIT(31)
+#define TDMIN_CTRL_I2S_MODE BIT(30)
+#define TDMIN_CTRL_RST_OUT BIT(29)
+#define TDMIN_CTRL_RST_IN BIT(28)
+#define TDMIN_CTRL_WS_INV BIT(25)
+#define TDMIN_CTRL_SEL_SHIFT 20
+#define TDMIN_CTRL_IN_BIT_SKEW_MASK GENMASK(18, 16)
+#define TDMIN_CTRL_IN_BIT_SKEW(x) ((x) << 16)
+#define TDMIN_CTRL_LSB_FIRST BIT(5)
+#define TDMIN_CTRL_BITNUM_MASK GENMASK(4, 0)
+#define TDMIN_CTRL_BITNUM(x) ((x) << 0)
+#define TDMIN_SWAP 0x04
+#define TDMIN_MASK0 0x08
+#define TDMIN_MASK1 0x0c
+#define TDMIN_MASK2 0x10
+#define TDMIN_MASK3 0x14
+#define TDMIN_STAT 0x18
+#define TDMIN_MUTE_VAL 0x1c
+#define TDMIN_MUTE0 0x20
+#define TDMIN_MUTE1 0x24
+#define TDMIN_MUTE2 0x28
+#define TDMIN_MUTE3 0x2c
+
+static const struct regmap_config axg_tdmin_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = TDMIN_MUTE3,
+};
+
+static const char * const axg_tdmin_sel_texts[] = {
+ "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 5",
+};
+
+/* Change to special mux control to reset dapm */
+static SOC_ENUM_SINGLE_DECL(axg_tdmin_sel_enum, TDMIN_CTRL,
+ TDMIN_CTRL_SEL_SHIFT, axg_tdmin_sel_texts);
+
+static const struct snd_kcontrol_new axg_tdmin_in_mux =
+ SOC_DAPM_ENUM("Input Source", axg_tdmin_sel_enum);
+
+static struct snd_soc_dai *
+axg_tdmin_get_be(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p = NULL;
+ struct snd_soc_dai *be;
+
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
+ if (!p->connect)
+ continue;
+
+ if (p->source->id == snd_soc_dapm_dai_out)
+ return (struct snd_soc_dai *)p->source->priv;
+
+ be = axg_tdmin_get_be(p->source);
+ if (be)
+ return be;
+ }
+
+ return NULL;
+}
+
+static struct axg_tdm_stream *
+axg_tdmin_get_tdm_stream(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dai *be = axg_tdmin_get_be(w);
+
+ if (!be)
+ return NULL;
+
+ return be->capture_dma_data;
+}
+
+static void axg_tdmin_enable(struct regmap *map)
+{
+ /* Apply both reset */
+ regmap_update_bits(map, TDMIN_CTRL,
+ TDMIN_CTRL_RST_OUT | TDMIN_CTRL_RST_IN, 0);
+
+ /* Clear out reset before in reset */
+ regmap_update_bits(map, TDMIN_CTRL,
+ TDMIN_CTRL_RST_OUT, TDMIN_CTRL_RST_OUT);
+ regmap_update_bits(map, TDMIN_CTRL,
+ TDMIN_CTRL_RST_IN, TDMIN_CTRL_RST_IN);
+
+ /* Actually enable tdmin */
+ regmap_update_bits(map, TDMIN_CTRL,
+ TDMIN_CTRL_ENABLE, TDMIN_CTRL_ENABLE);
+}
+
+static void axg_tdmin_disable(struct regmap *map)
+{
+ regmap_update_bits(map, TDMIN_CTRL, TDMIN_CTRL_ENABLE, 0);
+}
+
+static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts)
+{
+ unsigned int val = 0;
+
+ /* Set stream skew */
+ switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_DSP_A:
+ val |= TDMIN_CTRL_IN_BIT_SKEW(3);
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_DSP_B:
+ val = TDMIN_CTRL_IN_BIT_SKEW(2);
+ break;
+
+ default:
+ pr_err("Unsupported format: %u\n",
+ ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ /* Set stream format mode */
+ switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ val |= TDMIN_CTRL_I2S_MODE;
+ break;
+ }
+
+ /* If the sample clock is inverted, invert it back for the formatter */
+ if (axg_tdm_lrclk_invert(ts->iface->fmt))
+ val |= TDMIN_CTRL_WS_INV;
+
+ /* Set the slot width */
+ val |= TDMIN_CTRL_BITNUM(ts->iface->slot_width - 1);
+
+ /*
+ * The following also reset LSB_FIRST which result in the formatter
+ * placing the first bit received at bit 31
+ */
+ regmap_update_bits(map, TDMIN_CTRL,
+ (TDMIN_CTRL_IN_BIT_SKEW_MASK | TDMIN_CTRL_WS_INV |
+ TDMIN_CTRL_I2S_MODE | TDMIN_CTRL_LSB_FIRST |
+ TDMIN_CTRL_BITNUM_MASK), val);
+
+ /* Set static swap mask configuration */
+ regmap_write(map, TDMIN_SWAP, 0x76543210);
+
+ return axg_tdm_formatter_set_channel_masks(map, ts, TDMIN_MASK0);
+}
+
+static const struct snd_soc_dapm_widget axg_tdmin_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 5", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmin_in_mux),
+ SND_SOC_DAPM_PGA_E("DEC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ axg_tdm_formatter_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
+ SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_tdmin_dapm_routes[] = {
+ { "SRC SEL", "IN 0", "IN 0" },
+ { "SRC SEL", "IN 1", "IN 1" },
+ { "SRC SEL", "IN 2", "IN 2" },
+ { "SRC SEL", "IN 3", "IN 3" },
+ { "SRC SEL", "IN 4", "IN 4" },
+ { "SRC SEL", "IN 5", "IN 5" },
+ { "DEC", NULL, "SRC SEL" },
+ { "OUT", NULL, "DEC" },
+};
+
+static const struct snd_soc_component_driver axg_tdmin_component_drv = {
+ .dapm_widgets = axg_tdmin_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(axg_tdmin_dapm_widgets),
+ .dapm_routes = axg_tdmin_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(axg_tdmin_dapm_routes),
+};
+
+static const struct axg_tdm_formatter_ops axg_tdmin_ops = {
+ .get_stream = axg_tdmin_get_tdm_stream,
+ .prepare = axg_tdmin_prepare,
+ .enable = axg_tdmin_enable,
+ .disable = axg_tdmin_disable,
+};
+
+static const struct axg_tdm_formatter_driver axg_tdmin_drv = {
+ .component_drv = &axg_tdmin_component_drv,
+ .regmap_cfg = &axg_tdmin_regmap_cfg,
+ .ops = &axg_tdmin_ops,
+ .invert_sclk = false,
+};
+
+static const struct of_device_id axg_tdmin_of_match[] = {
+ {
+ .compatible = "amlogic,axg-tdmin",
+ .data = &axg_tdmin_drv,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_tdmin_of_match);
+
+static struct platform_driver axg_tdmin_pdrv = {
+ .probe = axg_tdm_formatter_probe,
+ .driver = {
+ .name = "axg-tdmin",
+ .of_match_table = axg_tdmin_of_match,
+ },
+};
+module_platform_driver(axg_tdmin_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM input formatter driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c
new file mode 100644
index 000000000000..f73368ee1088
--- /dev/null
+++ b/sound/soc/meson/axg-tdmout.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-tdm-formatter.h"
+
+#define TDMOUT_CTRL0 0x00
+#define TDMOUT_CTRL0_BITNUM_MASK GENMASK(4, 0)
+#define TDMOUT_CTRL0_BITNUM(x) ((x) << 0)
+#define TDMOUT_CTRL0_SLOTNUM_MASK GENMASK(9, 5)
+#define TDMOUT_CTRL0_SLOTNUM(x) ((x) << 5)
+#define TDMOUT_CTRL0_INIT_BITNUM_MASK GENMASK(19, 15)
+#define TDMOUT_CTRL0_INIT_BITNUM(x) ((x) << 15)
+#define TDMOUT_CTRL0_ENABLE BIT(31)
+#define TDMOUT_CTRL0_RST_OUT BIT(29)
+#define TDMOUT_CTRL0_RST_IN BIT(28)
+#define TDMOUT_CTRL1 0x04
+#define TDMOUT_CTRL1_TYPE_MASK GENMASK(6, 4)
+#define TDMOUT_CTRL1_TYPE(x) ((x) << 4)
+#define TDMOUT_CTRL1_MSB_POS_MASK GENMASK(12, 8)
+#define TDMOUT_CTRL1_MSB_POS(x) ((x) << 8)
+#define TDMOUT_CTRL1_SEL_SHIFT 24
+#define TDMOUT_CTRL1_GAIN_EN 26
+#define TDMOUT_CTRL1_WS_INV BIT(28)
+#define TDMOUT_SWAP 0x08
+#define TDMOUT_MASK0 0x0c
+#define TDMOUT_MASK1 0x10
+#define TDMOUT_MASK2 0x14
+#define TDMOUT_MASK3 0x18
+#define TDMOUT_STAT 0x1c
+#define TDMOUT_GAIN0 0x20
+#define TDMOUT_GAIN1 0x24
+#define TDMOUT_MUTE_VAL 0x28
+#define TDMOUT_MUTE0 0x2c
+#define TDMOUT_MUTE1 0x30
+#define TDMOUT_MUTE2 0x34
+#define TDMOUT_MUTE3 0x38
+#define TDMOUT_MASK_VAL 0x3c
+
+static const struct regmap_config axg_tdmout_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = TDMOUT_MASK_VAL,
+};
+
+static const struct snd_kcontrol_new axg_tdmout_controls[] = {
+ SOC_DOUBLE("Lane 0 Volume", TDMOUT_GAIN0, 0, 8, 255, 0),
+ SOC_DOUBLE("Lane 1 Volume", TDMOUT_GAIN0, 16, 24, 255, 0),
+ SOC_DOUBLE("Lane 2 Volume", TDMOUT_GAIN1, 0, 8, 255, 0),
+ SOC_DOUBLE("Lane 3 Volume", TDMOUT_GAIN1, 16, 24, 255, 0),
+ SOC_SINGLE("Gain Enable Switch", TDMOUT_CTRL1,
+ TDMOUT_CTRL1_GAIN_EN, 1, 0),
+};
+
+static const char * const tdmout_sel_texts[] = {
+ "IN 0", "IN 1", "IN 2",
+};
+
+static SOC_ENUM_SINGLE_DECL(axg_tdmout_sel_enum, TDMOUT_CTRL1,
+ TDMOUT_CTRL1_SEL_SHIFT, tdmout_sel_texts);
+
+static const struct snd_kcontrol_new axg_tdmout_in_mux =
+ SOC_DAPM_ENUM("Input Source", axg_tdmout_sel_enum);
+
+static struct snd_soc_dai *
+axg_tdmout_get_be(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p = NULL;
+ struct snd_soc_dai *be;
+
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ if (!p->connect)
+ continue;
+
+ if (p->sink->id == snd_soc_dapm_dai_in)
+ return (struct snd_soc_dai *)p->sink->priv;
+
+ be = axg_tdmout_get_be(p->sink);
+ if (be)
+ return be;
+ }
+
+ return NULL;
+}
+
+static struct axg_tdm_stream *
+axg_tdmout_get_tdm_stream(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dai *be = axg_tdmout_get_be(w);
+
+ if (!be)
+ return NULL;
+
+ return be->playback_dma_data;
+}
+
+static void axg_tdmout_enable(struct regmap *map)
+{
+ /* Apply both reset */
+ regmap_update_bits(map, TDMOUT_CTRL0,
+ TDMOUT_CTRL0_RST_OUT | TDMOUT_CTRL0_RST_IN, 0);
+
+ /* Clear out reset before in reset */
+ regmap_update_bits(map, TDMOUT_CTRL0,
+ TDMOUT_CTRL0_RST_OUT, TDMOUT_CTRL0_RST_OUT);
+ regmap_update_bits(map, TDMOUT_CTRL0,
+ TDMOUT_CTRL0_RST_IN, TDMOUT_CTRL0_RST_IN);
+
+ /* Actually enable tdmout */
+ regmap_update_bits(map, TDMOUT_CTRL0,
+ TDMOUT_CTRL0_ENABLE, TDMOUT_CTRL0_ENABLE);
+}
+
+static void axg_tdmout_disable(struct regmap *map)
+{
+ regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0);
+}
+
+static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts)
+{
+ unsigned int val = 0;
+
+ /* Set the stream skew */
+ switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_DSP_A:
+ val |= TDMOUT_CTRL0_INIT_BITNUM(1);
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_DSP_B:
+ val |= TDMOUT_CTRL0_INIT_BITNUM(2);
+ break;
+
+ default:
+ pr_err("Unsupported format: %u\n",
+ ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ /* Set the slot width */
+ val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1);
+
+ /* Set the slot number */
+ val |= TDMOUT_CTRL0_SLOTNUM(ts->iface->slots - 1);
+
+ regmap_update_bits(map, TDMOUT_CTRL0,
+ TDMOUT_CTRL0_INIT_BITNUM_MASK |
+ TDMOUT_CTRL0_BITNUM_MASK |
+ TDMOUT_CTRL0_SLOTNUM_MASK, val);
+
+ /* Set the sample width */
+ val = TDMOUT_CTRL1_MSB_POS(ts->width - 1);
+
+ /* FIFO data are arranged in chunks of 64bits */
+ switch (ts->physical_width) {
+ case 8:
+ /* 8 samples of 8 bits */
+ val |= TDMOUT_CTRL1_TYPE(0);
+ break;
+ case 16:
+ /* 4 samples of 16 bits - right justified */
+ val |= TDMOUT_CTRL1_TYPE(2);
+ break;
+ case 32:
+ /* 2 samples of 32 bits - right justified */
+ val |= TDMOUT_CTRL1_TYPE(4);
+ break;
+ default:
+ pr_err("Unsupported physical width: %u\n",
+ ts->physical_width);
+ return -EINVAL;
+ }
+
+ /* If the sample clock is inverted, invert it back for the formatter */
+ if (axg_tdm_lrclk_invert(ts->iface->fmt))
+ val |= TDMOUT_CTRL1_WS_INV;
+
+ regmap_update_bits(map, TDMOUT_CTRL1,
+ (TDMOUT_CTRL1_TYPE_MASK | TDMOUT_CTRL1_MSB_POS_MASK |
+ TDMOUT_CTRL1_WS_INV), val);
+
+ /* Set static swap mask configuration */
+ regmap_write(map, TDMOUT_SWAP, 0x76543210);
+
+ return axg_tdm_formatter_set_channel_masks(map, ts, TDMOUT_MASK0);
+}
+
+static const struct snd_soc_dapm_widget axg_tdmout_dapm_widgets[] = {
+ SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_tdmout_in_mux),
+ SND_SOC_DAPM_PGA_E("ENC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ axg_tdm_formatter_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
+ SND_SOC_DAPM_AIF_OUT("OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_tdmout_dapm_routes[] = {
+ { "SRC SEL", "IN 0", "IN 0" },
+ { "SRC SEL", "IN 1", "IN 1" },
+ { "SRC SEL", "IN 2", "IN 2" },
+ { "ENC", NULL, "SRC SEL" },
+ { "OUT", NULL, "ENC" },
+};
+
+static const struct snd_soc_component_driver axg_tdmout_component_drv = {
+ .controls = axg_tdmout_controls,
+ .num_controls = ARRAY_SIZE(axg_tdmout_controls),
+ .dapm_widgets = axg_tdmout_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(axg_tdmout_dapm_widgets),
+ .dapm_routes = axg_tdmout_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(axg_tdmout_dapm_routes),
+};
+
+static const struct axg_tdm_formatter_ops axg_tdmout_ops = {
+ .get_stream = axg_tdmout_get_tdm_stream,
+ .prepare = axg_tdmout_prepare,
+ .enable = axg_tdmout_enable,
+ .disable = axg_tdmout_disable,
+};
+
+static const struct axg_tdm_formatter_driver axg_tdmout_drv = {
+ .component_drv = &axg_tdmout_component_drv,
+ .regmap_cfg = &axg_tdmout_regmap_cfg,
+ .ops = &axg_tdmout_ops,
+ .invert_sclk = true,
+};
+
+static const struct of_device_id axg_tdmout_of_match[] = {
+ {
+ .compatible = "amlogic,axg-tdmout",
+ .data = &axg_tdmout_drv,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_tdmout_of_match);
+
+static struct platform_driver axg_tdmout_pdrv = {
+ .probe = axg_tdm_formatter_probe,
+ .driver = {
+ .name = "axg-tdmout",
+ .of_match_table = axg_tdmout_of_match,
+ },
+};
+module_platform_driver(axg_tdmout_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG TDM output formatter driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c
new file mode 100644
index 000000000000..c2c9bb312586
--- /dev/null
+++ b/sound/soc/meson/axg-toddr.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2018 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+/* This driver implements the frontend capture DAI of AXG based SoCs */
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "axg-fifo.h"
+
+#define CTRL0_TODDR_SEL_RESAMPLE BIT(30)
+#define CTRL0_TODDR_EXT_SIGNED BIT(29)
+#define CTRL0_TODDR_PP_MODE BIT(28)
+#define CTRL0_TODDR_TYPE_MASK GENMASK(15, 13)
+#define CTRL0_TODDR_TYPE(x) ((x) << 13)
+#define CTRL0_TODDR_MSB_POS_MASK GENMASK(12, 8)
+#define CTRL0_TODDR_MSB_POS(x) ((x) << 8)
+#define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3)
+#define CTRL0_TODDR_LSB_POS(x) ((x) << 3)
+
+static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *dai)
+{
+ return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+ unsigned int type, width, msb = 31;
+
+ /*
+ * NOTE:
+ * Almost all backend will place the MSB at bit 31, except SPDIF Input
+ * which will put it at index 28. When adding support for the SPDIF
+ * Input, we'll need to find which type of backend we are connected to.
+ */
+
+ switch (params_physical_width(params)) {
+ case 8:
+ type = 0; /* 8 samples of 8 bits */
+ break;
+ case 16:
+ type = 2; /* 4 samples of 16 bits - right justified */
+ break;
+ case 32:
+ type = 4; /* 2 samples of 32 bits - right justified */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ width = params_width(params);
+
+ regmap_update_bits(fifo->map, FIFO_CTRL0,
+ CTRL0_TODDR_TYPE_MASK |
+ CTRL0_TODDR_MSB_POS_MASK |
+ CTRL0_TODDR_LSB_POS_MASK,
+ CTRL0_TODDR_TYPE(type) |
+ CTRL0_TODDR_MSB_POS(msb) |
+ CTRL0_TODDR_LSB_POS(msb - (width - 1)));
+
+ return 0;
+}
+
+static int axg_toddr_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+ unsigned int fifo_threshold;
+ int ret;
+
+ /* Enable pclk to access registers and clock the fifo ip */
+ ret = clk_prepare_enable(fifo->pclk);
+ if (ret)
+ return ret;
+
+ /* Select orginal data - resampling not supported ATM */
+ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_SEL_RESAMPLE, 0);
+
+ /* Only signed format are supported ATM */
+ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_EXT_SIGNED,
+ CTRL0_TODDR_EXT_SIGNED);
+
+ /* Apply single buffer mode to the interface */
+ regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_TODDR_PP_MODE, 0);
+
+ /* TODDR does not have a configurable fifo depth */
+ fifo_threshold = AXG_FIFO_MIN_CNT - 1;
+ regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_THRESHOLD_MASK,
+ CTRL1_THRESHOLD(fifo_threshold));
+
+ return 0;
+}
+
+static void axg_toddr_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
+
+ clk_disable_unprepare(fifo->pclk);
+}
+
+static const struct snd_soc_dai_ops axg_toddr_ops = {
+ .hw_params = axg_toddr_dai_hw_params,
+ .startup = axg_toddr_dai_startup,
+ .shutdown = axg_toddr_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver axg_toddr_dai_drv = {
+ .name = "TODDR",
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = AXG_FIFO_CH_MAX,
+ .rates = AXG_FIFO_RATES,
+ .formats = AXG_FIFO_FORMATS,
+ },
+ .ops = &axg_toddr_ops,
+ .pcm_new = axg_toddr_pcm_new,
+};
+
+static const char * const axg_toddr_sel_texts[] = {
+ "IN 0", "IN 1", "IN 2", "IN 3", "IN 4", "IN 6"
+};
+
+static const unsigned int axg_toddr_sel_values[] = {
+ 0, 1, 2, 3, 4, 6
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(axg_toddr_sel_enum, FIFO_CTRL0,
+ CTRL0_SEL_SHIFT, CTRL0_SEL_MASK,
+ axg_toddr_sel_texts, axg_toddr_sel_values);
+
+static const struct snd_kcontrol_new axg_toddr_in_mux =
+ SOC_DAPM_ENUM("Input Source", axg_toddr_sel_enum);
+
+static const struct snd_soc_dapm_widget axg_toddr_dapm_widgets[] = {
+ SND_SOC_DAPM_MUX("SRC SEL", SND_SOC_NOPM, 0, 0, &axg_toddr_in_mux),
+ SND_SOC_DAPM_AIF_IN("IN 0", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 1", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 2", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 3", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 4", NULL, 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("IN 6", NULL, 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route axg_toddr_dapm_routes[] = {
+ { "Capture", NULL, "SRC SEL" },
+ { "SRC SEL", "IN 0", "IN 0" },
+ { "SRC SEL", "IN 1", "IN 1" },
+ { "SRC SEL", "IN 2", "IN 2" },
+ { "SRC SEL", "IN 3", "IN 3" },
+ { "SRC SEL", "IN 4", "IN 4" },
+ { "SRC SEL", "IN 6", "IN 6" },
+};
+
+static const struct snd_soc_component_driver axg_toddr_component_drv = {
+ .dapm_widgets = axg_toddr_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets),
+ .dapm_routes = axg_toddr_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes),
+ .ops = &axg_fifo_pcm_ops
+};
+
+static const struct axg_fifo_match_data axg_toddr_match_data = {
+ .component_drv = &axg_toddr_component_drv,
+ .dai_drv = &axg_toddr_dai_drv
+};
+
+static const struct of_device_id axg_toddr_of_match[] = {
+ {
+ .compatible = "amlogic,axg-toddr",
+ .data = &axg_toddr_match_data,
+ }, {}
+};
+MODULE_DEVICE_TABLE(of, axg_toddr_of_match);
+
+static struct platform_driver axg_toddr_pdrv = {
+ .probe = axg_fifo_probe,
+ .driver = {
+ .name = "axg-toddr",
+ .of_match_table = axg_toddr_of_match,
+ },
+};
+module_platform_driver(axg_toddr_pdrv);
+
+MODULE_DESCRIPTION("Amlogic AXG capture fifo driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index 15ccbf479c96..d5ae9eb8c756 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -40,7 +40,7 @@ struct abe_twl6040 {
int mclk_freq; /* MCLK frequency speed for twl6040 */
};
-struct platform_device *dmic_codec_dev;
+static struct platform_device *dmic_codec_dev;
static int omap_abe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 51dd7c65096b..fe966272bd0c 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -213,8 +213,10 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
switch (channels) {
case 6:
dmic->ch_enabled |= OMAP_DMIC_UP3_ENABLE;
+ /* fall through */
case 4:
dmic->ch_enabled |= OMAP_DMIC_UP2_ENABLE;
+ /* fall through */
case 2:
dmic->ch_enabled |= OMAP_DMIC_UP1_ENABLE;
break;
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 0e97360f9890..4c1be36c2207 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -310,15 +310,19 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
/* up to 3 channels for capture */
return -EINVAL;
link_mask |= 1 << 4;
+ /* fall through */
case 4:
if (stream == SNDRV_PCM_STREAM_CAPTURE)
/* up to 3 channels for capture */
return -EINVAL;
link_mask |= 1 << 3;
+ /* fall through */
case 3:
link_mask |= 1 << 2;
+ /* fall through */
case 2:
link_mask |= 1 << 1;
+ /* fall through */
case 1:
link_mask |= 1 << 0;
break;
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 960744e46edc..776e148b0aa2 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -24,15 +24,19 @@ config SND_PXA2XX_AC97
config SND_PXA2XX_SOC_AC97
tristate
select AC97_BUS
+ select SND_PXA2XX_LIB
select SND_PXA2XX_LIB_AC97
select SND_SOC_AC97_BUS
config SND_PXA2XX_SOC_I2S
+ select SND_PXA2XX_LIB
tristate
config SND_PXA_SOC_SSP
- tristate
+ tristate "Soc Audio via PXA2xx/PXA3xx SSP ports"
+ depends on PLAT_PXA
select PXA_SSP
+ select SND_PXA2XX_LIB
config SND_MMP_SOC_SSPA
tristate
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c
index 2fc012b06c43..935a248e5bf6 100644
--- a/sound/soc/pxa/magician.c
+++ b/sound/soc/pxa/magician.c
@@ -90,95 +90,9 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int acps, acds, width;
- unsigned int div4 = PXA_SSP_CLK_SCDB_4;
+ unsigned int width;
int ret = 0;
- width = snd_pcm_format_physical_width(params_format(params));
-
- /*
- * rate = SSPSCLK / (2 * width(16 or 32))
- * SSPSCLK = (ACPS / ACDS) / SSPSCLKDIV(div4 or div1)
- */
- switch (params_rate(params)) {
- case 8000:
- /* off by a factor of 2: bug in the PXA27x audio clock? */
- acps = 32842000;
- switch (width) {
- case 16:
- /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_16;
- break;
- default: /* 32 */
- /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_8;
- }
- break;
- case 11025:
- acps = 5622000;
- switch (width) {
- case 16:
- /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_4;
- break;
- default: /* 32 */
- /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_2;
- }
- break;
- case 22050:
- acps = 5622000;
- switch (width) {
- case 16:
- /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_2;
- break;
- default: /* 32 */
- /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_1;
- }
- break;
- case 44100:
- acps = 5622000;
- switch (width) {
- case 16:
- /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_2;
- break;
- default: /* 32 */
- /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_1;
- }
- break;
- case 48000:
- acps = 12235000;
- switch (width) {
- case 16:
- /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_2;
- break;
- default: /* 32 */
- /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_1;
- }
- break;
- case 96000:
- default:
- acps = 12235000;
- switch (width) {
- case 16:
- /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_1;
- break;
- default: /* 32 */
- /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */
- acds = PXA_SSP_CLK_AUDIO_DIV_2;
- div4 = PXA_SSP_CLK_SCDB_1;
- break;
- }
- break;
- }
-
/* set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
@@ -191,6 +105,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
+ width = snd_pcm_format_physical_width(params_format(params));
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width);
if (ret < 0)
return ret;
@@ -201,23 +116,6 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
return ret;
- /* set the SSP audio system clock ACDS divider */
- ret = snd_soc_dai_set_clkdiv(cpu_dai,
- PXA_SSP_AUDIO_DIV_ACDS, acds);
- if (ret < 0)
- return ret;
-
- /* set the SSP audio system clock SCDB divider4 */
- ret = snd_soc_dai_set_clkdiv(cpu_dai,
- PXA_SSP_AUDIO_DIV_SCDB, div4);
- if (ret < 0)
- return ret;
-
- /* set SSP audio pll clock */
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps);
- if (ret < 0)
- return ret;
-
return 0;
}
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 6fc986080130..69033e1a84e6 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -34,7 +34,6 @@
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>
-#include "../../arm/pxa2xx-pcm.h"
#include "pxa-ssp.h"
/*
@@ -42,6 +41,8 @@
*/
struct ssp_priv {
struct ssp_device *ssp;
+ struct clk *extclk;
+ unsigned long ssp_clk;
unsigned int sysclk;
unsigned int dai_fmt;
unsigned int configured_dai_fmt;
@@ -105,9 +106,8 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
if (!dma)
return -ENOMEM;
-
- dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- &ssp->drcmr_tx : &ssp->drcmr_rx;
+ dma->chan_name = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "tx" : "rx";
snd_soc_dai_set_dma_data(cpu_dai, substream, dma);
@@ -194,21 +194,6 @@ static void pxa_ssp_set_scr(struct ssp_device *ssp, u32 div)
pxa_ssp_write_reg(ssp, SSCR0, sscr0);
}
-/**
- * pxa_ssp_get_clkdiv - get SSP clock divider
- */
-static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
-{
- u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
- u32 div;
-
- if (ssp->type == PXA25x_SSP)
- div = ((sscr0 >> 8) & 0xff) * 2 + 2;
- else
- div = ((sscr0 >> 8) & 0xfff) + 1;
- return div;
-}
-
/*
* Set the SSP ports SYSCLK.
*/
@@ -221,6 +206,21 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+ if (priv->extclk) {
+ int ret;
+
+ /*
+ * For DT based boards, if an extclk is given, use it
+ * here and configure PXA_SSP_CLK_EXT.
+ */
+
+ ret = clk_set_rate(priv->extclk, freq);
+ if (ret < 0)
+ return ret;
+
+ clk_id = PXA_SSP_CLK_EXT;
+ }
+
dev_dbg(&ssp->pdev->dev,
"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
cpu_dai->id, clk_id, freq);
@@ -265,66 +265,17 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
}
/*
- * Set the SSP clock dividers.
- */
-static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
- int div_id, int div)
-{
- struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
- struct ssp_device *ssp = priv->ssp;
- int val;
-
- switch (div_id) {
- case PXA_SSP_AUDIO_DIV_ACDS:
- val = (pxa_ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div);
- pxa_ssp_write_reg(ssp, SSACD, val);
- break;
- case PXA_SSP_AUDIO_DIV_SCDB:
- val = pxa_ssp_read_reg(ssp, SSACD);
- val &= ~SSACD_SCDB;
- if (ssp->type == PXA3xx_SSP)
- val &= ~SSACD_SCDX8;
- switch (div) {
- case PXA_SSP_CLK_SCDB_1:
- val |= SSACD_SCDB;
- break;
- case PXA_SSP_CLK_SCDB_4:
- break;
- case PXA_SSP_CLK_SCDB_8:
- if (ssp->type == PXA3xx_SSP)
- val |= SSACD_SCDX8;
- else
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- pxa_ssp_write_reg(ssp, SSACD, val);
- break;
- case PXA_SSP_DIV_SCR:
- pxa_ssp_set_scr(ssp, div);
- break;
- default:
- return -ENODEV;
- }
-
- return 0;
-}
-
-/*
* Configure the PLL frequency pxa27x and (afaik - pxa320 only)
*/
-static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
- int source, unsigned int freq_in, unsigned int freq_out)
+static int pxa_ssp_set_pll(struct ssp_priv *priv, unsigned int freq)
{
- struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
if (ssp->type == PXA3xx_SSP)
pxa_ssp_write_reg(ssp, SSACDD, 0);
- switch (freq_out) {
+ switch (freq) {
case 5622000:
break;
case 11345000:
@@ -355,7 +306,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
u64 tmp = 19968;
tmp *= 1000000;
- do_div(tmp, freq_out);
+ do_div(tmp, freq);
val = tmp;
val = (val << 16) | 64;
@@ -365,7 +316,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
dev_dbg(&ssp->pdev->dev,
"Using SSACDD %x to supply %uHz\n",
- val, freq_out);
+ val, freq);
break;
}
@@ -535,6 +486,7 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
case SND_SOC_DAIFMT_DSP_A:
sspsp |= SSPSP_FSRT;
+ /* fall through */
case SND_SOC_DAIFMT_DSP_B:
sscr0 |= SSCR0_MOD | SSCR0_PSP;
sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
@@ -570,6 +522,24 @@ static int pxa_ssp_configure_dai_fmt(struct ssp_priv *priv)
return 0;
}
+struct pxa_ssp_clock_mode {
+ int rate;
+ int pll;
+ u8 acds;
+ u8 scdb;
+};
+
+static const struct pxa_ssp_clock_mode pxa_ssp_clock_modes[] = {
+ { .rate = 8000, .pll = 32842000, .acds = SSACD_ACDS_32, .scdb = SSACD_SCDB_4X },
+ { .rate = 11025, .pll = 5622000, .acds = SSACD_ACDS_4, .scdb = SSACD_SCDB_4X },
+ { .rate = 16000, .pll = 32842000, .acds = SSACD_ACDS_16, .scdb = SSACD_SCDB_4X },
+ { .rate = 22050, .pll = 5622000, .acds = SSACD_ACDS_2, .scdb = SSACD_SCDB_4X },
+ { .rate = 44100, .pll = 11345000, .acds = SSACD_ACDS_2, .scdb = SSACD_SCDB_4X },
+ { .rate = 48000, .pll = 12235000, .acds = SSACD_ACDS_2, .scdb = SSACD_SCDB_4X },
+ { .rate = 96000, .pll = 12235000, .acds = SSACD_ACDS_4, .scdb = SSACD_SCDB_1X },
+ {}
+};
+
/*
* Set the SSP audio DMA parameters and sample size.
* Can be called multiple times by oss emulation.
@@ -581,11 +551,12 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
int chn = params_channels(params);
- u32 sscr0;
- u32 sspsp;
+ u32 sscr0, sspsp;
int width = snd_pcm_format_physical_width(params_format(params));
int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
struct snd_dmaengine_dai_dma_data *dma_data;
+ int rate = params_rate(params);
+ int bclk = rate * chn * (width / 8);
int ret;
dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -625,11 +596,57 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
}
pxa_ssp_write_reg(ssp, SSCR0, sscr0);
+ if (sscr0 & SSCR0_ACS) {
+ ret = pxa_ssp_set_pll(priv, bclk);
+
+ /*
+ * If we were able to generate the bclk directly,
+ * all is fine. Otherwise, look up the closest rate
+ * from the table and also set the dividers.
+ */
+
+ if (ret < 0) {
+ const struct pxa_ssp_clock_mode *m;
+ int ssacd, acds;
+
+ for (m = pxa_ssp_clock_modes; m->rate; m++) {
+ if (m->rate == rate)
+ break;
+ }
+
+ if (!m->rate)
+ return -EINVAL;
+
+ acds = m->acds;
+
+ /* The values in the table are for 16 bits */
+ if (width == 32)
+ acds--;
+
+ ret = pxa_ssp_set_pll(priv, bclk);
+ if (ret < 0)
+ return ret;
+
+ ssacd = pxa_ssp_read_reg(ssp, SSACD);
+ ssacd &= ~(SSACD_ACDS(7) | SSACD_SCDB_1X);
+ ssacd |= SSACD_ACDS(m->acds);
+ ssacd |= m->scdb;
+ pxa_ssp_write_reg(ssp, SSACD, ssacd);
+ }
+ } else if (sscr0 & SSCR0_ECS) {
+ /*
+ * For setups with external clocking, the PLL and its diviers
+ * are not active. Instead, the SCR bits in SSCR0 can be used
+ * to divide the clock.
+ */
+ pxa_ssp_set_scr(ssp, bclk / rate);
+ }
+
switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
sspsp = pxa_ssp_read_reg(ssp, SSPSP);
- if ((pxa_ssp_get_scr(ssp) == 4) && (width == 16)) {
+ if (((priv->sysclk / bclk) == 64) && (width == 16)) {
/* This is a special case where the bitclk is 64fs
* and we're not dealing with 2*32 bits of audio
* samples.
@@ -773,6 +790,15 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai)
ret = -ENODEV;
goto err_priv;
}
+
+ priv->extclk = devm_clk_get(dev, "extclk");
+ if (IS_ERR(priv->extclk)) {
+ ret = PTR_ERR(priv->extclk);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ priv->extclk = NULL;
+ }
} else {
priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
if (priv->ssp == NULL) {
@@ -814,8 +840,6 @@ static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
.trigger = pxa_ssp_trigger,
.hw_params = pxa_ssp_hw_params,
.set_sysclk = pxa_ssp_set_dai_sysclk,
- .set_clkdiv = pxa_ssp_set_dai_clkdiv,
- .set_pll = pxa_ssp_set_dai_pll,
.set_fmt = pxa_ssp_set_dai_fmt,
.set_tdm_slot = pxa_ssp_set_dai_tdm_slot,
.set_tristate = pxa_ssp_set_dai_tristate,
@@ -843,6 +867,9 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
static const struct snd_soc_component_driver pxa_ssp_component = {
.name = "pxa-ssp",
+ .ops = &pxa2xx_pcm_ops,
+ .pcm_new = pxa2xx_soc_pcm_new,
+ .pcm_free = pxa2xx_pcm_free_dma_buffers,
};
#ifdef CONFIG_OF
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 803818aabee9..9f779657bc86 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -68,61 +68,39 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.reset = pxa2xx_ac97_cold_reset,
};
-static struct pxad_param pxa2xx_ac97_pcm_stereo_in_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 11,
-};
-
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
.addr = __PREG(PCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .chan_name = "pcm_pcm_stereo_in",
.maxburst = 32,
- .filter_data = &pxa2xx_ac97_pcm_stereo_in_req,
-};
-
-static struct pxad_param pxa2xx_ac97_pcm_stereo_out_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 12,
};
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
.addr = __PREG(PCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .chan_name = "pcm_pcm_stereo_out",
.maxburst = 32,
- .filter_data = &pxa2xx_ac97_pcm_stereo_out_req,
};
-static struct pxad_param pxa2xx_ac97_pcm_aux_mono_out_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 10,
-};
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
.addr = __PREG(MODR),
.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
+ .chan_name = "pcm_aux_mono_out",
.maxburst = 16,
- .filter_data = &pxa2xx_ac97_pcm_aux_mono_out_req,
};
-static struct pxad_param pxa2xx_ac97_pcm_aux_mono_in_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 9,
-};
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
.addr = __PREG(MODR),
.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
+ .chan_name = "pcm_aux_mono_in",
.maxburst = 16,
- .filter_data = &pxa2xx_ac97_pcm_aux_mono_in_req,
};
-static struct pxad_param pxa2xx_ac97_pcm_aux_mic_mono_req = {
- .prio = PXAD_PRIO_LOWEST,
- .drcmr = 8,
-};
static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
.addr = __PREG(MCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
+ .chan_name = "pcm_aux_mic_mono",
.maxburst = 16,
- .filter_data = &pxa2xx_ac97_pcm_aux_mic_mono_req,
};
static int pxa2xx_ac97_hifi_startup(struct snd_pcm_substream *substream,
@@ -236,7 +214,21 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
static const struct snd_soc_component_driver pxa_ac97_component = {
.name = "pxa-ac97",
+ .ops = &pxa2xx_pcm_ops,
+ .pcm_new = pxa2xx_soc_pcm_new,
+ .pcm_free = pxa2xx_pcm_free_dma_buffers,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pxa2xx_ac97_dt_ids[] = {
+ { .compatible = "marvell,pxa250-ac97", },
+ { .compatible = "marvell,pxa270-ac97", },
+ { .compatible = "marvell,pxa300-ac97", },
+ { }
};
+MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids);
+
+#endif
static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
{
@@ -296,6 +288,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
#ifdef CONFIG_PM_SLEEP
.pm = &pxa2xx_ac97_pm_ops,
#endif
+ .of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids),
},
};
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 3fb60baf6eab..42820121e5b9 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -82,20 +82,18 @@ static struct pxa_i2s_port pxa_i2s;
static struct clk *clk_i2s;
static int clk_ena = 0;
-static unsigned long pxa2xx_i2s_pcm_stereo_out_req = 3;
static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
.addr = __PREG(SADR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .chan_name = "tx",
.maxburst = 32,
- .filter_data = &pxa2xx_i2s_pcm_stereo_out_req,
};
-static unsigned long pxa2xx_i2s_pcm_stereo_in_req = 2;
static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
.addr = __PREG(SADR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .chan_name = "rx",
.maxburst = 32,
- .filter_data = &pxa2xx_i2s_pcm_stereo_in_req,
};
static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
@@ -366,6 +364,9 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
static const struct snd_soc_component_driver pxa_i2s_component = {
.name = "pxa-i2s",
+ .ops = &pxa2xx_pcm_ops,
+ .pcm_new = pxa2xx_soc_pcm_new,
+ .pcm_free = pxa2xx_pcm_free_dma_buffers,
};
static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c
index 8b6a70e94c01..72eaaef1b426 100644
--- a/sound/soc/pxa/pxa2xx-pcm.c
+++ b/sound/soc/pxa/pxa2xx-pcm.c
@@ -20,70 +20,6 @@
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>
-#include "../../arm/pxa2xx-pcm.h"
-
-static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_dmaengine_dai_dma_data *dma;
-
- dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
- /* return if this is a bufferless transfer e.g.
- * codec <--> BT codec or GSM modem -- lg FIXME */
- if (!dma)
- return 0;
-
- return __pxa2xx_pcm_hw_params(substream, params);
-}
-
-static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
-{
- __pxa2xx_pcm_hw_free(substream);
-
- return 0;
-}
-
-static const struct snd_pcm_ops pxa2xx_pcm_ops = {
- .open = __pxa2xx_pcm_open,
- .close = __pxa2xx_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = pxa2xx_pcm_hw_params,
- .hw_free = pxa2xx_pcm_hw_free,
- .prepare = __pxa2xx_pcm_prepare,
- .trigger = pxa2xx_pcm_trigger,
- .pointer = pxa2xx_pcm_pointer,
- .mmap = pxa2xx_pcm_mmap,
-};
-
-static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_card *card = rtd->card->snd_card;
- struct snd_pcm *pcm = rtd->pcm;
- int ret;
-
- ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
- ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (ret)
- goto out;
- }
-
- if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
- ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
- SNDRV_PCM_STREAM_CAPTURE);
- if (ret)
- goto out;
- }
- out:
- return ret;
-}
-
static const struct snd_soc_component_driver pxa2xx_soc_platform = {
.ops = &pxa2xx_pcm_ops,
.pcm_new = pxa2xx_soc_pcm_new,
@@ -96,18 +32,9 @@ static int pxa2xx_soc_platform_probe(struct platform_device *pdev)
NULL, 0);
}
-#ifdef CONFIG_OF
-static const struct of_device_id snd_soc_pxa_audio_match[] = {
- { .compatible = "mrvl,pxa-pcm-audio" },
- { }
-};
-MODULE_DEVICE_TABLE(of, snd_soc_pxa_audio_match);
-#endif
-
static struct platform_driver pxa_pcm_driver = {
.driver = {
.name = "pxa-pcm-audio",
- .of_match_table = of_match_ptr(snd_soc_pxa_audio_match),
},
.probe = pxa2xx_soc_platform_probe,
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c
index ba468e560dd2..230eee450f45 100644
--- a/sound/soc/pxa/zylonite.c
+++ b/sound/soc/pxa/zylonite.c
@@ -83,11 +83,9 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- unsigned int pll_out = 0;
unsigned int wm9713_div = 0;
int ret = 0;
int rate = params_rate(params);
- int width = snd_pcm_format_physical_width(params_format(params));
/* Only support ratios that we can generate neatly from the AC97
* based master clock - in particular, this excludes 44.1kHz.
@@ -109,17 +107,10 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- /* Add 1 to the width for the leading clock cycle */
- pll_out = rate * (width + 1) * 8;
-
ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
if (ret < 0)
return ret;
- ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out);
- if (ret < 0)
- return ret;
-
if (clk_pout)
ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
WM9713_PCMDIV(wm9713_div));
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 87838fa27997..2a4c912d1e48 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -41,6 +41,9 @@ config SND_SOC_APQ8016_SBC
APQ8016 SOC-based systems.
Say Y if you want to use audio devices on MI2S.
+config SND_SOC_QCOM_COMMON
+ tristate
+
config SND_SOC_QDSP6_COMMON
tristate
@@ -86,7 +89,18 @@ config SND_SOC_MSM8996
tristate "SoC Machine driver for MSM8996 and APQ8096 boards"
depends on QCOM_APR
select SND_SOC_QDSP6
+ select SND_SOC_QCOM_COMMON
help
Support for Qualcomm Technologies LPASS audio block in
APQ8096 SoC-based systems.
Say Y if you want to use audio device on this SoCs
+
+config SND_SOC_SDM845
+ tristate "SoC Machine driver for SDM845 boards"
+ depends on QCOM_APR
+ select SND_SOC_QDSP6
+ select SND_SOC_QCOM_COMMON
+ help
+ To add support for audio on Qualcomm Technologies Inc.
+ SDM845 SoC-based systems.
+ Say Y if you want to use audio device on this SoCs.
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 206945bb9ba1..41b2c7a23a4d 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -14,10 +14,14 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
snd-soc-storm-objs := storm.o
snd-soc-apq8016-sbc-objs := apq8016_sbc.o
snd-soc-apq8096-objs := apq8096.o
+snd-soc-sdm845-objs := sdm845.o
+snd-soc-qcom-common-objs := common.o
obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
+obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
+obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
#DSP lib
obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 561cd429e6f2..1543e85629f8 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -1,14 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018, Linaro Limited
-#include <linux/soc/qcom/apr.h>
#include <linux/module.h>
-#include <linux/component.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include "common.h"
static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
@@ -24,211 +23,57 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
-static int apq8096_sbc_parse_of(struct snd_soc_card *card)
+static void apq8096_add_be_ops(struct snd_soc_card *card)
{
- struct device_node *np;
- struct device_node *codec = NULL;
- struct device_node *platform = NULL;
- struct device_node *cpu = NULL;
- struct device *dev = card->dev;
- struct snd_soc_dai_link *link;
- int ret, num_links;
-
- ret = snd_soc_of_parse_card_name(card, "qcom,model");
- if (ret) {
- dev_err(dev, "Error parsing card name: %d\n", ret);
- return ret;
- }
-
- /* DAPM routes */
- if (of_property_read_bool(dev->of_node, "qcom,audio-routing")) {
- ret = snd_soc_of_parse_audio_routing(card,
- "qcom,audio-routing");
- if (ret)
- return ret;
- }
-
- /* Populate links */
- num_links = of_get_child_count(dev->of_node);
+ struct snd_soc_dai_link *link = card->dai_link;
+ int i, num_links = card->num_links;
- /* Allocate the DAI link array */
- card->dai_link = kcalloc(num_links, sizeof(*link), GFP_KERNEL);
- if (!card->dai_link)
- return -ENOMEM;
-
- card->num_links = num_links;
- link = card->dai_link;
-
- for_each_child_of_node(dev->of_node, np) {
- cpu = of_get_child_by_name(np, "cpu");
- if (!cpu) {
- dev_err(dev, "Can't find cpu DT node\n");
- ret = -EINVAL;
- goto err;
- }
-
- link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
- if (!link->cpu_of_node) {
- dev_err(card->dev, "error getting cpu phandle\n");
- ret = -EINVAL;
- goto err;
- }
-
- ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
- if (ret) {
- dev_err(card->dev, "error getting cpu dai name\n");
- goto err;
- }
-
- platform = of_get_child_by_name(np, "platform");
- codec = of_get_child_by_name(np, "codec");
- if (codec && platform) {
- link->platform_of_node = of_parse_phandle(platform,
- "sound-dai",
- 0);
- if (!link->platform_of_node) {
- dev_err(card->dev, "platform dai not found\n");
- ret = -EINVAL;
- goto err;
- }
-
- ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
- if (ret < 0) {
- dev_err(card->dev, "codec dai not found\n");
- goto err;
- }
- link->no_pcm = 1;
- link->ignore_pmdown_time = 1;
+ for (i = 0; i < num_links; i++) {
+ if (link->no_pcm == 1)
link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
- } else {
- link->platform_of_node = link->cpu_of_node;
- link->codec_dai_name = "snd-soc-dummy-dai";
- link->codec_name = "snd-soc-dummy";
- link->dynamic = 1;
- }
-
- link->ignore_suspend = 1;
- ret = of_property_read_string(np, "link-name", &link->name);
- if (ret) {
- dev_err(card->dev, "error getting codec dai_link name\n");
- goto err;
- }
-
- link->dpcm_playback = 1;
- link->dpcm_capture = 1;
- link->stream_name = link->name;
link++;
}
-
- return 0;
-err:
- of_node_put(cpu);
- of_node_put(codec);
- of_node_put(platform);
- kfree(card->dai_link);
- return ret;
}
-static int apq8096_bind(struct device *dev)
+static int apq8096_platform_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
+ struct device *dev = &pdev->dev;
int ret;
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
- component_bind_all(dev, card);
card->dev = dev;
- ret = apq8096_sbc_parse_of(card);
+ dev_set_drvdata(dev, card);
+ ret = qcom_snd_parse_of(card);
if (ret) {
dev_err(dev, "Error parsing OF data\n");
goto err;
}
+ apq8096_add_be_ops(card);
ret = snd_soc_register_card(card);
if (ret)
- goto err;
+ goto err_card_register;
return 0;
+err_card_register:
+ kfree(card->dai_link);
err:
- component_unbind_all(dev, card);
kfree(card);
return ret;
}
-static void apq8096_unbind(struct device *dev)
+static int apq8096_platform_remove(struct platform_device *pdev)
{
- struct snd_soc_card *card = dev_get_drvdata(dev);
+ struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_card(card);
- component_unbind_all(dev, card);
kfree(card->dai_link);
kfree(card);
-}
-
-static const struct component_master_ops apq8096_ops = {
- .bind = apq8096_bind,
- .unbind = apq8096_unbind,
-};
-
-static int apq8016_compare_of(struct device *dev, void *data)
-{
- return dev->of_node == data;
-}
-
-static void apq8016_release_of(struct device *dev, void *data)
-{
- of_node_put(data);
-}
-
-static int add_audio_components(struct device *dev,
- struct component_match **matchptr)
-{
- struct device_node *np, *platform, *cpu, *node, *dai_node;
-
- node = dev->of_node;
-
- for_each_child_of_node(node, np) {
- cpu = of_get_child_by_name(np, "cpu");
- if (cpu) {
- dai_node = of_parse_phandle(cpu, "sound-dai", 0);
- of_node_get(dai_node);
- component_match_add_release(dev, matchptr,
- apq8016_release_of,
- apq8016_compare_of,
- dai_node);
- }
-
- platform = of_get_child_by_name(np, "platform");
- if (platform) {
- dai_node = of_parse_phandle(platform, "sound-dai", 0);
- component_match_add_release(dev, matchptr,
- apq8016_release_of,
- apq8016_compare_of,
- dai_node);
- }
- }
-
- return 0;
-}
-
-static int apq8096_platform_probe(struct platform_device *pdev)
-{
- struct component_match *match = NULL;
- int ret;
-
- ret = add_audio_components(&pdev->dev, &match);
- if (ret)
- return ret;
-
- return component_master_add_with_match(&pdev->dev, &apq8096_ops, match);
-}
-
-static int apq8096_platform_remove(struct platform_device *pdev)
-{
- component_master_del(&pdev->dev, &apq8096_ops);
return 0;
}
@@ -245,7 +90,6 @@ static struct platform_driver msm_snd_apq8096_driver = {
.remove = apq8096_platform_remove,
.driver = {
.name = "msm-snd-apq8096",
- .owner = THIS_MODULE,
.of_match_table = msm_snd_apq8096_dt_match,
},
};
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
new file mode 100644
index 000000000000..eb1b9da05dd4
--- /dev/null
+++ b/sound/soc/qcom/common.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Linaro Limited.
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#include <linux/module.h>
+#include "common.h"
+
+int qcom_snd_parse_of(struct snd_soc_card *card)
+{
+ struct device_node *np;
+ struct device_node *codec = NULL;
+ struct device_node *platform = NULL;
+ struct device_node *cpu = NULL;
+ struct device *dev = card->dev;
+ struct snd_soc_dai_link *link;
+ int ret, num_links;
+
+ ret = snd_soc_of_parse_card_name(card, "model");
+ if (ret) {
+ dev_err(dev, "Error parsing card name: %d\n", ret);
+ return ret;
+ }
+
+ /* DAPM routes */
+ if (of_property_read_bool(dev->of_node, "audio-routing")) {
+ ret = snd_soc_of_parse_audio_routing(card,
+ "audio-routing");
+ if (ret)
+ return ret;
+ }
+
+ /* Populate links */
+ num_links = of_get_child_count(dev->of_node);
+
+ /* Allocate the DAI link array */
+ card->dai_link = kcalloc(num_links, sizeof(*link), GFP_KERNEL);
+ if (!card->dai_link)
+ return -ENOMEM;
+
+ card->num_links = num_links;
+ link = card->dai_link;
+ for_each_child_of_node(dev->of_node, np) {
+ cpu = of_get_child_by_name(np, "cpu");
+ if (!cpu) {
+ dev_err(dev, "Can't find cpu DT node\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+ if (!link->cpu_of_node) {
+ dev_err(card->dev, "error getting cpu phandle\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
+ if (ret) {
+ dev_err(card->dev, "error getting cpu dai name\n");
+ goto err;
+ }
+
+ platform = of_get_child_by_name(np, "platform");
+ codec = of_get_child_by_name(np, "codec");
+ if (codec && platform) {
+ link->platform_of_node = of_parse_phandle(platform,
+ "sound-dai",
+ 0);
+ if (!link->platform_of_node) {
+ dev_err(card->dev, "platform dai not found\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
+ if (ret < 0) {
+ dev_err(card->dev, "codec dai not found\n");
+ goto err;
+ }
+ link->no_pcm = 1;
+ link->ignore_pmdown_time = 1;
+ } else {
+ link->platform_of_node = link->cpu_of_node;
+ link->codec_dai_name = "snd-soc-dummy-dai";
+ link->codec_name = "snd-soc-dummy";
+ link->dynamic = 1;
+ }
+
+ link->ignore_suspend = 1;
+ ret = of_property_read_string(np, "link-name", &link->name);
+ if (ret) {
+ dev_err(card->dev, "error getting codec dai_link name\n");
+ goto err;
+ }
+
+ link->dpcm_playback = 1;
+ link->dpcm_capture = 1;
+ link->stream_name = link->name;
+ link++;
+ }
+
+ return 0;
+err:
+ of_node_put(cpu);
+ of_node_put(codec);
+ of_node_put(platform);
+ kfree(card->dai_link);
+ return ret;
+}
+EXPORT_SYMBOL(qcom_snd_parse_of);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
new file mode 100644
index 000000000000..f05c05b12bd7
--- /dev/null
+++ b/sound/soc/qcom/common.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+#ifndef __QCOM_SND_COMMON_H__
+#define __QCOM_SND_COMMON_H__
+
+#include <sound/soc.h>
+
+int qcom_snd_parse_of(struct snd_soc_card *card);
+
+#endif
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 31fe78aa207f..d07271ea4c45 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -458,7 +458,7 @@ static irqreturn_t lpass_dma_interrupt_handler(
return IRQ_NONE;
}
dev_warn(soc_runtime->dev, "xrun warning\n");
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stop_xrun(substream);
ret = IRQ_HANDLED;
}
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
index 9983c665a941..932c3ebfd252 100644
--- a/sound/soc/qcom/qdsp6/q6adm.c
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -64,7 +64,6 @@ struct q6adm {
struct aprv2_ibasic_rsp_result_t result;
struct mutex lock;
wait_queue_head_t matrix_map_wait;
- struct platform_device *pdev_routing;
};
struct q6adm_cmd_device_open_v5 {
@@ -588,7 +587,6 @@ EXPORT_SYMBOL_GPL(q6adm_close);
static int q6adm_probe(struct apr_device *adev)
{
struct device *dev = &adev->dev;
- struct device_node *dais_np;
struct q6adm *adm;
adm = devm_kzalloc(&adev->dev, sizeof(*adm), GFP_KERNEL);
@@ -605,22 +603,12 @@ static int q6adm_probe(struct apr_device *adev)
INIT_LIST_HEAD(&adm->copps_list);
spin_lock_init(&adm->copps_list_lock);
- dais_np = of_get_child_by_name(dev->of_node, "routing");
- if (dais_np) {
- adm->pdev_routing = of_platform_device_create(dais_np,
- "q6routing", dev);
- of_node_put(dais_np);
- }
-
- return 0;
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
static int q6adm_remove(struct apr_device *adev)
{
- struct q6adm *adm = dev_get_drvdata(&adev->dev);
-
- if (adm->pdev_routing)
- of_platform_device_destroy(&adm->pdev_routing->dev, NULL);
+ of_platform_depopulate(&adev->dev);
return 0;
}
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 5002dd05bf27..60ff4a2d3577 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -4,7 +4,6 @@
#include <linux/err.h>
#include <linux/init.h>
-#include <linux/component.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
@@ -81,7 +80,6 @@ static int q6slim_hw_params(struct snd_pcm_substream *substream,
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct q6afe_slim_cfg *slim = &dai_data->port_config[dai->id].slim;
- slim->num_channels = params_channels(params);
slim->sample_rate = params_rate(params);
switch (params_format(params)) {
@@ -315,6 +313,9 @@ static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
int rc;
+ if (!dai_data->is_port_started[dai->id])
+ return;
+
rc = q6afe_port_stop(dai_data->port[dai->id]);
if (rc < 0)
dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
@@ -382,23 +383,31 @@ static int q6slim_set_channel_map(struct snd_soc_dai *dai,
struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
int i;
- if (!rx_slot) {
- pr_err("%s: rx slot not found\n", __func__);
- return -EINVAL;
- }
+ if (dai->id & 0x1) {
+ /* TX */
+ if (!tx_slot) {
+ pr_err("%s: tx slot not found\n", __func__);
+ return -EINVAL;
+ }
- for (i = 0; i < rx_num; i++) {
- pcfg->slim.ch_mapping[i] = rx_slot[i];
- pr_debug("%s: find number of channels[%d] ch[%d]\n",
- __func__, i, rx_slot[i]);
- }
+ for (i = 0; i < tx_num; i++)
+ pcfg->slim.ch_mapping[i] = tx_slot[i];
+
+ pcfg->slim.num_channels = tx_num;
+
+
+ } else {
+ if (!rx_slot) {
+ pr_err("%s: rx slot not found\n", __func__);
+ return -EINVAL;
+ }
- pcfg->slim.num_channels = rx_num;
+ for (i = 0; i < rx_num; i++)
+ pcfg->slim.ch_mapping[i] = rx_slot[i];
- pr_debug("%s: SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
- (dai->id - SLIMBUS_0_RX) / 2, rx_num,
- pcfg->slim.ch_mapping[0],
- pcfg->slim.ch_mapping[1]);
+ pcfg->slim.num_channels = rx_num;
+
+ }
return 0;
}
@@ -443,6 +452,14 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"},
{"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"},
+ {"SLIMBUS_0_TX", NULL, "Slimbus Capture"},
+ {"SLIMBUS_1_TX", NULL, "Slimbus1 Capture"},
+ {"SLIMBUS_2_TX", NULL, "Slimbus2 Capture"},
+ {"SLIMBUS_3_TX", NULL, "Slimbus3 Capture"},
+ {"SLIMBUS_4_TX", NULL, "Slimbus4 Capture"},
+ {"SLIMBUS_5_TX", NULL, "Slimbus5 Capture"},
+ {"SLIMBUS_6_TX", NULL, "Slimbus6 Capture"},
+
{"Primary MI2S Playback", NULL, "PRI_MI2S_RX"},
{"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"},
{"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
@@ -637,6 +654,24 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.rate_max = 192000,
},
}, {
+ .name = "SLIMBUS_0_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_0_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ }, {
.playback = {
.stream_name = "Slimbus1 Playback",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
@@ -655,6 +690,24 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
}, {
+ .name = "SLIMBUS_1_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_1_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus1 Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
+ }, {
.playback = {
.stream_name = "Slimbus2 Playback",
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -672,6 +725,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.id = SLIMBUS_2_RX,
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
+
+ }, {
+ .name = "SLIMBUS_2_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_2_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus2 Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
}, {
.playback = {
.stream_name = "Slimbus3 Playback",
@@ -690,6 +762,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.id = SLIMBUS_3_RX,
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
+
+ }, {
+ .name = "SLIMBUS_3_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_3_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus3 Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
}, {
.playback = {
.stream_name = "Slimbus4 Playback",
@@ -708,6 +799,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.id = SLIMBUS_4_RX,
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
+
+ }, {
+ .name = "SLIMBUS_4_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_4_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus4 Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
}, {
.playback = {
.stream_name = "Slimbus5 Playback",
@@ -726,6 +836,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.id = SLIMBUS_5_RX,
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
+
+ }, {
+ .name = "SLIMBUS_5_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_5_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus5 Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
}, {
.playback = {
.stream_name = "Slimbus6 Playback",
@@ -744,6 +873,25 @@ static struct snd_soc_dai_driver q6afe_dais[] = {
.id = SLIMBUS_6_RX,
.probe = msm_dai_q6_dai_probe,
.remove = msm_dai_q6_dai_remove,
+
+ }, {
+ .name = "SLIMBUS_6_TX",
+ .ops = &q6slim_ops,
+ .id = SLIMBUS_6_TX,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ .capture = {
+ .stream_name = "Slimbus6 Capture",
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 1,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ },
}, {
.playback = {
.stream_name = "Primary MI2S Playback",
@@ -972,6 +1120,13 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_RX", "Slimbus6 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_0_TX", "Slimbus Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_2_TX", "Slimbus2 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_4_TX", "Slimbus4 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_5_TX", "Slimbus5 Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_6_TX", "Slimbus6 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback",
0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture",
@@ -1180,7 +1335,7 @@ static void of_q6afe_parse_dai_data(struct device *dev,
int id, i, num_lines;
ret = of_property_read_u32(node, "reg", &id);
- if (ret || id > AFE_PORT_MAX) {
+ if (ret || id < 0 || id >= AFE_PORT_MAX) {
dev_err(dev, "valid dai id not found:%d\n", ret);
continue;
}
@@ -1249,11 +1404,12 @@ static void of_q6afe_parse_dai_data(struct device *dev,
}
}
-static int q6afe_dai_bind(struct device *dev, struct device *master, void *data)
+static int q6afe_dai_dev_probe(struct platform_device *pdev)
{
struct q6afe_dai_data *dai_data;
+ struct device *dev = &pdev->dev;
- dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL);
+ dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL);
if (!dai_data)
return -ENOMEM;
@@ -1261,41 +1417,22 @@ static int q6afe_dai_bind(struct device *dev, struct device *master, void *data)
of_q6afe_parse_dai_data(dev, dai_data);
- return snd_soc_register_component(dev, &q6afe_dai_component,
+ return devm_snd_soc_register_component(dev, &q6afe_dai_component,
q6afe_dais, ARRAY_SIZE(q6afe_dais));
}
-static void q6afe_dai_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct q6afe_dai_data *dai_data = dev_get_drvdata(dev);
-
- snd_soc_unregister_component(dev);
- kfree(dai_data);
-}
-
-static const struct component_ops q6afe_dai_comp_ops = {
- .bind = q6afe_dai_bind,
- .unbind = q6afe_dai_unbind,
+static const struct of_device_id q6afe_dai_device_id[] = {
+ { .compatible = "qcom,q6afe-dais" },
+ {},
};
-
-static int q6afe_dai_dev_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &q6afe_dai_comp_ops);
-}
-
-static int q6afe_dai_dev_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &q6afe_dai_comp_ops);
- return 0;
-}
+MODULE_DEVICE_TABLE(of, q6afe_dai_device_id);
static struct platform_driver q6afe_dai_platform_driver = {
.driver = {
.name = "q6afe-dai",
+ .of_match_table = of_match_ptr(q6afe_dai_device_id),
},
.probe = q6afe_dai_dev_probe,
- .remove = q6afe_dai_dev_remove,
};
module_platform_driver(q6afe_dai_platform_driver);
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 01f43218984b..000775b4bba8 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -316,7 +316,6 @@ struct q6afe {
struct mutex lock;
struct list_head port_list;
spinlock_t port_list_lock;
- struct platform_device *pdev_dais;
};
struct afe_port_cmd_device_start {
@@ -515,6 +514,20 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
SLIMBUS_5_RX, 1, 1},
[SLIMBUS_6_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX,
SLIMBUS_6_RX, 1, 1},
+ [SLIMBUS_0_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX,
+ SLIMBUS_0_TX, 0, 1},
+ [SLIMBUS_1_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX,
+ SLIMBUS_1_TX, 0, 1},
+ [SLIMBUS_2_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX,
+ SLIMBUS_2_TX, 0, 1},
+ [SLIMBUS_3_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX,
+ SLIMBUS_3_TX, 0, 1},
+ [SLIMBUS_4_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX,
+ SLIMBUS_4_TX, 0, 1},
+ [SLIMBUS_5_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX,
+ SLIMBUS_5_TX, 0, 1},
+ [SLIMBUS_6_TX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX,
+ SLIMBUS_6_TX, 0, 1},
[PRIMARY_MI2S_RX] = { AFE_PORT_ID_PRIMARY_MI2S_RX,
PRIMARY_MI2S_RX, 1, 1},
[PRIMARY_MI2S_TX] = { AFE_PORT_ID_PRIMARY_MI2S_TX,
@@ -777,7 +790,7 @@ static int q6afe_callback(struct apr_device *adev, struct apr_resp_pkt *data)
*/
int q6afe_get_port_id(int index)
{
- if (index < 0 || index > AFE_PORT_MAX)
+ if (index < 0 || index >= AFE_PORT_MAX)
return -EINVAL;
return port_maps[index].port_id;
@@ -1014,7 +1027,7 @@ int q6afe_port_stop(struct q6afe_port *port)
port_id = port->id;
index = port->token;
- if (index < 0 || index > AFE_PORT_MAX) {
+ if (index < 0 || index >= AFE_PORT_MAX) {
dev_err(afe->dev, "AFE port index[%d] invalid!\n", index);
return -EINVAL;
}
@@ -1355,7 +1368,7 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
unsigned long flags;
int cfg_type;
- if (id < 0 || id > AFE_PORT_MAX) {
+ if (id < 0 || id >= AFE_PORT_MAX) {
dev_err(dev, "AFE port token[%d] invalid!\n", id);
return ERR_PTR(-EINVAL);
}
@@ -1373,6 +1386,13 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
case AFE_PORT_ID_MULTICHAN_HDMI_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
break;
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX:
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX:
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX:
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX:
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX:
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX:
+ case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX:
case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX:
case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX:
case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX:
@@ -1438,7 +1458,6 @@ static int q6afe_probe(struct apr_device *adev)
{
struct q6afe *afe;
struct device *dev = &adev->dev;
- struct device_node *dais_np;
afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
if (!afe)
@@ -1453,22 +1472,12 @@ static int q6afe_probe(struct apr_device *adev)
dev_set_drvdata(dev, afe);
- dais_np = of_get_child_by_name(dev->of_node, "dais");
- if (dais_np) {
- afe->pdev_dais = of_platform_device_create(dais_np,
- "q6afe-dai", dev);
- of_node_put(dais_np);
- }
-
- return 0;
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
static int q6afe_remove(struct apr_device *adev)
{
- struct q6afe *afe = dev_get_drvdata(&adev->dev);
-
- if (afe->pdev_dais)
- of_platform_device_destroy(&afe->pdev_dais->dev, NULL);
+ of_platform_depopulate(&adev->dev);
return 0;
}
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 349c6a883c63..9db9a2944ef2 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/component.h>
#include <sound/soc.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -390,7 +389,9 @@ static int q6asm_dai_close(struct snd_pcm_substream *substream)
struct q6asm_dai_rtd *prtd = runtime->private_data;
if (prtd->audio_client) {
- q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+ if (prtd->state)
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+
q6asm_unmap_memory_regions(substream->stream,
prtd->audio_client);
q6asm_audio_client_free(prtd->audio_client);
@@ -561,14 +562,15 @@ static struct snd_soc_dai_driver q6asm_fe_dais[] = {
Q6ASM_FEDAI_DRIVER(8),
};
-static int q6asm_dai_bind(struct device *dev, struct device *master, void *data)
+static int q6asm_dai_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct of_phandle_args args;
struct q6asm_dai_data *pdata;
int rc;
- pdata = kzalloc(sizeof(struct q6asm_dai_data), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -580,43 +582,23 @@ static int q6asm_dai_bind(struct device *dev, struct device *master, void *data)
dev_set_drvdata(dev, pdata);
- return snd_soc_register_component(dev, &q6asm_fe_dai_component,
+ return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
q6asm_fe_dais,
ARRAY_SIZE(q6asm_fe_dais));
}
-static void q6asm_dai_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct q6asm_dai_data *pdata = dev_get_drvdata(dev);
-
- snd_soc_unregister_component(dev);
-
- kfree(pdata);
-
-}
-static const struct component_ops q6asm_dai_comp_ops = {
- .bind = q6asm_dai_bind,
- .unbind = q6asm_dai_unbind,
+static const struct of_device_id q6asm_dai_device_id[] = {
+ { .compatible = "qcom,q6asm-dais" },
+ {},
};
-
-static int q6asm_dai_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &q6asm_dai_comp_ops);
-}
-
-static int q6asm_dai_dev_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &q6asm_dai_comp_ops);
- return 0;
-}
+MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
static struct platform_driver q6asm_dai_platform_driver = {
.driver = {
.name = "q6asm-dai",
+ .of_match_table = of_match_ptr(q6asm_dai_device_id),
},
.probe = q6asm_dai_probe,
- .remove = q6asm_dai_dev_remove,
};
module_platform_driver(q6asm_dai_platform_driver);
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 530852385cad..2b2c7233bb5f 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -174,10 +174,8 @@ struct q6asm {
struct device *dev;
struct q6core_svc_api_info ainfo;
wait_queue_head_t mem_wait;
- struct platform_device *pcmdev;
spinlock_t slock;
struct audio_client *session[MAX_SESSIONS + 1];
- struct platform_device *pdev_dais;
};
struct audio_client {
@@ -1344,7 +1342,6 @@ EXPORT_SYMBOL_GPL(q6asm_cmd_nowait);
static int q6asm_probe(struct apr_device *adev)
{
struct device *dev = &adev->dev;
- struct device_node *dais_np;
struct q6asm *q6asm;
q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL);
@@ -1359,22 +1356,12 @@ static int q6asm_probe(struct apr_device *adev)
spin_lock_init(&q6asm->slock);
dev_set_drvdata(dev, q6asm);
- dais_np = of_get_child_by_name(dev->of_node, "dais");
- if (dais_np) {
- q6asm->pdev_dais = of_platform_device_create(dais_np,
- "q6asm-dai", dev);
- of_node_put(dais_np);
- }
-
- return 0;
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
static int q6asm_remove(struct apr_device *adev)
{
- struct q6asm *q6asm = dev_get_drvdata(&adev->dev);
-
- if (q6asm->pdev_dais)
- of_platform_device_destroy(&q6asm->pdev_dais->dev, NULL);
+ of_platform_depopulate(&adev->dev);
return 0;
}
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 593f66b8622f..dc94c5c53788 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -8,7 +8,6 @@
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/bitops.h>
-#include <linux/component.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/slab.h>
@@ -68,6 +67,13 @@
{ mix_name, "SEC_MI2S_TX", "SEC_MI2S_TX" }, \
{ mix_name, "QUAT_MI2S_TX", "QUAT_MI2S_TX" }, \
{ mix_name, "TERT_MI2S_TX", "TERT_MI2S_TX" }, \
+ { mix_name, "SLIMBUS_0_TX", "SLIMBUS_0_TX" }, \
+ { mix_name, "SLIMBUS_1_TX", "SLIMBUS_1_TX" }, \
+ { mix_name, "SLIMBUS_2_TX", "SLIMBUS_2_TX" }, \
+ { mix_name, "SLIMBUS_3_TX", "SLIMBUS_3_TX" }, \
+ { mix_name, "SLIMBUS_4_TX", "SLIMBUS_4_TX" }, \
+ { mix_name, "SLIMBUS_5_TX", "SLIMBUS_5_TX" }, \
+ { mix_name, "SLIMBUS_6_TX", "SLIMBUS_6_TX" }, \
{ mix_name, "PRIMARY_TDM_TX_0", "PRIMARY_TDM_TX_0"}, \
{ mix_name, "PRIMARY_TDM_TX_1", "PRIMARY_TDM_TX_1"}, \
{ mix_name, "PRIMARY_TDM_TX_2", "PRIMARY_TDM_TX_2"}, \
@@ -122,6 +128,27 @@
SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, \
id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_0_TX", SLIMBUS_0_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_1_TX", SLIMBUS_1_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_2_TX", SLIMBUS_2_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_3_TX", SLIMBUS_3_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_4_TX", SLIMBUS_4_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_5_TX", SLIMBUS_5_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("SLIMBUS_6_TX", SLIMBUS_6_TX, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
SOC_SINGLE_EXT("PRIMARY_TDM_TX_0", PRIMARY_TDM_TX_0, \
id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer), \
@@ -310,7 +337,7 @@ int q6routing_stream_open(int fedai_id, int perf_mode,
session->channels, topology, perf_mode,
session->bits_per_sample, 0, 0);
- if (!copp) {
+ if (IS_ERR_OR_NULL(copp)) {
mutex_unlock(&routing_data->lock);
return -EINVAL;
}
@@ -899,7 +926,7 @@ static int routing_hw_params(struct snd_pcm_substream *substream,
else
path_type = ADM_PATH_LIVE_REC;
- if (be_id > AFE_MAX_PORTS)
+ if (be_id >= AFE_MAX_PORTS)
return -EINVAL;
session = &data->port_data[be_id];
@@ -949,9 +976,10 @@ static const struct snd_soc_component_driver msm_soc_routing_component = {
.num_dapm_routes = ARRAY_SIZE(intercon),
};
-static int q6routing_dai_bind(struct device *dev, struct device *master,
- void *data)
+static int q6pcm_routing_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
+
routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL);
if (!routing_data)
return -ENOMEM;
@@ -961,41 +989,28 @@ static int q6routing_dai_bind(struct device *dev, struct device *master,
mutex_init(&routing_data->lock);
dev_set_drvdata(dev, routing_data);
- return snd_soc_register_component(dev, &msm_soc_routing_component,
+ return devm_snd_soc_register_component(dev, &msm_soc_routing_component,
NULL, 0);
}
-static void q6routing_dai_unbind(struct device *dev, struct device *master,
- void *d)
+static int q6pcm_routing_remove(struct platform_device *pdev)
{
- struct msm_routing_data *data = dev_get_drvdata(dev);
-
- snd_soc_unregister_component(dev);
-
- kfree(data);
-
+ kfree(routing_data);
routing_data = NULL;
-}
-
-static const struct component_ops q6routing_dai_comp_ops = {
- .bind = q6routing_dai_bind,
- .unbind = q6routing_dai_unbind,
-};
-static int q6pcm_routing_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &q6routing_dai_comp_ops);
-}
-
-static int q6pcm_routing_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &q6routing_dai_comp_ops);
return 0;
}
+static const struct of_device_id q6pcm_routing_device_id[] = {
+ { .compatible = "qcom,q6adm-routing" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, q6pcm_routing_device_id);
+
static struct platform_driver q6pcm_routing_platform_driver = {
.driver = {
.name = "q6routing",
+ .of_match_table = of_match_ptr(q6pcm_routing_device_id),
},
.probe = q6pcm_routing_probe,
.remove = q6pcm_routing_remove,
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
new file mode 100644
index 000000000000..2a781d87ee65
--- /dev/null
+++ b/sound/soc/qcom/sdm845.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include "common.h"
+#include "qdsp6/q6afe.h"
+
+#define DEFAULT_SAMPLE_RATE_48K 48000
+#define DEFAULT_MCLK_RATE 24576000
+#define DEFAULT_BCLK_RATE 12288000
+
+struct sdm845_snd_data {
+ struct snd_soc_card *card;
+ uint32_t pri_mi2s_clk_count;
+ uint32_t quat_tdm_clk_count;
+};
+
+static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ slot_width = 32;
+ break;
+ default:
+ dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
+ __func__, params_format(params));
+ return -EINVAL;
+ }
+
+ channels = params_channels(params);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x3,
+ 8, slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ channels, tdm_slot_offset);
+ if (ret < 0) {
+ dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0,
+ 8, slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, channels,
+ tdm_slot_offset, 0, NULL);
+ if (ret < 0) {
+ dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
+static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+
+ switch (cpu_dai->id) {
+ case QUATERNARY_TDM_RX_0:
+ case QUATERNARY_TDM_TX_0:
+ ret = sdm845_tdm_snd_hw_params(substream, params);
+ break;
+ default:
+ pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
+ break;
+ }
+ return ret;
+}
+
+static int sdm845_snd_startup(struct snd_pcm_substream *substream)
+{
+ unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ if (++(data->pri_mi2s_clk_count) == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_MCLK_1,
+ DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ break;
+
+ case QUATERNARY_TDM_RX_0:
+ case QUATERNARY_TDM_TX_0:
+ if (++(data->quat_tdm_clk_count) == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
+ DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ break;
+
+ default:
+ pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
+ break;
+ }
+ return 0;
+}
+
+static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ if (--(data->pri_mi2s_clk_count) == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_MCLK_1,
+ 0, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
+ 0, SNDRV_PCM_STREAM_PLAYBACK);
+ };
+ break;
+
+ case QUATERNARY_TDM_RX_0:
+ case QUATERNARY_TDM_TX_0:
+ if (--(data->quat_tdm_clk_count) == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
+ 0, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ break;
+
+ default:
+ pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
+ break;
+ }
+}
+
+static struct snd_soc_ops sdm845_be_ops = {
+ .hw_params = sdm845_snd_hw_params,
+ .startup = sdm845_snd_startup,
+ .shutdown = sdm845_snd_shutdown,
+};
+
+static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
+ channels->min = channels->max = 2;
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
+
+ return 0;
+}
+
+static void sdm845_add_be_ops(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *link = card->dai_link;
+ int i, num_links = card->num_links;
+
+ for (i = 0; i < num_links; i++) {
+ if (link->no_pcm == 1) {
+ link->ops = &sdm845_be_ops;
+ link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
+ }
+ link++;
+ }
+}
+
+static int sdm845_snd_platform_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card;
+ struct sdm845_snd_data *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ card = kzalloc(sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ /* Allocate the private data */
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto data_alloc_fail;
+ }
+
+ card->dev = dev;
+ dev_set_drvdata(dev, card);
+ ret = qcom_snd_parse_of(card);
+ if (ret) {
+ dev_err(dev, "Error parsing OF data\n");
+ goto parse_dt_fail;
+ }
+
+ data->card = card;
+ snd_soc_card_set_drvdata(card, data);
+
+ sdm845_add_be_ops(card);
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(dev, "Sound card registration failed\n");
+ goto register_card_fail;
+ }
+ return ret;
+
+register_card_fail:
+ kfree(card->dai_link);
+parse_dt_fail:
+ kfree(data);
+data_alloc_fail:
+ kfree(card);
+ return ret;
+}
+
+static int sdm845_snd_platform_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
+ struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+ kfree(card->dai_link);
+ kfree(data);
+ kfree(card);
+ return 0;
+}
+
+static const struct of_device_id sdm845_snd_device_id[] = {
+ { .compatible = "qcom,sdm845-sndcard" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
+
+static struct platform_driver sdm845_snd_driver = {
+ .probe = sdm845_snd_platform_probe,
+ .remove = sdm845_snd_platform_remove,
+ .driver = {
+ .name = "msm-snd-sdm845",
+ .of_match_table = sdm845_snd_device_id,
+ },
+};
+module_platform_driver(sdm845_snd_driver);
+
+MODULE_DESCRIPTION("sdm845 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index 05b078e7b87f..65e814d46006 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
# ROCKCHIP Platform Support
snd-soc-rockchip-i2s-objs := rockchip_i2s.o
+snd-soc-rockchip-pcm-objs := rockchip_pcm.o
snd-soc-rockchip-pdm-objs := rockchip_pdm.o
snd-soc-rockchip-spdif-objs := rockchip_spdif.o
-obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o snd-soc-rockchip-pcm.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_PDM) += snd-soc-rockchip-pdm.o
obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 950823d69e9c..60d43d53a8f5 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -22,6 +22,7 @@
#include <sound/dmaengine_pcm.h>
#include "rockchip_i2s.h"
+#include "rockchip_pcm.h"
#define DRV_NAME "rockchip-i2s"
@@ -674,7 +675,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
goto err_suspend;
}
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ ret = rockchip_pcm_platform_register(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM\n");
return ret;
diff --git a/sound/soc/rockchip/rockchip_pcm.c b/sound/soc/rockchip/rockchip_pcm.c
new file mode 100644
index 000000000000..f77538319221
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_pcm.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "rockchip_pcm.h"
+
+static const struct snd_pcm_hardware snd_rockchip_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .period_bytes_min = 32,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 52,
+ .buffer_bytes_max = 64 * 1024,
+ .fifo_size = 32,
+};
+
+static const struct snd_dmaengine_pcm_config rk_dmaengine_pcm_config = {
+ .pcm_hardware = &snd_rockchip_hardware,
+ .prealloc_buffer_size = 32 * 1024,
+};
+
+int rockchip_pcm_platform_register(struct device *dev)
+{
+ return devm_snd_dmaengine_pcm_register(dev, &rk_dmaengine_pcm_config,
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+EXPORT_SYMBOL_GPL(rockchip_pcm_platform_register);
+
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/rockchip/rockchip_pcm.h b/sound/soc/rockchip/rockchip_pcm.h
new file mode 100644
index 000000000000..d6c36115c60a
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_pcm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ROCKCHIP_PCM_H
+#define _ROCKCHIP_PCM_H
+
+int rockchip_pcm_platform_register(struct device *dev);
+
+#endif
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index 4db4fd56db35..881c32498808 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -181,7 +181,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
if (!rk_dailink.cpu_of_node) {
dev_err(&pdev->dev,
"Property 'rockchip,i2s-controller' missing or invalid\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_codec_of_node;
}
rk_dailink.platform_of_node = rk_dailink.cpu_of_node;
@@ -190,17 +191,36 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Soc parse card name failed %d\n", ret);
- return ret;
+ goto put_cpu_of_node;
}
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
dev_err(&pdev->dev,
"Soc register card failed %d\n", ret);
- return ret;
+ goto put_cpu_of_node;
}
return ret;
+
+put_cpu_of_node:
+ of_node_put(rk_dailink.cpu_of_node);
+ rk_dailink.cpu_of_node = NULL;
+put_codec_of_node:
+ of_node_put(rk_dailink.codec_of_node);
+ rk_dailink.codec_of_node = NULL;
+
+ return ret;
+}
+
+static int snd_rk_mc_remove(struct platform_device *pdev)
+{
+ of_node_put(rk_dailink.cpu_of_node);
+ rk_dailink.cpu_of_node = NULL;
+ of_node_put(rk_dailink.codec_of_node);
+ rk_dailink.codec_of_node = NULL;
+
+ return 0;
}
static const struct of_device_id rockchip_rt5645_of_match[] = {
@@ -212,6 +232,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match);
static struct platform_driver snd_rk_mc_driver = {
.probe = snd_rk_mc_probe,
+ .remove = snd_rk_mc_remove,
.driver = {
.name = DRV_NAME,
.pm = &snd_soc_pm_ops,
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index f914ed45db7d..d6c62aa13041 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -710,6 +710,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
switch (params_channels(params)) {
case 6:
val |= MOD_DC2_EN;
+ /* fall through */
case 4:
val |= MOD_DC1_EN;
break;
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 0ae0800bf3a8..dc20f0f7080a 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
menu "SoC Audio support for Renesas SoCs"
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
index 2dc3b762fdd9..922fb6aa3ed1 100644
--- a/sound/soc/sh/dma-sh7760.c
+++ b/sound/soc/sh/dma-sh7760.c
@@ -1,16 +1,14 @@
-/*
- * SH7760 ("camelot") DMABRG audio DMA unit support
- *
- * Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- * licensed under the terms outlined in the file COPYING at the root
- * of the linux kernel sources.
- *
- * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
- * trigger an interrupt when one half of the programmed transfer size
- * has been xmitted.
- *
- * FIXME: little-endian only for now
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// SH7760 ("camelot") DMABRG audio DMA unit support
+//
+// Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+// trigger an interrupt when one half of the programmed transfer size
+// has been xmitted.
+//
+// FIXME: little-endian only for now
#include <linux/module.h>
#include <linux/gfp.h>
@@ -341,6 +339,6 @@ static struct platform_driver sh7760_pcm_driver = {
module_platform_driver(sh7760_pcm_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 3bae06dd121f..aa7e902f0c02 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -1,16 +1,12 @@
-/*
- * Fifo-attached Serial Interface (FSI) support for SH7724
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ssi.c
- * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Fifo-attached Serial Interface (FSI) support for SH7724
+//
+// Copyright (C) 2009 Renesas Solutions Corp.
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
+//
+// Based on ssi.c
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 624aaf569fef..c2b496398e6b 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -1,13 +1,11 @@
-/*
- * Hitachi Audio Controller (AC97) support for SH7760/SH7780
- *
- * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- * licensed under the terms outlined in the file COPYING at the root
- * of the linux kernel sources.
- *
- * dont forget to set IPSEL/OMSEL register bits (in your board code) to
- * enable HAC output pins!
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Hitachi Audio Controller (AC97) support for SH7760/SH7780
+//
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// dont forget to set IPSEL/OMSEL register bits (in your board code) to
+// enable HAC output pins!
/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
* the FIRST can be used since ASoC does not pass any information to the
@@ -343,6 +341,6 @@ static struct platform_driver hac_pcm_driver = {
module_platform_driver(hac_pcm_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c
index ecb057ff9fbb..8739c9f60672 100644
--- a/sound/soc/sh/migor.c
+++ b/sound/soc/sh/migor.c
@@ -1,12 +1,8 @@
-/*
- * ALSA SoC driver for Migo-R
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ALSA SoC driver for Migo-R
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
#include <linux/clkdev.h>
#include <linux/device.h>
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
index 9c3d5aed99d1..5d1ff8ef26f9 100644
--- a/sound/soc/sh/rcar/Makefile
+++ b/sound/soc/sh/rcar/Makefile
@@ -1,2 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o
obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index 4672688cac32..3a3064dda57f 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -1,12 +1,9 @@
-/*
- * Helper routines for R-Car sound ADG.
- *
- * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Helper routines for R-Car sound ADG.
+//
+// Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include <linux/clk-provider.h>
#include "rsnd.h"
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c
index 5900fb535a2b..cc191cd5fb82 100644
--- a/sound/soc/sh/rcar/cmd.c
+++ b/sound/soc/sh/rcar/cmd.c
@@ -1,13 +1,10 @@
-/*
- * Renesas R-Car CMD support
- *
- * Copyright (C) 2015 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car CMD support
+//
+// Copyright (C) 2015 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include "rsnd.h"
struct rsnd_cmd {
@@ -89,7 +86,7 @@ static int rsnd_cmd_init(struct rsnd_mod *mod,
cmd_case[rsnd_mod_id(src)] << 16;
}
- dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+ dev_dbg(dev, "ctu/mix path = 0x%08x\n", data);
rsnd_mod_write(mod, CMD_ROUTE_SLCT, data);
rsnd_mod_write(mod, CMD_BUSIF_MODE, rsnd_get_busif_shift(io, mod) | 1);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index f237002180c0..f8425d8b44d2 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -1,16 +1,12 @@
-/*
- * Renesas R-Car SRU/SCU/SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on fsi.c
- * Kuninori Morimoto <morimoto.kuninori@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRU/SCU/SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
/*
* Renesas R-Car sound device structure
@@ -552,6 +548,15 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
return priv->rdai + id;
}
+static struct snd_soc_dai_driver
+*rsnd_daidrv_get(struct rsnd_priv *priv, int id)
+{
+ if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
+ return NULL;
+
+ return priv->daidrv + id;
+}
+
#define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai)
static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
{
@@ -1037,7 +1042,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
int io_i;
rdai = rsnd_rdai_get(priv, dai_i);
- drv = priv->daidrv + dai_i;
+ drv = rsnd_daidrv_get(priv, dai_i);
io_playback = &rdai->playback;
io_capture = &rdai->capture;
@@ -1085,6 +1090,12 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
of_node_put(capture);
}
+ if (rsnd_ssi_is_pin_sharing(io_capture) ||
+ rsnd_ssi_is_pin_sharing(io_playback)) {
+ /* should have symmetric_rates if pin sharing */
+ drv->symmetric_rates = 1;
+ }
+
dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
@@ -1606,7 +1617,7 @@ static struct platform_driver rsnd_driver = {
};
module_platform_driver(rsnd_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Renesas R-Car audio driver");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
index 83be7d3ae0a8..6a55aa753003 100644
--- a/sound/soc/sh/rcar/ctu.c
+++ b/sound/soc/sh/rcar/ctu.c
@@ -1,12 +1,9 @@
-/*
- * ctu.c
- *
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// ctu.c
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include "rsnd.h"
#define CTU_NAME_SIZE 16
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index ef82b94d038b..fe63ef8600d0 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -1,13 +1,10 @@
-/*
- * Renesas R-Car Audio DMAC support
- *
- * Copyright (C) 2015 Renesas Electronics Corp.
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Audio DMAC support
+//
+// Copyright (C) 2015 Renesas Electronics Corp.
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include <linux/delay.h>
#include <linux/of_dma.h>
#include "rsnd.h"
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index ca1780e0b830..2b16e0ce6bc5 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -1,13 +1,9 @@
-/*
- * Renesas R-Car DVC support
- *
- * Copyright (C) 2014 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car DVC support
+//
+// Copyright (C) 2014 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
/*
* Playback Volume
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 25642e92dae0..0230301fe078 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -1,13 +1,9 @@
-/*
- * Renesas R-Car Gen1 SRU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car Gen1 SRU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
/*
* #define DEBUG
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
index 1881b2de9126..8e3b57eaa708 100644
--- a/sound/soc/sh/rcar/mix.c
+++ b/sound/soc/sh/rcar/mix.c
@@ -1,12 +1,8 @@
-/*
- * mix.c
- *
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// mix.c
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
/*
* CTUn MIXn
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index 6d7280d2d9be..96d93330b1e1 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -1,13 +1,10 @@
-/*
- * Renesas R-Car
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#ifndef RSND_H
#define RSND_H
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 6c72d1a81cf5..beccfbac7581 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -1,13 +1,9 @@
-/*
- * Renesas R-Car SRC support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SRC support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
/*
* you can enable below define if you don't need
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 6e1166ec24a0..8304e4ec9242 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -1,16 +1,12 @@
-/*
- * Renesas R-Car SSIU/SSI support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * Based on fsi.c
- * Kuninori Morimoto <morimoto.kuninori@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SSIU/SSI support
+//
+// Copyright (C) 2013 Renesas Solutions Corp.
+// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+//
+// Based on fsi.c
+// Kuninori Morimoto <morimoto.kuninori@renesas.com>
/*
* you can enable below define if you don't need
@@ -37,6 +33,7 @@
#define CHNL_4 (1 << 22) /* Channels */
#define CHNL_6 (2 << 22) /* Channels */
#define CHNL_8 (3 << 22) /* Channels */
+#define DWL_MASK (7 << 19) /* Data Word Length mask */
#define DWL_8 (0 << 19) /* Data Word Length */
#define DWL_16 (1 << 19) /* Data Word Length */
#define DWL_18 (2 << 19) /* Data Word Length */
@@ -353,21 +350,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- u32 cr_own;
- u32 cr_mode;
- u32 wsr;
+ u32 cr_own = ssi->cr_own;
+ u32 cr_mode = ssi->cr_mode;
+ u32 wsr = ssi->wsr;
int is_tdm;
- if (rsnd_ssi_is_parent(mod, io))
- return;
-
is_tdm = rsnd_runtime_is_ssi_tdm(io);
/*
* always use 32bit system word.
* see also rsnd_ssi_master_clk_enable()
*/
- cr_own = FORCE | SWL_32;
+ cr_own |= FORCE | SWL_32;
if (rdai->bit_clk_inv)
cr_own |= SCKP;
@@ -377,9 +371,18 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
cr_own |= SDTA;
if (rdai->sys_delay)
cr_own |= DEL;
+
+ /*
+ * We shouldn't exchange SWSP after running.
+ * This means, parent needs to care it.
+ */
+ if (rsnd_ssi_is_parent(mod, io))
+ goto init_end;
+
if (rsnd_io_is_play(io))
cr_own |= TRMD;
+ cr_own &= ~DWL_MASK;
switch (snd_pcm_format_width(runtime->format)) {
case 16:
cr_own |= DWL_16;
@@ -406,7 +409,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
wsr |= WS_MODE;
cr_own |= CHNL_8;
}
-
+init_end:
ssi->cr_own = cr_own;
ssi->cr_mode = cr_mode;
ssi->wsr = wsr;
@@ -470,15 +473,18 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod,
return -EIO;
}
- if (!rsnd_ssi_is_parent(mod, io))
- ssi->cr_own = 0;
-
rsnd_ssi_master_clk_stop(mod, io);
rsnd_mod_power_off(mod);
ssi->usrcnt--;
+ if (!ssi->usrcnt) {
+ ssi->cr_own = 0;
+ ssi->cr_mode = 0;
+ ssi->wsr = 0;
+ }
+
return 0;
}
@@ -1055,9 +1061,10 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ if (!mod)
+ return 0;
- return !!(rsnd_flags_has(ssi, RSND_SSI_CLK_PIN_SHARE));
+ return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
}
static u32 *rsnd_ssi_get_status(struct rsnd_dai_stream *io,
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c
index 47bdba9fc582..016fbf5ac242 100644
--- a/sound/soc/sh/rcar/ssiu.c
+++ b/sound/soc/sh/rcar/ssiu.c
@@ -1,12 +1,9 @@
-/*
- * Renesas R-Car SSIU support
- *
- * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Renesas R-Car SSIU support
+//
+// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
#include "rsnd.h"
#define SSIU_NAME "ssiu"
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
index 4a3568a9bf59..4bb4c13cf860 100644
--- a/sound/soc/sh/sh7760-ac97.c
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -1,10 +1,8 @@
-/*
- * Generic AC97 sound support for SH7760
- *
- * (c) 2007 Manuel Lauss
- *
- * Licensed under the GPLv2.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Generic AC97 sound support for SH7760
+//
+// (c) 2007 Manuel Lauss
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -68,6 +66,6 @@ static void __exit sh7760_ac97_exit(void)
module_init(sh7760_ac97_init);
module_exit(sh7760_ac97_exit);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h
index 6088d627c0e4..63a508fdfe78 100644
--- a/sound/soc/sh/siu.h
+++ b/sound/soc/sh/siu.h
@@ -1,23 +1,9 @@
-/*
- * siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu.h - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
#ifndef SIU_H
#define SIU_H
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index ee2211635e92..f2a386fcd92e 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -1,23 +1,9 @@
-/*
- * siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu_dai.c - ALSA SoC driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
#include <linux/delay.h>
#include <linux/firmware.h>
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c
index 172909570ed5..e263757e4a69 100644
--- a/sound/soc/sh/siu_pcm.c
+++ b/sound/soc/sh/siu_pcm.c
@@ -1,23 +1,10 @@
-/*
- * siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
- *
- * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
+//
+// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
+
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
index 89ed1b107ac5..8125fa3840b6 100644
--- a/sound/soc/sh/ssi.c
+++ b/sound/soc/sh/ssi.c
@@ -1,14 +1,11 @@
-/*
- * Serial Sound Interface (I2S) support for SH7760/SH7780
- *
- * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
- *
- * licensed under the terms outlined in the file COPYING at the root
- * of the linux kernel sources.
- *
- * dont forget to set IPSEL/OMSEL register bits (in your board code) to
- * enable SSI output pins!
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Serial Sound Interface (I2S) support for SH7760/SH7780
+//
+// Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+//
+// dont forget to set IPSEL/OMSEL register bits (in your board code) to
+// enable SSI output pins!
/*
* LIMITATIONS:
@@ -400,6 +397,6 @@ static struct platform_driver sh4_ssi_driver = {
module_platform_driver(sh4_ssi_driver);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
index 77e7dcf969d0..d70fcd4a1adf 100644
--- a/sound/soc/sirf/sirf-usp.c
+++ b/sound/soc/sirf/sirf-usp.c
@@ -370,10 +370,9 @@ static int sirf_usp_pcm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, usp);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap(&pdev->dev, mem_res->start,
- resource_size(mem_res));
- if (base == NULL)
- return -ENOMEM;
+ base = devm_ioremap_resource(&pdev->dev, mem_res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
usp->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sirf_usp_regmap_config);
if (IS_ERR(usp->regmap))
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
index 3f424f214bca..c086786e4471 100644
--- a/sound/soc/soc-ac97.c
+++ b/sound/soc/soc-ac97.c
@@ -1,20 +1,15 @@
-/*
- * soc-ac97.c -- ALSA SoC Audio Layer AC97 support
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- * with code, comments and ideas from :-
- * Richard Purdie <richard@openedhand.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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-ac97.c -- ALSA SoC Audio Layer AC97 support
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+// with code, comments and ideas from :-
+// Richard Purdie <richard@openedhand.com>
#include <linux/ctype.h>
#include <linux/delay.h>
diff --git a/sound/soc/soc-acpi.c b/sound/soc/soc-acpi.c
index 3d7e1ff79139..b8e72b52db30 100644
--- a/sound/soc/soc-acpi.c
+++ b/sound/soc/soc-acpi.c
@@ -1,18 +1,8 @@
-/*
- * soc-apci.c - support for ACPI enumeration.
- *
- * Copyright (c) 2013-15, Intel Corporation.
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// soc-apci.c - support for ACPI enumeration.
+//
+// Copyright (c) 2013-15, Intel Corporation.
#include <sound/soc-acpi.h>
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index e095115fa9f9..409d082e80d1 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -1,18 +1,12 @@
-/*
- * soc-compress.c -- ALSA SoC Compress
- *
- * Copyright (C) 2012 Intel Corp.
- *
- * Authors: Namarta Kohli <namartax.kohli@intel.com>
- * Ramesh Babu K V <ramesh.babu@linux.intel.com>
- * Vinod Koul <vinod.koul@linux.intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-compress.c -- ALSA SoC Compress
+//
+// Copyright (C) 2012 Intel Corp.
+//
+// Authors: Namarta Kohli <namartax.kohli@intel.com>
+// Ramesh Babu K V <ramesh.babu@linux.intel.com>
+// Vinod Koul <vinod.koul@linux.intel.com>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -146,6 +140,30 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
stream = SNDRV_PCM_STREAM_CAPTURE;
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ fe->dpcm[stream].runtime = fe_substream->runtime;
+
+ ret = dpcm_path_get(fe, stream, &list);
+ if (ret < 0)
+ goto be_err;
+ else if (ret == 0)
+ dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
+ fe->dai_link->name, stream ? "capture" : "playback");
+ /* calculate valid and active FE <-> BE dpcms */
+ dpcm_process_paths(fe, stream, &list, 1);
+ fe->dpcm[stream].runtime = fe_substream->runtime;
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_startup(fe, stream);
+ if (ret < 0) {
+ /* clean up all links */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+ dpcm_be_disconnect(fe, stream);
+ fe->dpcm[stream].runtime = NULL;
+ goto out;
+ }
if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) {
ret = cpu_dai->driver->cops->startup(cstream, cpu_dai);
@@ -159,7 +177,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
ret = soc_compr_components_open(cstream, &component);
if (ret < 0)
- goto machine_err;
+ goto open_err;
if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->startup) {
ret = fe->dai_link->compr_ops->startup(cstream);
@@ -170,31 +188,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
}
}
- fe->dpcm[stream].runtime = fe_substream->runtime;
-
- ret = dpcm_path_get(fe, stream, &list);
- if (ret < 0)
- goto fe_err;
- else if (ret == 0)
- dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
- fe->dai_link->name, stream ? "capture" : "playback");
-
- /* calculate valid and active FE <-> BE dpcms */
- dpcm_process_paths(fe, stream, &list, 1);
-
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
-
- ret = dpcm_be_dai_startup(fe, stream);
- if (ret < 0) {
- /* clean up all links */
- list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
- dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
-
- dpcm_be_disconnect(fe, stream);
- fe->dpcm[stream].runtime = NULL;
- goto path_err;
- }
-
dpcm_clear_pending_state(fe, stream);
dpcm_path_put(&list);
@@ -207,17 +200,14 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
return 0;
-path_err:
- dpcm_path_put(&list);
-fe_err:
- if (fe->dai_link->compr_ops && fe->dai_link->compr_ops->shutdown)
- fe->dai_link->compr_ops->shutdown(cstream);
machine_err:
soc_compr_components_free(cstream, component);
-
+open_err:
if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown)
cpu_dai->driver->cops->shutdown(cstream, cpu_dai);
out:
+ dpcm_path_put(&list);
+be_err:
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
mutex_unlock(&fe->card->mutex);
return ret;
@@ -557,6 +547,24 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ /*
+ * Create an empty hw_params for the BE as the machine driver must
+ * fix this up to match DSP decoder and ASRC configuration.
+ * I.e. machine driver fixup for compressed BE is mandatory.
+ */
+ memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
+ sizeof(struct snd_pcm_hw_params));
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_hw_params(fe, stream);
+ if (ret < 0)
+ goto out;
+
+ ret = dpcm_be_dai_prepare(fe, stream);
+ if (ret < 0)
+ goto out;
+
if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) {
ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai);
if (ret < 0)
@@ -583,24 +591,6 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
goto out;
}
- /*
- * Create an empty hw_params for the BE as the machine driver must
- * fix this up to match DSP decoder and ASRC configuration.
- * I.e. machine driver fixup for compressed BE is mandatory.
- */
- memset(&fe->dpcm[fe_substream->stream].hw_params, 0,
- sizeof(struct snd_pcm_hw_params));
-
- fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
-
- ret = dpcm_be_dai_hw_params(fe, stream);
- if (ret < 0)
- goto out;
-
- ret = dpcm_be_dai_prepare(fe, stream);
- if (ret < 0)
- goto out;
-
dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4663de3cf495..9cfe10d8040c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1,26 +1,21 @@
-/*
- * soc-core.c -- ALSA SoC Audio Layer
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- * with code, comments and ideas from :-
- * Richard Purdie <richard@openedhand.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.
- *
- * TODO:
- * o Add hw rules to enforce rates, etc.
- * o More testing with other codecs/machines.
- * o Add more codecs and platforms to ensure good API coverage.
- * o Support TDM on PCM and I2S
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-core.c -- ALSA SoC Audio Layer
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+// with code, comments and ideas from :-
+// Richard Purdie <richard@openedhand.com>
+//
+// TODO:
+// o Add hw rules to enforce rates, etc.
+// o More testing with other codecs/machines.
+// o Add more codecs and platforms to ensure good API coverage.
+// o Support TDM on PCM and I2S
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -533,6 +528,7 @@ int snd_soc_suspend(struct device *dev)
"ASoC: idle_bias_off CODEC on over suspend\n");
break;
}
+ /* fall through */
case SND_SOC_BIAS_OFF:
if (component->driver->suspend)
@@ -852,6 +848,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card,
const char *platform_name;
int i;
+ if (dai_link->ignore)
+ return 0;
+
dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name);
if (soc_is_dai_link_bound(card, dai_link)) {
@@ -1195,15 +1194,27 @@ void snd_soc_remove_dai_link(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link);
+static void soc_set_of_name_prefix(struct snd_soc_component *component)
+{
+ struct device_node *component_of_node = component->dev->of_node;
+ const char *str;
+ int ret;
+
+ if (!component_of_node && component->dev->parent)
+ component_of_node = component->dev->parent->of_node;
+
+ ret = of_property_read_string(component_of_node, "sound-name-prefix",
+ &str);
+ if (!ret)
+ component->name_prefix = str;
+}
+
static void soc_set_name_prefix(struct snd_soc_card *card,
struct snd_soc_component *component)
{
int i;
- if (card->codec_conf == NULL)
- return;
-
- for (i = 0; i < card->num_configs; i++) {
+ for (i = 0; i < card->num_configs && card->codec_conf; i++) {
struct snd_soc_codec_conf *map = &card->codec_conf[i];
struct device_node *component_of_node = component->dev->of_node;
@@ -1215,8 +1226,14 @@ static void soc_set_name_prefix(struct snd_soc_card *card,
if (map->dev_name && strcmp(component->name, map->dev_name))
continue;
component->name_prefix = map->name_prefix;
- break;
+ return;
}
+
+ /*
+ * If there is no configuration table or no match in the table,
+ * check if a prefix is provided in the node
+ */
+ soc_set_of_name_prefix(component);
}
static int soc_probe_component(struct snd_soc_card *card,
@@ -1461,7 +1478,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int i, ret;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+ int i, ret, num;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
card->name, rtd->num, order);
@@ -1507,9 +1526,28 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
soc_dpcm_debugfs_add(rtd);
#endif
+ num = rtd->num;
+
+ /*
+ * most drivers will register their PCMs using DAI link ordering but
+ * topology based drivers can use the DAI link id field to set PCM
+ * device number and then use rtd + a base offset of the BEs.
+ */
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (!component->driver->use_dai_pcm_id)
+ continue;
+
+ if (rtd->dai_link->no_pcm)
+ num += component->driver->be_pcm_base;
+ else
+ num = rtd->dai_link->id;
+ }
+
if (cpu_dai->driver->compress_new) {
/*create compress_device"*/
- ret = cpu_dai->driver->compress_new(rtd, rtd->num);
+ ret = cpu_dai->driver->compress_new(rtd, num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create compress %s\n",
dai_link->stream_name);
@@ -1519,7 +1557,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card,
if (!dai_link->params) {
/* create the pcm */
- ret = soc_new_pcm(rtd, rtd->num);
+ ret = soc_new_pcm(rtd, num);
if (ret < 0) {
dev_err(card->dev, "ASoC: can't create pcm %s :%d\n",
dai_link->stream_name, ret);
@@ -1846,6 +1884,74 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
#endif /* CONFIG_DMI */
+static void soc_check_tplg_fes(struct snd_soc_card *card)
+{
+ struct snd_soc_component *component;
+ const struct snd_soc_component_driver *comp_drv;
+ struct snd_soc_dai_link *dai_link;
+ int i;
+
+ list_for_each_entry(component, &component_list, list) {
+
+ /* does this component override FEs ? */
+ if (!component->driver->ignore_machine)
+ continue;
+
+ /* for this machine ? */
+ if (strcmp(component->driver->ignore_machine,
+ card->dev->driver->name))
+ continue;
+
+ /* machine matches, so override the rtd data */
+ for (i = 0; i < card->num_links; i++) {
+
+ dai_link = &card->dai_link[i];
+
+ /* ignore this FE */
+ if (dai_link->dynamic) {
+ dai_link->ignore = true;
+ continue;
+ }
+
+ dev_info(card->dev, "info: override FE DAI link %s\n",
+ card->dai_link[i].name);
+
+ /* override platform component */
+ dai_link->platform_name = component->name;
+
+ /* convert non BE into BE */
+ dai_link->no_pcm = 1;
+
+ /* override any BE fixups */
+ dai_link->be_hw_params_fixup =
+ component->driver->be_hw_params_fixup;
+
+ /* most BE links don't set stream name, so set it to
+ * dai link name if it's NULL to help bind widgets.
+ */
+ if (!dai_link->stream_name)
+ dai_link->stream_name = dai_link->name;
+ }
+
+ /* Inform userspace we are using alternate topology */
+ if (component->driver->topology_name_prefix) {
+
+ /* topology shortname created ? */
+ if (!card->topology_shortname_created) {
+ comp_drv = component->driver;
+
+ snprintf(card->topology_shortname, 32, "%s-%s",
+ comp_drv->topology_name_prefix,
+ card->name);
+ card->topology_shortname_created = true;
+ }
+
+ /* use topology shortname */
+ card->name = card->topology_shortname;
+ }
+ }
+}
+
static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_pcm_runtime *rtd;
@@ -1855,6 +1961,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
mutex_lock(&client_mutex);
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
+ /* check whether any platform is ignore machine FE and using topology */
+ soc_check_tplg_fes(card);
+
/* bind DAIs */
for (i = 0; i < card->num_links; i++) {
ret = soc_bind_dai_link(card, &card->dai_link[i]);
@@ -2523,6 +2632,28 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
/**
+ * snd_soc_dai_get_channel_map - Get DAI audio channel map
+ * @dai: DAI
+ * @tx_num: how many TX channels
+ * @tx_slot: pointer to an array which imply the TX slot number channel
+ * 0~num-1 uses
+ * @rx_num: how many RX channels
+ * @rx_slot: pointer to an array which imply the RX slot number channel
+ * 0~num-1 uses
+ */
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ if (dai->driver->ops->get_channel_map)
+ return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
+ rx_num, rx_slot);
+ else
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
+
+/**
* snd_soc_dai_set_tristate - configure DAI system or master clock.
* @dai: DAI
* @tristate: tristate enable
@@ -3258,9 +3389,9 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets);
-static int snd_soc_of_get_slot_mask(struct device_node *np,
- const char *prop_name,
- unsigned int *mask)
+int snd_soc_of_get_slot_mask(struct device_node *np,
+ const char *prop_name,
+ unsigned int *mask)
{
u32 val;
const __be32 *of_slot_mask = of_get_property(np, prop_name, &val);
@@ -3275,6 +3406,7 @@ static int snd_soc_of_get_slot_mask(struct device_node *np,
return val;
}
+EXPORT_SYMBOL_GPL(snd_soc_of_get_slot_mask);
int snd_soc_of_parse_tdm_slot(struct device_node *np,
unsigned int *tx_mask,
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 229c12349803..7e96793050c9 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1,27 +1,21 @@
-/*
- * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Features:
- * o Changes power status of internal codec blocks depending on the
- * dynamic configuration of codec internal audio paths and active
- * DACs/ADCs.
- * o Platform power domain - can support external components i.e. amps and
- * mic/headphone insertion events.
- * o Automatic Mic Bias support
- * o Jack insertion power event initiation - e.g. hp insertion will enable
- * sinks, dacs, etc
- * o Delayed power down of audio subsystem to reduce pops between a quick
- * device reopen.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+//
+// Features:
+// o Changes power status of internal codec blocks depending on the
+// dynamic configuration of codec internal audio paths and active
+// DACs/ADCs.
+// o Platform power domain - can support external components i.e. amps and
+// mic/headphone insertion events.
+// o Automatic Mic Bias support
+// o Jack insertion power event initiation - e.g. hp insertion will enable
+// sinks, dacs, etc
+// o Delayed power down of audio subsystem to reduce pops between a quick
+// device reopen.
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -3662,7 +3656,7 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
struct snd_pcm_substream substream;
struct snd_pcm_hw_params *params = NULL;
struct snd_pcm_runtime *runtime = NULL;
- u64 fmt;
+ unsigned int fmt;
int ret;
if (WARN_ON(!config) ||
@@ -4073,6 +4067,13 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
continue;
}
+ /* let users know there is no DAI to link */
+ if (!dai_w->priv) {
+ dev_dbg(card->dev, "dai widget %s has no DAI\n",
+ dai_w->name);
+ continue;
+ }
+
dai = dai_w->priv;
/* ...find all widgets with the same stream and link them */
diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c
index 7ac745df1412..a9ea172a66a7 100644
--- a/sound/soc/soc-devres.c
+++ b/sound/soc/soc-devres.c
@@ -1,13 +1,8 @@
-/*
- * soc-devres.c -- ALSA SoC Audio Layer devres functions
- *
- * Copyright (C) 2013 Linaro Ltd
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-devres.c -- ALSA SoC Audio Layer devres functions
+//
+// Copyright (C) 2013 Linaro Ltd
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 76c46d793843..30e791a53352 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -1,17 +1,8 @@
-/*
- * Copyright (C) 2013, Analog Devices Inc.
- * Author: Lars-Peter Clausen <lars@metafoo.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2013, Analog Devices Inc.
+// Author: Lars-Peter Clausen <lars@metafoo.de>
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dmaengine.h>
@@ -197,7 +188,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
case 32:
case 64:
if (addr_widths & (1 << (bits / 8)))
- hw.formats |= (1LL << i);
+ hw.formats |= pcm_format_to_bits(i);
break;
default:
/* Unsupported types */
@@ -343,7 +334,7 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
static int dmaengine_copy_user(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
- void *buf, unsigned long bytes)
+ void __user *buf, unsigned long bytes)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component =
@@ -359,18 +350,17 @@ static int dmaengine_copy_user(struct snd_pcm_substream *substream,
int ret;
if (is_playback)
- if (copy_from_user(dma_ptr, (void __user *)buf, bytes))
+ if (copy_from_user(dma_ptr, buf, bytes))
return -EFAULT;
if (process) {
- ret = process(substream, channel, hwoff,
- (void __user *)buf, bytes);
+ ret = process(substream, channel, hwoff, (__force void *)buf, bytes);
if (ret < 0)
return ret;
}
if (!is_playback)
- if (copy_to_user((void __user *)buf, dma_ptr, bytes))
+ if (copy_to_user(buf, dma_ptr, bytes))
return -EFAULT;
return 0;
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 026cd5347e53..1ff9175e9d5e 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -1,15 +1,10 @@
-/*
- * soc-io.c -- ASoC register I/O helpers
- *
- * Copyright 2009-2011 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-io.c -- ASoC register I/O helpers
+//
+// Copyright 2009-2011 Wolfson Microelectronics PLC.
+//
+// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index b2b16044ae80..c7b990abdbaa 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -1,15 +1,10 @@
-/*
- * soc-jack.c -- ALSA SoC jack handling
- *
- * Copyright 2008 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-jack.c -- ALSA SoC jack handling
+//
+// Copyright 2008 Wolfson Microelectronics PLC.
+//
+// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
#include <sound/jack.h>
#include <sound/soc.h>
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 7144a51ddfa9..592efb370c44 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -1,20 +1,15 @@
-/*
- * soc-ops.c -- Generic ASoC operations
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Author: Liam Girdwood <lrg@slimlogic.co.uk>
- * with code, comments and ideas from :-
- * Richard Purdie <richard@openedhand.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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-ops.c -- Generic ASoC operations
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Author: Liam Girdwood <lrg@slimlogic.co.uk>
+// with code, comments and ideas from :-
+// Richard Purdie <richard@openedhand.com>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 5e7ae47a9658..e8b98bfd4cf1 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1,20 +1,14 @@
-/*
- * soc-pcm.c -- ALSA SoC PCM
- *
- * Copyright 2005 Wolfson Microelectronics PLC.
- * Copyright 2005 Openedhand Ltd.
- * Copyright (C) 2010 Slimlogic Ltd.
- * Copyright (C) 2010 Texas Instruments Inc.
- *
- * Authors: Liam Girdwood <lrg@ti.com>
- * Mark Brown <broonie@opensource.wolfsonmicro.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-pcm.c -- ALSA SoC PCM
+//
+// Copyright 2005 Wolfson Microelectronics PLC.
+// Copyright 2005 Openedhand Ltd.
+// Copyright (C) 2010 Slimlogic Ltd.
+// Copyright (C) 2010 Texas Instruments Inc.
+//
+// Authors: Liam Girdwood <lrg@ti.com>
+// Mark Brown <broonie@opensource.wolfsonmicro.com>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -448,6 +442,29 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
hw->rate_max = min_not_zero(hw->rate_max, rate_max);
}
+static int soc_pcm_components_close(struct snd_pcm_substream *substream,
+ struct snd_soc_component *last)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (component == last)
+ break;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->close)
+ continue;
+
+ component->driver->ops->close(substream);
+ }
+
+ return 0;
+}
+
/*
* Called by ALSA when a PCM substream is opened, the runtime->hw record is
* then initialized and any private data can be allocated. This also calls
@@ -462,7 +479,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
const char *codec_dai_name = "multicodec";
- int i, ret = 0, __ret;
+ int i, ret = 0;
pinctrl_pm_select_default_state(cpu_dai->dev);
for (i = 0; i < rtd->num_codecs; i++)
@@ -486,7 +503,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
- ret = 0;
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
@@ -494,16 +510,15 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
!component->driver->ops->open)
continue;
- __ret = component->driver->ops->open(substream);
- if (__ret < 0) {
+ ret = component->driver->ops->open(substream);
+ if (ret < 0) {
dev_err(component->dev,
"ASoC: can't open component %s: %d\n",
- component->name, __ret);
- ret = __ret;
+ component->name, ret);
+ goto component_err;
}
}
- if (ret < 0)
- goto component_err;
+ component = NULL;
for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i];
@@ -612,15 +627,7 @@ codec_dai_err:
}
component_err:
- for_each_rtdcom(rtd, rtdcom) {
- component = rtdcom->component;
-
- if (!component->driver->ops ||
- !component->driver->ops->close)
- continue;
-
- component->driver->ops->close(substream);
- }
+ soc_pcm_components_close(substream, component);
if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai);
@@ -714,15 +721,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (rtd->dai_link->ops->shutdown)
rtd->dai_link->ops->shutdown(substream);
- for_each_rtdcom(rtd, rtdcom) {
- component = rtdcom->component;
-
- if (!component->driver->ops ||
- !component->driver->ops->close)
- continue;
-
- component->driver->ops->close(substream);
- }
+ soc_pcm_components_close(substream, NULL);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
@@ -860,8 +859,20 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret;
+ /* perform any topology hw_params fixups before DAI */
+ if (rtd->dai_link->be_hw_params_fixup) {
+ ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "ASoC: hw_params topology fixup failed %d\n",
+ ret);
+ return ret;
+ }
+ }
+
if (dai->driver->ops->hw_params) {
ret = dai->driver->ops->hw_params(substream, params, dai);
if (ret < 0) {
@@ -874,6 +885,29 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_component *last)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_rtdcom_list *rtdcom;
+ struct snd_soc_component *component;
+
+ for_each_rtdcom(rtd, rtdcom) {
+ component = rtdcom->component;
+
+ if (component == last)
+ break;
+
+ if (!component->driver->ops ||
+ !component->driver->ops->hw_free)
+ continue;
+
+ component->driver->ops->hw_free(substream);
+ }
+
+ return 0;
+}
+
/*
* Called by ALSA when the hardware params are set by application. This
* function can also be called multiple times and can allocate buffers
@@ -886,7 +920,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int i, ret = 0, __ret;
+ int i, ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
if (rtd->dai_link->ops->hw_params) {
@@ -944,7 +978,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
if (ret < 0)
goto interface_err;
- ret = 0;
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
@@ -952,16 +985,15 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
!component->driver->ops->hw_params)
continue;
- __ret = component->driver->ops->hw_params(substream, params);
- if (__ret < 0) {
+ ret = component->driver->ops->hw_params(substream, params);
+ if (ret < 0) {
dev_err(component->dev,
"ASoC: %s hw params failed: %d\n",
- component->name, __ret);
- ret = __ret;
+ component->name, ret);
+ goto component_err;
}
}
- if (ret < 0)
- goto component_err;
+ component = NULL;
/* store the parameters for each DAIs */
cpu_dai->rate = params_rate(params);
@@ -977,15 +1009,7 @@ out:
return ret;
component_err:
- for_each_rtdcom(rtd, rtdcom) {
- component = rtdcom->component;
-
- if (!component->driver->ops ||
- !component->driver->ops->hw_free)
- continue;
-
- component->driver->ops->hw_free(substream);
- }
+ soc_pcm_components_hw_free(substream, component);
if (cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai);
@@ -1014,8 +1038,6 @@ codec_err:
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_component *component;
- struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai;
bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
@@ -1052,15 +1074,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
rtd->dai_link->ops->hw_free(substream);
/* free any component resources */
- for_each_rtdcom(rtd, rtdcom) {
- component = rtdcom->component;
-
- if (!component->driver->ops ||
- !component->driver->ops->hw_free)
- continue;
-
- component->driver->ops->hw_free(substream);
- }
+ soc_pcm_components_hw_free(substream, NULL);
/* now free hw params for the DAIs */
for (i = 0; i < rtd->num_codecs; i++) {
@@ -1165,6 +1179,9 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
snd_pcm_sframes_t codec_delay = 0;
int i;
+ /* clearing the previous total delay */
+ runtime->delay = 0;
+
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
@@ -1176,6 +1193,8 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
offset = component->driver->ops->pointer(substream);
break;
}
+ /* base delay if assigned in pointer callback */
+ delay = runtime->delay;
if (cpu_dai->driver->ops->delay)
delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
@@ -1658,29 +1677,28 @@ unwind:
}
static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
- struct snd_soc_pcm_stream *stream,
- u64 formats)
+ struct snd_soc_pcm_stream *stream)
{
runtime->hw.rate_min = stream->rate_min;
runtime->hw.rate_max = stream->rate_max;
runtime->hw.channels_min = stream->channels_min;
runtime->hw.channels_max = stream->channels_max;
if (runtime->hw.formats)
- runtime->hw.formats &= formats & stream->formats;
+ runtime->hw.formats &= stream->formats;
else
- runtime->hw.formats = formats & stream->formats;
+ runtime->hw.formats = stream->formats;
runtime->hw.rates = stream->rates;
}
-static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
+static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
+ u64 *formats)
{
struct snd_soc_pcm_runtime *fe = substream->private_data;
struct snd_soc_dpcm *dpcm;
- u64 formats = ULLONG_MAX;
int stream = substream->stream;
if (!fe->dai_link->dpcm_merged_format)
- return formats;
+ return;
/*
* It returns merged BE codec format
@@ -1694,17 +1712,132 @@ static u64 dpcm_runtime_base_format(struct snd_pcm_substream *substream)
int i;
for (i = 0; i < be->num_codecs; i++) {
+ /*
+ * Skip CODECs which don't support the current stream
+ * type. See soc_pcm_init_runtime_hw() for more details
+ */
+ if (!snd_soc_dai_stream_valid(be->codec_dais[i],
+ stream))
+ continue;
+
codec_dai_drv = be->codec_dais[i]->driver;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
codec_stream = &codec_dai_drv->playback;
else
codec_stream = &codec_dai_drv->capture;
- formats &= codec_stream->formats;
+ *formats &= codec_stream->formats;
}
}
+}
+
+static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
+ unsigned int *channels_min,
+ unsigned int *channels_max)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ struct snd_soc_dpcm *dpcm;
+ int stream = substream->stream;
- return formats;
+ if (!fe->dai_link->dpcm_merged_chan)
+ return;
+
+ /*
+ * It returns merged BE codec channel;
+ * if FE want to use it (= dpcm_merged_chan)
+ */
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
+ struct snd_soc_dai_driver *codec_dai_drv;
+ struct snd_soc_pcm_stream *codec_stream;
+ struct snd_soc_pcm_stream *cpu_stream;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_stream = &cpu_dai_drv->playback;
+ else
+ cpu_stream = &cpu_dai_drv->capture;
+
+ *channels_min = max(*channels_min, cpu_stream->channels_min);
+ *channels_max = min(*channels_max, cpu_stream->channels_max);
+
+ /*
+ * chan min/max cannot be enforced if there are multiple CODEC
+ * DAIs connected to a single CPU DAI, use CPU DAI's directly
+ */
+ if (be->num_codecs == 1) {
+ codec_dai_drv = be->codec_dais[0]->driver;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ codec_stream = &codec_dai_drv->playback;
+ else
+ codec_stream = &codec_dai_drv->capture;
+
+ *channels_min = max(*channels_min,
+ codec_stream->channels_min);
+ *channels_max = min(*channels_max,
+ codec_stream->channels_max);
+ }
+ }
+}
+
+static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
+ unsigned int *rates,
+ unsigned int *rate_min,
+ unsigned int *rate_max)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ struct snd_soc_dpcm *dpcm;
+ int stream = substream->stream;
+
+ if (!fe->dai_link->dpcm_merged_rate)
+ return;
+
+ /*
+ * It returns merged BE codec channel;
+ * if FE want to use it (= dpcm_merged_chan)
+ */
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
+ struct snd_soc_dai_driver *codec_dai_drv;
+ struct snd_soc_pcm_stream *codec_stream;
+ struct snd_soc_pcm_stream *cpu_stream;
+ int i;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_stream = &cpu_dai_drv->playback;
+ else
+ cpu_stream = &cpu_dai_drv->capture;
+
+ *rate_min = max(*rate_min, cpu_stream->rate_min);
+ *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
+ *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
+
+ for (i = 0; i < be->num_codecs; i++) {
+ /*
+ * Skip CODECs which don't support the current stream
+ * type. See soc_pcm_init_runtime_hw() for more details
+ */
+ if (!snd_soc_dai_stream_valid(be->codec_dais[i],
+ stream))
+ continue;
+
+ codec_dai_drv = be->codec_dais[i]->driver;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ codec_stream = &codec_dai_drv->playback;
+ else
+ codec_stream = &codec_dai_drv->capture;
+
+ *rate_min = max(*rate_min, codec_stream->rate_min);
+ *rate_max = min_not_zero(*rate_max,
+ codec_stream->rate_max);
+ *rates = snd_pcm_rate_mask_intersect(*rates,
+ codec_stream->rates);
+ }
+ }
}
static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
@@ -1713,12 +1846,17 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
- u64 format = dpcm_runtime_base_format(substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback, format);
+ dpcm_init_runtime_hw(runtime, &cpu_dai_drv->playback);
else
- dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture, format);
+ dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
+
+ dpcm_runtime_merge_format(substream, &runtime->hw.formats);
+ dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
+ &runtime->hw.channels_max);
+ dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
+ &runtime->hw.rate_min, &runtime->hw.rate_max);
}
static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
@@ -2543,106 +2681,113 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
return ret;
}
-/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
- * any DAI links.
- */
-int soc_dpcm_runtime_update(struct snd_soc_card *card)
+static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
{
- struct snd_soc_pcm_runtime *fe;
- int old, new, paths;
+ struct snd_soc_dapm_widget_list *list;
+ int count, paths;
- mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
- list_for_each_entry(fe, &card->rtd_list, list) {
- struct snd_soc_dapm_widget_list *list;
+ if (!fe->dai_link->dynamic)
+ return 0;
- /* make sure link is FE */
- if (!fe->dai_link->dynamic)
- continue;
+ /* only check active links */
+ if (!fe->cpu_dai->active)
+ return 0;
- /* only check active links */
- if (!fe->cpu_dai->active)
- continue;
+ /* DAPM sync will call this to update DSP paths */
+ dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n",
+ new ? "new" : "old", fe->dai_link->name);
- /* DAPM sync will call this to update DSP paths */
- dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n",
- fe->dai_link->name);
+ /* skip if FE doesn't have playback capability */
+ if (!fe->cpu_dai->driver->playback.channels_min ||
+ !fe->codec_dai->driver->playback.channels_min)
+ goto capture;
- /* skip if FE doesn't have playback capability */
- if (!fe->cpu_dai->driver->playback.channels_min
- || !fe->codec_dai->driver->playback.channels_min)
- goto capture;
-
- /* skip if FE isn't currently playing */
- if (!fe->cpu_dai->playback_active
- || !fe->codec_dai->playback_active)
- goto capture;
-
- paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
- if (paths < 0) {
- dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
- fe->dai_link->name, "playback");
- mutex_unlock(&card->mutex);
- return paths;
- }
+ /* skip if FE isn't currently playing */
+ if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active)
+ goto capture;
- /* update any new playback paths */
- new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
- if (new) {
- dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
- dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
- dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
- }
+ paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
+ if (paths < 0) {
+ dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
+ fe->dai_link->name, "playback");
+ return paths;
+ }
- /* update any old playback paths */
- old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
- if (old) {
+ /* update any playback paths */
+ count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new);
+ if (count) {
+ if (new)
+ dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ else
dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
- dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
- dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
- }
- dpcm_path_put(&list);
+ dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+
+ dpcm_path_put(&list);
+
capture:
- /* skip if FE doesn't have capture capability */
- if (!fe->cpu_dai->driver->capture.channels_min
- || !fe->codec_dai->driver->capture.channels_min)
- continue;
+ /* skip if FE doesn't have capture capability */
+ if (!fe->cpu_dai->driver->capture.channels_min ||
+ !fe->codec_dai->driver->capture.channels_min)
+ return 0;
- /* skip if FE isn't currently capturing */
- if (!fe->cpu_dai->capture_active
- || !fe->codec_dai->capture_active)
- continue;
+ /* skip if FE isn't currently capturing */
+ if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active)
+ return 0;
- paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
- if (paths < 0) {
- dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
- fe->dai_link->name, "capture");
- mutex_unlock(&card->mutex);
- return paths;
- }
+ paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
+ if (paths < 0) {
+ dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
+ fe->dai_link->name, "capture");
+ return paths;
+ }
- /* update any new capture paths */
- new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
- if (new) {
+ /* update any old capture paths */
+ count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new);
+ if (count) {
+ if (new)
dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
- dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
- dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
- }
-
- /* update any old capture paths */
- old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
- if (old) {
+ else
dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
- dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
- dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
- }
- dpcm_path_put(&list);
+ dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+ dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
}
- mutex_unlock(&card->mutex);
+ dpcm_path_put(&list);
+
return 0;
}
+
+/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
+ * any DAI links.
+ */
+int soc_dpcm_runtime_update(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *fe;
+ int ret = 0;
+
+ mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ /* shutdown all old paths first */
+ list_for_each_entry(fe, &card->rtd_list, list) {
+ ret = soc_dpcm_fe_runtime_update(fe, 0);
+ if (ret)
+ goto out;
+ }
+
+ /* bring new paths up */
+ list_for_each_entry(fe, &card->rtd_list, list) {
+ ret = soc_dpcm_fe_runtime_update(fe, 1);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&card->mutex);
+ return ret;
+}
int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
{
struct snd_soc_dpcm *dpcm;
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 53f121a50c97..66e77e020745 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1,29 +1,24 @@
-/*
- * soc-topology.c -- ALSA SoC Topology
- *
- * Copyright (C) 2012 Texas Instruments Inc.
- * Copyright (C) 2015 Intel Corporation.
- *
- * Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- * K, Mythri P <mythri.p.k@intel.com>
- * Prusty, Subhransu S <subhransu.s.prusty@intel.com>
- * B, Jayachandran <jayachandran.b@intel.com>
- * Abdullah, Omair M <omair.m.abdullah@intel.com>
- * Jin, Yao <yao.jin@intel.com>
- * Lin, Mengdong <mengdong.lin@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * Add support to read audio firmware topology alongside firmware text. The
- * topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links,
- * equalizers, firmware, coefficients etc.
- *
- * This file only manages the core ALSA and ASoC components, all other bespoke
- * firmware topology data is passed to component drivers for bespoke handling.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-topology.c -- ALSA SoC Topology
+//
+// Copyright (C) 2012 Texas Instruments Inc.
+// Copyright (C) 2015 Intel Corporation.
+//
+// Authors: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+// K, Mythri P <mythri.p.k@intel.com>
+// Prusty, Subhransu S <subhransu.s.prusty@intel.com>
+// B, Jayachandran <jayachandran.b@intel.com>
+// Abdullah, Omair M <omair.m.abdullah@intel.com>
+// Jin, Yao <yao.jin@intel.com>
+// Lin, Mengdong <mengdong.lin@intel.com>
+//
+// Add support to read audio firmware topology alongside firmware text. The
+// topology data can contain kcontrols, DAPM graphs, widgets, DAIs, DAI links,
+// equalizers, firmware, coefficients etc.
+//
+// This file only manages the core ALSA and ASoC components, all other bespoke
+// firmware topology data is passed to component drivers for bespoke handling.
#include <linux/kernel.h>
#include <linux/export.h>
@@ -259,7 +254,7 @@ static int soc_tplg_vendor_load_(struct soc_tplg *tplg,
int ret = 0;
if (tplg->comp && tplg->ops && tplg->ops->vendor_load)
- ret = tplg->ops->vendor_load(tplg->comp, hdr);
+ ret = tplg->ops->vendor_load(tplg->comp, tplg->index, hdr);
else {
dev_err(tplg->dev, "ASoC: no vendor load callback for ID %d\n",
hdr->vendor_type);
@@ -291,7 +286,8 @@ static int soc_tplg_widget_load(struct soc_tplg *tplg,
struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
{
if (tplg->comp && tplg->ops && tplg->ops->widget_load)
- return tplg->ops->widget_load(tplg->comp, w, tplg_w);
+ return tplg->ops->widget_load(tplg->comp, tplg->index, w,
+ tplg_w);
return 0;
}
@@ -302,27 +298,30 @@ static int soc_tplg_widget_ready(struct soc_tplg *tplg,
struct snd_soc_dapm_widget *w, struct snd_soc_tplg_dapm_widget *tplg_w)
{
if (tplg->comp && tplg->ops && tplg->ops->widget_ready)
- return tplg->ops->widget_ready(tplg->comp, w, tplg_w);
+ return tplg->ops->widget_ready(tplg->comp, tplg->index, w,
+ tplg_w);
return 0;
}
/* pass DAI configurations to component driver for extra initialization */
static int soc_tplg_dai_load(struct soc_tplg *tplg,
- struct snd_soc_dai_driver *dai_drv)
+ struct snd_soc_dai_driver *dai_drv,
+ struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai)
{
if (tplg->comp && tplg->ops && tplg->ops->dai_load)
- return tplg->ops->dai_load(tplg->comp, dai_drv);
+ return tplg->ops->dai_load(tplg->comp, tplg->index, dai_drv,
+ pcm, dai);
return 0;
}
/* pass link configurations to component driver for extra initialization */
static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
- struct snd_soc_dai_link *link)
+ struct snd_soc_dai_link *link, struct snd_soc_tplg_link_config *cfg)
{
if (tplg->comp && tplg->ops && tplg->ops->link_load)
- return tplg->ops->link_load(tplg->comp, link);
+ return tplg->ops->link_load(tplg->comp, tplg->index, link, cfg);
return 0;
}
@@ -643,7 +642,8 @@ static int soc_tplg_init_kcontrol(struct soc_tplg *tplg,
struct snd_kcontrol_new *k, struct snd_soc_tplg_ctl_hdr *hdr)
{
if (tplg->comp && tplg->ops && tplg->ops->control_load)
- return tplg->ops->control_load(tplg->comp, k, hdr);
+ return tplg->ops->control_load(tplg->comp, tplg->index, k,
+ hdr);
return 0;
}
@@ -1100,6 +1100,17 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
return 0;
}
+/* optionally pass new dynamic kcontrol to component driver. */
+static int soc_tplg_add_route(struct soc_tplg *tplg,
+ struct snd_soc_dapm_route *route)
+{
+ if (tplg->comp && tplg->ops && tplg->ops->dapm_route_load)
+ return tplg->ops->dapm_route_load(tplg->comp, tplg->index,
+ route);
+
+ return 0;
+}
+
static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
@@ -1148,6 +1159,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
else
route.control = elem->control;
+ soc_tplg_add_route(tplg, &route);
+
/* add route, but keep going if some fail */
snd_soc_dapm_add_routes(dapm, &route, 1);
}
@@ -1702,7 +1715,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
dai_drv->compress_new = snd_soc_new_compress;
/* pass control to component driver for optional further init */
- ret = soc_tplg_dai_load(tplg, dai_drv);
+ ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
if (ret < 0) {
dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
kfree(dai_drv);
@@ -1772,7 +1785,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
set_link_flags(link, pcm->flag_mask, pcm->flags);
/* pass control to component driver for optional further init */
- ret = soc_tplg_dai_link_load(tplg, link);
+ ret = soc_tplg_dai_link_load(tplg, link, NULL);
if (ret < 0) {
dev_err(tplg->comp->dev, "ASoC: FE link loading failed\n");
kfree(link);
@@ -2080,7 +2093,7 @@ static int soc_tplg_link_config(struct soc_tplg *tplg,
set_link_flags(link, cfg->flag_mask, cfg->flags);
/* pass control to component driver for optional further init */
- ret = soc_tplg_dai_link_load(tplg, link);
+ ret = soc_tplg_dai_link_load(tplg, link, cfg);
if (ret < 0) {
dev_err(tplg->dev, "ASoC: physical link loading failed\n");
return ret;
@@ -2202,7 +2215,7 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
set_dai_flags(dai_drv, d->flag_mask, d->flags);
/* pass control to component driver for optional further init */
- ret = soc_tplg_dai_load(tplg, dai_drv);
+ ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
if (ret < 0) {
dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
return ret;
@@ -2311,7 +2324,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
/* pass control to component driver for optional further init */
if (tplg->comp && tplg->ops && tplg->ops->manifest)
- return tplg->ops->manifest(tplg->comp, _manifest);
+ return tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
if (!abi_match) /* free the duplicated one */
kfree(_manifest);
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index 2d9e98bd1530..e0c93496c0cd 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -1,17 +1,11 @@
-/*
- * soc-util.c -- ALSA SoC Audio Layer utility functions
- *
- * Copyright 2009 Wolfson Microelectronics PLC.
- *
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- * Liam Girdwood <lrg@slimlogic.co.uk>
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// soc-util.c -- ALSA SoC Audio Layer utility functions
+//
+// Copyright 2009 Wolfson Microelectronics PLC.
+//
+// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+// Liam Girdwood <lrg@slimlogic.co.uk>
#include <linux/platform_device.h>
#include <linux/export.h>
@@ -381,6 +375,6 @@ int __init snd_soc_util_init(void)
void __exit snd_soc_util_exit(void)
{
- platform_device_unregister(soc_dummy_dev);
platform_driver_unregister(&soc_dummy_driver);
+ platform_device_unregister(soc_dummy_dev);
}
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index d8b6936e544e..313dab2857ef 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -91,7 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player);
/* Stop the player */
- snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stop_xrun(player->substream);
}
ret = IRQ_HANDLED;
@@ -105,7 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player);
/* Stop the player */
- snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stop_xrun(player->substream);
ret = IRQ_HANDLED;
}
@@ -138,7 +138,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id)
dev_err(player->dev, "Underflow recovery failed\n");
/* Stop the player */
- snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stop_xrun(player->substream);
ret = IRQ_HANDLED;
}
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
index ee0055e60852..7b63d35ef428 100644
--- a/sound/soc/sti/uniperif_reader.c
+++ b/sound/soc/sti/uniperif_reader.c
@@ -65,7 +65,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id)
if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) {
dev_err(reader->dev, "FIFO error detected\n");
- snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stop_xrun(reader->substream);
ret = IRQ_HANDLED;
}
diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig
index 48f9ddd94016..9b2681397dba 100644
--- a/sound/soc/stm/Kconfig
+++ b/sound/soc/stm/Kconfig
@@ -6,6 +6,7 @@ config SND_SOC_STM32_SAI
depends on SND_SOC
select SND_SOC_GENERIC_DMAENGINE_PCM
select REGMAP_MMIO
+ select SND_PCM_IEC958
help
Say Y if you want to enable SAI for STM32
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index db73fef3e500..706ff005234f 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -149,7 +149,7 @@ static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
unsigned int old_pos = priv->pos;
unsigned int cur_size = size;
- dev_dbg(rtd->dev, "%s: buff_add :%p, pos = %d, size = %zu\n",
+ dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n",
__func__, &pcm_buff[priv->pos], priv->pos, size);
if ((priv->pos + size) > buff_size) {
@@ -269,16 +269,10 @@ static int stm32_adfsdm_pcm_new(struct snd_soc_pcm_runtime *rtd)
static void stm32_adfsdm_pcm_free(struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
- struct snd_soc_pcm_runtime *rtd;
- struct stm32_adfsdm_priv *priv;
substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
- if (substream) {
- rtd = substream->private_data;
- priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
-
+ if (substream)
snd_pcm_lib_preallocate_free_for_all(pcm);
- }
}
static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index cfeb219e1d78..06fba9650ac4 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -96,7 +96,8 @@
* @slot_mask: rx or tx active slots mask. set at init or at runtime
* @data_size: PCM data width. corresponds to PCM substream width.
* @spdif_frm_cnt: S/PDIF playback frame counter
- * @spdif_status_bits: S/PDIF status bits
+ * @snd_aes_iec958: iec958 data
+ * @ctrl_lock: control lock
*/
struct stm32_sai_sub_data {
struct platform_device *pdev;
@@ -125,7 +126,8 @@ struct stm32_sai_sub_data {
int slot_mask;
int data_size;
unsigned int spdif_frm_cnt;
- unsigned char spdif_status_bits[SAI_IEC60958_STATUS_BYTES];
+ struct snd_aes_iec958 iec958;
+ struct mutex ctrl_lock; /* protect resources accessed by controls */
};
enum stm32_sai_fifo_th {
@@ -184,10 +186,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static const unsigned char default_status_bits[SAI_IEC60958_STATUS_BYTES] = {
- 0, 0, 0, IEC958_AES3_CON_FS_48000,
-};
-
static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
.reg_bits = 32,
.reg_stride = 4,
@@ -210,6 +208,49 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
.fast_io = true,
};
+static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+
+ return 0;
+}
+
+static int snd_pcm_iec958_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol);
+
+ mutex_lock(&sai->ctrl_lock);
+ memcpy(uctl->value.iec958.status, sai->iec958.status, 4);
+ mutex_unlock(&sai->ctrl_lock);
+
+ return 0;
+}
+
+static int snd_pcm_iec958_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uctl)
+{
+ struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol);
+
+ mutex_lock(&sai->ctrl_lock);
+ memcpy(sai->iec958.status, uctl->value.iec958.status, 4);
+ mutex_unlock(&sai->ctrl_lock);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new iec958_ctls = {
+ .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = snd_pcm_iec958_info,
+ .get = snd_pcm_iec958_get,
+ .put = snd_pcm_iec958_put,
+};
+
static irqreturn_t stm32_sai_isr(int irq, void *devid)
{
struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
@@ -259,11 +300,8 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid)
status = SNDRV_PCM_STATE_XRUN;
}
- if (status != SNDRV_PCM_STATE_RUNNING) {
- snd_pcm_stream_lock(sai->substream);
- snd_pcm_stop(sai->substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(sai->substream);
- }
+ if (status != SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_stop_xrun(sai->substream);
return IRQ_HANDLED;
}
@@ -619,6 +657,59 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
}
}
+static void stm32_sai_init_iec958_status(struct stm32_sai_sub_data *sai)
+{
+ unsigned char *cs = sai->iec958.status;
+
+ cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+ cs[1] = IEC958_AES1_CON_GENERAL;
+ cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
+ cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;
+}
+
+static void stm32_sai_set_iec958_status(struct stm32_sai_sub_data *sai,
+ struct snd_pcm_runtime *runtime)
+{
+ if (!runtime)
+ return;
+
+ /* Force the sample rate according to runtime rate */
+ mutex_lock(&sai->ctrl_lock);
+ switch (runtime->rate) {
+ case 22050:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_22050;
+ break;
+ case 44100:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_44100;
+ break;
+ case 88200:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_88200;
+ break;
+ case 176400:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_176400;
+ break;
+ case 24000:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_24000;
+ break;
+ case 48000:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_48000;
+ break;
+ case 96000:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_96000;
+ break;
+ case 192000:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_192000;
+ break;
+ case 32000:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_32000;
+ break;
+ default:
+ sai->iec958.status[3] = IEC958_AES3_CON_FS_NOTID;
+ break;
+ }
+ mutex_unlock(&sai->ctrl_lock);
+}
+
static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
struct snd_pcm_hw_params *params)
{
@@ -709,7 +800,11 @@ static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
sai->data_size = params_width(params);
- if (!STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ /* Rate not already set in runtime structure */
+ substream->runtime->rate = params_rate(params);
+ stm32_sai_set_iec958_status(sai, substream->runtime);
+ } else {
ret = stm32_sai_set_slots(cpu_dai);
if (ret < 0)
return ret;
@@ -789,6 +884,20 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
sai->substream = NULL;
}
+static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
+ dev_dbg(&sai->pdev->dev, "%s: register iec controls", __func__);
+ return snd_ctl_add(rtd->pcm->card,
+ snd_ctl_new1(&iec958_ctls, sai));
+ }
+
+ return 0;
+}
+
static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
{
struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
@@ -809,6 +918,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
else
snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
+ /* Next settings are not relevant for spdif mode */
+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
+ return 0;
+
cr1_mask = SAI_XCR1_RX_TX;
if (STM_SAI_IS_CAPTURE(sai))
cr1 |= SAI_XCR1_RX_TX;
@@ -820,10 +933,6 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
sai->synco, sai->synci);
}
- if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
- memcpy(sai->spdif_status_bits, default_status_bits,
- sizeof(default_status_bits));
-
cr1_mask |= SAI_XCR1_SYNCEN_MASK;
cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
@@ -861,7 +970,7 @@ static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream,
/* Set channel status bit */
byte = frm_cnt >> 3;
mask = 1 << (frm_cnt - (byte << 3));
- if (sai->spdif_status_bits[byte] & mask)
+ if (sai->iec958.status[byte] & mask)
*ptr |= 0x04000000;
ptr++;
@@ -888,6 +997,7 @@ static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
static struct snd_soc_dai_driver stm32_sai_playback_dai[] = {
{
.probe = stm32_sai_dai_probe,
+ .pcm_new = stm32_sai_pcm_new,
.id = 1, /* avoid call to fmt_single_name() */
.playback = {
.channels_min = 1,
@@ -998,6 +1108,7 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev,
dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n");
return -EINVAL;
}
+ stm32_sai_init_iec958_status(sai);
sai->spdif = true;
sai->master = true;
}
@@ -1114,6 +1225,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
sai->id = (uintptr_t)of_id->data;
sai->pdev = pdev;
+ mutex_init(&sai->ctrl_lock);
platform_set_drvdata(pdev, sai);
sai->pdata = dev_get_drvdata(pdev->dev.parent);
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index affad46bf188..682ef33afb5f 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -377,7 +377,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
ret = clk_prepare_enable(ac97->clk_ac97);
if (ret) {
dev_err(&pdev->dev, "clk_enable failed: %d\n", ret);
- goto err;
+ goto err_clk_put;
}
ret = snd_soc_set_ac97_ops(&tegra20_ac97_ops);
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index 774fc6ad2026..2e561e946de2 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -173,7 +173,7 @@
/* Number of slots in frame, minus 1 */
#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16
#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7
-#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT)
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT)
/* TDM mode slot enable bitmask */
#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index 5197d6b18cb6..98d87801d57a 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -190,14 +190,14 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Property 'nvidia,i2s-controller' missing or invalid\n");
ret = -EINVAL;
- goto err;
+ goto err_put_codec_of_node;
}
tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node;
ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
if (ret)
- goto err;
+ goto err_put_cpu_of_node;
ret = snd_soc_register_card(card);
if (ret) {
@@ -210,6 +210,13 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
err_fini_utils:
tegra_asoc_utils_fini(&alc5632->util_data);
+err_put_cpu_of_node:
+ of_node_put(tegra_alc5632_dai.cpu_of_node);
+ tegra_alc5632_dai.cpu_of_node = NULL;
+ tegra_alc5632_dai.platform_of_node = NULL;
+err_put_codec_of_node:
+ of_node_put(tegra_alc5632_dai.codec_of_node);
+ tegra_alc5632_dai.codec_of_node = NULL;
err:
return ret;
}
@@ -223,6 +230,12 @@ static int tegra_alc5632_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&machine->util_data);
+ of_node_put(tegra_alc5632_dai.cpu_of_node);
+ tegra_alc5632_dai.cpu_of_node = NULL;
+ tegra_alc5632_dai.platform_of_node = NULL;
+ of_node_put(tegra_alc5632_dai.codec_of_node);
+ tegra_alc5632_dai.codec_of_node = NULL;
+
return 0;
}
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
index 0e4805c7b4ca..7081f15302cc 100644
--- a/sound/soc/tegra/tegra_rt5677.c
+++ b/sound/soc/tegra/tegra_rt5677.c
@@ -264,13 +264,13 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Property 'nvidia,i2s-controller' missing or invalid\n");
ret = -EINVAL;
- goto err;
+ goto err_put_codec_of_node;
}
tegra_rt5677_dai.platform_of_node = tegra_rt5677_dai.cpu_of_node;
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
if (ret)
- goto err;
+ goto err_put_cpu_of_node;
ret = snd_soc_register_card(card);
if (ret) {
@@ -283,6 +283,13 @@ static int tegra_rt5677_probe(struct platform_device *pdev)
err_fini_utils:
tegra_asoc_utils_fini(&machine->util_data);
+err_put_cpu_of_node:
+ of_node_put(tegra_rt5677_dai.cpu_of_node);
+ tegra_rt5677_dai.cpu_of_node = NULL;
+ tegra_rt5677_dai.platform_of_node = NULL;
+err_put_codec_of_node:
+ of_node_put(tegra_rt5677_dai.codec_of_node);
+ tegra_rt5677_dai.codec_of_node = NULL;
err:
return ret;
}
@@ -296,6 +303,12 @@ static int tegra_rt5677_remove(struct platform_device *pdev)
tegra_asoc_utils_fini(&machine->util_data);
+ tegra_rt5677_dai.platform_of_node = NULL;
+ of_node_put(tegra_rt5677_dai.codec_of_node);
+ tegra_rt5677_dai.codec_of_node = NULL;
+ of_node_put(tegra_rt5677_dai.cpu_of_node);
+ tegra_rt5677_dai.cpu_of_node = NULL;
+
return 0;
}
diff --git a/sound/soc/uniphier/aio-core.c b/sound/soc/uniphier/aio-core.c
index 638cb3fc5f7b..9bcba06ba52e 100644
--- a/sound/soc/uniphier/aio-core.c
+++ b/sound/soc/uniphier/aio-core.c
@@ -265,6 +265,57 @@ void aio_port_reset(struct uniphier_aio_sub *sub)
}
/**
+ * aio_port_set_ch - set channels of LPCM
+ * @sub: the AIO substream pointer, PCM substream only
+ * @ch : count of channels
+ *
+ * Set suitable slot selecting to input/output port block of AIO.
+ *
+ * This function may return error if non-PCM substream.
+ *
+ * Return: Zero if successful, otherwise a negative value on error.
+ */
+static int aio_port_set_ch(struct uniphier_aio_sub *sub)
+{
+ struct regmap *r = sub->aio->chip->regmap;
+ u32 slotsel_2ch[] = {
+ 0, 0, 0, 0, 0,
+ };
+ u32 slotsel_multi[] = {
+ OPORTMXTYSLOTCTR_SLOTSEL_SLOT0,
+ OPORTMXTYSLOTCTR_SLOTSEL_SLOT1,
+ OPORTMXTYSLOTCTR_SLOTSEL_SLOT2,
+ OPORTMXTYSLOTCTR_SLOTSEL_SLOT3,
+ OPORTMXTYSLOTCTR_SLOTSEL_SLOT4,
+ };
+ u32 mode, *slotsel;
+ int i;
+
+ switch (params_channels(&sub->params)) {
+ case 8:
+ case 6:
+ mode = OPORTMXTYSLOTCTR_MODE;
+ slotsel = slotsel_multi;
+ break;
+ case 2:
+ mode = 0;
+ slotsel = slotsel_2ch;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < AUD_MAX_SLOTSEL; i++) {
+ regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
+ OPORTMXTYSLOTCTR_MODE, mode);
+ regmap_update_bits(r, OPORTMXTYSLOTCTR(sub->swm->oport.map, i),
+ OPORTMXTYSLOTCTR_SLOTSEL_MASK, slotsel[i]);
+ }
+
+ return 0;
+}
+
+/**
* aio_port_set_rate - set sampling rate of LPCM
* @sub: the AIO substream pointer, PCM substream only
* @rate: Sampling rate in Hz.
@@ -276,7 +327,7 @@ void aio_port_reset(struct uniphier_aio_sub *sub)
*
* Return: Zero if successful, otherwise a negative value on error.
*/
-int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
+static int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
{
struct regmap *r = sub->aio->chip->regmap;
struct device *dev = &sub->aio->chip->pdev->dev;
@@ -395,7 +446,7 @@ int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate)
*
* Return: Zero if successful, otherwise a negative value on error.
*/
-int aio_port_set_fmt(struct uniphier_aio_sub *sub)
+static int aio_port_set_fmt(struct uniphier_aio_sub *sub)
{
struct regmap *r = sub->aio->chip->regmap;
struct device *dev = &sub->aio->chip->pdev->dev;
@@ -460,7 +511,7 @@ int aio_port_set_fmt(struct uniphier_aio_sub *sub)
*
* Return: Zero if successful, otherwise a negative value on error.
*/
-int aio_port_set_clk(struct uniphier_aio_sub *sub)
+static int aio_port_set_clk(struct uniphier_aio_sub *sub)
{
struct uniphier_aio_chip *chip = sub->aio->chip;
struct device *dev = &sub->aio->chip->pdev->dev;
@@ -575,6 +626,10 @@ int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
rate = params_rate(params);
}
+ ret = aio_port_set_ch(sub);
+ if (ret)
+ return ret;
+
ret = aio_port_set_rate(sub, rate);
if (ret)
return ret;
@@ -731,15 +786,28 @@ void aio_port_set_volume(struct uniphier_aio_sub *sub, int vol)
int aio_if_set_param(struct uniphier_aio_sub *sub, int pass_through)
{
struct regmap *r = sub->aio->chip->regmap;
- u32 v;
+ u32 memfmt, v;
if (sub->swm->dir == PORT_DIR_OUTPUT) {
- if (pass_through)
+ if (pass_through) {
v = PBOUTMXCTR0_ENDIAN_0123 |
PBOUTMXCTR0_MEMFMT_STREAM;
- else
- v = PBOUTMXCTR0_ENDIAN_3210 |
- PBOUTMXCTR0_MEMFMT_2CH;
+ } else {
+ switch (params_channels(&sub->params)) {
+ case 2:
+ memfmt = PBOUTMXCTR0_MEMFMT_2CH;
+ break;
+ case 6:
+ memfmt = PBOUTMXCTR0_MEMFMT_6CH;
+ break;
+ case 8:
+ memfmt = PBOUTMXCTR0_MEMFMT_8CH;
+ break;
+ default:
+ return -EINVAL;
+ }
+ v = PBOUTMXCTR0_ENDIAN_3210 | memfmt;
+ }
regmap_write(r, PBOUTMXCTR0(sub->swm->oif.map), v);
regmap_write(r, PBOUTMXCTR1(sub->swm->oif.map), 0);
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 2d9b7dde2ffa..ee90e6c3937c 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -219,15 +219,10 @@ static int uniphier_aio_set_pll(struct snd_soc_dai *dai, int pll_id,
unsigned int freq_out)
{
struct uniphier_aio *aio = uniphier_priv(dai);
- struct device *dev = &aio->chip->pdev->dev;
int ret;
if (!is_valid_pll(aio->chip, pll_id))
return -EINVAL;
- if (!aio->chip->plls[pll_id].enable) {
- dev_err(dev, "PLL(%d) is not implemented\n", pll_id);
- return -ENOTSUPP;
- }
ret = aio_chip_set_pll(aio->chip, pll_id, freq_out);
if (ret < 0)
diff --git a/sound/soc/uniphier/aio-ld11.c b/sound/soc/uniphier/aio-ld11.c
index ab04d3331be9..de962df245ba 100644
--- a/sound/soc/uniphier/aio-ld11.c
+++ b/sound/soc/uniphier/aio-ld11.c
@@ -286,7 +286,7 @@ static struct snd_soc_dai_driver uniphier_aio_dai_ld11[] = {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.rates = SNDRV_PCM_RATE_48000,
.channels_min = 2,
- .channels_max = 2,
+ .channels_max = 8,
},
.ops = &uniphier_aio_i2s_ops,
},
diff --git a/sound/soc/uniphier/aio-reg.h b/sound/soc/uniphier/aio-reg.h
index 45fdc6ae358a..734395dbcffb 100644
--- a/sound/soc/uniphier/aio-reg.h
+++ b/sound/soc/uniphier/aio-reg.h
@@ -374,6 +374,7 @@
#define OPORTMXTYVOLGAINSTATUS(n, m) (0x42108 + 0x400 * (n) + 0x20 * (m))
#define OPORTMXTYVOLGAINSTATUS_CUR_MASK GENMASK(15, 0)
#define OPORTMXTYSLOTCTR(n, m) (0x42114 + 0x400 * (n) + 0x20 * (m))
+#define OPORTMXTYSLOTCTR_MODE BIT(15)
#define OPORTMXTYSLOTCTR_SLOTSEL_MASK GENMASK(11, 8)
#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT0 (0x8 << 8)
#define OPORTMXTYSLOTCTR_SLOTSEL_SLOT1 (0x9 << 8)
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index aa89c2f6fa24..ca6ccbae0ee8 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -141,6 +141,9 @@ enum IEC61937_PC {
#define AUD_MIN_FRAGMENT_SIZE (4 * 1024)
#define AUD_MAX_FRAGMENT_SIZE (16 * 1024)
+/* max 5 slots, 10 channels, 2 channel in 1 slot */
+#define AUD_MAX_SLOTSEL 5
+
/*
* This is a selector for virtual register map of AIO.
*
@@ -322,9 +325,6 @@ int aio_chip_set_pll(struct uniphier_aio_chip *chip, int pll_id,
void aio_chip_init(struct uniphier_aio_chip *chip);
int aio_init(struct uniphier_aio_sub *sub);
void aio_port_reset(struct uniphier_aio_sub *sub);
-int aio_port_set_rate(struct uniphier_aio_sub *sub, int rate);
-int aio_port_set_fmt(struct uniphier_aio_sub *sub);
-int aio_port_set_clk(struct uniphier_aio_sub *sub);
int aio_port_set_param(struct uniphier_aio_sub *sub, int pass_through,
const struct snd_pcm_hw_params *params);
void aio_port_set_enable(struct uniphier_aio_sub *sub, int enable);
diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c
index dc955272f58b..389272eeba9a 100644
--- a/sound/soc/zte/zx-tdm.c
+++ b/sound/soc/zte/zx-tdm.c
@@ -144,8 +144,8 @@ static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
#define ZX_TDM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
#define ZX_TDM_FMTBIT \
- (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \
- SNDRV_PCM_FORMAT_A_LAW)
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_MU_LAW | \
+ SNDRV_PCM_FMTBIT_A_LAW)
static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
{
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index b840ff2dcfbb..64f3141a3e1b 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -163,20 +163,3 @@ int snd_emux_free(struct snd_emux *emu)
}
EXPORT_SYMBOL(snd_emux_free);
-
-
-/*
- * INIT part
- */
-
-static int __init alsa_emux_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_emux_exit(void)
-{
-}
-
-module_init(alsa_emux_init)
-module_exit(alsa_emux_exit)
diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c
index 8e34bc4e07ec..4bd1e98200d2 100644
--- a/sound/synth/util_mem.c
+++ b/sound/synth/util_mem.c
@@ -193,19 +193,3 @@ EXPORT_SYMBOL(snd_util_mem_avail);
EXPORT_SYMBOL(__snd_util_mem_alloc);
EXPORT_SYMBOL(__snd_util_mem_free);
EXPORT_SYMBOL(__snd_util_memblk_new);
-
-/*
- * INIT part
- */
-
-static int __init alsa_util_mem_init(void)
-{
- return 0;
-}
-
-static void __exit alsa_util_mem_exit(void)
-{
-}
-
-module_init(alsa_util_mem_init)
-module_exit(alsa_util_mem_exit)
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index 2dd2518a71d3..f8ef3e2a8ca0 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -565,7 +565,6 @@ static const struct snd_pcm_ops pcm_ops = {
.trigger = usb6fire_pcm_trigger,
.pointer = usb6fire_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 05440e2df8d9..d330f74c90e6 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -13,6 +13,7 @@ snd-usb-audio-objs := card.o \
mixer_scarlett.o \
mixer_us16x08.o \
pcm.o \
+ power.o \
proc.o \
quirks.o \
stream.o
diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index f35d29f49ffe..c6108a3d7f8f 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -348,7 +348,6 @@ static const struct snd_pcm_ops snd_usb_caiaq_ops = {
.trigger = snd_usb_caiaq_pcm_trigger,
.pointer = snd_usb_caiaq_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
@@ -636,6 +635,7 @@ static void read_completed(struct urb *urb)
struct device *dev;
struct urb *out = NULL;
int i, frame, len, send_it = 0, outframe = 0;
+ unsigned long flags;
size_t offset = 0;
if (urb->status || !info)
@@ -672,10 +672,10 @@ static void read_completed(struct urb *urb)
offset += len;
if (len > 0) {
- spin_lock(&cdev->spinlock);
+ spin_lock_irqsave(&cdev->spinlock, flags);
fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
- spin_unlock(&cdev->spinlock);
+ spin_unlock_irqrestore(&cdev->spinlock, flags);
check_for_elapsed_periods(cdev, cdev->sub_playback);
check_for_elapsed_periods(cdev, cdev->sub_capture);
send_it = 1;
diff --git a/sound/usb/card.c b/sound/usb/card.c
index a1ed798a1c6b..2bfe4e80a6b9 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -809,6 +809,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
if (!chip->num_suspended_intf++) {
list_for_each_entry(as, &chip->pcm_list, list) {
snd_pcm_suspend_all(as->pcm);
+ snd_usb_pcm_suspend(as);
as->substream[0].need_setup_ep =
as->substream[1].need_setup_ep = true;
}
@@ -824,6 +825,7 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
{
struct snd_usb_audio *chip = usb_get_intfdata(intf);
+ struct snd_usb_stream *as;
struct usb_mixer_interface *mixer;
struct list_head *p;
int err = 0;
@@ -834,6 +836,13 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume)
return 0;
atomic_inc(&chip->active); /* avoid autopm */
+
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ err = snd_usb_pcm_resume(as);
+ if (err < 0)
+ goto err_out;
+ }
+
/*
* ALSA leaves material resumption to user space
* we just notify and restart the mixers
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 9b41b7dda84f..ac785d15ced4 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -37,6 +37,7 @@ struct audioformat {
struct snd_usb_substream;
struct snd_usb_endpoint;
+struct snd_usb_power_domain;
struct snd_urb_ctx {
struct urb *urb;
@@ -115,6 +116,7 @@ struct snd_usb_substream {
int interface; /* current interface */
int endpoint; /* assigned endpoint */
struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
+ struct snd_usb_power_domain *str_pd; /* UAC3 Power Domain for streaming path */
snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */
unsigned int channels; /* current number of channels (for hw_params callback) */
unsigned int channels_max; /* max channels in the all audiofmts */
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index c79749613fa6..db5e39d67a90 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -513,14 +513,28 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
bool writeable;
u32 bmControls;
+ /* First, try to find a valid clock. This may trigger
+ * automatic clock selection if the current clock is not
+ * valid.
+ */
clock = snd_usb_clock_find_source(chip, fmt->protocol,
fmt->clock, true);
- if (clock < 0)
- return clock;
+ if (clock < 0) {
+ /* We did not find a valid clock, but that might be
+ * because the current sample rate does not match an
+ * external clock source. Try again without validation
+ * and we will do another validation after setting the
+ * rate.
+ */
+ clock = snd_usb_clock_find_source(chip, fmt->protocol,
+ fmt->clock, false);
+ if (clock < 0)
+ return clock;
+ }
prev_rate = get_sample_rate_v2v3(chip, iface, fmt->altsetting, clock);
if (prev_rate == rate)
- return 0;
+ goto validation;
if (fmt->protocol == UAC_VERSION_3) {
struct uac3_clock_source_descriptor *cs_desc;
@@ -577,6 +591,10 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
snd_usb_set_interface_quirk(dev);
}
+validation:
+ /* validate clock after rate change */
+ if (!uac_clock_source_is_valid(chip, fmt->protocol, clock))
+ return -ENXIO;
return 0;
}
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index c90607ebe155..d86be8bfe412 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -325,7 +325,6 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
unsigned long flags;
struct snd_usb_packet_info *uninitialized_var(packet);
struct snd_urb_ctx *ctx = NULL;
- struct urb *urb;
int err, i;
spin_lock_irqsave(&ep->lock, flags);
@@ -345,7 +344,6 @@ static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
return;
list_del_init(&ctx->ready_list);
- urb = ctx->urb;
/* copy over the length information */
for (i = 0; i < packet->packets; i++)
diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c
index 396c317115b1..e1fbb9cc9ea7 100644
--- a/sound/usb/hiface/pcm.c
+++ b/sound/usb/hiface/pcm.c
@@ -523,7 +523,6 @@ static const struct snd_pcm_ops pcm_ops = {
.trigger = hiface_pcm_trigger,
.pointer = hiface_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static int hiface_pcm_init_urb(struct pcm_urb *urb,
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index 750467fb95db..f47ba94e6f4a 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -367,12 +367,13 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
*/
static void toneport_setup(struct usb_line6_toneport *toneport)
{
- int ticks;
+ u32 ticks;
struct usb_line6 *line6 = &toneport->line6;
struct usb_device *usbdev = line6->usbdev;
/* sync time on device with host: */
- ticks = (int)get_seconds();
+ /* note: 32-bit timestamps overflow in year 2106 */
+ ticks = (u32)ktime_get_real_seconds();
line6_write_data(line6, 0x80c6, &ticks, 4);
/* enable device: */
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 2c1aaa3292bf..dcfc546d81b9 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -281,15 +281,16 @@ static void snd_usbmidi_out_urb_complete(struct urb *urb)
struct out_urb_context *context = urb->context;
struct snd_usb_midi_out_endpoint *ep = context->ep;
unsigned int urb_index;
+ unsigned long flags;
- spin_lock(&ep->buffer_lock);
+ spin_lock_irqsave(&ep->buffer_lock, flags);
urb_index = context - ep->urbs;
ep->active_urbs &= ~(1 << urb_index);
if (unlikely(ep->drain_urbs)) {
ep->drain_urbs &= ~(1 << urb_index);
wake_up(&ep->drain_wait);
}
- spin_unlock(&ep->buffer_lock);
+ spin_unlock_irqrestore(&ep->buffer_lock, flags);
if (urb->status < 0) {
int err = snd_usbmidi_urb_error(urb);
if (err < 0) {
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 386fbfd5c617..a0b6d039017f 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -900,7 +900,6 @@ static const struct snd_pcm_ops capture_pcm_ops = {
.trigger = capture_pcm_trigger,
.pointer = capture_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops playback_pcm_ops = {
@@ -913,7 +912,6 @@ static const struct snd_pcm_ops playback_pcm_ops = {
.trigger = playback_pcm_trigger,
.pointer = playback_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct uac_format_type_i_discrete_descriptor *
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index ca963e94ec03..c63c84b54969 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -675,16 +675,16 @@ static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iter
if (term_only)
return 0;
switch (iterm->type >> 16) {
- case UAC_SELECTOR_UNIT:
+ case UAC3_SELECTOR_UNIT:
strcpy(name, "Selector");
return 8;
- case UAC1_PROCESSING_UNIT:
+ case UAC3_PROCESSING_UNIT:
strcpy(name, "Process Unit");
return 12;
- case UAC1_EXTENSION_UNIT:
+ case UAC3_EXTENSION_UNIT:
strcpy(name, "Ext Unit");
return 8;
- case UAC_MIXER_UNIT:
+ case UAC3_MIXER_UNIT:
strcpy(name, "Mixer");
return 5;
default:
@@ -832,7 +832,7 @@ static int check_input_term(struct mixer_build *state, int id,
case UAC_MIXER_UNIT: {
struct uac_mixer_unit_descriptor *d = p1;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
term->channels = uac_mixer_unit_bNrChannels(d);
term->chconfig = uac_mixer_unit_wChannelConfig(d, protocol);
term->name = uac_mixer_unit_iMixer(d);
@@ -845,15 +845,25 @@ static int check_input_term(struct mixer_build *state, int id,
err = check_input_term(state, d->baSourceID[0], term);
if (err < 0)
return err;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
term->id = id;
term->name = uac_selector_unit_iSelector(d);
return 0;
}
case UAC1_PROCESSING_UNIT:
+ /* UAC2_EFFECT_UNIT */
+ if (protocol == UAC_VERSION_1)
+ term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
+ else /* UAC_VERSION_2 */
+ term->type = UAC3_EFFECT_UNIT << 16; /* virtual type */
+ /* fall through */
case UAC1_EXTENSION_UNIT:
/* UAC2_PROCESSING_UNIT_V2 */
- /* UAC2_EFFECT_UNIT */
+ if (protocol == UAC_VERSION_1 && !term->type)
+ term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */
+ else if (protocol == UAC_VERSION_2 && !term->type)
+ term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
+ /* fall through */
case UAC2_EXTENSION_UNIT_V2: {
struct uac_processing_unit_descriptor *d = p1;
@@ -869,7 +879,9 @@ static int check_input_term(struct mixer_build *state, int id,
id = d->baSourceID[0];
break; /* continue to parse */
}
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ if (!term->type)
+ term->type = UAC3_EXTENSION_UNIT << 16; /* virtual type */
+
term->channels = uac_processing_unit_bNrChannels(d);
term->chconfig = uac_processing_unit_wChannelConfig(d, protocol);
term->name = uac_processing_unit_iProcessing(d, protocol);
@@ -878,7 +890,7 @@ static int check_input_term(struct mixer_build *state, int id,
case UAC2_CLOCK_SOURCE: {
struct uac_clock_source_descriptor *d = p1;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
term->id = id;
term->name = d->iClockSource;
return 0;
@@ -923,7 +935,7 @@ static int check_input_term(struct mixer_build *state, int id,
case UAC3_CLOCK_SOURCE: {
struct uac3_clock_source_descriptor *d = p1;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ term->type = UAC3_CLOCK_SOURCE << 16; /* virtual type */
term->id = id;
term->name = le16_to_cpu(d->wClockSourceStr);
return 0;
@@ -936,7 +948,37 @@ static int check_input_term(struct mixer_build *state, int id,
return err;
term->channels = err;
- term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ term->type = UAC3_MIXER_UNIT << 16; /* virtual type */
+
+ return 0;
+ }
+ case UAC3_SELECTOR_UNIT:
+ case UAC3_CLOCK_SELECTOR: {
+ struct uac_selector_unit_descriptor *d = p1;
+ /* call recursively to retrieve the channel info */
+ err = check_input_term(state, d->baSourceID[0], term);
+ if (err < 0)
+ return err;
+ term->type = UAC3_SELECTOR_UNIT << 16; /* virtual type */
+ term->id = id;
+ term->name = 0; /* TODO: UAC3 Class-specific strings */
+
+ return 0;
+ }
+ case UAC3_PROCESSING_UNIT: {
+ struct uac_processing_unit_descriptor *d = p1;
+
+ if (!d->bNrInPins)
+ return -EINVAL;
+
+ /* call recursively to retrieve the channel info */
+ err = check_input_term(state, d->baSourceID[0], term);
+ if (err < 0)
+ return err;
+
+ term->type = UAC3_PROCESSING_UNIT << 16; /* virtual type */
+ term->id = id;
+ term->name = 0; /* TODO: UAC3 Class-specific strings */
return 0;
}
@@ -2167,6 +2209,11 @@ struct procunit_info {
struct procunit_value_info *values;
};
+static struct procunit_value_info undefined_proc_info[] = {
+ { 0x00, "Control Undefined", 0 },
+ { 0 }
+};
+
static struct procunit_value_info updown_proc_info[] = {
{ UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN },
{ UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
@@ -2215,6 +2262,23 @@ static struct procunit_info procunits[] = {
{ UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info },
{ 0 },
};
+
+static struct procunit_value_info uac3_updown_proc_info[] = {
+ { UAC3_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
+ { 0 }
+};
+static struct procunit_value_info uac3_stereo_ext_proc_info[] = {
+ { UAC3_EXT_WIDTH_CONTROL, "Width Control", USB_MIXER_U8 },
+ { 0 }
+};
+
+static struct procunit_info uac3_procunits[] = {
+ { UAC3_PROCESS_UP_DOWNMIX, "Up Down", uac3_updown_proc_info },
+ { UAC3_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", uac3_stereo_ext_proc_info },
+ { UAC3_PROCESS_MULTI_FUNCTION, "Multi-Function", undefined_proc_info },
+ { 0 },
+};
+
/*
* predefined data for extension units
*/
@@ -2287,8 +2351,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
for (valinfo = info->values; valinfo->control; valinfo++) {
__u8 *controls = uac_processing_unit_bmControls(desc, state->mixer->protocol);
- if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1))))
- continue;
+ if (state->mixer->protocol == UAC_VERSION_1) {
+ if (!(controls[valinfo->control / 8] &
+ (1 << ((valinfo->control % 8) - 1))))
+ continue;
+ } else { /* UAC_VERSION_2/3 */
+ if (!uac_v2v3_control_is_readable(controls[valinfo->control / 8],
+ valinfo->control))
+ continue;
+ }
+
map = find_map(state->map, unitid, valinfo->control);
if (check_ignored_ctl(map))
continue;
@@ -2300,26 +2372,55 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
cval->val_type = valinfo->val_type;
cval->channels = 1;
+ if (state->mixer->protocol > UAC_VERSION_1 &&
+ !uac_v2v3_control_is_writeable(controls[valinfo->control / 8],
+ valinfo->control))
+ cval->master_readonly = 1;
+
/* get min/max values */
- if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) {
- __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol);
- /* FIXME: hard-coded */
- cval->min = 1;
- cval->max = control_spec[0];
- cval->res = 1;
- cval->initialized = 1;
- } else {
- if (type == USB_XU_CLOCK_RATE) {
- /*
- * E-Mu USB 0404/0202/TrackerPre/0204
- * samplerate control quirk
- */
- cval->min = 0;
- cval->max = 5;
+ switch (type) {
+ case UAC_PROCESS_UP_DOWNMIX: {
+ bool mode_sel = false;
+
+ switch (state->mixer->protocol) {
+ case UAC_VERSION_1:
+ case UAC_VERSION_2:
+ default:
+ if (cval->control == UAC_UD_MODE_SELECT)
+ mode_sel = true;
+ break;
+ case UAC_VERSION_3:
+ if (cval->control == UAC3_UD_MODE_SELECT)
+ mode_sel = true;
+ break;
+ }
+
+ if (mode_sel) {
+ __u8 *control_spec = uac_processing_unit_specific(desc,
+ state->mixer->protocol);
+ cval->min = 1;
+ cval->max = control_spec[0];
cval->res = 1;
cval->initialized = 1;
- } else
- get_min_max(cval, valinfo->min_value);
+ break;
+ }
+
+ get_min_max(cval, valinfo->min_value);
+ break;
+ }
+ case USB_XU_CLOCK_RATE:
+ /*
+ * E-Mu USB 0404/0202/TrackerPre/0204
+ * samplerate control quirk
+ */
+ cval->min = 0;
+ cval->max = 5;
+ cval->res = 1;
+ cval->initialized = 1;
+ break;
+ default:
+ get_min_max(cval, valinfo->min_value);
+ break;
}
kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
@@ -2362,8 +2463,16 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
static int parse_audio_processing_unit(struct mixer_build *state, int unitid,
void *raw_desc)
{
- return build_audio_procunit(state, unitid, raw_desc,
- procunits, "Processing Unit");
+ switch (state->mixer->protocol) {
+ case UAC_VERSION_1:
+ case UAC_VERSION_2:
+ default:
+ return build_audio_procunit(state, unitid, raw_desc,
+ procunits, "Processing Unit");
+ case UAC_VERSION_3:
+ return build_audio_procunit(state, unitid, raw_desc,
+ uac3_procunits, "Processing Unit");
+ }
}
static int parse_audio_extension_unit(struct mixer_build *state, int unitid,
@@ -2509,11 +2618,20 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
cval->res = 1;
cval->initialized = 1;
- if (state->mixer->protocol == UAC_VERSION_1)
+ switch (state->mixer->protocol) {
+ case UAC_VERSION_1:
+ default:
cval->control = 0;
- else /* UAC_VERSION_2 */
- cval->control = (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) ?
- UAC2_CX_CLOCK_SELECTOR : UAC2_SU_SELECTOR;
+ break;
+ case UAC_VERSION_2:
+ case UAC_VERSION_3:
+ if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
+ desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR)
+ cval->control = UAC2_CX_CLOCK_SELECTOR;
+ else /* UAC2/3_SELECTOR_UNIT */
+ cval->control = UAC2_SU_SELECTOR;
+ break;
+ }
namelist = kmalloc_array(desc->bNrInPins, sizeof(char *), GFP_KERNEL);
if (!namelist) {
@@ -2555,12 +2673,22 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (!len) {
/* no mapping ? */
+ switch (state->mixer->protocol) {
+ case UAC_VERSION_1:
+ case UAC_VERSION_2:
+ default:
/* if iSelector is given, use it */
- nameid = uac_selector_unit_iSelector(desc);
- if (nameid)
- len = snd_usb_copy_string_desc(state->chip, nameid,
- kctl->id.name,
- sizeof(kctl->id.name));
+ nameid = uac_selector_unit_iSelector(desc);
+ if (nameid)
+ len = snd_usb_copy_string_desc(state->chip,
+ nameid, kctl->id.name,
+ sizeof(kctl->id.name));
+ break;
+ case UAC_VERSION_3:
+ /* TODO: Class-Specific strings not yet supported */
+ break;
+ }
+
/* ... or pick up the terminal name at next */
if (!len)
len = get_term_name(state->chip, &state->oterm,
@@ -2570,7 +2698,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
/* and add the proper suffix */
- if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
+ if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR ||
+ desc->bDescriptorSubtype == UAC3_CLOCK_SELECTOR)
append_ctl_name(kctl, " Clock Source");
else if ((state->oterm.type & 0xff00) == 0x0100)
append_ctl_name(kctl, " Capture Source");
@@ -2641,6 +2770,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
return parse_audio_mixer_unit(state, unitid, p1);
case UAC3_CLOCK_SOURCE:
return parse_clock_source_unit(state, unitid, p1);
+ case UAC3_SELECTOR_UNIT:
case UAC3_CLOCK_SELECTOR:
return parse_audio_selector_unit(state, unitid, p1);
case UAC3_FEATURE_UNIT:
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index e02653465e29..3d12af8bf191 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -109,4 +109,6 @@ int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
extern void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl);
+extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+
#endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index e82a72fea9a1..cbfb48bdea51 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -47,8 +47,6 @@
#include "mixer_us16x08.h"
#include "helper.h"
-extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
-
struct std_mono_table {
unsigned int unitid, control, cmask;
int val_type;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 160f52c4871b..382847154227 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -711,6 +711,54 @@ static int configure_endpoint(struct snd_usb_substream *subs)
return ret;
}
+static int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state)
+{
+ int ret;
+
+ if (!subs->str_pd)
+ return 0;
+
+ ret = snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, state);
+ if (ret < 0) {
+ dev_err(&subs->dev->dev,
+ "Cannot change Power Domain ID: %d to state: %d. Err: %d\n",
+ subs->str_pd->pd_id, state, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int snd_usb_pcm_suspend(struct snd_usb_stream *as)
+{
+ int ret;
+
+ ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D2);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D2);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int snd_usb_pcm_resume(struct snd_usb_stream *as)
+{
+ int ret;
+
+ ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D1);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
/*
* hw_params callback
*
@@ -755,16 +803,22 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
ret = snd_usb_lock_shutdown(subs->stream->chip);
if (ret < 0)
return ret;
+
+ ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
+ if (ret < 0)
+ goto unlock;
+
ret = set_format(subs, fmt);
- snd_usb_unlock_shutdown(subs->stream->chip);
if (ret < 0)
- return ret;
+ goto unlock;
subs->interface = fmt->iface;
subs->altset_idx = fmt->altset_idx;
subs->need_setup_ep = true;
- return 0;
+ unlock:
+ snd_usb_unlock_shutdown(subs->stream->chip);
+ return ret;
}
/*
@@ -821,6 +875,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint);
snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);
+ ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
+ if (ret < 0)
+ goto unlock;
+
ret = set_format(subs, subs->cur_audiofmt);
if (ret < 0)
goto unlock;
@@ -1265,6 +1323,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
int direction = substream->stream;
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
struct snd_usb_substream *subs = &as->substream[direction];
+ int ret;
stop_endpoints(subs, true);
@@ -1273,7 +1332,10 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream)
!snd_usb_lock_shutdown(subs->stream->chip)) {
usb_set_interface(subs->dev, subs->interface, 0);
subs->interface = -1;
+ ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1);
snd_usb_unlock_shutdown(subs->stream->chip);
+ if (ret < 0)
+ return ret;
}
subs->pcm_substream = NULL;
@@ -1632,6 +1694,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
subs->trigger_tstamp_pending_update = true;
+ /* fall through */
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
subs->data_endpoint->retire_data_urb = retire_playback_urb;
@@ -1694,7 +1757,6 @@ static const struct snd_pcm_ops snd_usb_playback_ops = {
.trigger = snd_usb_substream_playback_trigger,
.pointer = snd_usb_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops snd_usb_capture_ops = {
@@ -1707,7 +1769,6 @@ static const struct snd_pcm_ops snd_usb_capture_ops = {
.trigger = snd_usb_substream_capture_trigger,
.pointer = snd_usb_pcm_pointer,
.page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
};
static const struct snd_pcm_ops snd_usb_playback_dev_ops = {
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h
index f77ec58bf1a1..9833627c1eca 100644
--- a/sound/usb/pcm.h
+++ b/sound/usb/pcm.h
@@ -6,6 +6,8 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
unsigned int rate);
void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
+int snd_usb_pcm_suspend(struct snd_usb_stream *as);
+int snd_usb_pcm_resume(struct snd_usb_stream *as);
int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
diff --git a/sound/usb/power.c b/sound/usb/power.c
new file mode 100644
index 000000000000..bd303a1ba1b7
--- /dev/null
+++ b/sound/usb/power.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * UAC3 Power Domain state management functions
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
+#include <linux/usb/audio-v3.h>
+
+#include "usbaudio.h"
+#include "helper.h"
+#include "power.h"
+
+struct snd_usb_power_domain *
+snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
+ unsigned char id)
+{
+ struct snd_usb_power_domain *pd;
+ void *p;
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return NULL;
+
+ p = NULL;
+ while ((p = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ p, UAC3_POWER_DOMAIN)) != NULL) {
+ struct uac3_power_domain_descriptor *pd_desc = p;
+ int i;
+
+ for (i = 0; i < pd_desc->bNrEntities; i++) {
+ if (pd_desc->baEntityID[i] == id) {
+ pd->pd_id = pd_desc->bPowerDomainID;
+ pd->pd_d1d0_rec =
+ le16_to_cpu(pd_desc->waRecoveryTime1);
+ pd->pd_d2d0_rec =
+ le16_to_cpu(pd_desc->waRecoveryTime2);
+ return pd;
+ }
+ }
+ }
+
+ kfree(pd);
+ return NULL;
+}
+
+int snd_usb_power_domain_set(struct snd_usb_audio *chip,
+ struct snd_usb_power_domain *pd,
+ unsigned char state)
+{
+ struct usb_device *dev = chip->dev;
+ unsigned char current_state;
+ int err, idx;
+
+ idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
+
+ err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+ UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
+ &current_state, sizeof(current_state));
+ if (err < 0) {
+ dev_err(&dev->dev, "Can't get UAC3 power state for id %d\n",
+ pd->pd_id);
+ return err;
+ }
+
+ if (current_state == state) {
+ dev_dbg(&dev->dev, "UAC3 power domain id %d already in state %d\n",
+ pd->pd_id, state);
+ return 0;
+ }
+
+ err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ UAC3_AC_POWER_DOMAIN_CONTROL << 8, idx,
+ &state, sizeof(state));
+ if (err < 0) {
+ dev_err(&dev->dev, "Can't set UAC3 power state to %d for id %d\n",
+ state, pd->pd_id);
+ return err;
+ }
+
+ if (state == UAC3_PD_STATE_D0) {
+ switch (current_state) {
+ case UAC3_PD_STATE_D2:
+ udelay(pd->pd_d2d0_rec * 50);
+ break;
+ case UAC3_PD_STATE_D1:
+ udelay(pd->pd_d1d0_rec * 50);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ dev_dbg(&dev->dev, "UAC3 power domain id %d change to state %d\n",
+ pd->pd_id, state);
+
+ return 0;
+}
diff --git a/sound/usb/power.h b/sound/usb/power.h
index b2e25f60c5a2..6004231a7c75 100644
--- a/sound/usb/power.h
+++ b/sound/usb/power.h
@@ -2,6 +2,25 @@
#ifndef __USBAUDIO_POWER_H
#define __USBAUDIO_POWER_H
+struct snd_usb_power_domain {
+ int pd_id; /* UAC3 Power Domain ID */
+ int pd_d1d0_rec; /* D1 to D0 recovery time */
+ int pd_d2d0_rec; /* D2 to D0 recovery time */
+};
+
+enum {
+ UAC3_PD_STATE_D0,
+ UAC3_PD_STATE_D1,
+ UAC3_PD_STATE_D2,
+};
+
+int snd_usb_power_domain_set(struct snd_usb_audio *chip,
+ struct snd_usb_power_domain *pd,
+ unsigned char state);
+struct snd_usb_power_domain *
+snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
+ unsigned char id);
+
#ifdef CONFIG_PM
int snd_usb_autoresume(struct snd_usb_audio *chip);
void snd_usb_autosuspend(struct snd_usb_audio *chip);
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 8aac48f9c322..08aa78007020 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2875,7 +2875,8 @@ YAMAHA_DEVICE(0x7010, "UB99"),
*/
#define AU0828_DEVICE(vid, pid, vname, pname) { \
- USB_DEVICE_VENDOR_SPEC(vid, pid), \
+ .idVendor = vid, \
+ .idProduct = pid, \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
USB_DEVICE_ID_MATCH_INT_CLASS | \
USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 02b6cc02767f..8a945ece9869 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1213,7 +1213,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
if (err < 0)
return err;
- mdelay(20); /* Delay needed after setting the interface */
+ msleep(20); /* Delay needed after setting the interface */
/* Vendor mode switch cmd is required. */
if (fmt->formats & SNDRV_PCM_FMTBIT_DSD_U32_BE) {
@@ -1234,7 +1234,7 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
return err;
}
- mdelay(20);
+ msleep(20);
}
return 0;
}
@@ -1281,7 +1281,7 @@ void snd_usb_set_interface_quirk(struct usb_device *dev)
switch (USB_ID_VENDOR(chip->usb_id)) {
case 0x23ba: /* Playback Design */
case 0x0644: /* TEAC Corp. */
- mdelay(50);
+ msleep(50);
break;
}
}
@@ -1301,7 +1301,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
*/
if (USB_ID_VENDOR(chip->usb_id) == 0x23ba &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- mdelay(20);
+ msleep(20);
/*
* "TEAC Corp." products need a 20ms delay after each
@@ -1309,14 +1309,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
*/
if (USB_ID_VENDOR(chip->usb_id) == 0x0644 &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- mdelay(20);
+ msleep(20);
/* ITF-USB DSD based DACs functionality need a delay
* after each class compliant request
*/
if (is_itf_usb_dsd_dac(chip->usb_id)
&& (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- mdelay(20);
+ msleep(20);
/* Zoom R16/24, Logitech H650e, Jabra 550a needs a tiny delay here,
* otherwise requests like get/set frequency return as failed despite
@@ -1326,7 +1326,7 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
chip->usb_id == USB_ID(0x046d, 0x0a46) ||
chip->usb_id == USB_ID(0x0b0e, 0x0349)) &&
(requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
- mdelay(1);
+ usleep_range(1000, 2000);
}
/*
@@ -1373,6 +1373,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
+ case USB_ID(0x16d0, 0x09dd): /* Encore mDSD */
case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */
case USB_ID(0x16b0, 0x06b2): /* NuPrime DAC-10 */
case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */
@@ -1443,6 +1444,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
*/
switch (USB_ID_VENDOR(chip->usb_id)) {
case 0x20b1: /* XMOS based devices */
+ case 0x152a: /* Thesycon devices */
case 0x25ce: /* Mytek devices */
if (fp->dsd_raw)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 729afd808cc4..67cf849aa16b 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -37,6 +37,7 @@
#include "format.h"
#include "clock.h"
#include "stream.h"
+#include "power.h"
/*
* free a substream
@@ -53,6 +54,7 @@ static void free_substream(struct snd_usb_substream *subs)
kfree(fp);
}
kfree(subs->rate_list.list);
+ kfree(subs->str_pd);
}
@@ -82,7 +84,8 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
static void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
- struct audioformat *fp)
+ struct audioformat *fp,
+ struct snd_usb_power_domain *pd)
{
struct snd_usb_substream *subs = &as->substream[stream];
@@ -107,6 +110,13 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
if (fp->channels > subs->channels_max)
subs->channels_max = fp->channels;
+ if (pd) {
+ subs->str_pd = pd;
+ /* Initialize Power Domain to idle status D1 */
+ snd_usb_power_domain_set(subs->stream->chip, pd,
+ UAC3_PD_STATE_D1);
+ }
+
snd_usb_preallocate_buffer(subs);
}
@@ -468,9 +478,11 @@ snd_pcm_chmap_elem *convert_chmap_v3(struct uac3_cluster_header_descriptor
* fmt_list and will be freed on the chip instance release. do not free
* fp or do remove it from the substream fmt_list to avoid double-free.
*/
-int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
- int stream,
- struct audioformat *fp)
+static int __snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+ int stream,
+ struct audioformat *fp,
+ struct snd_usb_power_domain *pd)
+
{
struct snd_usb_stream *as;
struct snd_usb_substream *subs;
@@ -498,7 +510,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
return err;
- snd_usb_init_substream(as, stream, fp);
+ snd_usb_init_substream(as, stream, fp, pd);
return add_chmap(as->pcm, stream, subs);
}
@@ -526,7 +538,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
else
strcpy(pcm->name, "USB Audio");
- snd_usb_init_substream(as, stream, fp);
+ snd_usb_init_substream(as, stream, fp, pd);
/*
* Keep using head insertion for M-Audio Audiophile USB (tm) which has a
@@ -544,6 +556,21 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
return add_chmap(pcm, stream, &as->substream[stream]);
}
+int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
+ int stream,
+ struct audioformat *fp)
+{
+ return __snd_usb_add_audio_stream(chip, stream, fp, NULL);
+}
+
+static int snd_usb_add_audio_stream_v3(struct snd_usb_audio *chip,
+ int stream,
+ struct audioformat *fp,
+ struct snd_usb_power_domain *pd)
+{
+ return __snd_usb_add_audio_stream(chip, stream, fp, pd);
+}
+
static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
int protocol, int iface_no)
@@ -819,6 +846,7 @@ found_clock:
static struct audioformat *
snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
struct usb_host_interface *alts,
+ struct snd_usb_power_domain **pd_out,
int iface_no, int altset_idx,
int altno, int stream)
{
@@ -829,6 +857,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
struct uac3_as_header_descriptor *as = NULL;
struct uac3_hc_descriptor_header hc_header;
struct snd_pcm_chmap_elem *chmap;
+ struct snd_usb_power_domain *pd;
unsigned char badd_profile;
u64 badd_formats = 0;
unsigned int num_channels;
@@ -1008,12 +1037,28 @@ found_clock:
fp->rate_max = UAC3_BADD_SAMPLING_RATE;
fp->rates = SNDRV_PCM_RATE_CONTINUOUS;
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ kfree(fp->rate_table);
+ kfree(fp);
+ return NULL;
+ }
+ pd->pd_id = (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ UAC3_BADD_PD_ID10 : UAC3_BADD_PD_ID11;
+ pd->pd_d1d0_rec = UAC3_BADD_PD_RECOVER_D1D0;
+ pd->pd_d2d0_rec = UAC3_BADD_PD_RECOVER_D2D0;
+
} else {
fp->attributes = parse_uac_endpoint_attributes(chip, alts,
UAC_VERSION_3,
iface_no);
+
+ pd = snd_usb_find_power_domain(chip->ctrl_intf,
+ as->bTerminalLink);
+
/* ok, let's parse further... */
if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) {
+ kfree(pd);
kfree(fp->chmap);
kfree(fp->rate_table);
kfree(fp);
@@ -1021,6 +1066,9 @@ found_clock:
}
}
+ if (pd)
+ *pd_out = pd;
+
return fp;
}
@@ -1032,6 +1080,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
struct usb_interface_descriptor *altsd;
int i, altno, err, stream;
struct audioformat *fp = NULL;
+ struct snd_usb_power_domain *pd = NULL;
int num, protocol;
dev = chip->dev;
@@ -1114,7 +1163,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
break;
}
case UAC_VERSION_3:
- fp = snd_usb_get_audioformat_uac3(chip, alts,
+ fp = snd_usb_get_audioformat_uac3(chip, alts, &pd,
iface_no, i, altno, stream);
break;
}
@@ -1125,9 +1174,14 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
return PTR_ERR(fp);
dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint);
- err = snd_usb_add_audio_stream(chip, stream, fp);
+ if (protocol == UAC_VERSION_3)
+ err = snd_usb_add_audio_stream_v3(chip, stream, fp, pd);
+ else
+ err = snd_usb_add_audio_stream(chip, stream, fp);
+
if (err < 0) {
list_del(&fp->list); /* unlink for avoiding double-free */
+ kfree(pd);
kfree(fp->rate_table);
kfree(fp->chmap);
kfree(fp);
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index 4ed9d0c41843..fa7dca5a68c8 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -290,7 +290,6 @@ static void had_reset_audio(struct snd_intelhad *intelhaddata)
static int had_prog_status_reg(struct snd_pcm_substream *substream,
struct snd_intelhad *intelhaddata)
{
- union aud_cfg cfg_val = {.regval = 0};
union aud_ch_status_0 ch_stat0 = {.regval = 0};
union aud_ch_status_1 ch_stat1 = {.regval = 0};
@@ -298,7 +297,6 @@ static int had_prog_status_reg(struct snd_pcm_substream *substream,
IEC958_AES0_NONAUDIO) >> 1;
ch_stat0.regx.clk_acc = (intelhaddata->aes_bits &
IEC958_AES3_CON_CLOCK) >> 4;
- cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id;
switch (substream->runtime->rate) {
case AUD_SAMPLE_RATE_32:
@@ -1854,7 +1852,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
/* setup private data which can be retrieved when required */
pcm->private_data = ctx;
pcm->info_flags = 0;
- strncpy(pcm->name, card->shortname, strlen(card->shortname));
+ strlcpy(pcm->name, card->shortname, strlen(card->shortname));
/* setup the ops for playabck */
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops);
diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c
index 5a2bd70a2fa1..129180e17db1 100644
--- a/sound/xen/xen_snd_front_alsa.c
+++ b/sound/xen/xen_snd_front_alsa.c
@@ -188,7 +188,7 @@ static u64 to_sndif_formats_mask(u64 alsa_formats)
mask = 0;
for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
- if (1 << ALSA_SNDIF_FORMATS[i].alsa & alsa_formats)
+ if (pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa) & alsa_formats)
mask |= 1 << ALSA_SNDIF_FORMATS[i].sndif;
return mask;
@@ -202,7 +202,7 @@ static u64 to_alsa_formats_mask(u64 sndif_formats)
mask = 0;
for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++)
if (1 << ALSA_SNDIF_FORMATS[i].sndif & sndif_formats)
- mask |= 1 << ALSA_SNDIF_FORMATS[i].alsa;
+ mask |= pcm_format_to_bits(ALSA_SNDIF_FORMATS[i].alsa);
return mask;
}