summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:04:59 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-19 10:04:59 -0700
commite5c91aac491def6ab3f90c4cc246e3fcb0f8f058 (patch)
tree20ce0b23e5e56efa3707c7ff4244fe4da65547c7
parenta93f3bf4e1d60777b1659b812c9e818cfc53b449 (diff)
parentc139e7e44f58a6f8ddc9d850ea9924d34963b5da (diff)
Merge tag 'sound-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "It was a fairly busy development cycle - the changes spread over from the core side to leaf drivers, with lots of cleanups and enhancements. Here we go, some highlights: ALSA core: - Extension of ALSA control component list ABI - Locking optimization and RCU conversion of ALSA sequencer core - A few hardening fixes for UMP and sequencer core - Drop __bitwise and __force prefix from UAPI definitions ASoC: - Automatic DAI format selection code deployment across many drivers - Sorting of register default tables to prevent ordering issues in many drivers - Lots of code cleanups and refactoring - Updates in Qualcomm driver stack - New platforms: AMD ACP7.B/F, Cirrus Logic CS35L62, Loongson 2K0300, Meson GX, Qualcomm LPI MI2S, SM8475, WSA855X, Realtek RT1321 VA1/2 and RT766/7 HD-audio: - Support for AW88399 HD-audio side codec for Lenovo Legion laptops - Support for Hygon and Lisuan HDMI controllers - Robustness fixes for wild device binding - Lots of quirks/fixups: Realtek and Conexant codecs for ASUS, Lenovo, Acer, etc USB-audio: - Support for Pioneer DJ DJM-S11 - Scarlett2/FCP private URB notification fixes - Extended quirk_flags to 64bit - Hardening fixes for 6fire, bcd2000, usx2y - Device-specific quirks for Mackie, Valeton, SPACETOUCH General: - Auto-cleanup for put_device() and firmware loading across multiple platforms" * tag 'sound-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (791 commits) ALSA: hda: Fix connection list comparison in proc output ALSA: docs: fix dead link to Intel HD-audio spec ALSA: usb-audio: Add delay quirk for SPACETOUCH USB Audio ALSA: hda: Add Lisuan HDMI controller and codec support ALSA: hda/realtek: Fix Lenovo Yoga Slim 7 14AKP10 quirk ordering ALSA: hda/tas2781: Add hardware stabilization delay during firmware load retries ALSA: hda/realtek: Fix mute LED for HP Victus 15-fa1xxx (MB 8C3F) ALSA: hda/realtek: Add micmute LED quirk for Acer Aspire A515-57 ASoC: tas2783-sdw: do not treat read-only Controls as writable ASoC: SOF: validate topology volume range before allocation ASoC: cs35l56: Use IRQ provided by the SoundWire core soundwire: bus_type: Create IRQ mapping before calling driver probe() ASoC: cs35l56: Move cs35l56_irq_request() after cs35l56_irq() ASoC: cs35l56: Request IRQ in cs35l56_common_probe() ALSA: core: Fix use-after-free in snd_card_do_free() ALSA: hda/realtek: Drop duplicate quirk for Lenovo 0x17aa:0x38df ALSA: usb-audio: Rename the Audient iD14 monitor mix volume control ASoC: tas2781: Refactor calibration start kcontrol creation to separate helper ASoC: dt-bindings: es8316: Fix supply property constraints ALSA: seq: midi: Serialize input teardown with event_input ...
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml240
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/cs35l36.txt168
-rw-r--r--Documentation/devicetree/bindings/sound/dmic-codec.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml61
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea-tlv320.txt26
-rw-r--r--Documentation/devicetree/bindings/sound/everest,es8316.yaml28
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,micfil.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml53
-rw-r--r--Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml22
-rw-r--r--Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml59
-rw-r--r--Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt24
-rw-r--r--Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/omap-dmic.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml8
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml11
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml50
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml4
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,sm8250.yaml31
-rw-r--r--Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml93
-rw-r--r--Documentation/devicetree/bindings/sound/realtek,rt1015.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,r9a09g047-sound.yaml2
-rw-r--r--Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml64
-rw-r--r--Documentation/devicetree/bindings/sound/st,sta32x.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml58
-rw-r--r--Documentation/devicetree/bindings/sound/wlf,wm8524.yaml4
-rw-r--r--Documentation/sound/alsa-configuration.rst5
-rw-r--r--Documentation/sound/hd-audio/notes.rst2
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c2
-rw-r--r--drivers/platform/x86/serial-multi-instantiate.c10
-rw-r--r--drivers/soundwire/bus_type.c6
-rw-r--r--include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h36
-rw-r--r--include/linux/platform_data/omap-twl4030.h42
-rw-r--r--include/sound/ac97/codec.h4
-rw-r--r--include/sound/asequencer.h3
-rw-r--r--include/sound/aw88399.h621
-rw-r--r--include/sound/control.h3
-rw-r--r--include/sound/core.h4
-rw-r--r--include/sound/cs35l56.h1
-rw-r--r--include/sound/dmaengine_pcm.h6
-rw-r--r--include/sound/hda-mlink.h23
-rw-r--r--include/sound/hda_codec.h1
-rw-r--r--include/sound/hda_regmap.h42
-rw-r--r--include/sound/pcm.h118
-rw-r--r--include/sound/pcm_params.h13
-rw-r--r--include/sound/rawmidi.h14
-rw-r--r--include/sound/sdca_asoc.h15
-rw-r--r--include/sound/sdca_fdl.h4
-rw-r--r--include/sound/sdca_function.h32
-rw-r--r--include/sound/sdca_hid.h11
-rw-r--r--include/sound/seq_virmidi.h1
-rw-r--r--include/sound/simple_card_utils.h37
-rw-r--r--include/sound/soc-acpi.h23
-rw-r--r--include/sound/soc-component.h11
-rw-r--r--include/sound/soc.h15
-rw-r--r--include/sound/soc_sdw_utils.h31
-rw-r--r--include/sound/sof/dai-amd.h1
-rw-r--r--include/sound/sof/dai.h3
-rw-r--r--include/sound/sof/header.h4
-rw-r--r--include/sound/sof/ipc4/header.h133
-rw-r--r--include/sound/tas2781-dsp.h7
-rw-r--r--include/sound/tlv320aic32x4.h43
-rw-r--r--include/sound/wm8904.h4
-rw-r--r--include/uapi/sound/asequencer.h18
-rw-r--r--include/uapi/sound/asound.h200
-rw-r--r--include/uapi/sound/firewire.h24
-rw-r--r--include/uapi/sound/skl-tplg-interface.h168
-rw-r--r--include/uapi/sound/snd_ar_tokens.h95
-rw-r--r--include/uapi/sound/snd_sst_tokens.h324
-rw-r--r--include/uapi/sound/sof/tokens.h5
-rw-r--r--sound/atmel/ac97c.c67
-rw-r--r--sound/core/compress_offload.c18
-rw-r--r--sound/core/control.c93
-rw-r--r--sound/core/control_compat.c15
-rw-r--r--sound/core/hwdep.c25
-rw-r--r--sound/core/info.c2
-rw-r--r--sound/core/init.c67
-rw-r--r--sound/core/jack.c38
-rw-r--r--sound/core/oss/mixer_oss.c19
-rw-r--r--sound/core/oss/pcm_oss.c43
-rw-r--r--sound/core/oss/pcm_plugin.c20
-rw-r--r--sound/core/pcm.c12
-rw-r--r--sound/core/pcm_misc.c25
-rw-r--r--sound/core/pcm_native.c90
-rw-r--r--sound/core/rawmidi.c32
-rw-r--r--sound/core/seq/oss/seq_oss.c21
-rw-r--r--sound/core/seq/seq_clientmgr.c114
-rw-r--r--sound/core/seq/seq_clientmgr.h1
-rw-r--r--sound/core/seq/seq_midi.c61
-rw-r--r--sound/core/seq/seq_ports.c103
-rw-r--r--sound/core/seq/seq_ports.h8
-rw-r--r--sound/core/seq/seq_ump_client.c38
-rw-r--r--sound/core/seq/seq_virmidi.c19
-rw-r--r--sound/core/sound.c25
-rw-r--r--sound/core/sound_kunit.c4
-rw-r--r--sound/core/timer.c30
-rw-r--r--sound/core/ump.c9
-rw-r--r--sound/core/ump_convert.c1
-rw-r--r--sound/drivers/aloop.c130
-rw-r--r--sound/drivers/dummy.c39
-rw-r--r--sound/drivers/mpu401/mpu401.c6
-rw-r--r--sound/drivers/mts64.c6
-rw-r--r--sound/drivers/portman2x4.c6
-rw-r--r--sound/drivers/serial-u16550.c6
-rw-r--r--sound/drivers/virmidi.c6
-rw-r--r--sound/hda/codecs/ca0132.c33
-rw-r--r--sound/hda/codecs/cm9825.c148
-rw-r--r--sound/hda/codecs/conexant.c16
-rw-r--r--sound/hda/codecs/generic.c23
-rw-r--r--sound/hda/codecs/hdmi/hdmi.c5
-rw-r--r--sound/hda/codecs/helpers/razer_blade16_2025.c820
-rw-r--r--sound/hda/codecs/realtek/alc269.c252
-rw-r--r--sound/hda/codecs/realtek/alc662.c7
-rw-r--r--sound/hda/codecs/side-codecs/Kconfig18
-rw-r--r--sound/hda/codecs/side-codecs/Makefile4
-rw-r--r--sound/hda/codecs/side-codecs/aw88399_hda.c373
-rw-r--r--sound/hda/codecs/side-codecs/aw88399_hda.h36
-rw-r--r--sound/hda/codecs/side-codecs/aw88399_hda_i2c.c54
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda.c43
-rw-r--r--sound/hda/codecs/side-codecs/cs35l56_hda.c35
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_i2c.c16
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_spi.c21
-rw-r--r--sound/hda/common/auto_parser.c66
-rw-r--r--sound/hda/common/codec.c13
-rw-r--r--sound/hda/common/hda_auto_parser.h2
-rw-r--r--sound/hda/common/hda_local.h7
-rw-r--r--sound/hda/common/jack.c4
-rw-r--r--sound/hda/common/proc.c2
-rw-r--r--sound/hda/controllers/Kconfig1
-rw-r--r--sound/hda/controllers/intel.c25
-rw-r--r--sound/hda/core/controller.c33
-rw-r--r--sound/hda/core/device.c3
-rw-r--r--sound/hda/core/ext/stream.c4
-rw-r--r--sound/hda/core/hda_bus_type.c9
-rw-r--r--sound/hda/core/stream.c40
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c18
-rw-r--r--sound/isa/sscape.c8
-rw-r--r--sound/isa/wavefront/wavefront_fx.c23
-rw-r--r--sound/isa/wavefront/wavefront_synth.c4
-rw-r--r--sound/pci/asihpi/asihpi.c2
-rw-r--r--sound/pci/asihpi/hpi6000.c5
-rw-r--r--sound/pci/asihpi/hpidspcd.c18
-rw-r--r--sound/pci/asihpi/hpioctl.c17
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c30
-rw-r--r--sound/pci/emu10k1/emufx.c18
-rw-r--r--sound/pci/korg1212/korg1212.c8
-rw-r--r--sound/pci/mixart/mixart_hwdep.c4
-rw-r--r--sound/pci/pcxhr/pcxhr_hwdep.c3
-rw-r--r--sound/pci/sis7019.c10
-rw-r--r--sound/pci/via82xx_modem.c26
-rw-r--r--sound/sh/aica.c4
-rw-r--r--sound/soc/amd/acp-config.c19
-rw-r--r--sound/soc/amd/acp-pcm-dma.c8
-rw-r--r--sound/soc/amd/acp/acp-i2s.c6
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c11
-rw-r--r--sound/soc/amd/acp/acp-pci.c26
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c20
-rw-r--r--sound/soc/amd/acp/acp-sdw-sof-mach.c16
-rw-r--r--sound/soc/amd/acp/acp-sof-mach.c14
-rw-r--r--sound/soc/amd/acp/amd-acp70-acpi-match.c56
-rw-r--r--sound/soc/amd/mach-config.h1
-rw-r--r--sound/soc/amd/raven/acp3x-i2s.c6
-rw-r--r--sound/soc/amd/vangogh/acp5x-i2s.c6
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c12
-rw-r--r--sound/soc/apple/mca.c315
-rw-r--r--sound/soc/atmel/atmel-i2s.c4
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c7
-rw-r--r--sound/soc/atmel/atmel_wm8904.c13
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c9
-rw-r--r--sound/soc/atmel/mchp-pdmc.c4
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/au1x/i2sc.c11
-rw-r--r--sound/soc/au1x/psc-ac97.c4
-rw-r--r--sound/soc/au1x/psc-i2s.c11
-rw-r--r--sound/soc/bcm/bcm2835-i2s.c13
-rw-r--r--sound/soc/bcm/cygnus-ssp.c7
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c11
-rw-r--r--sound/soc/codecs/Kconfig61
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ab8500-codec.c12
-rw-r--r--sound/soc/codecs/ad1836.c6
-rw-r--r--sound/soc/codecs/ad193x.c10
-rw-r--r--sound/soc/codecs/adau1761.c34
-rw-r--r--sound/soc/codecs/adau7118-hw.c2
-rw-r--r--sound/soc/codecs/adav80x.c8
-rw-r--r--sound/soc/codecs/ak4613.c83
-rw-r--r--sound/soc/codecs/arizona-jack.c117
-rw-r--r--sound/soc/codecs/arizona.c26
-rw-r--r--sound/soc/codecs/aw87390.c17
-rw-r--r--sound/soc/codecs/aw88081.c27
-rw-r--r--sound/soc/codecs/aw88166.c32
-rw-r--r--sound/soc/codecs/aw88261.c35
-rw-r--r--sound/soc/codecs/aw88261.h6
-rw-r--r--sound/soc/codecs/aw88395/aw88395.c32
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.c40
-rw-r--r--sound/soc/codecs/aw88399-lib.c1409
-rw-r--r--sound/soc/codecs/aw88399.c1358
-rw-r--r--sound/soc/codecs/aw88399.h582
-rw-r--r--sound/soc/codecs/bt-sco.c10
-rw-r--r--sound/soc/codecs/cpcap.c130
-rw-r--r--sound/soc/codecs/cros_ec_codec.c26
-rw-r--r--sound/soc/codecs/cs-amp-lib.c11
-rw-r--r--sound/soc/codecs/cs35l32.c10
-rw-r--r--sound/soc/codecs/cs35l33.c14
-rw-r--r--sound/soc/codecs/cs35l34.c14
-rw-r--r--sound/soc/codecs/cs35l56-i2c.c10
-rw-r--r--sound/soc/codecs/cs35l56-sdw.c71
-rw-r--r--sound/soc/codecs/cs35l56-shared.c69
-rw-r--r--sound/soc/codecs/cs35l56-spi.c10
-rw-r--r--sound/soc/codecs/cs35l56.c58
-rw-r--r--sound/soc/codecs/cs35l56.h11
-rw-r--r--sound/soc/codecs/cs40l50-codec.c4
-rw-r--r--sound/soc/codecs/cs42l42-sdw.c14
-rw-r--r--sound/soc/codecs/cs42l42.c54
-rw-r--r--sound/soc/codecs/cs42l43-jack.c138
-rw-r--r--sound/soc/codecs/cs42l43.c20
-rw-r--r--sound/soc/codecs/cs42l84.c10
-rw-r--r--sound/soc/codecs/cs43130.c72
-rw-r--r--sound/soc/codecs/cs4349.c8
-rw-r--r--sound/soc/codecs/cs47l15.c11
-rw-r--r--sound/soc/codecs/cs47l35.c11
-rw-r--r--sound/soc/codecs/cs47l85.c11
-rw-r--r--sound/soc/codecs/cs47l90.c11
-rw-r--r--sound/soc/codecs/cs47l92.c11
-rw-r--r--sound/soc/codecs/cs48l32.c26
-rw-r--r--sound/soc/codecs/cx2072x.c127
-rw-r--r--sound/soc/codecs/da7213.c37
-rw-r--r--sound/soc/codecs/da7219.c62
-rw-r--r--sound/soc/codecs/es8316.c44
-rw-r--r--sound/soc/codecs/es8326.c30
-rw-r--r--sound/soc/codecs/es8328.c5
-rw-r--r--sound/soc/codecs/es8389.c236
-rw-r--r--sound/soc/codecs/es8389.h11
-rw-r--r--sound/soc/codecs/es9356.c33
-rw-r--r--sound/soc/codecs/fs-amp-lib.c3
-rw-r--r--sound/soc/codecs/fs210x.c89
-rw-r--r--sound/soc/codecs/hdac_hda.c7
-rw-r--r--sound/soc/codecs/hdac_hdmi.c127
-rw-r--r--sound/soc/codecs/hdmi-codec.c15
-rw-r--r--sound/soc/codecs/idt821034.c144
-rw-r--r--sound/soc/codecs/lochnagar-sc.c8
-rw-r--r--sound/soc/codecs/lpass-macro-common.c12
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c137
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c128
-rw-r--r--sound/soc/codecs/lpass-va-macro.c137
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c138
-rw-r--r--sound/soc/codecs/madera.c51
-rw-r--r--sound/soc/codecs/max98090.c9
-rw-r--r--sound/soc/codecs/max98095.c35
-rw-r--r--sound/soc/codecs/max98363.c7
-rw-r--r--sound/soc/codecs/max98373-i2c.c9
-rw-r--r--sound/soc/codecs/max98373-sdw.c7
-rw-r--r--sound/soc/codecs/max98388.c8
-rw-r--r--sound/soc/codecs/max98390.c24
-rw-r--r--sound/soc/codecs/max98396.c24
-rw-r--r--sound/soc/codecs/max9860.c2
-rw-r--r--sound/soc/codecs/max98927.c8
-rw-r--r--sound/soc/codecs/ml26124.c4
-rw-r--r--sound/soc/codecs/msm8916-wcd-analog.c144
-rw-r--r--sound/soc/codecs/mt6357.c4
-rw-r--r--sound/soc/codecs/mt6359-accdet.c13
-rw-r--r--sound/soc/codecs/ntpfw.c21
-rw-r--r--sound/soc/codecs/ntpfw.h11
-rw-r--r--sound/soc/codecs/pcm1681.c7
-rw-r--r--sound/soc/codecs/pcm1754.c6
-rw-r--r--sound/soc/codecs/pcm1789.c7
-rw-r--r--sound/soc/codecs/pcm179x.c6
-rw-r--r--sound/soc/codecs/pcm186x.c9
-rw-r--r--sound/soc/codecs/pcm3060.c8
-rw-r--r--sound/soc/codecs/pcm512x.c68
-rw-r--r--sound/soc/codecs/pcm6240.c41
-rw-r--r--sound/soc/codecs/peb2466.c23
-rw-r--r--sound/soc/codecs/pm4125-sdw.c10
-rw-r--r--sound/soc/codecs/pm4125.c3
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c7
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.h10
-rw-r--r--sound/soc/codecs/rt1316-sdw.c9
-rw-r--r--sound/soc/codecs/rt1318-sdw.c9
-rw-r--r--sound/soc/codecs/rt1318.c4
-rw-r--r--sound/soc/codecs/rt1320-sdw.c882
-rw-r--r--sound/soc/codecs/rt1320-sdw.h19
-rw-r--r--sound/soc/codecs/rt274.c8
-rw-r--r--sound/soc/codecs/rt286.c12
-rw-r--r--sound/soc/codecs/rt298.c12
-rw-r--r--sound/soc/codecs/rt5514-spi.c21
-rw-r--r--sound/soc/codecs/rt5514.c16
-rw-r--r--sound/soc/codecs/rt5575-spi.c3
-rw-r--r--sound/soc/codecs/rt5645.c176
-rw-r--r--sound/soc/codecs/rt5665.c15
-rw-r--r--sound/soc/codecs/rt5668.c10
-rw-r--r--sound/soc/codecs/rt5677-spi.c36
-rw-r--r--sound/soc/codecs/rt5677.c100
-rw-r--r--sound/soc/codecs/rt5682-sdw.c44
-rw-r--r--sound/soc/codecs/rt5682.c5
-rw-r--r--sound/soc/codecs/rt5682s.c17
-rw-r--r--sound/soc/codecs/rt700-sdw.c20
-rw-r--r--sound/soc/codecs/rt700-sdw.h11
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c29
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.h6
-rw-r--r--sound/soc/codecs/rt711-sdca.c5
-rw-r--r--sound/soc/codecs/rt711-sdw.c24
-rw-r--r--sound/soc/codecs/rt711-sdw.h10
-rw-r--r--sound/soc/codecs/rt711.c50
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c17
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.h6
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c45
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.h11
-rw-r--r--sound/soc/codecs/rt712-sdca.c5
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.h12
-rw-r--r--sound/soc/codecs/rt715-sdw.h32
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c44
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.h28
-rw-r--r--sound/soc/codecs/rt721-sdca.c5
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c37
-rw-r--r--sound/soc/codecs/rt722-sdca.c16
-rw-r--r--sound/soc/codecs/rt766-sdca-sdw.c339
-rw-r--r--sound/soc/codecs/rt766-sdca-sdw.h61
-rw-r--r--sound/soc/codecs/rt766-sdca.c1378
-rw-r--r--sound/soc/codecs/rt766-sdca.h140
-rw-r--r--sound/soc/codecs/rt9120.c9
-rw-r--r--sound/soc/codecs/sgtl5000.c2
-rw-r--r--sound/soc/codecs/sigmadsp.c30
-rw-r--r--sound/soc/codecs/sma1303.c2
-rw-r--r--sound/soc/codecs/sma1307.c6
-rw-r--r--sound/soc/codecs/sta32x.c21
-rw-r--r--sound/soc/codecs/sta350.c20
-rw-r--r--sound/soc/codecs/sti-sas.c2
-rw-r--r--sound/soc/codecs/tac5xx2-sdw.c90
-rw-r--r--sound/soc/codecs/tas2552.c24
-rw-r--r--sound/soc/codecs/tas2764.c2
-rw-r--r--sound/soc/codecs/tas2780.c2
-rw-r--r--sound/soc/codecs/tas2781-comlib-i2c.c5
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c65
-rw-r--r--sound/soc/codecs/tas2781-i2c.c253
-rw-r--r--sound/soc/codecs/tas2783-sdw.c310
-rw-r--r--sound/soc/codecs/tas5805m.c30
-rw-r--r--sound/soc/codecs/tas675x.c18
-rw-r--r--sound/soc/codecs/tlv320aic26.c6
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c8
-rw-r--r--sound/soc/codecs/tlv320aic32x4-clk.c68
-rw-r--r--sound/soc/codecs/tlv320aic32x4-i2c.c21
-rw-r--r--sound/soc/codecs/tlv320aic32x4-spi.c25
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c480
-rw-r--r--sound/soc/codecs/tlv320aic32x4.h32
-rw-r--r--sound/soc/codecs/tlv320dac33.c87
-rw-r--r--sound/soc/codecs/tscs42xx.c61
-rw-r--r--sound/soc/codecs/tscs454.c107
-rw-r--r--sound/soc/codecs/twl6040.c5
-rw-r--r--sound/soc/codecs/uda1342.c9
-rw-r--r--sound/soc/codecs/wcd9335.c4
-rw-r--r--sound/soc/codecs/wcd934x.c48
-rw-r--r--sound/soc/codecs/wcd937x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd937x.c25
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd938x.c22
-rw-r--r--sound/soc/codecs/wcd939x-sdw.c8
-rw-r--r--sound/soc/codecs/wcd939x.c20
-rw-r--r--sound/soc/codecs/wm0010.c86
-rw-r--r--sound/soc/codecs/wm2000.c35
-rw-r--r--sound/soc/codecs/wm2200.c10
-rw-r--r--sound/soc/codecs/wm5100.c10
-rw-r--r--sound/soc/codecs/wm5102.c23
-rw-r--r--sound/soc/codecs/wm8731.c9
-rw-r--r--sound/soc/codecs/wm8903.c9
-rw-r--r--sound/soc/codecs/wm8940.c2
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c10
-rw-r--r--sound/soc/codecs/wm8962.c22
-rw-r--r--sound/soc/codecs/wm8994.c30
-rw-r--r--sound/soc/codecs/wm9712.c5
-rw-r--r--sound/soc/codecs/wm9713.c5
-rw-r--r--sound/soc/codecs/wm_adsp.c77
-rw-r--r--sound/soc/codecs/wsa881x.c8
-rw-r--r--sound/soc/codecs/wsa883x.c19
-rw-r--r--sound/soc/codecs/wsa884x.c18
-rw-r--r--sound/soc/codecs/wsa885x.c1533
-rw-r--r--sound/soc/codecs/zl38060.c11
-rw-r--r--sound/soc/dwc/dwc-i2s.c4
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c730
-rw-r--r--sound/soc/fsl/fsl_asrc.c12
-rw-r--r--sound/soc/fsl/fsl_asrc.h6
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c4
-rw-r--r--sound/soc/fsl/fsl_asrc_m2m.c10
-rw-r--r--sound/soc/fsl/fsl_audmix.c35
-rw-r--r--sound/soc/fsl/fsl_dma.c68
-rw-r--r--sound/soc/fsl/fsl_dma.h4
-rw-r--r--sound/soc/fsl/fsl_easrc.c45
-rw-r--r--sound/soc/fsl/fsl_easrc.h4
-rw-r--r--sound/soc/fsl/fsl_esai.c16
-rw-r--r--sound/soc/fsl/fsl_qmc_audio.c8
-rw-r--r--sound/soc/fsl/fsl_spdif.c8
-rw-r--r--sound/soc/fsl/fsl_ssi.c13
-rw-r--r--sound/soc/fsl/fsl_xcvr.c39
-rw-r--r--sound/soc/fsl/imx-audio-rpmsg.c25
-rw-r--r--sound/soc/fsl/imx-card.c4
-rw-r--r--sound/soc/fsl/imx-pcm-rpmsg.c75
-rw-r--r--sound/soc/fsl/mpc5200_dma.c114
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c38
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c12
-rw-r--r--sound/soc/fsl/p1022_ds.c14
-rw-r--r--sound/soc/fsl/p1022_rdk.c14
-rw-r--r--sound/soc/generic/audio-graph-card.c16
-rw-r--r--sound/soc/generic/audio-graph-card2.c35
-rw-r--r--sound/soc/generic/simple-card-utils.c82
-rw-r--r--sound/soc/generic/simple-card.c127
-rw-r--r--sound/soc/intel/atom/sst-atom-controls.c67
-rw-r--r--sound/soc/intel/atom/sst-mfld-platform-pcm.c66
-rw-r--r--sound/soc/intel/atom/sst/sst_ipc.c5
-rw-r--r--sound/soc/intel/atom/sst/sst_pci.c4
-rw-r--r--sound/soc/intel/atom/sst/sst_pvt.c9
-rw-r--r--sound/soc/intel/avs/apl.c8
-rw-r--r--sound/soc/intel/avs/avs.h5
-rw-r--r--sound/soc/intel/avs/boards/da7219.c7
-rw-r--r--sound/soc/intel/avs/boards/dmic.c6
-rw-r--r--sound/soc/intel/avs/boards/es8336.c6
-rw-r--r--sound/soc/intel/avs/boards/hdaudio.c6
-rw-r--r--sound/soc/intel/avs/boards/i2s_test.c6
-rw-r--r--sound/soc/intel/avs/boards/max98357a.c6
-rw-r--r--sound/soc/intel/avs/boards/max98373.c6
-rw-r--r--sound/soc/intel/avs/boards/max98927.c6
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c6
-rw-r--r--sound/soc/intel/avs/boards/pcm3168a.c6
-rw-r--r--sound/soc/intel/avs/boards/probe.c2
-rw-r--r--sound/soc/intel/avs/boards/rt274.c2
-rw-r--r--sound/soc/intel/avs/boards/rt286.c2
-rw-r--r--sound/soc/intel/avs/boards/rt298.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5514.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5640.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c2
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c2
-rw-r--r--sound/soc/intel/avs/control.c7
-rw-r--r--sound/soc/intel/avs/core.c4
-rw-r--r--sound/soc/intel/avs/debug.h10
-rw-r--r--sound/soc/intel/avs/debugfs.c19
-rw-r--r--sound/soc/intel/avs/ipc.c59
-rw-r--r--sound/soc/intel/avs/loader.c15
-rw-r--r--sound/soc/intel/avs/path.c30
-rw-r--r--sound/soc/intel/avs/pcm.c19
-rw-r--r--sound/soc/intel/avs/probes.c18
-rw-r--r--sound/soc/intel/avs/topology.c3
-rw-r--r--sound/soc/intel/avs/utils.c45
-rw-r--r--sound/soc/intel/boards/sof_sdw.c16
-rw-r--r--sound/soc/intel/catpt/core.h4
-rw-r--r--sound/soc/intel/catpt/device.c33
-rw-r--r--sound/soc/intel/catpt/loader.c146
-rw-r--r--sound/soc/intel/catpt/pcm.c59
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c3
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c15
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c18
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ptl-match.c6
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c8
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h1
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c2
-rw-r--r--sound/soc/loongson/loongson_card.c171
-rw-r--r--sound/soc/loongson/loongson_i2s_plat.c42
-rw-r--r--sound/soc/mediatek/Kconfig2
-rw-r--r--sound/soc/mediatek/common/mtk-dsp-sof-common.c7
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c4
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c4
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366.c2
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-mt6359.c2
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-dai-adda.c2
-rw-r--r--sound/soc/mediatek/mt8189/mt8189-nau8825.c2
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c14
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359.c4
-rw-r--r--sound/soc/mediatek/mt8196/mt8196-nau8825.c4
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-pcm.c16
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-mt6357.c10
-rw-r--r--sound/soc/meson/Makefile2
-rw-r--r--sound/soc/meson/aiu-encoder-i2s.c365
-rw-r--r--sound/soc/meson/aiu-formatter-i2s.c103
-rw-r--r--sound/soc/meson/aiu.c33
-rw-r--r--sound/soc/meson/aiu.h4
-rw-r--r--sound/soc/meson/axg-card.c25
-rw-r--r--sound/soc/meson/g12a-toacodec.c2
-rw-r--r--sound/soc/meson/g12a-tohdmitx.c2
-rw-r--r--sound/soc/meson/gx-card.c6
-rw-r--r--sound/soc/meson/gx-formatter.c282
-rw-r--r--sound/soc/meson/gx-formatter.h56
-rw-r--r--sound/soc/meson/gx-interface.h42
-rw-r--r--sound/soc/meson/meson-card-utils.c39
-rw-r--r--sound/soc/meson/meson-codec-glue.c2
-rw-r--r--sound/soc/meson/t9015.c12
-rw-r--r--sound/soc/mxs/mxs-saif.c21
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c2
-rw-r--r--sound/soc/pxa/pxa-ssp.c7
-rw-r--r--sound/soc/pxa/pxa2xx-ac97-lib.c4
-rw-r--r--sound/soc/qcom/common.c164
-rw-r--r--sound/soc/qcom/common.h16
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.c140
-rw-r--r--sound/soc/qcom/qdsp6/audioreach.h90
-rw-r--r--sound/soc/qcom/qdsp6/q6afe-dai.c48
-rw-r--r--sound/soc/qcom/qdsp6/q6afe.c56
-rw-r--r--sound/soc/qcom/qdsp6/q6apm-lpass-dais.c228
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c12
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c2
-rw-r--r--sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c5
-rw-r--r--sound/soc/qcom/qdsp6/q6prm-clocks.c35
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.c16
-rw-r--r--sound/soc/qcom/qdsp6/q6prm.h44
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c78
-rw-r--r--sound/soc/qcom/qdsp6/topology.c107
-rw-r--r--sound/soc/qcom/sc8280xp.c430
-rw-r--r--sound/soc/qcom/sdm845.c2
-rw-r--r--sound/soc/qcom/sm8250.c17
-rw-r--r--sound/soc/qcom/storm.c12
-rw-r--r--sound/soc/renesas/fsi.c13
-rw-r--r--sound/soc/renesas/rcar/adg.c8
-rw-r--r--sound/soc/renesas/siu_dai.c4
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c16
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c30
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.c15
-rw-r--r--sound/soc/rockchip/rockchip_max98090.c5
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c8
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c5
-rw-r--r--sound/soc/rockchip/rockchip_sai.c15
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c4
-rw-r--r--sound/soc/samsung/aries_wm8994.c1
-rw-r--r--sound/soc/samsung/i2s.c58
-rw-r--r--sound/soc/samsung/smdk_spdif.c8
-rw-r--r--sound/soc/samsung/spdif.c8
-rw-r--r--sound/soc/sdca/sdca_asoc.c18
-rw-r--r--sound/soc/sdca/sdca_class_function.c2
-rw-r--r--sound/soc/sdca/sdca_fdl.c8
-rw-r--r--sound/soc/sdca/sdca_function_device.c7
-rw-r--r--sound/soc/sdca/sdca_functions.c187
-rw-r--r--sound/soc/sdca/sdca_hid.c48
-rw-r--r--sound/soc/sdca/sdca_interrupts.c6
-rw-r--r--sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c4
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c72
-rw-r--r--sound/soc/soc-component.c53
-rw-r--r--sound/soc/soc-core.c44
-rw-r--r--sound/soc/soc-dapm.c6
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c58
-rw-r--r--sound/soc/soc-topology-test.c133
-rw-r--r--sound/soc/sof/amd/Kconfig11
-rw-r--r--sound/soc/sof/amd/Makefile2
-rw-r--r--sound/soc/sof/amd/acp-dsp-offset.h17
-rw-r--r--sound/soc/sof/amd/acp-ipc.c15
-rw-r--r--sound/soc/sof/amd/acp-loader.c37
-rw-r--r--sound/soc/sof/amd/acp.c267
-rw-r--r--sound/soc/sof/amd/acp.h20
-rw-r--r--sound/soc/sof/amd/acp7x.c185
-rw-r--r--sound/soc/sof/amd/pci-acp7x.c116
-rw-r--r--sound/soc/sof/fw-file-profile.c19
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c19
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c76
-rw-r--r--sound/soc/sof/intel/hda-dai.c2
-rw-r--r--sound/soc/sof/intel/hda-dsp.c6
-rw-r--r--sound/soc/sof/intel/hda-loader.c11
-rw-r--r--sound/soc/sof/intel/hda-mlink.c35
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c2
-rw-r--r--sound/soc/sof/intel/hda-stream.c18
-rw-r--r--sound/soc/sof/intel/hda.c18
-rw-r--r--sound/soc/sof/intel/hda.h31
-rw-r--r--sound/soc/sof/intel/icl.c10
-rw-r--r--sound/soc/sof/intel/mtl.c23
-rw-r--r--sound/soc/sof/ipc3-pcm.c6
-rw-r--r--sound/soc/sof/ipc3-topology.c39
-rw-r--r--sound/soc/sof/ipc4-topology.c382
-rw-r--r--sound/soc/sof/ipc4-topology.h12
-rw-r--r--sound/soc/sof/ipc4.c84
-rw-r--r--sound/soc/sof/nocodec.c16
-rw-r--r--sound/soc/sof/pcm.c2
-rw-r--r--sound/soc/sof/sof-audio.c5
-rw-r--r--sound/soc/sof/sof-audio.h8
-rw-r--r--sound/soc/sof/topology.c53
-rw-r--r--sound/soc/sophgo/cv1800b-tdm.c16
-rw-r--r--sound/soc/spacemit/k1_i2s.c47
-rw-r--r--sound/soc/spear/spdif_in.c12
-rw-r--r--sound/soc/spear/spdif_out.c2
-rw-r--r--sound/soc/sprd/sprd-mcdt.c4
-rw-r--r--sound/soc/sprd/sprd-pcm-dma.c2
-rw-r--r--sound/soc/starfive/jh7110_pwmdac.c15
-rw-r--r--sound/soc/starfive/jh7110_tdm.c27
-rw-r--r--sound/soc/stm/stm32_adfsdm.c5
-rw-r--r--sound/soc/stm/stm32_i2s.c6
-rw-r--r--sound/soc/stm/stm32_sai_sub.c8
-rw-r--r--sound/soc/stm/stm32_spdifrx.c6
-rw-r--r--sound/soc/sunxi/sun4i-codec.c93
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c28
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c23
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c11
-rw-r--r--sound/soc/sunxi/sun8i-codec-analog.c11
-rw-r--r--sound/soc/tegra/tegra20_das.c7
-rw-r--r--sound/soc/tegra/tegra210_adx.c12
-rw-r--r--sound/soc/tegra/tegra210_amx.c12
-rw-r--r--sound/soc/tegra/tegra210_i2s.c18
-rw-r--r--sound/soc/tegra/tegra210_mixer.c2
-rw-r--r--sound/soc/ti/ams-delta.c8
-rw-r--r--sound/soc/ti/davinci-evm.c3
-rw-r--r--sound/soc/ti/j721e-evm.c11
-rw-r--r--sound/soc/ti/omap-abe-twl6040.c15
-rw-r--r--sound/soc/ti/omap-dmic.c7
-rw-r--r--sound/soc/ti/omap-hdmi.c9
-rw-r--r--sound/soc/ti/omap-twl4030.c170
-rw-r--r--sound/soc/ti/rx51.c53
-rw-r--r--sound/soc/uniphier/aio-cpu.c8
-rw-r--r--sound/soc/uniphier/aio.h2
-rw-r--r--sound/soc/ux500/mop500.c12
-rw-r--r--sound/soc/ux500/mop500_ab8500.c2
-rw-r--r--sound/soc/xilinx/xlnx_formatter_pcm.c16
-rw-r--r--sound/soc/xilinx/xlnx_i2s.c30
-rw-r--r--sound/soc/xilinx/xlnx_spdif.c39
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c60
-rw-r--r--sound/sparc/dbri.c2
-rw-r--r--sound/usb/6fire/comm.c9
-rw-r--r--sound/usb/6fire/firmware.c24
-rw-r--r--sound/usb/bcd2000/bcd2000.c11
-rw-r--r--sound/usb/card.c72
-rw-r--r--sound/usb/clock.c11
-rw-r--r--sound/usb/endpoint.c7
-rw-r--r--sound/usb/fcp.c42
-rw-r--r--sound/usb/mixer.c6
-rw-r--r--sound/usb/mixer.h2
-rw-r--r--sound/usb/mixer_maps.c18
-rw-r--r--sound/usb/mixer_quirks.c20
-rw-r--r--sound/usb/mixer_scarlett2.c98
-rw-r--r--sound/usb/quirks-table.h77
-rw-r--r--sound/usb/quirks.c29
-rw-r--r--sound/usb/quirks.h3
-rw-r--r--sound/usb/usbaudio.h18
-rw-r--r--sound/usb/usx2y/us144mkii_pcm.h6
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c1
628 files changed, 20521 insertions, 10073 deletions
diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
index 4f13e8ab50b2..177db900d4a0 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,axg-sound-card.yaml
@@ -30,7 +30,7 @@ properties:
minItems: 1
maxItems: 3
description:
- Base PLL clocks of audio susbsytem, used to configure base clock
+ Base PLL clocks of audio subsystem, used to configure base clock
frequencies for different audio use-cases.
patternProperties:
diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
index 413b47778181..6fdf605ad59c 100644
--- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
+++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml
@@ -31,7 +31,7 @@ properties:
minItems: 1
maxItems: 3
description:
- Base PLL clocks of audio susbsytem, used to configure base clock
+ Base PLL clocks of audio subsystem, used to configure base clock
frequencies for different audio use-cases.
patternProperties:
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
new file mode 100644
index 000000000000..2a142b32acf5
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l36.yaml
@@ -0,0 +1,240 @@
+# SPDX-License-Identifier: GPL-2.0-only
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/cirrus,cs35l36.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus Logic CS35L36 Speaker Amplifier
+
+maintainers:
+ - David Rhodes <drhodes@opensource.cirrus.com>
+ - patches@opensource.cirrus.com
+
+description:
+ CS35L36 is a boosted mono Class D amplifier
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ enum:
+ - cirrus,cs35l36
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ VA-supply:
+ description: Voltage regulator of analog internal section
+
+ VP-supply:
+ description: Voltage regulator of boost converter
+
+ reset-gpios:
+ maxItems: 1
+
+ cirrus,boost-ctl-millivolt:
+ description: Boost converter output voltage (step 50)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2550
+ maximum: 12000
+
+ cirrus,boost-peak-milliamp:
+ description: Boost-converter peak current limit (step 50)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 4500
+ minimum: 1600
+ maximum: 4500
+
+ cirrus,boost-ind-nanohenry:
+ description: Initial inductor estimation reference value (1000=1μH, 1200=1.2μH)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1000
+
+ cirrus,multi-amp-mode:
+ description: Hi-Z ASP port when more than one amplifier in system
+ type: boolean
+
+ cirrus,boost-ctl-select:
+ description: Boost converter control source selection
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # Control Port
+ - 1 # Class
+ - 2 # Sync
+
+ cirrus,amp-pcm-inv:
+ description: Invert incoming PCM data when true
+ type: boolean
+
+ cirrus,imon-pol-inv:
+ description: Invert polarity of outbound IMON feedback when true
+ type: boolean
+
+ cirrus,vmon-pol-inv:
+ description: Invert polarity of outbound VMON feedback when true
+ type: boolean
+
+ cirrus,dcm-mode-enable:
+ description: Enable boost converter automatic Discontinuous Conduction Mode
+ type: boolean
+
+ cirrus,weak-fet-disable:
+ description: Reduce output driver strength in Weak-FET Drive Mode when true
+ type: boolean
+
+ cirrus,classh-wk-fet-delay-ms:
+ description: Weak-FET entry delay
+ default: 100
+ enum: [0, 5, 10, 50, 100, 200, 500, 1000]
+
+ cirrus,classh-weak-fet-thld-millivolt:
+ description: Weak-FET drive threshold
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700]
+
+ cirrus,temp-warn-threshold:
+ description: Overtemperature warning threshold
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 2
+ enum:
+ - 0 # 105°C
+ - 1 # 115°C
+ - 2 # 125°C
+ - 3 # 135°C
+
+ cirrus,irq-drive-select:
+ description: Interrupt output driver type
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # open-drain
+ - 1 # push-pull
+
+ cirrus,irq-gpio-select:
+ description: Programmable IRQ pin selection
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum:
+ - 0 # PDM_DATA/SWIRE_SD/INT
+ - 1 # GPIO
+
+ cirrus,vpbr-config:
+ $ref: "#/$defs/vpbr-config"
+
+$defs:
+ vpbr-config:
+ description: Brownout prevention configuration sub-node
+ type: object
+ additionalProperties: false
+
+ properties:
+ cirrus,vpbr-en:
+ description: VBST brownout prevention enable
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 0
+ enum:
+ - 0 # disabled
+ - 1 # enabled
+
+ cirrus,vpbr-thld:
+ description: Initial VPBR threshold voltage
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 2
+ maximum: 31
+
+ cirrus,vpbr-atk-rate:
+ description: Attenuation attack step rate
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-atk-vol:
+ description: VP brownout prevention step size
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-max-attn:
+ description: Maximum attenuation during VP brownout prevention (dB)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 15
+
+ cirrus,vpbr-wait:
+ description: Delay between brownout clearance and attenuation release (ms)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ default: 1
+ enum:
+ - 0 # 10
+ - 1 # 100
+ - 2 # 250
+ - 3 # 500
+
+ cirrus,vpbr-rel-rate:
+ description: Attenuation release step rate
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+
+ cirrus,vpbr-mute-en:
+ description: Mute audio if maximum attenuation reached
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - VA-supply
+ - cirrus,boost-ctl-millivolt
+ - cirrus,boost-peak-milliamp
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ codec@40 {
+ compatible = "cirrus,cs35l36";
+ reg = <0x40>;
+ VA-supply = <&dummy_vreg>;
+ VP-supply = <&dummy_vreg>;
+ reset-gpios = <&gpio0 54 GPIO_ACTIVE_HIGH>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+ cirrus,boost-ind-nanohenry = <1000>;
+ cirrus,boost-ctl-millivolt = <10000>;
+ cirrus,boost-peak-milliamp = <4500>;
+ cirrus,boost-ctl-select = <0>;
+ cirrus,classh-wk-fet-delay-ms = <100>;
+ cirrus,classh-weak-fet-thld-millivolt = <100>;
+ cirrus,temp-warn-threshold = <1>;
+ cirrus,multi-amp-mode;
+ cirrus,irq-drive-select = <1>;
+ cirrus,irq-gpio-select = <1>;
+
+ cirrus,vpbr-config {
+ cirrus,vpbr-en = <0>;
+ cirrus,vpbr-thld = <5>;
+ cirrus,vpbr-atk-rate = <2>;
+ cirrus,vpbr-atk-vol = <1>;
+ cirrus,vpbr-max-attn = <9>;
+ cirrus,vpbr-wait = <1>;
+ cirrus,vpbr-rel-rate = <5>;
+ cirrus,vpbr-mute-en = <0>;
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
index 376928d1f64b..c1ef9f308396 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs42l43.yaml
@@ -27,6 +27,7 @@ properties:
enum:
- cirrus,cs42l43
- cirrus,cs42l43b
+ - cirrus,cs42l44
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/cs35l36.txt b/Documentation/devicetree/bindings/sound/cs35l36.txt
deleted file mode 100644
index d34117b8558e..000000000000
--- a/Documentation/devicetree/bindings/sound/cs35l36.txt
+++ /dev/null
@@ -1,168 +0,0 @@
-CS35L36 Speaker Amplifier
-
-Required properties:
-
- - compatible : "cirrus,cs35l36"
-
- - reg : the I2C address of the device for I2C
-
- - VA-supply, VP-supply : power supplies for the device,
- as covered in
- Documentation/devicetree/bindings/regulator/regulator.txt.
-
- - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the boost
- converter's output voltage in mV. The range is from 2550mV to 12000mV with
- increments of 50mV.
- (Default) VP
-
- - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA.
- Configures the peak current by monitoring the current through the boost FET.
- Range starts at 1600mA and goes to a maximum of 4500mA with increments of
- 50mA.
- (Default) 4.50 Amps
-
- - cirrus,boost-ind-nanohenry : Inductor estimation LBST reference value.
- Seeds the digital boost converter's inductor estimation block with the initial
- inductance value to reference.
-
- 1000 = 1uH (Default)
- 1200 = 1.2uH
-
-Optional properties:
- - cirrus,multi-amp-mode : Boolean to determine if there are more than
- one amplifier in the system. If more than one it is best to Hi-Z the ASP
- port to prevent bus contention on the output signal
-
- - cirrus,boost-ctl-select : Boost converter control source selection.
- Selects the source of the BST_CTL target VBST voltage for the boost
- converter to generate.
- 0x00 - Control Port Value
- 0x01 - Class H Tracking (Default)
- 0x10 - MultiDevice Sync Value
-
- - cirrus,amp-pcm-inv : Boolean to determine Amplifier will invert incoming
- PCM data
-
- - cirrus,imon-pol-inv : Boolean to determine Amplifier will invert the
- polarity of outbound IMON feedback data
-
- - cirrus,vmon-pol-inv : Boolean to determine Amplifier will invert the
- polarity of outbound VMON feedback data
-
- - cirrus,dcm-mode-enable : Boost converter automatic DCM Mode enable.
- This enables the digital boost converter to operate in a low power
- (Discontinuous Conduction) mode during low loading conditions.
-
- - cirrus,weak-fet-disable : Boolean : The strength of the output drivers is
- reduced when operating in a Weak-FET Drive Mode and must not be used to drive
- a large load.
-
- - cirrus,classh-wk-fet-delay : Weak-FET entry delay. Controls the delay
- (in ms) before the Class H algorithm switches to the weak-FET voltage
- (after the audio falls and remains below the value specified in WKFET_AMP_THLD).
-
- 0 = 0ms
- 1 = 5ms
- 2 = 10ms
- 3 = 50ms
- 4 = 100ms (Default)
- 5 = 200ms
- 6 = 500ms
- 7 = 1000ms
-
- - cirrus,classh-weak-fet-thld-millivolt : Weak-FET amplifier drive threshold.
- Configures the signal threshold at which the PWM output stage enters
- weak-FET operation. The range is 50mV to 700mV in 50mV increments.
-
- - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold.
- Configures the threshold at which the overtemperature warning condition occurs.
- When the threshold is met, the overtemperature warning attenuation is applied
- and the TEMP_WARN_EINT interrupt status bit is set.
- If TEMP_WARN_MASK = 0, INTb is asserted.
-
- 0 = 105C
- 1 = 115C
- 2 = 125C (Default)
- 3 = 135C
-
- - cirrus,irq-drive-select : Selects the driver type of the selected interrupt
- output.
-
- 0 = Open-drain
- 1 = Push-pull (Default)
-
- - cirrus,irq-gpio-select : Selects the pin to serve as the programmable
- interrupt output.
-
- 0 = PDM_DATA / SWIRE_SD / INT (Default)
- 1 = GPIO
-
-Optional properties for the "cirrus,vpbr-config" Sub-node
-
- - cirrus,vpbr-en : VBST brownout prevention enable. Configures whether the
- VBST brownout prevention algorithm is enabled or disabled.
-
- 0 = VBST brownout prevention disabled (default)
- 1 = VBST brownout prevention enabled
-
- See Section 7.31.1 VPBR Config for configuration options & further details
-
- - cirrus,vpbr-thld : Initial VPBR threshold. Configures the VP brownout
- threshold voltage
-
- - cirrus,cirrus,vpbr-atk-rate : Attenuation attack step rate. Configures the
- amount delay between consecutive volume attenuation steps when a brownout
- condition is present and the VP brownout condition is in an attacking state.
-
- - cirrus,vpbr-atk-vol : VP brownout prevention step size. Configures the VP
- brownout prevention attacking attenuation step size when operating in either
- digital volume or analog gain modes.
-
- - cirrus,vpbr-max-attn : Maximum attenuation that the VP brownout prevention
- can apply to the audio signal.
-
- - cirrus,vpbr-wait : Configures the delay time between a brownout condition
- no longer being present and the VP brownout prevention entering an attenuation
- release state.
-
- - cirrus,vpbr-rel-rate : Attenuation release step rate. Configures the delay
- between consecutive volume attenuation release steps when a brownout condition
- is not longer present and the VP brownout is in an attenuation release state.
-
- - cirrus,vpbr-mute-en : During the attack state, if the vpbr-max-attn value
- is reached, the error condition still remains, and this bit is set, the audio
- is muted.
-
-Example:
-
-cs35l36: cs35l36@40 {
- compatible = "cirrus,cs35l36";
- reg = <0x40>;
- VA-supply = <&dummy_vreg>;
- VP-supply = <&dummy_vreg>;
- reset-gpios = <&gpio0 54 0>;
- interrupt-parent = <&gpio8>;
- interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
-
- cirrus,boost-ind-nanohenry = <1000>;
- cirrus,boost-ctl-millivolt = <10000>;
- cirrus,boost-peak-milliamp = <4500>;
- cirrus,boost-ctl-select = <0x00>;
- cirrus,weak-fet-delay = <0x04>;
- cirrus,weak-fet-thld = <0x01>;
- cirrus,temp-warn-threshold = <0x01>;
- cirrus,multi-amp-mode;
- cirrus,irq-drive-select = <0x01>;
- cirrus,irq-gpio-select = <0x01>;
-
- cirrus,vpbr-config {
- cirrus,vpbr-en = <0x00>;
- cirrus,vpbr-thld = <0x05>;
- cirrus,vpbr-atk-rate = <0x02>;
- cirrus,vpbr-atk-vol = <0x01>;
- cirrus,vpbr-max-attn = <0x09>;
- cirrus,vpbr-wait = <0x01>;
- cirrus,vpbr-rel-rate = <0x05>;
- cirrus,vpbr-mute-en = <0x00>;
- };
-};
diff --git a/Documentation/devicetree/bindings/sound/dmic-codec.yaml b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
index cc3c84dd4c26..83c23e029ea4 100644
--- a/Documentation/devicetree/bindings/sound/dmic-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/dmic-codec.yaml
@@ -39,6 +39,10 @@ properties:
wakeup-delay-ms:
description: Delay (in ms) after enabling the DMIC
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
diff --git a/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml b/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml
new file mode 100644
index 000000000000..24b793feb02d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/eukrea,asoc-tlv320.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/eukrea,asoc-tlv320.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Audio complex for Eukrea boards with tlv320aic23 codec.
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+properties:
+ compatible:
+ const: eukrea,asoc-tlv320
+
+ eukrea,model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ The user-visible name of this sound complex.
+
+ ssi-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The phandle of the SSI controller.
+
+ fsl,mux-int-port:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ The internal port of the i.MX audio muxer (AUDMUX).
+ Note: The AUDMUX port numbering should start at 1, which is consistent with
+ hardware manual.
+ minimum: 1
+ maximum: 8
+
+ fsl,mux-ext-port:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ The external port of the i.MX audio muxer.
+ Note: The AUDMUX port numbering should start at 1, which is consistent with
+ hardware manual.
+ minimum: 1
+ maximum: 8
+
+required:
+ - compatible
+ - eukrea,model
+ - ssi-controller
+ - fsl,mux-int-port
+ - fsl,mux-ext-port
+
+additionalProperties: false
+
+examples:
+ - |
+ sound {
+ compatible = "eukrea,asoc-tlv320";
+ eukrea,model = "imx51-eukrea-tlv320aic23";
+ ssi-controller = <&ssi2>;
+ fsl,mux-int-port = <2>;
+ fsl,mux-ext-port = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
deleted file mode 100644
index 6dfa88c4dc1e..000000000000
--- a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Audio complex for Eukrea boards with tlv320aic23 codec.
-
-Required properties:
-
- - compatible : "eukrea,asoc-tlv320"
-
- - eukrea,model : The user-visible name of this sound complex.
-
- - ssi-controller : The phandle of the SSI controller.
-
- - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
-
- - fsl,mux-ext-port : The external port of the i.MX audio muxer.
-
-Note: The AUDMUX port numbering should start at 1, which is consistent with
-hardware manual.
-
-Example:
-
- sound {
- compatible = "eukrea,asoc-tlv320";
- eukrea,model = "imx51-eukrea-tlv320aic23";
- ssi-controller = <&ssi2>;
- fsl,mux-int-port = <2>;
- fsl,mux-ext-port = <3>;
- };
diff --git a/Documentation/devicetree/bindings/sound/everest,es8316.yaml b/Documentation/devicetree/bindings/sound/everest,es8316.yaml
index fe5d938ca310..f4ff23120c5b 100644
--- a/Documentation/devicetree/bindings/sound/everest,es8316.yaml
+++ b/Documentation/devicetree/bindings/sound/everest,es8316.yaml
@@ -30,6 +30,18 @@ description: |
allOf:
- $ref: dai-common.yaml#
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ const: everest,es8316
+ then:
+ properties:
+ avdd-supply: false
+ cpvdd-supply: false
+ dvdd-supply: false
+ pvdd-supply: false
properties:
compatible:
@@ -49,6 +61,18 @@ properties:
items:
- const: mclk
+ avdd-supply:
+ description: Regulator providing the analog supply, from 2.0 V to 3.6 V
+
+ cpvdd-supply:
+ description: Regulator providing the charge pump supply, from 1.6 V to 2.0 V
+
+ dvdd-supply:
+ description: Regulator providing the digital core supply, from 1.6 V to 3.6 V
+
+ pvdd-supply:
+ description: Regulator providing the digital I/O supply, from 1.6 V to 3.6 V
+
interrupts:
maxItems: 1
description: Headphone detect interrupt
@@ -77,6 +101,10 @@ examples:
reg = <0x11>;
clocks = <&clks 10>;
clock-names = "mclk";
+ avdd-supply = <&reg_3p3v>;
+ cpvdd-supply = <&reg_1p8v>;
+ dvdd-supply = <&reg_1p8v>;
+ pvdd-supply = <&reg_1p8v>;
#sound-dai-cells = <0>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
index c47b7a097490..4c7dadb310de 100644
--- a/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
+++ b/Documentation/devicetree/bindings/sound/fsl,micfil.yaml
@@ -66,6 +66,10 @@ properties:
"#sound-dai-cells":
const: 0
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
index 61e8babed402..dc7f4afbb777 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls-audio-card.yaml
@@ -8,19 +8,22 @@ title: Loongson 7axxx/2kxxx ASoC audio sound card driver
maintainers:
- Yingkun Meng <mengyingkun@loongson.cn>
+ - Binbin Zhou <zhoubinbin@loongson.cn>
description:
The binding describes the sound card present in loongson
7axxx/2kxxx platform. The sound card is an ASoC component
which uses Loongson I2S controller to transfer the audio data.
+allOf:
+ - $ref: sound-card-common.yaml#
+
properties:
compatible:
- const: loongson,ls-audio-card
-
- model:
- $ref: /schemas/types.yaml#/definitions/string
- description: User specified audio sound card name
+ enum:
+ - loongson,ls-audio-card # Loongson-2K1000/Loongson-2K2000/LS7A
+ - loongson,ls2k0300-forever-pi-audio-card # CTCISZ Forever Pi
+ - loongson,ls2k0300-dl2k0300b-audio-card # ATK-DL2K0300B
mclk-fs:
$ref: simple-card.yaml#/definitions/mclk-fs
@@ -45,14 +48,25 @@ properties:
required:
- sound-dai
+ spkr-en-gpios:
+ maxItems: 1
+ description: The GPIO that enables the speakers
+
+ hp-ctl-gpios:
+ maxItems: 1
+ description: The GPIO that control the headphones
+
+ hp-det-gpios:
+ maxItems: 1
+ description: The GPIO that detect headphones are plugged in
+
required:
- compatible
- - model
- mclk-fs
- cpu
- codec
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -68,3 +82,28 @@ examples:
sound-dai = <&es8323>;
};
};
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ sound {
+ compatible = "loongson,ls2k0300-dl2k0300b-audio-card";
+ model = "loongson-audio";
+ mclk-fs = <512>;
+ hp-det-gpios = <&gpio 81 GPIO_ACTIVE_HIGH>;
+ spkr-en-gpios = <&gpio 86 GPIO_ACTIVE_HIGH>;
+ hp-ctl-gpios = <&gpio 87 GPIO_ACTIVE_HIGH>;
+ audio-routing =
+ "Headphone", "LOUT1",
+ "Headphone", "ROUT1",
+ "Speaker", "LOUT2",
+ "Speaker", "ROUT2";
+
+ cpu {
+ sound-dai = <&i2s>;
+ };
+
+ codec {
+ sound-dai = <&es8388>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
index da79510bb2d9..51e23c189f7a 100644
--- a/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/loongson,ls2k1000-i2s.yaml
@@ -14,9 +14,12 @@ allOf:
properties:
compatible:
- const: loongson,ls2k1000-i2s
+ enum:
+ - loongson,ls2k0300-i2s
+ - loongson,ls2k1000-i2s
reg:
+ minItems: 1
items:
- description: Loongson I2S controller Registers.
- description: APB DMA config register for Loongson I2S controller.
@@ -49,6 +52,23 @@ required:
unevaluatedProperties: false
+if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - loongson,ls2k1000-i2s
+
+then:
+ properties:
+ reg:
+ minItems: 2
+
+else:
+ properties:
+ reg:
+ maxItems: 1
+
examples:
- |
#include <dt-bindings/clock/loongson,ls2k-clk.h>
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
new file mode 100644
index 000000000000..1b7451655476
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/mediatek,mtk-btcvsd-snd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek ALSA BT SCO CVSD/MSBC
+
+maintainers:
+ - Luca Leonardo Scorcia <l.scorcia@gmail.com>
+
+properties:
+ compatible:
+ const: mediatek,mtk-btcvsd-snd
+
+ reg:
+ items:
+ - description: PKV region
+ - description: SRAM_BANK2 region
+
+ interrupts:
+ items:
+ - description: BT-SCO interrupt
+
+ mediatek,infracfg:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of the infracfg controller
+
+ mediatek,offset:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Array of register offsets and masks
+ items:
+ - description: infra_misc_offset
+ - description: infra_conn_bt_cvsd_mask
+ - description: cvsd_mcu_read_offset
+ - description: cvsd_mcu_write_offset
+ - description: cvsd_packet_indicator_offset
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - mediatek,infracfg
+ - mediatek,offset
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ mtk-btcvsd-snd@18000000 {
+ compatible = "mediatek,mtk-btcvsd-snd";
+ reg = <0x18000000 0x1000>,
+ <0x18080000 0x8000>;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
+ mediatek,infracfg = <&infrasys>;
+ mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
deleted file mode 100644
index 679e44839b48..000000000000
--- a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Mediatek ALSA BT SCO CVSD/MSBC Driver
-
-Required properties:
-- compatible = "mediatek,mtk-btcvsd-snd";
-- reg: register location and size of PKV and SRAM_BANK2
-- interrupts: should contain BTSCO interrupt
-- mediatek,infracfg: the phandles of INFRASYS
-- mediatek,offset: Array contains of register offset and mask
- infra_misc_offset,
- infra_conn_bt_cvsd_mask,
- cvsd_mcu_read_offset,
- cvsd_mcu_write_offset,
- cvsd_packet_indicator_offset
-
-Example:
-
- mtk-btcvsd-snd@18000000 {
- compatible = "mediatek,mtk-btcvsd-snd";
- reg=<0 0x18000000 0 0x1000>,
- <0 0x18080000 0 0x8000>;
- interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
- mediatek,infracfg = <&infrasys>;
- mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
- };
diff --git a/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml b/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml
index 6946177e391a..99b739595ebf 100644
--- a/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml
+++ b/Documentation/devicetree/bindings/sound/neofidelity,ntp8918.yaml
@@ -66,7 +66,7 @@ examples:
#sound-dai-cells = <0>;
reg = <0x2a>;
clocks = <&clkc 150>, <&clkc 151>, <&clkc 152>;
- clock-names = "wck", "scl", "bck";
+ clock-names = "wck", "scl", "bck";
reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
};
};
diff --git a/Documentation/devicetree/bindings/sound/omap-dmic.txt b/Documentation/devicetree/bindings/sound/omap-dmic.txt
deleted file mode 100644
index 418e30e72e89..000000000000
--- a/Documentation/devicetree/bindings/sound/omap-dmic.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-* Texas Instruments OMAP4+ Digital Microphone Module
-
-Required properties:
-- compatible: "ti,omap4-dmic"
-- reg: Register location and size as an array:
- <MPU access base address, size>,
- <L3 interconnect address, size>;
-- interrupts: Interrupt number for DMIC
-- ti,hwmods: Name of the hwmod associated with OMAP dmic IP
-
-Example:
-
-dmic: dmic@4012e000 {
- compatible = "ti,omap4-dmic";
- reg = <0x4012e000 0x7f>, /* MPU private access */
- <0x4902e000 0x7f>; /* L3 Interconnect */
- interrupts = <0 114 0x4>;
- interrupt-parent = <&gic>;
- ti,hwmods = "dmic";
-};
diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
index a899c4e7c1c9..33bc23b6176a 100644
--- a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital-codec.yaml
@@ -14,7 +14,13 @@ description:
properties:
compatible:
- const: qcom,msm8916-wcd-digital-codec
+ oneOf:
+ - items:
+ - enum:
+ - qcom,sdm660-wcd-digital-codec
+ - const: qcom,msm8916-wcd-digital-codec
+
+ - const: qcom,msm8916-wcd-digital-codec
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
index 94e7a1860977..be47dbdb2e92 100644
--- a/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,pm8916-wcd-analog-codec.yaml
@@ -14,7 +14,16 @@ description:
properties:
compatible:
- const: qcom,pm8916-wcd-analog-codec
+ oneOf:
+ - items:
+ - enum:
+ - qcom,pm660l-wcd-analog-codec
+ - const: qcom,pm8953-wcd-analog-codec
+
+ - enum:
+ - qcom,pm8916-wcd-analog-codec
+ - qcom,pm8950-wcd-analog-codec
+ - qcom,pm8953-wcd-analog-codec
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
index 2fb95544db8b..4878c424ef03 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml
@@ -21,6 +21,43 @@ properties:
'#sound-dai-cells':
const: 1
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+# Digital Audio Interfaces
+patternProperties:
+ '^dai@[0-9a-f]+$':
+ type: object
+ description:
+ Q6DSP Digital Audio Interfaces.
+
+ properties:
+ reg:
+ maxItems: 1
+ description:
+ Digital Audio Interface ID
+
+ clocks:
+ minItems: 1
+ maxItems: 2
+
+ clock-names:
+ minItems: 1
+ items:
+ - enum: [bclk, mclk]
+ - const: mclk
+
+ dependencies:
+ clocks: [clock-names]
+
+ required:
+ - reg
+
+ additionalProperties: false
+
required:
- compatible
- '#sound-dai-cells'
@@ -29,7 +66,20 @@ unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/sound/qcom,q6afe.h>
+
dais {
compatible = "qcom,q6apm-lpass-dais";
#sound-dai-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dai@10 {
+ reg = <PRIMARY_MI2S_RX>;
+ clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT
+ LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_CLK_ID_MCLK_1
+ LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ clock-names = "bclk", "mclk";
+ };
};
diff --git a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
index 2b27d6c8f58f..3b03e2acd67e 100644
--- a/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
@@ -127,7 +127,7 @@ patternProperties:
contains:
# MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and
# QUINARY_MI2S_RX - QUINARY_MI2S_TX and
- # LPI_MI2S_RX_0 - SENARY_MI2S_TX
+ # LPI_MI2S_RX_0 - LPI_MI2S_TX_6
items:
oneOf:
- minimum: 16
@@ -135,7 +135,7 @@ patternProperties:
- minimum: 127
maximum: 128
- minimum: 137
- maximum: 148
+ maximum: 152
then:
required:
- qcom,sd-lines
diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
index dae440ecab59..1536fcd96d68 100644
--- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
@@ -24,12 +24,16 @@ properties:
- items:
- enum:
- qcom,eliza-sndcard
+ - qcom,hawi-sndcard
- qcom,kaanapali-sndcard
+ - qcom,maili-sndcard
+ - qcom,sm8475-sndcard
- qcom,sm8550-sndcard
- qcom,sm8650-sndcard
- qcom,sm8750-sndcard
- const: qcom,sm8450-sndcard
- enum:
+ - ayaneo,pocket-s2-sndcard
- fairphone,fp4-sndcard
- fairphone,fp5-sndcard
- qcom,apq8096-sndcard
@@ -45,6 +49,7 @@ properties:
- qcom,qrb5165-rb5-sndcard
- qcom,sc7180-qdsp6-sndcard
- qcom,sc8280xp-sndcard
+ - qcom,sdm660-sndcard
- qcom,sdm845-sndcard
- qcom,sm8250-sndcard
- qcom,sm8450-sndcard
@@ -91,6 +96,19 @@ patternProperties:
sound-dai:
maxItems: 1
+ dai-tdm-slot-num:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Number of slots in use
+
+ dai-tdm-slot-width:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Width, in bits, of each slot
+
+ patternProperties:
+ '^dai-tdm-slot-[rt]x-mask$':
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Slot mask for active TDM slots
+
platform:
description: Holds subnode which indicates platform dai.
type: object
@@ -110,6 +128,19 @@ patternProperties:
minItems: 1
maxItems: 8
+ dai-tdm-slot-num:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Number of slots in use
+
+ dai-tdm-slot-width:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: Width, in bits, of each slot
+
+ patternProperties:
+ '^dai-tdm-slot-[rt]x-mask$':
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Slot mask for active TDM slots
+
required:
- link-name
- cpu
diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml
new file mode 100644
index 000000000000..00a6a05e9443
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,wsa8855.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/qcom,wsa8855.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm WSA8855 stereo smart speaker amplifier
+
+maintainers:
+ - Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
+ - Prasad Kumpatla <prasad.kumpatla@oss.qualcomm.com>
+
+description:
+ WSA885X is a Qualcomm Aqstic stereo smart speaker amplifier. It uses a PCM
+ audio interface, an I2C control interface, and a Class-H amplifier path for
+ high efficiency, low output noise, and low idle power consumption.
+
+allOf:
+ - $ref: dai-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,wsa8855
+
+ reg:
+ maxItems: 1
+
+ '#sound-dai-cells':
+ const: 0
+
+ powerdown-gpios:
+ description: GPIO controlling the SD_N powerdown pin.
+ maxItems: 1
+
+ reset-gpios:
+ description: GPIO controlling the SD_N powerdown pin.
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ vdd-1p8-supply: true
+
+ vdd-io-supply: true
+
+ qcom,battery-config:
+ description:
+ Battery topology connected to the speaker amplifier. 1S indicates one
+ battery cell in series, while 2S indicates two battery cells in series.
+ $ref: /schemas/types.yaml#/definitions/string
+ default: 1s
+ enum:
+ - 1s
+ - 2s
+
+required:
+ - compatible
+ - reg
+ - '#sound-dai-cells'
+ - interrupts
+ - vdd-1p8-supply
+ - vdd-io-supply
+
+oneOf:
+ - required:
+ - powerdown-gpios
+ - required:
+ - reset-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ speaker@c {
+ compatible = "qcom,wsa8855";
+ reg = <0x0c>;
+ #sound-dai-cells = <0>;
+ powerdown-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <77 IRQ_TYPE_EDGE_FALLING>;
+ vdd-1p8-supply = <&vreg_l2g_1p8>;
+ vdd-io-supply = <&vreg_l1g_1p2>;
+ qcom,battery-config = "1s";
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml b/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
index 880196081a60..3c44ebf93a44 100644
--- a/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
+++ b/Documentation/devicetree/bindings/sound/realtek,rt1015.yaml
@@ -19,7 +19,7 @@ properties:
realtek,power-up-delay-ms:
description: Set a delay time for flush work to be completed,
- this vlaue is adjustable depending on platform.
+ this value is adjustable depending on platform.
maxItems: 1
required:
diff --git a/Documentation/devicetree/bindings/sound/renesas,r9a09g047-sound.yaml b/Documentation/devicetree/bindings/sound/renesas,r9a09g047-sound.yaml
index d7fa16554698..213c1c40b6f0 100644
--- a/Documentation/devicetree/bindings/sound/renesas,r9a09g047-sound.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,r9a09g047-sound.yaml
@@ -793,7 +793,7 @@ examples:
bitclock-master = <&rsnd_endpoint0>;
frame-master = <&rsnd_endpoint0>;
playback = <&ssi3>, <&src1>, <&dvc1>;
- capture = <&ssi4>, <&src0>, <&dvc0>;
+ capture = <&ssi4>, <&src0>, <&dvc0>;
};
};
};
diff --git a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
index 240d90402e4f..72723f067b2a 100644
--- a/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
+++ b/Documentation/devicetree/bindings/sound/spacemit,k1-i2s.yaml
@@ -23,9 +23,9 @@ allOf:
then:
properties:
clocks:
- minItems: 7
+ minItems: 6
clock-names:
- minItems: 7
+ minItems: 6
else:
properties:
clocks:
@@ -43,26 +43,50 @@ properties:
maxItems: 1
clocks:
- minItems: 4
- items:
- - description: clock for I2S sysclk
- - description: clock for I2S bclk
- - description: clock for I2S bus
- - description: clock for I2S controller
- - description: clock for I2S sysclk divider
- - description: clock for I2S common sysclk
- - description: clock for I2S common bclk
+ oneOf:
+ - items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+ - items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+ - description: clock for I2S common sysclk
+ - description: clock for I2S common bclk
+ - items:
+ - description: clock for I2S sysclk
+ - description: clock for I2S bclk
+ - description: clock for I2S bus
+ - description: clock for I2S controller
+ - description: clock for I2S sysclk divider
+ - description: clock for I2S common sysclk
+ - description: clock for I2S common bclk
clock-names:
- minItems: 4
- items:
- - const: sysclk
- - const: bclk
- - const: bus
- - const: func
- - const: sysclk_div
- - const: c_sysclk
- - const: c_bclk
+ oneOf:
+ - items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+ - items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+ - const: c_sysclk
+ - const: c_bclk
+ - items:
+ - const: sysclk
+ - const: bclk
+ - const: bus
+ - const: func
+ - const: sysclk_div
+ - const: c_sysclk
+ - const: c_bclk
dmas:
minItems: 1
diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt
index 52265fb757c5..266b6fc9f009 100644
--- a/Documentation/devicetree/bindings/sound/st,sta32x.txt
+++ b/Documentation/devicetree/bindings/sound/st,sta32x.txt
@@ -73,7 +73,7 @@ Optional properties:
- st,odd-pwm-speed-mode:
If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
- channels. If not present, normal PWM spped mode (384 kHz) will be used.
+ channels. If not present, normal PWM speed mode (384 kHz) will be used.
- st,invalid-input-detect-mute:
If present, automatic invalid input detect mute is enabled.
diff --git a/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml b/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml
new file mode 100644
index 000000000000..773b9bf2f1c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ti,omap4-dmic.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/ti,omap4-dmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments OMAP4+ Digital Microphone Module
+
+maintainers:
+ - Peter Ujfalusi <peter.ujfalusi@ti.com>
+
+properties:
+ compatible:
+ const: ti,omap4-dmic
+
+ reg:
+ items:
+ - description: MPU access base address
+ - description: L3 interconnect address
+
+ reg-names:
+ items:
+ - const: mpu
+ - const: dma
+
+ interrupts:
+ maxItems: 1
+
+ dmas:
+ maxItems: 1
+
+ dma-names:
+ items:
+ - const: up_link
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - dmas
+ - dma-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ dmic@0 {
+ compatible = "ti,omap4-dmic";
+ reg = <0x0 0x7f>, /* MPU private access */
+ <0x4902e000 0x7f>; /* L3 Interconnect */
+ reg-names = "mpu", "dma";
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&sdma 67>;
+ dma-names = "up_link";
+ };
diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
index 4d951ece394e..dffc41d5f7de 100644
--- a/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
+++ b/Documentation/devicetree/bindings/sound/wlf,wm8524.yaml
@@ -24,6 +24,10 @@ properties:
description:
a GPIO spec for the MUTE pin.
+ port:
+ $ref: audio-graph-port.yaml#
+ unevaluatedProperties: false
+
required:
- compatible
- wlf,mute-gpios
diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst
index c4aef14a3147..b2171472e6cb 100644
--- a/Documentation/sound/alsa-configuration.rst
+++ b/Documentation/sound/alsa-configuration.rst
@@ -2401,6 +2401,11 @@ quirk_flags
disabling GET_CUR instead of the whole mixer. The current volume will
then be provided by the internal cache that stores the last set
volume
+ * bit 31: ``playback_urb_fixup``
+ Some devices show the stuttering at playback, and this quirk
+ works around it by enforcing the fixed max URBs (12) instead of
+ the dynamic calculation from the buffer size, and passing the
+ `URB_ISO_ASAP` URB flag.
This module supports multiple devices, autoprobe and hotplugging.
diff --git a/Documentation/sound/hd-audio/notes.rst b/Documentation/sound/hd-audio/notes.rst
index 6993bfa159b4..c16f83875b80 100644
--- a/Documentation/sound/hd-audio/notes.rst
+++ b/Documentation/sound/hd-audio/notes.rst
@@ -42,7 +42,7 @@ If you are interested in the deep debugging of HD-audio, read the
HD-audio specification at first. The specification is found on
Intel's web page, for example:
-* https://www.intel.com/content/www/us/en/standards/high-definition-audio-specification.html
+* https://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/high-definition-audio-specification.pdf
HD-Audio Controller
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e9e374f2ad66..fce86b1b2fae 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1749,6 +1749,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
* by the drivers/platform/x86/serial-multi-instantiate.c driver, which
* knows which client device id to use for each resource.
*/
+ {"AWDZ8399", },
{"BSG1160", },
{"BSG2150", },
{"CSC3551", },
diff --git a/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c b/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c
index 5167305521cd..c966b30e1082 100644
--- a/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c
+++ b/drivers/firmware/cirrus/test/cs_dsp_mock_regmap.c
@@ -147,7 +147,7 @@ static const struct reg_default halo_register_defaults[] = {
{ 0x2b805c0, 0 }, /* HALO_SCRATCH1 */
{ 0x2b805c8, 0 }, /* HALO_SCRATCH2 */
{ 0x2b805d0, 0 }, /* HALO_SCRATCH3 */
- { 0x2b805c8, 0 }, /* HALO_SCRATCH4 */
+ { 0x2b805d8, 0 }, /* HALO_SCRATCH4 */
{ 0x2bc1000, 0 }, /* HALO_CCM_CORE_CONTROL */
{ 0x2bc7000, 0 }, /* HALO_WDT_CONTROL */
diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c
index 1a369334f9cb..3e89fcdd45f7 100644
--- a/drivers/platform/x86/serial-multi-instantiate.c
+++ b/drivers/platform/x86/serial-multi-instantiate.c
@@ -307,6 +307,15 @@ static void smi_remove(struct platform_device *pdev)
smi_devs_unregister(smi);
}
+static const struct smi_node aw88399_hda = {
+ .instances = {
+ { "aw88399-hda", IRQ_RESOURCE_AUTO, 0 },
+ { "aw88399-hda", IRQ_RESOURCE_AUTO, 0 },
+ {}
+ },
+ .bus_type = SMI_AUTO_DETECT,
+};
+
static const struct smi_node bsg1160_data = {
.instances = {
{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
@@ -405,6 +414,7 @@ static const struct smi_node tas2781_hda = {
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
*/
static const struct acpi_device_id smi_acpi_ids[] = {
+ { "AWDZ8399", (unsigned long)&aw88399_hda },
{ "BSG1160", (unsigned long)&bsg1160_data },
{ "BSG2150", (unsigned long)&bsg2150_data },
{ "CSC3551", (unsigned long)&cs35l41_hda },
diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
index e73c1bea9059..d61a97c5b41e 100644
--- a/drivers/soundwire/bus_type.c
+++ b/drivers/soundwire/bus_type.c
@@ -105,6 +105,9 @@ static int sdw_bus_probe(struct device *dev)
}
slave->index = ret;
+ /* Create IRQ mapping now so the driver can get it in probe() */
+ sdw_irq_create_mapping(slave);
+
ret = drv->probe(slave, id);
if (ret) {
ida_free(&slave->bus->slave_ida, slave->index);
@@ -117,9 +120,6 @@ static int sdw_bus_probe(struct device *dev)
if (drv->ops && drv->ops->read_prop)
drv->ops->read_prop(slave);
- if (slave->prop.use_domain_irq)
- sdw_irq_create_mapping(slave);
-
/* init the dynamic sysfs attributes we need */
ret = sdw_slave_sysfs_dpn_init(slave);
if (ret < 0)
diff --git a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
index 45850f2d4342..2e879a3c09ae 100644
--- a/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
+++ b/include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
@@ -152,6 +152,10 @@
#define LPI_MI2S_TX_4 146
#define SENARY_MI2S_RX 147
#define SENARY_MI2S_TX 148
+#define LPI_MI2S_RX_5 149
+#define LPI_MI2S_TX_5 150
+#define LPI_MI2S_RX_6 151
+#define LPI_MI2S_TX_6 152
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2
@@ -233,11 +237,39 @@
/* Clock ID for RX CORE MCLK2 2X MCLK */
#define LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 70
+#define LAPSS_CLK_ID_QAIF_IF0_IBIT 71
+#define LAPSS_CLK_ID_QAIF_IF0_EBIT 72
+#define LAPSS_CLK_ID_QAIF_IF1_IBIT 73
+#define LAPSS_CLK_ID_QAIF_IF1_EBIT 74
+#define LAPSS_CLK_ID_QAIF_IF2_IBIT 75
+#define LAPSS_CLK_ID_QAIF_IF2_EBIT 76
+#define LAPSS_CLK_ID_QAIF_IF3_IBIT 77
+#define LAPSS_CLK_ID_QAIF_IF3_EBIT 78
+#define LAPSS_CLK_ID_QAIF_IF4_IBIT 79
+#define LAPSS_CLK_ID_QAIF_IF4_EBIT 80
+#define LAPSS_CLK_ID_QAIF_IF5_IBIT 81
+#define LAPSS_CLK_ID_QAIF_IF5_EBIT 82
+#define LAPSS_CLK_ID_QAIF_IF6_IBIT 83
+#define LAPSS_CLK_ID_QAIF_IF6_EBIT 84
+#define LAPSS_CLK_ID_QAIF_IF7_IBIT 85
+#define LAPSS_CLK_ID_QAIF_IF7_EBIT 86
+#define LAPSS_CLK_ID_QAIF_IF8_IBIT 87
+#define LAPSS_CLK_ID_QAIF_IF8_EBIT 88
+#define LAPSS_CLK_ID_QAIF_IF9_IBIT 89
+#define LAPSS_CLK_ID_QAIF_IF9_EBIT 90
+#define LAPSS_CLK_ID_QAIF_IF10_IBIT 91
+#define LAPSS_CLK_ID_QAIF_IF10_EBIT 92
+#define LAPSS_CLK_ID_QAIF_IF11_IBIT 93
+#define LAPSS_CLK_ID_QAIF_IF11_EBIT 94
+#define LAPSS_CLK_ID_QAIF_IF12_IBIT 95
+#define LAPSS_CLK_ID_QAIF_IF12_EBIT 96
+#define LAPSS_CLK_ID_VA_QAIF_IF0_IBIT 97
+#define LAPSS_CLK_ID_VA_QAIF_IF0_EBIT 98
+
#define LPASS_HW_AVTIMER_VOTE 101
#define LPASS_HW_MACRO_VOTE 102
#define LPASS_HW_DCODEC_VOTE 103
-
-#define Q6AFE_MAX_CLK_ID 104
+#define LPASS_HW_LPR_VOTE 104
#define LPASS_CLK_ATTRIBUTE_INVALID 0x0
#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1
diff --git a/include/linux/platform_data/omap-twl4030.h b/include/linux/platform_data/omap-twl4030.h
deleted file mode 100644
index 7fcb55fe21c9..000000000000
--- a/include/linux/platform_data/omap-twl4030.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/**
- * omap-twl4030.h - ASoC machine driver for TI SoC based boards with twl4030
- * codec, header.
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com
- * All rights reserved.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- */
-
-#ifndef _OMAP_TWL4030_H_
-#define _OMAP_TWL4030_H_
-
-/* To select if only one channel is connected in a stereo port */
-#define OMAP_TWL4030_LEFT (1 << 0)
-#define OMAP_TWL4030_RIGHT (1 << 1)
-
-struct omap_tw4030_pdata {
- const char *card_name;
- /* Voice port is connected to McBSP3 */
- bool voice_connected;
-
- /* The driver will parse the connection flags if this flag is set */
- bool custom_routing;
- /* Flags to indicate connected audio ports. */
- u8 has_hs;
- u8 has_hf;
- u8 has_predriv;
- u8 has_carkit;
- bool has_ear;
-
- bool has_mainmic;
- bool has_submic;
- bool has_hsmic;
- bool has_carkitmic;
- bool has_digimic0;
- bool has_digimic1;
- u8 has_linein;
-};
-
-#endif /* _OMAP_TWL4030_H_ */
diff --git a/include/sound/ac97/codec.h b/include/sound/ac97/codec.h
index 69b404c354f5..69aa7ee15b91 100644
--- a/include/sound/ac97/codec.h
+++ b/include/sound/ac97/codec.h
@@ -33,7 +33,7 @@ struct ac97_id {
};
/**
- * ac97_codec_device - a ac97 codec
+ * struct ac97_codec_device - a ac97 codec
* @dev: the core device
* @vendor_id: the vendor_id of the codec, as sensed on the AC-link
* @num: the codec number, 0 is primary, 1 is first slave, etc ...
@@ -53,7 +53,7 @@ struct ac97_codec_device {
};
/**
- * ac97_codec_driver - a ac97 codec driver
+ * struct ac97_codec_driver - a ac97 codec driver
* @driver: the device driver structure
* @probe: the function called when a ac97_codec_device is matched
* @remove: the function called when the device is unbound/removed
diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h
index ddbb6bf801bb..efad366736a4 100644
--- a/include/sound/asequencer.h
+++ b/include/sound/asequencer.h
@@ -11,9 +11,6 @@
#include <sound/asound.h>
#include <uapi/sound/asequencer.h>
-/* helper macro */
-#define snd_seq_event_bounce_ext_data(ev) ((void*)((char *)(ev)->data.ext.ptr + sizeof(struct snd_seq_event_bounce)))
-
/*
* type check macros
*/
diff --git a/include/sound/aw88399.h b/include/sound/aw88399.h
new file mode 100644
index 000000000000..a1e0de6be8ea
--- /dev/null
+++ b/include/sound/aw88399.h
@@ -0,0 +1,621 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * linux/sound/aw88399.h -- Platform data for AW88399
+ *
+ * Copyright (c) 2023 AWINIC Technology CO., LTD
+ *
+ * Author: Weidong Wang <wangweidong.a@awinic.com>
+ */
+
+#ifndef __SOUND_AW88399_H
+#define __SOUND_AW88399_H
+
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+/* registers list */
+#define AW88399_ID_REG (0x00)
+#define AW88399_SYSST_REG (0x01)
+#define AW88399_SYSINT_REG (0x02)
+#define AW88399_SYSINTM_REG (0x03)
+#define AW88399_SYSCTRL_REG (0x04)
+#define AW88399_SYSCTRL2_REG (0x05)
+#define AW88399_I2SCTRL1_REG (0x06)
+#define AW88399_I2SCTRL2_REG (0x07)
+#define AW88399_I2SCTRL3_REG (0x08)
+#define AW88399_DACCFG1_REG (0x09)
+#define AW88399_DACCFG2_REG (0x0A)
+#define AW88399_DACCFG3_REG (0x0B)
+#define AW88399_DACCFG4_REG (0x0C)
+#define AW88399_DACCFG5_REG (0x0D)
+#define AW88399_DACCFG6_REG (0x0E)
+#define AW88399_DACCFG7_REG (0x0F)
+#define AW88399_MPDCFG1_REG (0x10)
+#define AW88399_MPDCFG2_REG (0x11)
+#define AW88399_MPDCFG3_REG (0x12)
+#define AW88399_MPDCFG4_REG (0x13)
+#define AW88399_PWMCTRL1_REG (0x14)
+#define AW88399_PWMCTRL2_REG (0x15)
+#define AW88399_PWMCTRL3_REG (0x16)
+#define AW88399_I2SCFG1_REG (0x17)
+#define AW88399_DBGCTRL_REG (0x18)
+#define AW88399_HAGCST_REG (0x20)
+#define AW88399_VBAT_REG (0x21)
+#define AW88399_TEMP_REG (0x22)
+#define AW88399_PVDD_REG (0x23)
+#define AW88399_ISNDAT_REG (0x24)
+#define AW88399_VSNDAT_REG (0x25)
+#define AW88399_I2SINT_REG (0x26)
+#define AW88399_I2SCAPCNT_REG (0x27)
+#define AW88399_ANASTA1_REG (0x28)
+#define AW88399_ANASTA2_REG (0x29)
+#define AW88399_ANASTA3_REG (0x2A)
+#define AW88399_TESTDET_REG (0x2B)
+#define AW88399_DSMCFG1_REG (0x30)
+#define AW88399_DSMCFG2_REG (0x31)
+#define AW88399_DSMCFG3_REG (0x32)
+#define AW88399_DSMCFG4_REG (0x33)
+#define AW88399_DSMCFG5_REG (0x34)
+#define AW88399_DSMCFG6_REG (0x35)
+#define AW88399_DSMCFG7_REG (0x36)
+#define AW88399_DSMCFG8_REG (0x37)
+#define AW88399_TESTIN_REG (0x38)
+#define AW88399_TESTOUT_REG (0x39)
+#define AW88399_MEMTEST_REG (0x3A)
+#define AW88399_VSNCTRL1_REG (0x3B)
+#define AW88399_ISNCTRL1_REG (0x3C)
+#define AW88399_ISNCTRL2_REG (0x3D)
+#define AW88399_DSPMADD_REG (0x40)
+#define AW88399_DSPMDAT_REG (0x41)
+#define AW88399_WDT_REG (0x42)
+#define AW88399_ACR1_REG (0x43)
+#define AW88399_ACR2_REG (0x44)
+#define AW88399_ASR1_REG (0x45)
+#define AW88399_ASR2_REG (0x46)
+#define AW88399_DSPCFG_REG (0x47)
+#define AW88399_ASR3_REG (0x48)
+#define AW88399_ASR4_REG (0x49)
+#define AW88399_DSPVCALB_REG (0x4A)
+#define AW88399_CRCCTRL_REG (0x4B)
+#define AW88399_DSPDBG1_REG (0x4C)
+#define AW88399_DSPDBG2_REG (0x4D)
+#define AW88399_DSPDBG3_REG (0x4E)
+#define AW88399_PLLCTRL1_REG (0x50)
+#define AW88399_PLLCTRL2_REG (0x51)
+#define AW88399_PLLCTRL3_REG (0x52)
+#define AW88399_CDACTRL1_REG (0x53)
+#define AW88399_CDACTRL2_REG (0x54)
+#define AW88399_CDACTRL3_REG (0x55)
+#define AW88399_SADCCTRL1_REG (0x56)
+#define AW88399_SADCCTRL2_REG (0x57)
+#define AW88399_BOPCTRL1_REG (0x58)
+#define AW88399_BOPCTRL2_REG (0x5A)
+#define AW88399_BOPCTRL3_REG (0x5B)
+#define AW88399_BOPCTRL4_REG (0x5C)
+#define AW88399_BOPCTRL5_REG (0x5D)
+#define AW88399_BOPCTRL6_REG (0x5E)
+#define AW88399_BOPCTRL7_REG (0x5F)
+#define AW88399_BSTCTRL1_REG (0x60)
+#define AW88399_BSTCTRL2_REG (0x61)
+#define AW88399_BSTCTRL3_REG (0x62)
+#define AW88399_BSTCTRL4_REG (0x63)
+#define AW88399_BSTCTRL5_REG (0x64)
+#define AW88399_BSTCTRL6_REG (0x65)
+#define AW88399_BSTCTRL7_REG (0x66)
+#define AW88399_BSTCTRL8_REG (0x67)
+#define AW88399_BSTCTRL9_REG (0x68)
+#define AW88399_BSTCTRL10_REG (0x69)
+#define AW88399_CPCTRL_REG (0x6A)
+#define AW88399_EFWH_REG (0x6C)
+#define AW88399_EFWM2_REG (0x6D)
+#define AW88399_EFWM1_REG (0x6E)
+#define AW88399_EFWL_REG (0x6F)
+#define AW88399_TESTCTRL1_REG (0x70)
+#define AW88399_TESTCTRL2_REG (0x71)
+#define AW88399_EFCTRL1_REG (0x72)
+#define AW88399_EFCTRL2_REG (0x73)
+#define AW88399_EFRH4_REG (0x74)
+#define AW88399_EFRH3_REG (0x75)
+#define AW88399_EFRH2_REG (0x76)
+#define AW88399_EFRH1_REG (0x77)
+#define AW88399_EFRL4_REG (0x78)
+#define AW88399_EFRL3_REG (0x79)
+#define AW88399_EFRL2_REG (0x7A)
+#define AW88399_EFRL1_REG (0x7B)
+#define AW88399_TM_REG (0x7C)
+#define AW88399_TM2_REG (0x7D)
+
+#define AW88399_REG_MAX (0x7E)
+#define AW88399_MUTE_VOL (1023)
+
+#define AW88399_DSP_CFG_ADDR (0x9B00)
+#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68)
+#define AW88399_DSP_FW_ADDR (0x8980)
+#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40)
+#define AW88399_DSP_ROM_CHECK_DATA (0x4638)
+
+#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000))
+#define AW88399_CALI_RE_HBITS_SHIFT (16)
+
+#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF))
+#define AW88399_CALI_RE_LBITS_SHIFT (0)
+
+#define AW88399_I2STXEN_START_BIT (9)
+#define AW88399_I2STXEN_BITS_LEN (1)
+#define AW88399_I2STXEN_MASK \
+ (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT))
+
+#define AW88399_I2STXEN_DISABLE (0)
+#define AW88399_I2STXEN_DISABLE_VALUE \
+ (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT)
+
+#define AW88399_I2STXEN_ENABLE (1)
+#define AW88399_I2STXEN_ENABLE_VALUE \
+ (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT)
+
+#define AW88399_VOL_START_BIT (0)
+#define AW88399_VOL_BITS_LEN (10)
+#define AW88399_VOL_MASK \
+ (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT))
+
+#define AW88399_PWDN_START_BIT (0)
+#define AW88399_PWDN_BITS_LEN (1)
+#define AW88399_PWDN_MASK \
+ (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT))
+
+#define AW88399_PWDN_POWER_DOWN (1)
+#define AW88399_PWDN_POWER_DOWN_VALUE \
+ (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT)
+
+#define AW88399_PWDN_WORKING (0)
+#define AW88399_PWDN_WORKING_VALUE \
+ (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT)
+
+#define AW88399_DSPBY_START_BIT (2)
+#define AW88399_DSPBY_BITS_LEN (1)
+#define AW88399_DSPBY_MASK \
+ (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT))
+
+#define AW88399_DSPBY_WORKING (0)
+#define AW88399_DSPBY_WORKING_VALUE \
+ (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT)
+
+#define AW88399_DSPBY_BYPASS (1)
+#define AW88399_DSPBY_BYPASS_VALUE \
+ (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT)
+
+#define AW88399_MEM_CLKSEL_START_BIT (3)
+#define AW88399_MEM_CLKSEL_BITS_LEN (1)
+#define AW88399_MEM_CLKSEL_MASK \
+ (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT))
+
+#define AW88399_MEM_CLKSEL_OSCCLK (0)
+#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \
+ (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT)
+
+#define AW88399_MEM_CLKSEL_DAPHCLK (1)
+#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \
+ (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT)
+
+#define AW88399_DITHER_EN_START_BIT (15)
+#define AW88399_DITHER_EN_BITS_LEN (1)
+#define AW88399_DITHER_EN_MASK \
+ (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT))
+
+#define AW88399_DITHER_EN_DISABLE (0)
+#define AW88399_DITHER_EN_DISABLE_VALUE \
+ (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT)
+
+#define AW88399_DITHER_EN_ENABLE (1)
+#define AW88399_DITHER_EN_ENABLE_VALUE \
+ (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT)
+
+#define AW88399_HMUTE_START_BIT (8)
+#define AW88399_HMUTE_BITS_LEN (1)
+#define AW88399_HMUTE_MASK \
+ (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT))
+
+#define AW88399_HMUTE_DISABLE (0)
+#define AW88399_HMUTE_DISABLE_VALUE \
+ (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT)
+
+#define AW88399_HMUTE_ENABLE (1)
+#define AW88399_HMUTE_ENABLE_VALUE \
+ (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT)
+
+#define AW88399_EF_DBMD_START_BIT (2)
+#define AW88399_EF_DBMD_BITS_LEN (1)
+#define AW88399_EF_DBMD_MASK \
+ (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT))
+
+#define AW88399_EF_DBMD_OR (1)
+#define AW88399_EF_DBMD_OR_VALUE \
+ (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT)
+
+#define AW88399_VDSEL_START_BIT (5)
+#define AW88399_VDSEL_BITS_LEN (1)
+#define AW88399_VDSEL_MASK \
+ (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT))
+
+#define AW88399_EF_ISN_GESLP_H_START_BIT (0)
+#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10)
+#define AW88399_EF_ISN_GESLP_H_MASK \
+ (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT))
+
+/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */
+#define AW88399_EF_VSN_GESLP_H_START_BIT (0)
+#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10)
+#define AW88399_EF_VSN_GESLP_H_MASK \
+ (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT))
+
+#define AW88399_EF_ISN_GESLP_L_START_BIT (0)
+#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10)
+#define AW88399_EF_ISN_GESLP_L_MASK \
+ (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT))
+
+/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */
+#define AW88399_EF_VSN_GESLP_L_START_BIT (0)
+#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10)
+#define AW88399_EF_VSN_GESLP_L_MASK \
+ (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT))
+
+#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9)
+#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6)
+#define AW88399_INTERNAL_VSN_TRIM_H_MASK \
+ (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT))
+
+#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9)
+#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6)
+#define AW88399_INTERNAL_VSN_TRIM_L_MASK \
+ (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT))
+
+#define AW88399_RCV_MODE_START_BIT (7)
+#define AW88399_RCV_MODE_BITS_LEN (1)
+#define AW88399_RCV_MODE_MASK \
+ (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT))
+
+#define AW88399_CLKI_START_BIT (4)
+#define AW88399_NOCLKI_START_BIT (5)
+#define AW88399_PLLI_START_BIT (0)
+#define AW88399_PLLI_INT_VALUE (1)
+#define AW88399_PLLI_INT_INTERRUPT \
+ (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT)
+
+#define AW88399_CLKI_INT_VALUE (1)
+#define AW88399_CLKI_INT_INTERRUPT \
+ (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT)
+
+#define AW88399_NOCLKI_INT_VALUE (1)
+#define AW88399_NOCLKI_INT_INTERRUPT \
+ (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT)
+
+#define AW88399_BIT_SYSINT_CHECK \
+ (AW88399_PLLI_INT_INTERRUPT | \
+ AW88399_CLKI_INT_INTERRUPT | \
+ AW88399_NOCLKI_INT_INTERRUPT)
+
+#define AW88399_CRC_CHECK_START_BIT (12)
+#define AW88399_CRC_CHECK_BITS_LEN (3)
+#define AW88399_CRC_CHECK_BITS_MASK \
+ (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT))
+
+#define AW88399_RCV_MODE_RECEIVER (1)
+#define AW88399_RCV_MODE_RECEIVER_VALUE \
+ (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT)
+
+#define AW88399_AMPPD_START_BIT (1)
+#define AW88399_AMPPD_BITS_LEN (1)
+#define AW88399_AMPPD_MASK \
+ (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT))
+
+#define AW88399_AMPPD_WORKING (0)
+#define AW88399_AMPPD_WORKING_VALUE \
+ (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT)
+
+#define AW88399_AMPPD_POWER_DOWN (1)
+#define AW88399_AMPPD_POWER_DOWN_VALUE \
+ (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT)
+
+#define AW88399_RAM_CG_BYP_START_BIT (0)
+#define AW88399_RAM_CG_BYP_BITS_LEN (1)
+#define AW88399_RAM_CG_BYP_MASK \
+ (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT))
+
+#define AW88399_RAM_CG_BYP_WORK (0)
+#define AW88399_RAM_CG_BYP_WORK_VALUE \
+ (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT)
+
+#define AW88399_RAM_CG_BYP_BYPASS (1)
+#define AW88399_RAM_CG_BYP_BYPASS_VALUE \
+ (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT)
+
+#define AW88399_CRC_END_ADDR_START_BIT (0)
+#define AW88399_CRC_END_ADDR_BITS_LEN (12)
+#define AW88399_CRC_END_ADDR_MASK \
+ (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT))
+
+#define AW88399_CRC_CODE_EN_START_BIT (13)
+#define AW88399_CRC_CODE_EN_BITS_LEN (1)
+#define AW88399_CRC_CODE_EN_MASK \
+ (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT))
+
+#define AW88399_CRC_CODE_EN_DISABLE (0)
+#define AW88399_CRC_CODE_EN_DISABLE_VALUE \
+ (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT)
+
+#define AW88399_CRC_CODE_EN_ENABLE (1)
+#define AW88399_CRC_CODE_EN_ENABLE_VALUE \
+ (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT)
+
+#define AW88399_CRC_CFG_EN_START_BIT (12)
+#define AW88399_CRC_CFG_EN_BITS_LEN (1)
+#define AW88399_CRC_CFG_EN_MASK \
+ (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT))
+
+#define AW88399_CRC_CFG_EN_DISABLE (0)
+#define AW88399_CRC_CFG_EN_DISABLE_VALUE \
+ (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT)
+
+#define AW88399_CRC_CFG_EN_ENABLE (1)
+#define AW88399_CRC_CFG_EN_ENABLE_VALUE \
+ (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT)
+
+#define AW88399_OCDS_START_BIT (3)
+#define AW88399_OCDS_OC (1)
+#define AW88399_OCDS_OC_VALUE \
+ (AW88399_OCDS_OC << AW88399_OCDS_START_BIT)
+
+#define AW88399_NOCLKS_START_BIT (5)
+#define AW88399_NOCLKS_NO_CLOCK (1)
+#define AW88399_NOCLKS_NO_CLOCK_VALUE \
+ (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT)
+
+#define AW88399_SWS_START_BIT (8)
+#define AW88399_SWS_SWITCHING (1)
+#define AW88399_SWS_SWITCHING_VALUE \
+ (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT)
+
+#define AW88399_BSTS_START_BIT (9)
+#define AW88399_BSTS_FINISHED (1)
+#define AW88399_BSTS_FINISHED_VALUE \
+ (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT)
+
+#define AW88399_UVLS_START_BIT (14)
+#define AW88399_UVLS_NORMAL (0)
+#define AW88399_UVLS_NORMAL_VALUE \
+ (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT)
+
+#define AW88399_BSTOCS_START_BIT (11)
+#define AW88399_BSTOCS_OVER_CURRENT (1)
+#define AW88399_BSTOCS_OVER_CURRENT_VALUE \
+ (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT)
+
+#define AW88399_OTHS_START_BIT (1)
+#define AW88399_OTHS_OT (1)
+#define AW88399_OTHS_OT_VALUE \
+ (AW88399_OTHS_OT << AW88399_OTHS_START_BIT)
+
+#define AW88399_PLLS_START_BIT (0)
+#define AW88399_PLLS_LOCKED (1)
+#define AW88399_PLLS_LOCKED_VALUE \
+ (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT)
+
+#define AW88399_CLKS_START_BIT (4)
+#define AW88399_CLKS_STABLE (1)
+#define AW88399_CLKS_STABLE_VALUE \
+ (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT)
+
+#define AW88399_BIT_PLL_CHECK \
+ (AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE)
+
+#define AW88399_BIT_SYSST_CHECK_MASK \
+ (~(AW88399_UVLS_NORMAL_VALUE | \
+ AW88399_BSTOCS_OVER_CURRENT_VALUE | \
+ AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_SWS_SWITCHING_VALUE | \
+ AW88399_NOCLKS_NO_CLOCK_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_OCDS_OC_VALUE | \
+ AW88399_OTHS_OT_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE))
+
+#define AW88399_BIT_SYSST_NOSWS_CHECK \
+ (AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE)
+
+#define AW88399_BIT_SYSST_SWS_CHECK \
+ (AW88399_BSTS_FINISHED_VALUE | \
+ AW88399_CLKS_STABLE_VALUE | \
+ AW88399_PLLS_LOCKED_VALUE | \
+ AW88399_SWS_SWITCHING_VALUE)
+
+#define AW88399_CCO_MUX_START_BIT (14)
+#define AW88399_CCO_MUX_BITS_LEN (1)
+#define AW88399_CCO_MUX_MASK \
+ (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT))
+
+#define AW88399_CCO_MUX_DIVIDED (0)
+#define AW88399_CCO_MUX_DIVIDED_VALUE \
+ (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT)
+
+#define AW88399_CCO_MUX_BYPASS (1)
+#define AW88399_CCO_MUX_BYPASS_VALUE \
+ (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT)
+
+#define AW88399_NOISE_GATE_EN_START_BIT (13)
+#define AW88399_NOISE_GATE_EN_BITS_LEN (1)
+#define AW88399_NOISE_GATE_EN_MASK \
+ (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
+
+#define AW88399_WDT_CNT_START_BIT (0)
+#define AW88399_WDT_CNT_BITS_LEN (8)
+#define AW88399_WDT_CNT_MASK \
+ (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT))
+
+#define AW88399_REABS_START_BIT (3)
+#define AW88399_REABS_BITS_LEN (1)
+#define AW88399_REABS_MASK \
+ (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT))
+
+#define AW88399_DSP_VOL_START_BIT (8)
+#define AW88399_DSP_VOL_BITS_LEN (8)
+#define AW88399_DSP_VOL_MASK \
+ (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT))
+
+#define AW883XX_DSP_NG_EN_START (13)
+#define AW883XX_DSP_NG_EN_LEN (1)
+#define AW883XX_DSP_NG_EN_MASK \
+ (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START))
+#define AW883XX_DSP_NG_EN_DISABLE (0)
+#define AW883XX_DSP_NG_EN_DISABLE_VALUE \
+ (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START)
+
+#define AW88399_VOLUME_STEP_DB (64)
+#define AW88399_VOL_DEFAULT_VALUE (0)
+#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555)
+#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9))
+#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00)
+
+#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9))
+#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00)
+
+#define AW88399_TEM4_SIGN_MASK (~(1 << 5))
+#define AW88399_TEM4_SIGN_NEG (0xffc0)
+
+#define AW88399_ICABLK_FACTOR (1)
+#define AW88399_VCABLK_FACTOR (1)
+#define AW88399_VCABLK_DAC_FACTOR (2)
+
+#define AW88399_VCALB_ADJ_FACTOR (12)
+#define AW88399_VCALB_ACCURACY (1 << 12)
+
+#define AW88399_ISCAL_FACTOR (3125)
+#define AW88399_VSCAL_FACTOR (18875)
+#define AW88399_ISCAL_DAC_FACTOR (3125)
+#define AW88399_VSCAL_DAC_FACTOR (12600)
+#define AW88399_CABL_BASE_VALUE (1000)
+
+#define AW88399_DEV_DEFAULT_CH (0)
+#define AW88399_DEV_DSP_CHECK_MAX (5)
+#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128)
+#define AW88399_DSP_RE_SHIFT (12)
+#define AW88399_CALI_RE_MAX (15000)
+#define AW88399_CALI_RE_MIN (4000)
+#define AW_FW_ADDR_LEN (4)
+#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
+#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
+#define AW88399_CRC_CHECK_PASS_VAL (0x4)
+
+#define AW88399_CRC_CFG_BASE_ADDR (0xD80)
+#define AW88399_CRC_FW_BASE_ADDR (0x4C0)
+#define AW88399_ACF_FILE "aw88399_acf.bin"
+#define AW88399_DEV_SYSST_CHECK_MAX (10)
+#define AW88399_CHIP_ID 0x2183
+
+#define AW88399_START_RETRIES (5)
+#define AW88399_START_WORK_DELAY_MS (0)
+
+enum {
+ AW_EF_AND_CHECK = 0,
+ AW_EF_OR_CHECK,
+};
+
+enum {
+ AW88399_DEV_VDSEL_DAC = 0,
+ AW88399_DEV_VDSEL_VSENSE = 32,
+};
+
+enum {
+ AW88399_DSP_CRC_NA = 0,
+ AW88399_DSP_CRC_OK = 1,
+};
+
+enum {
+ AW88399_DSP_FW_UPDATE_OFF = 0,
+ AW88399_DSP_FW_UPDATE_ON = 1,
+};
+
+enum {
+ AW88399_FORCE_UPDATE_OFF = 0,
+ AW88399_FORCE_UPDATE_ON = 1,
+};
+
+enum {
+ AW88399_1000_US = 1000,
+ AW88399_2000_US = 2000,
+ AW88399_3000_US = 3000,
+ AW88399_4000_US = 4000,
+};
+
+enum AW88399_DEV_STATUS {
+ AW88399_DEV_PW_OFF = 0,
+ AW88399_DEV_PW_ON,
+};
+
+enum AW88399_DEV_FW_STATUS {
+ AW88399_DEV_FW_FAILED = 0,
+ AW88399_DEV_FW_OK,
+};
+
+enum AW88399_DEV_MEMCLK {
+ AW88399_DEV_MEMCLK_OSC = 0,
+ AW88399_DEV_MEMCLK_PLL = 1,
+};
+
+enum AW88399_DEV_DSP_CFG {
+ AW88399_DEV_DSP_WORK = 0,
+ AW88399_DEV_DSP_BYPASS = 1,
+};
+
+enum {
+ AW88399_NOT_RCV_MODE = 0,
+ AW88399_RCV_MODE = 1,
+};
+
+enum {
+ AW88399_SYNC_START = 0,
+ AW88399_ASYNC_START,
+};
+
+struct aw_device;
+struct aw_container;
+struct aw_cali_desc;
+struct gpio_desc;
+struct i2c_client;
+struct regmap;
+
+struct aw88399 {
+ struct aw_device *aw_pa;
+ struct mutex lock;
+ struct gpio_desc *reset_gpio;
+ struct delayed_work start_work;
+ struct regmap *regmap;
+ struct aw_container *aw_cfg;
+
+ unsigned int check_val;
+ unsigned int crc_init_val;
+ unsigned int vcalb_init_val;
+ unsigned int dither_st;
+ bool bsts_unreliable;
+ bool fw_needs_reload;
+};
+
+int aw_dev_check_syspll(struct aw_device *aw_dev);
+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable);
+int aw_dev_get_dsp_status(struct aw_device *aw_dev);
+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value);
+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc);
+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name);
+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute);
+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel);
+void aw88399_hw_reset(struct aw88399 *aw88399);
+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap);
+extern const struct regmap_config aw88399_remap_config;
+int aw88399_request_firmware_file(struct aw88399 *aw88399);
+void aw88399_start(struct aw88399 *aw88399, bool sync_start);
+void aw88399_startup_work(struct work_struct *work);
+int aw88399_stop(struct aw_device *aw_dev);
+
+#endif /* __SOUND_AW88399_H */
diff --git a/include/sound/control.h b/include/sound/control.h
index e07f6b960641..909db0d0485d 100644
--- a/include/sound/control.h
+++ b/include/sound/control.h
@@ -7,6 +7,7 @@
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*/
+#include <linux/rwsem.h>
#include <linux/wait.h>
#include <linux/nospec.h>
#include <sound/asound.h>
@@ -167,6 +168,8 @@ snd_ctl_find_id_mixer(struct snd_card *card, const char *name)
int snd_ctl_create(struct snd_card *card);
+extern struct rw_semaphore snd_ioctl_rwsem;
+
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn);
#ifdef CONFIG_COMPAT
diff --git a/include/sound/core.h b/include/sound/core.h
index 404785b7d885..2ca24ac7e37f 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -108,8 +108,8 @@ struct snd_card {
char longname[80]; /* name of this soundcard */
char irq_descr[32]; /* Interrupt description */
char mixername[80]; /* mixer name */
- char components[128]; /* card components delimited with
- space */
+ char *components; /* card components, space-delimited */
+ unsigned int components_alloc_size; /* current allocation size of components */
struct module *module; /* top-level module */
void *private_data; /* private data for soundcard */
diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index 2490b72c0a7a..45a5df574aa6 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -417,7 +417,6 @@ void cs35l56_wait_control_port_ready(void);
void cs35l56_wait_min_reset_pulse(void);
void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire);
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
-irqreturn_t cs35l56_irq(int irq, void *data);
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base);
int cs35l56_runtime_suspend_common(struct cs35l56_base *cs35l56_base);
int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_soundwire);
diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index 9472f0a966a2..81422219ed39 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -175,12 +175,6 @@ int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
struct dmaengine_pcm {
struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
const struct snd_dmaengine_pcm_config *config;
- struct snd_soc_component component;
unsigned int flags;
};
-
-static inline struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p)
-{
- return container_of(p, struct dmaengine_pcm, component);
-}
#endif
diff --git a/include/sound/hda-mlink.h b/include/sound/hda-mlink.h
index fed69998c93f..ba35f03576b9 100644
--- a/include/sound/hda-mlink.h
+++ b/include/sound/hda-mlink.h
@@ -9,6 +9,22 @@
struct hdac_bus;
struct hdac_ext_link;
+/**
+ * enum hda_bus_ml_link_type - mlink link type, used by SOF link DMA
+ * allocator constraints (see struct sof_intel_hda_dev).
+ *
+ * @HDA_BUS_ML_LINK_HDA: non-alt link, i.e. HDA codec or iDisp
+ * @HDA_BUS_ML_LINK_SDW: alt link, SoundWire
+ * @HDA_BUS_ML_LINK_UAOL: alt link, USB Audio Offload
+ * @HDA_BUS_ML_LINK_OTHER: alt link, SSP or DMIC
+ */
+enum hda_bus_ml_link_type {
+ HDA_BUS_ML_LINK_HDA,
+ HDA_BUS_ML_LINK_SDW,
+ HDA_BUS_ML_LINK_UAOL,
+ HDA_BUS_ML_LINK_OTHER,
+};
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
int hda_bus_ml_init(struct hdac_bus *bus);
@@ -49,11 +65,12 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num);
int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
int channel_mask, int stream_id, int dir);
-void hda_bus_ml_put_all(struct hdac_bus *bus);
void hda_bus_ml_reset_losidv(struct hdac_bus *bus);
int hda_bus_ml_resume(struct hdac_bus *bus);
int hda_bus_ml_suspend(struct hdac_bus *bus);
+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink);
+
struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus);
struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus);
struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus);
@@ -169,11 +186,13 @@ hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
return 0;
}
-static inline void hda_bus_ml_put_all(struct hdac_bus *bus) { }
static inline void hda_bus_ml_reset_losidv(struct hdac_bus *bus) { }
static inline int hda_bus_ml_resume(struct hdac_bus *bus) { return 0; }
static inline int hda_bus_ml_suspend(struct hdac_bus *bus) { return 0; }
+static inline enum hda_bus_ml_link_type
+hda_bus_ml_link_get_type(struct hdac_ext_link *hlink) { return HDA_BUS_ML_LINK_HDA; }
+
static inline struct hdac_ext_link *
hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus) { return NULL; }
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
index b4e327877739..1d05f991f2ce 100644
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -256,6 +256,7 @@ struct hda_codec {
unsigned int link_down_at_suspend:1; /* link down at runtime suspend */
unsigned int relaxed_resume:1; /* don't resume forcibly for jack */
unsigned int forced_resume:1; /* forced resume for jack */
+ unsigned int acomp_requested_resume:1; /* resume requested by acomp */
unsigned int no_stream_clean_at_suspend:1; /* do not clean streams at suspend */
unsigned int ctl_dev_id:1; /* old control element id build behaviour */
unsigned int eld_jack_detect:1; /* Machine jack-detection by ELD */
diff --git a/include/sound/hda_regmap.h b/include/sound/hda_regmap.h
index 4c1b9bebbd60..e06e4847ed28 100644
--- a/include/sound/hda_regmap.h
+++ b/include/sound/hda_regmap.h
@@ -69,11 +69,14 @@ void snd_hdac_regmap_sync(struct hdac_device *codec);
/**
* snd_hdac_regmap_write - Write a verb with caching
+ * @codec: HD-audio codec base device
* @nid: codec NID
- * @reg: verb to write
+ * @verb: verb to write
* @val: value to write
*
* For writing an amp value, use snd_hdac_regmap_update_amp().
+ *
+ * Returns: %0 if successful or a negative error code.
*/
static inline int
snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
@@ -85,13 +88,16 @@ snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
}
/**
- * snd_hda_regmap_update - Update a verb value with caching
+ * snd_hdac_regmap_update - Update a verb value with caching
+ * @codec: HD-audio codec
* @nid: codec NID
* @verb: verb to update
* @mask: bit mask to update
* @val: value to update
*
* For updating an amp value, use snd_hdac_regmap_update_amp().
+ *
+ * Returns: %0 if successful or a negative error code.
*/
static inline int
snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
@@ -104,12 +110,15 @@ snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
}
/**
- * snd_hda_regmap_read - Read a verb with caching
+ * snd_hdac_regmap_read - Read a verb with caching
+ * @codec: HD-audio codec
* @nid: codec NID
* @verb: verb to read
* @val: pointer to store the value
*
* For reading an amp value, use snd_hda_regmap_get_amp().
+ *
+ * Returns: %0 if successful or a negative error code.
*/
static inline int
snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
@@ -125,12 +134,12 @@ snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @index: the index value (only for input direction)
- * @val: the pointer to store the value
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
*
* Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
- * Returns the value or a negative error.
+ *
+ * Returns: the value or a negative error.
*/
static inline int
snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
@@ -148,13 +157,14 @@ snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
* @codec: HD-audio codec
* @nid: NID to read the AMP value
* @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
* @idx: the index value (only for input direction)
* @mask: bit mask to set
* @val: the bits value to set
*
* Update the AMP value with a bit mask.
- * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ *
+ * Returns: 0 if the value is unchanged, 1 if changed, or a negative error.
*/
static inline int
snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
@@ -169,13 +179,12 @@ snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
* snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
* @codec: HD-audio codec
* @nid: NID to read the AMP value
- * @ch: channel (left=0 or right=1)
- * @direction: #HDA_INPUT or #HDA_OUTPUT
- * @index: the index value (only for input direction)
- * @val: the pointer to store the value
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
*
* Read stereo AMP values. The lower byte is left, the upper byte is right.
- * Returns the value or a negative error.
+ *
+ * Returns: the value or a negative error.
*/
static inline int
snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
@@ -192,14 +201,15 @@ snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
* snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
* @codec: HD-audio codec
* @nid: NID to read the AMP value
- * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
* @idx: the index value (only for input direction)
* @mask: bit mask to set
* @val: the bits value to set
*
* Update the stereo AMP value with a bit mask.
* The lower byte is left, the upper byte is right.
- * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ *
+ * Returns: 0 if the value is unchanged, 1 if changed, or a negative error.
*/
static inline int
snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 76fc33dce537..02d8689354c4 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -145,61 +145,60 @@ struct snd_pcm_ops {
#define SNDRV_PCM_RATE_8000_768000 (SNDRV_PCM_RATE_8000_384000|\
SNDRV_PCM_RATE_705600|\
SNDRV_PCM_RATE_768000)
-#define _SNDRV_PCM_FMTBIT(fmt) (1ULL << (__force int)SNDRV_PCM_FORMAT_##fmt)
-#define SNDRV_PCM_FMTBIT_S8 _SNDRV_PCM_FMTBIT(S8)
-#define SNDRV_PCM_FMTBIT_U8 _SNDRV_PCM_FMTBIT(U8)
-#define SNDRV_PCM_FMTBIT_S16_LE _SNDRV_PCM_FMTBIT(S16_LE)
-#define SNDRV_PCM_FMTBIT_S16_BE _SNDRV_PCM_FMTBIT(S16_BE)
-#define SNDRV_PCM_FMTBIT_U16_LE _SNDRV_PCM_FMTBIT(U16_LE)
-#define SNDRV_PCM_FMTBIT_U16_BE _SNDRV_PCM_FMTBIT(U16_BE)
-#define SNDRV_PCM_FMTBIT_S24_LE _SNDRV_PCM_FMTBIT(S24_LE)
-#define SNDRV_PCM_FMTBIT_S24_BE _SNDRV_PCM_FMTBIT(S24_BE)
-#define SNDRV_PCM_FMTBIT_U24_LE _SNDRV_PCM_FMTBIT(U24_LE)
-#define SNDRV_PCM_FMTBIT_U24_BE _SNDRV_PCM_FMTBIT(U24_BE)
+#define SNDRV_PCM_FMTBIT_S8 (1ULL << SNDRV_PCM_FORMAT_S8)
+#define SNDRV_PCM_FMTBIT_U8 (1ULL << SNDRV_PCM_FORMAT_U8)
+#define SNDRV_PCM_FMTBIT_S16_LE (1ULL << SNDRV_PCM_FORMAT_S16_LE)
+#define SNDRV_PCM_FMTBIT_S16_BE (1ULL << SNDRV_PCM_FORMAT_S16_BE)
+#define SNDRV_PCM_FMTBIT_U16_LE (1ULL << SNDRV_PCM_FORMAT_U16_LE)
+#define SNDRV_PCM_FMTBIT_U16_BE (1ULL << SNDRV_PCM_FORMAT_U16_BE)
+#define SNDRV_PCM_FMTBIT_S24_LE (1ULL << SNDRV_PCM_FORMAT_S24_LE)
+#define SNDRV_PCM_FMTBIT_S24_BE (1ULL << SNDRV_PCM_FORMAT_S24_BE)
+#define SNDRV_PCM_FMTBIT_U24_LE (1ULL << SNDRV_PCM_FORMAT_U24_LE)
+#define SNDRV_PCM_FMTBIT_U24_BE (1ULL << SNDRV_PCM_FORMAT_U24_BE)
// For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
// available bit count in most significant bit. It's for the case of so-called 'left-justified' or
// `right-padding` sample which has less width than 32 bit.
-#define SNDRV_PCM_FMTBIT_S32_LE _SNDRV_PCM_FMTBIT(S32_LE)
-#define SNDRV_PCM_FMTBIT_S32_BE _SNDRV_PCM_FMTBIT(S32_BE)
-#define SNDRV_PCM_FMTBIT_U32_LE _SNDRV_PCM_FMTBIT(U32_LE)
-#define SNDRV_PCM_FMTBIT_U32_BE _SNDRV_PCM_FMTBIT(U32_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT_LE _SNDRV_PCM_FMTBIT(FLOAT_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT_BE _SNDRV_PCM_FMTBIT(FLOAT_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_LE _SNDRV_PCM_FMTBIT(FLOAT64_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_BE _SNDRV_PCM_FMTBIT(FLOAT64_BE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_LE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE _SNDRV_PCM_FMTBIT(IEC958_SUBFRAME_BE)
-#define SNDRV_PCM_FMTBIT_MU_LAW _SNDRV_PCM_FMTBIT(MU_LAW)
-#define SNDRV_PCM_FMTBIT_A_LAW _SNDRV_PCM_FMTBIT(A_LAW)
-#define SNDRV_PCM_FMTBIT_IMA_ADPCM _SNDRV_PCM_FMTBIT(IMA_ADPCM)
-#define SNDRV_PCM_FMTBIT_MPEG _SNDRV_PCM_FMTBIT(MPEG)
-#define SNDRV_PCM_FMTBIT_GSM _SNDRV_PCM_FMTBIT(GSM)
-#define SNDRV_PCM_FMTBIT_S20_LE _SNDRV_PCM_FMTBIT(S20_LE)
-#define SNDRV_PCM_FMTBIT_U20_LE _SNDRV_PCM_FMTBIT(U20_LE)
-#define SNDRV_PCM_FMTBIT_S20_BE _SNDRV_PCM_FMTBIT(S20_BE)
-#define SNDRV_PCM_FMTBIT_U20_BE _SNDRV_PCM_FMTBIT(U20_BE)
-#define SNDRV_PCM_FMTBIT_SPECIAL _SNDRV_PCM_FMTBIT(SPECIAL)
-#define SNDRV_PCM_FMTBIT_S24_3LE _SNDRV_PCM_FMTBIT(S24_3LE)
-#define SNDRV_PCM_FMTBIT_U24_3LE _SNDRV_PCM_FMTBIT(U24_3LE)
-#define SNDRV_PCM_FMTBIT_S24_3BE _SNDRV_PCM_FMTBIT(S24_3BE)
-#define SNDRV_PCM_FMTBIT_U24_3BE _SNDRV_PCM_FMTBIT(U24_3BE)
-#define SNDRV_PCM_FMTBIT_S20_3LE _SNDRV_PCM_FMTBIT(S20_3LE)
-#define SNDRV_PCM_FMTBIT_U20_3LE _SNDRV_PCM_FMTBIT(U20_3LE)
-#define SNDRV_PCM_FMTBIT_S20_3BE _SNDRV_PCM_FMTBIT(S20_3BE)
-#define SNDRV_PCM_FMTBIT_U20_3BE _SNDRV_PCM_FMTBIT(U20_3BE)
-#define SNDRV_PCM_FMTBIT_S18_3LE _SNDRV_PCM_FMTBIT(S18_3LE)
-#define SNDRV_PCM_FMTBIT_U18_3LE _SNDRV_PCM_FMTBIT(U18_3LE)
-#define SNDRV_PCM_FMTBIT_S18_3BE _SNDRV_PCM_FMTBIT(S18_3BE)
-#define SNDRV_PCM_FMTBIT_U18_3BE _SNDRV_PCM_FMTBIT(U18_3BE)
-#define SNDRV_PCM_FMTBIT_G723_24 _SNDRV_PCM_FMTBIT(G723_24)
-#define SNDRV_PCM_FMTBIT_G723_24_1B _SNDRV_PCM_FMTBIT(G723_24_1B)
-#define SNDRV_PCM_FMTBIT_G723_40 _SNDRV_PCM_FMTBIT(G723_40)
-#define SNDRV_PCM_FMTBIT_G723_40_1B _SNDRV_PCM_FMTBIT(G723_40_1B)
-#define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8)
-#define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE)
-#define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE)
-#define SNDRV_PCM_FMTBIT_DSD_U16_BE _SNDRV_PCM_FMTBIT(DSD_U16_BE)
-#define SNDRV_PCM_FMTBIT_DSD_U32_BE _SNDRV_PCM_FMTBIT(DSD_U32_BE)
+#define SNDRV_PCM_FMTBIT_S32_LE (1ULL << SNDRV_PCM_FORMAT_S32_LE)
+#define SNDRV_PCM_FMTBIT_S32_BE (1ULL << SNDRV_PCM_FORMAT_S32_BE)
+#define SNDRV_PCM_FMTBIT_U32_LE (1ULL << SNDRV_PCM_FORMAT_U32_LE)
+#define SNDRV_PCM_FMTBIT_U32_BE (1ULL << SNDRV_PCM_FORMAT_U32_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_LE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_BE (1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE)
+#define SNDRV_PCM_FMTBIT_MU_LAW (1ULL << SNDRV_PCM_FORMAT_MU_LAW)
+#define SNDRV_PCM_FMTBIT_A_LAW (1ULL << SNDRV_PCM_FORMAT_A_LAW)
+#define SNDRV_PCM_FMTBIT_IMA_ADPCM (1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM)
+#define SNDRV_PCM_FMTBIT_MPEG (1ULL << SNDRV_PCM_FORMAT_MPEG)
+#define SNDRV_PCM_FMTBIT_GSM (1ULL << SNDRV_PCM_FORMAT_GSM)
+#define SNDRV_PCM_FMTBIT_S20_LE (1ULL << SNDRV_PCM_FORMAT_S20_LE)
+#define SNDRV_PCM_FMTBIT_U20_LE (1ULL << SNDRV_PCM_FORMAT_U20_LE)
+#define SNDRV_PCM_FMTBIT_S20_BE (1ULL << SNDRV_PCM_FORMAT_S20_BE)
+#define SNDRV_PCM_FMTBIT_U20_BE (1ULL << SNDRV_PCM_FORMAT_U20_BE)
+#define SNDRV_PCM_FMTBIT_SPECIAL (1ULL << SNDRV_PCM_FORMAT_SPECIAL)
+#define SNDRV_PCM_FMTBIT_S24_3LE (1ULL << SNDRV_PCM_FORMAT_S24_3LE)
+#define SNDRV_PCM_FMTBIT_U24_3LE (1ULL << SNDRV_PCM_FORMAT_U24_3LE)
+#define SNDRV_PCM_FMTBIT_S24_3BE (1ULL << SNDRV_PCM_FORMAT_S24_3BE)
+#define SNDRV_PCM_FMTBIT_U24_3BE (1ULL << SNDRV_PCM_FORMAT_U24_3BE)
+#define SNDRV_PCM_FMTBIT_S20_3LE (1ULL << SNDRV_PCM_FORMAT_S20_3LE)
+#define SNDRV_PCM_FMTBIT_U20_3LE (1ULL << SNDRV_PCM_FORMAT_U20_3LE)
+#define SNDRV_PCM_FMTBIT_S20_3BE (1ULL << SNDRV_PCM_FORMAT_S20_3BE)
+#define SNDRV_PCM_FMTBIT_U20_3BE (1ULL << SNDRV_PCM_FORMAT_U20_3BE)
+#define SNDRV_PCM_FMTBIT_S18_3LE (1ULL << SNDRV_PCM_FORMAT_S18_3LE)
+#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE)
+#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE)
+#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE)
+#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24)
+#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B)
+#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40)
+#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B)
+#define SNDRV_PCM_FMTBIT_DSD_U8 (1ULL << SNDRV_PCM_FORMAT_DSD_U8)
+#define SNDRV_PCM_FMTBIT_DSD_U16_LE (1ULL << SNDRV_PCM_FORMAT_DSD_U16_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_LE (1ULL << SNDRV_PCM_FORMAT_DSD_U32_LE)
+#define SNDRV_PCM_FMTBIT_DSD_U16_BE (1ULL << SNDRV_PCM_FORMAT_DSD_U16_BE)
+#define SNDRV_PCM_FMTBIT_DSD_U32_BE (1ULL << SNDRV_PCM_FORMAT_DSD_U32_BE)
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE
@@ -228,11 +227,10 @@ struct snd_pcm_ops {
#define SNDRV_PCM_FMTBIT_U20 SNDRV_PCM_FMTBIT_U20_BE
#endif
-#define _SNDRV_PCM_SUBFMTBIT(fmt) BIT((__force int)SNDRV_PCM_SUBFORMAT_##fmt)
-#define SNDRV_PCM_SUBFMTBIT_STD _SNDRV_PCM_SUBFMTBIT(STD)
-#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX _SNDRV_PCM_SUBFMTBIT(MSBITS_MAX)
-#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 _SNDRV_PCM_SUBFMTBIT(MSBITS_20)
-#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 _SNDRV_PCM_SUBFMTBIT(MSBITS_24)
+#define SNDRV_PCM_SUBFMTBIT_STD (1U << SNDRV_PCM_SUBFORMAT_STD)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX (1U << SNDRV_PCM_SUBFORMAT_MSBITS_MAX)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_20 (1U << SNDRV_PCM_SUBFORMAT_MSBITS_20)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_24 (1U << SNDRV_PCM_SUBFORMAT_MSBITS_24)
struct snd_pcm_file {
struct snd_pcm_substream *substream;
@@ -1515,7 +1513,7 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
*/
static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
{
- return 1ULL << (__force int) pcm_format;
+ return 1ULL << pcm_format;
}
/**
@@ -1523,9 +1521,7 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
* @f: the iterator variable in snd_pcm_format_t type
*/
#define pcm_for_each_format(f) \
- for ((f) = SNDRV_PCM_FORMAT_FIRST; \
- (__force int)(f) <= (__force int)SNDRV_PCM_FORMAT_LAST; \
- (f) = (__force snd_pcm_format_t)((__force int)(f) + 1))
+ for ((f) = SNDRV_PCM_FORMAT_FIRST; (f) <= SNDRV_PCM_FORMAT_LAST; (f)++)
/* printk helpers */
#define pcm_err(pcm, fmt, args...) \
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h
index fbf35df6e5cf..bc43955fcb76 100644
--- a/include/sound/pcm_params.h
+++ b/include/sound/pcm_params.h
@@ -71,7 +71,7 @@ static inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
static inline void snd_mask_set_format(struct snd_mask *mask,
snd_pcm_format_t format)
{
- snd_mask_set(mask, (__force unsigned int)format);
+ snd_mask_set(mask, format);
}
static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
@@ -132,7 +132,7 @@ static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val)
static inline int snd_mask_test_format(const struct snd_mask *mask,
snd_pcm_format_t format)
{
- return snd_mask_test(mask, (__force unsigned int)format);
+ return snd_mask_test(mask, format);
}
static inline int snd_mask_single(const struct snd_mask *mask)
@@ -302,8 +302,7 @@ static inline int snd_interval_eq(const struct snd_interval *i1, const struct sn
*/
static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
{
- return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
- SNDRV_PCM_HW_PARAM_ACCESS));
+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_ACCESS));
}
/**
@@ -312,8 +311,7 @@ static inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
*/
static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
{
- return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
- SNDRV_PCM_HW_PARAM_FORMAT));
+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_FORMAT));
}
/**
@@ -323,8 +321,7 @@ static inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
static inline snd_pcm_subformat_t
params_subformat(const struct snd_pcm_hw_params *p)
{
- return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
- SNDRV_PCM_HW_PARAM_SUBFORMAT));
+ return snd_mask_min(hw_param_mask_c(p, SNDRV_PCM_HW_PARAM_SUBFORMAT));
}
/**
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index 6916f7133597..88a6159364d0 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -176,8 +176,9 @@ int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
/* main midi functions */
int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info);
-int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
- int mode, struct snd_rawmidi_file *rfile);
+int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice,
+ int mode, struct snd_rawmidi_file *rfile,
+ int depth);
int snd_rawmidi_kernel_release(struct snd_rawmidi_file *rfile);
int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params *params);
@@ -191,6 +192,15 @@ long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream,
long snd_rawmidi_kernel_write(struct snd_rawmidi_substream *substream,
const unsigned char *buf, long count);
+/* non-nested version */
+static inline int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi,
+ int subdevice,
+ int mode,
+ struct snd_rawmidi_file *rfile)
+{
+ return snd_rawmidi_kernel_open_nested(rmidi, subdevice, mode, rfile, 0);
+}
+
/* set up the tied devices */
static inline void snd_rawmidi_tie_devices(struct snd_rawmidi *r1,
struct snd_rawmidi *r2)
diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h
index ca35d5a44370..599a72f33515 100644
--- a/include/sound/sdca_asoc.h
+++ b/include/sound/sdca_asoc.h
@@ -25,6 +25,8 @@ struct snd_soc_dai_driver;
struct snd_soc_dai_ops;
struct snd_soc_dapm_route;
struct snd_soc_dapm_widget;
+struct snd_soc_pcm_stream;
+struct sdca_entity;
/* convenient macro to handle the mono volume in 7.8 fixed format representation */
#define SDCA_SINGLE_Q78_TLV(xname, xreg, xmin, xmax, xstep, tlv_array) \
@@ -82,6 +84,11 @@ int sdca_asoc_populate_component(struct device *dev,
struct snd_soc_dai_driver **dai_drv, int *num_dai_drv,
const struct snd_soc_dai_ops *ops);
+int sdca_asoc_populate_rate_format(struct device *dev,
+ struct sdca_function_data *function,
+ struct sdca_entity *entity,
+ struct snd_soc_pcm_stream *stream);
+
int sdca_asoc_set_constraints(struct device *dev, struct regmap *regmap,
struct sdca_function_data *function,
struct snd_pcm_substream *substream,
@@ -100,9 +107,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
+int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap,
int function_id, int entity_id,
- int from_ps, int to_ps,
- const struct sdca_pde_delay *pde_delays,
- int num_delays);
+ int from_ps, int to_ps,
+ const struct sdca_pde_delay *pde_delays,
+ int num_delays);
#endif // __SDCA_ASOC_H__
diff --git a/include/sound/sdca_fdl.h b/include/sound/sdca_fdl.h
index dc33927b82bd..bc3600cdd2ec 100644
--- a/include/sound/sdca_fdl.h
+++ b/include/sound/sdca_fdl.h
@@ -83,6 +83,10 @@ static inline int sdca_fdl_alloc_state(struct sdca_interrupt *interrupt)
return 0;
}
+static inline void sdca_fdl_free_state(struct sdca_interrupt *interrupt)
+{
+}
+
static inline int sdca_fdl_process(struct sdca_interrupt *interrupt)
{
return 0;
diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h
index b1489178b0ef..e580201d69d5 100644
--- a/include/sound/sdca_function.h
+++ b/include/sound/sdca_function.h
@@ -298,7 +298,7 @@ enum sdca_xu_controls {
};
/**
- * enum sdca_set_index_range - Column definitions UMP SetIndex
+ * enum sdca_fdl_set_index_range - Column definitions UMP SetIndex
*/
enum sdca_fdl_set_index_range {
SDCA_FDL_SET_INDEX_SET_NUMBER = 0,
@@ -803,6 +803,8 @@ struct sdca_control_range {
* @mode: Access mode of the Control.
* @layers: Bitmask of access layers of the Control.
* @deferrable: Indicates if the access to the Control can be deferred.
+ * @is_volatile: Indicates the Control registers are forced to be treated
+ * as volatile.
* @has_default: Indicates the Control has a default value to be written.
* @has_reset: Indicates the Control has a defined reset value.
* @has_fixed: Indicates the Control only supports a single value.
@@ -1116,7 +1118,6 @@ struct sdca_entity_ge {
/**
* struct sdca_entity_hide - information specific to HIDE Entities
- * @hid: HID device structure
* @num_hidtx_ids: number of HIDTx Report ID
* @num_hidrx_ids: number of HIDRx Report ID
* @hidtx_ids: HIDTx Report ID
@@ -1127,11 +1128,8 @@ struct sdca_entity_ge {
* within this Device
* @max_delay: the maximum time in microseconds allowed for the Device
* to change the ownership from Device to Host
- * @hid_report_desc: HID Report Descriptor for the HIDE Entity
- * @hid_desc: HID descriptor for the HIDE Entity
*/
struct sdca_entity_hide {
- struct hid_device *hid;
unsigned int *hidtx_ids;
unsigned int *hidrx_ids;
int num_hidtx_ids;
@@ -1139,12 +1137,10 @@ struct sdca_entity_hide {
unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT];
unsigned int hide_reside_function_num;
unsigned int max_delay;
- unsigned char *hid_report_desc;
- struct hid_descriptor hid_desc;
};
/**
- * enum sdca_xu_reset_machanism - SDCA FDL Resets
+ * enum sdca_xu_reset_mechanism - SDCA FDL Resets
*/
enum sdca_xu_reset_mechanism {
SDCA_XU_RESET_FUNCTION = 0x0,
@@ -1402,6 +1398,16 @@ struct sdca_fdl_data {
};
/**
+ * struct sdca_function_hid - information about a function's HID descriptors
+ * @report_desc: HID Report Descriptor for the HID Function
+ * @desc: HID descriptor for the HID Function
+ */
+struct sdca_function_hid {
+ unsigned char *report_desc;
+ struct hid_descriptor desc;
+};
+
+/**
* struct sdca_function_data - top-level information for one SDCA function
* @desc: Pointer to short descriptor from initial parsing.
* @init_table: Pointer to a table of initialization writes.
@@ -1415,6 +1421,7 @@ struct sdca_fdl_data {
* @reset_max_delay: Maximum Function reset delay in microseconds, before an
* error should be reported.
* @fdl_data: FDL data for this Function, if available.
+ * @hid: HID data for this Function, if available.
*/
struct sdca_function_data {
struct sdca_function_desc *desc;
@@ -1430,6 +1437,10 @@ struct sdca_function_data {
unsigned int reset_max_delay;
struct sdca_fdl_data fdl_data;
+
+ union {
+ struct sdca_function_hid hid;
+ };
};
static inline u32 sdca_range(struct sdca_control_range *range,
@@ -1451,8 +1462,7 @@ static inline u32 sdca_range_search(struct sdca_control_range *range,
return 0;
}
-int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
- struct sdca_function_data *function);
+int sdca_parse_function(struct device *dev, struct sdca_function_data *function);
const char *sdca_find_terminal_name(enum sdca_terminal_type type);
@@ -1469,5 +1479,7 @@ struct sdca_control_range *sdca_selector_find_range(struct device *dev,
struct sdca_cluster *sdca_id_find_cluster(struct device *dev,
struct sdca_function_data *function,
const int id);
+struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function,
+ const char *entity_label);
#endif
diff --git a/include/sound/sdca_hid.h b/include/sound/sdca_hid.h
index 18bebbe428c9..848081df3e4e 100644
--- a/include/sound/sdca_hid.h
+++ b/include/sound/sdca_hid.h
@@ -16,18 +16,21 @@ struct sdca_interrupt;
#if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID)
-int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
- struct sdca_entity *entity);
+int sdca_add_hid_device(struct sdca_interrupt *interrupt);
+void sdca_destroy_hid_device(struct sdca_interrupt *interrupt);
int sdca_hid_process_report(struct sdca_interrupt *interrupt);
#else
-static inline int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
- struct sdca_entity *entity)
+static inline int sdca_add_hid_device(struct sdca_interrupt *interrupt)
{
return 0;
}
+static inline void sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
+{
+}
+
static inline int sdca_hid_process_report(struct sdca_interrupt *interrupt)
{
return 0;
diff --git a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h
index 56a3f38df8c3..359cb363369d 100644
--- a/include/sound/seq_virmidi.h
+++ b/include/sound/seq_virmidi.h
@@ -46,7 +46,6 @@ struct snd_virmidi_dev {
int client; /* created/attached client */
int port; /* created/attached port */
unsigned int flags; /* SNDRV_VIRMIDI_* */
- rwlock_t filelist_lock;
struct rw_semaphore filelist_sem;
struct list_head filelist;
};
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 915e6ae5f68d..bd8c3a033577 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -181,7 +181,7 @@ void simple_util_canonicalize_platform(struct snd_soc_dai_link_component *platfo
void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
int is_single_links);
-void simple_util_clean_reference(struct snd_soc_card *card);
+void simple_util_clean_reference(struct simple_util_priv *priv);
void simple_util_parse_convert(struct device_node *np, char *prefix,
struct simple_util_data *data);
@@ -189,18 +189,37 @@ bool simple_util_is_convert_required(const struct simple_util_data *data);
int simple_util_get_sample_fmt(struct simple_util_data *data);
-int simple_util_parse_routing(struct snd_soc_card *card,
- char *prefix);
-int simple_util_parse_widgets(struct snd_soc_card *card,
- char *prefix);
-int simple_util_parse_pin_switches(struct snd_soc_card *card,
- char *prefix);
+int simple_util_parse_property(struct simple_util_priv *priv,
+ int (*func)(struct snd_soc_card *card, const char *propname),
+ char *prefix, char *property);
+static inline int simple_util_parse_routing(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_audio_routing,
+ prefix, "routing");
+}
+
+static inline int simple_util_parse_widgets(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_audio_simple_widgets,
+ prefix, "widgets");
+}
+
+static inline int simple_util_parse_pin_switches(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_pin_switches,
+ prefix, "pin-switches");
+}
+
+static inline int simple_util_parse_aux_devs(struct simple_util_priv *priv, char *prefix)
+{
+ return simple_util_parse_property(priv, snd_soc_of_parse_aux_devs,
+ prefix, "aux-devs");
+}
int simple_util_init_jack(struct snd_soc_card *card,
struct simple_util_jack *sjack,
int is_hp, char *prefix, char *pin);
-int simple_util_init_aux_jacks(struct simple_util_priv *priv,
- char *prefix);
+int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix);
int simple_util_init_priv(struct simple_util_priv *priv,
struct link_info *li);
void simple_util_remove(struct platform_device *pdev);
diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h
index 0519afd7217f..2ee303b791dc 100644
--- a/include/sound/soc-acpi.h
+++ b/include/sound/soc-acpi.h
@@ -57,7 +57,7 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
#endif
/**
- * snd_soc_acpi_mach_params: interface for machine driver configuration
+ * struct snd_soc_acpi_mach_params - interface for machine driver configuration
*
* @acpi_ipc_irq_index: used for BYT-CR detection
* @platform: string used for HDAudio codec support
@@ -93,7 +93,7 @@ struct snd_soc_acpi_mach_params {
};
/**
- * snd_soc_acpi_endpoint - endpoint descriptor
+ * struct snd_soc_acpi_endpoint - endpoint descriptor
* @num: endpoint number (mandatory, unique per device)
* @aggregated: 0 (independent) or 1 (logically grouped)
* @group_position: zero-based order (only when @aggregated is 1)
@@ -107,7 +107,7 @@ struct snd_soc_acpi_endpoint {
};
/**
- * snd_soc_acpi_adr_device - descriptor for _ADR-enumerated device
+ * struct snd_soc_acpi_adr_device - descriptor for _ADR-enumerated device
* @adr: 64 bit ACPI _ADR value
* @num_endpoints: number of endpoints for this device
* @endpoints: array of endpoints
@@ -121,7 +121,7 @@ struct snd_soc_acpi_adr_device {
};
/**
- * snd_soc_acpi_link_adr - ACPI-based list of _ADR enumerated devices
+ * struct snd_soc_acpi_link_adr - ACPI-based list of _ADR enumerated devices
* @mask: one bit set indicates the link this list applies to
* @num_adr: ARRAY_SIZE of devices
* @adr_d: array of devices
@@ -167,8 +167,8 @@ struct snd_soc_acpi_link_adr {
#define SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME BIT(4)
/**
- * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are
- * related to the hardware, except for the firmware and topology file names.
+ * struct snd_soc_acpi_mach - ACPI-based machine descriptor. Most of the fields
+ * are related to the hardware, except for the firmware and topology file names.
* A platform supported by legacy and Sound Open Firmware (SOF) would expose
* all firmware/topology related fields.
*
@@ -192,6 +192,7 @@ struct snd_soc_acpi_link_adr {
* the initial selection in the snd_soc_acpi_mach table.
* @pdata: intended for platform data or machine specific-ops. This structure
* is not constant since this field may be updated at run-time
+ * @mach_params: machine driver configuration
* @sof_tplg_filename: Sound Open Firmware topology file name, if enabled
* @tplg_quirk_mask: quirks to select different topology files dynamically
* @get_function_tplg_files: This is an optional callback, if specified then instead of
@@ -199,11 +200,11 @@ struct snd_soc_acpi_link_adr {
* files to be loaded.
* Return value: The number of the files or negative ERRNO. 0 means that the single topology
* file should be used, no function topology split can be used on the machine.
- * @card: the pointer of the card
- * @mach: the pointer of the machine driver
- * @prefix: the prefix of the topology file name. Typically, it is the path.
- * @tplg_files: the pointer of the array of the topology file names.
- * @best_effort: ignore non supported links and try to build the card in best effort
+ * card: the pointer of the card
+ * mach: the pointer of the machine driver
+ * prefix: the prefix of the topology file name. Typically, it is the path.
+ * tplg_files: the pointer of the array of the topology file names.
+ * best_effort: ignore non supported links and try to build the card in best effort
* with supported links
*/
/* Descriptor for SST ASoC machine driver */
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 4b7d7954953d..c49b59630101 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -253,6 +253,9 @@ struct snd_soc_component {
void *mark_pm;
struct dentry *debugfs_root;
+
+ /* Component private data */
+ void *priv;
};
#define for_each_component_dais(component, dai)\
@@ -283,6 +286,14 @@ static inline int snd_soc_component_cache_sync(
return regcache_sync(component->regmap);
}
+struct snd_soc_component *snd_soc_component_alloc(struct device *dev);
+
+void snd_soc_component_set_name(struct snd_soc_component *component, const char *name);
+const char *snd_soc_component_name(struct snd_soc_component *component);
+
+void snd_soc_component_set_priv(struct snd_soc_component *component, void *priv);
+void *snd_soc_component_to_priv(struct snd_soc_component *component);
+
void snd_soc_component_set_aux(struct snd_soc_component *component,
struct snd_soc_aux_dev *aux);
int snd_soc_component_init(struct snd_soc_component *component);
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 10ad80f930c2..f46b2bc2a022 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -447,15 +447,16 @@ static inline int snd_soc_resume(struct device *dev)
}
#endif
int snd_soc_poweroff(struct device *dev);
-int snd_soc_component_initialize(struct snd_soc_component *component,
- const struct snd_soc_component_driver *driver,
- struct device *dev);
-int snd_soc_add_component(struct snd_soc_component *component,
- struct snd_soc_dai_driver *dai_drv,
- int num_dai);
-int snd_soc_register_component(struct device *dev,
+int snd_soc_register_component_c(struct snd_soc_component *component,
const struct snd_soc_component_driver *component_driver,
struct snd_soc_dai_driver *dai_drv, int num_dai);
+int snd_soc_register_component_d(struct device *dev,
+ const struct snd_soc_component_driver *component_driver,
+ struct snd_soc_dai_driver *dai_drv, int num_dai);
+#define snd_soc_register_component(x, ...) _Generic((x), \
+struct device * : snd_soc_register_component_d, \
+struct snd_soc_component * : snd_soc_register_component_c)(x, __VA_ARGS__)
+
int devm_snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *component_driver,
struct snd_soc_dai_driver *dai_drv, int num_dai);
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 79c21966220b..9b28e9aef4f1 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -44,6 +44,18 @@
struct asoc_sdw_codec_info;
+struct asoc_sdw_mc_private {
+ struct snd_soc_card card;
+ struct snd_soc_jack sdw_headset;
+ struct device *headset_codec_dev; /* only one headset per card */
+ struct device *amp_dev1, *amp_dev2;
+ bool append_dai_type;
+ bool ignore_internal_dmic;
+ void *private;
+ unsigned long mc_quirk;
+ int codec_info_list_count;
+};
+
struct asoc_sdw_dai_info {
const bool direction[2]; /* playback & capture support */
const char *codec_name;
@@ -88,25 +100,13 @@ struct asoc_sdw_codec_info {
int (*codec_card_late_probe)(struct snd_soc_card *card);
- int (*count_sidecar)(struct snd_soc_card *card,
+ int (*count_sidecar)(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs);
int (*add_sidecar)(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
struct snd_soc_codec_conf **codec_conf);
};
-struct asoc_sdw_mc_private {
- struct snd_soc_card card;
- struct snd_soc_jack sdw_headset;
- struct device *headset_codec_dev; /* only one headset per card */
- struct device *amp_dev1, *amp_dev2;
- bool append_dai_type;
- bool ignore_internal_dmic;
- void *private;
- unsigned long mc_quirk;
- int codec_info_list_count;
-};
-
struct asoc_sdw_endpoint {
struct list_head list;
@@ -182,7 +182,8 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_get_dai_type(u32 type);
-int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+int asoc_sdw_parse_sdw_endpoints(struct device *dev,
+ struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
@@ -235,7 +236,7 @@ int asoc_sdw_es9356_amp_init(struct snd_soc_card *card,
int asoc_sdw_es9356_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* CS AMP support */
-int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs);
int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h
index 59cd014392c1..e2107da6558f 100644
--- a/include/sound/sof/dai-amd.h
+++ b/include/sound/sof/dai-amd.h
@@ -18,6 +18,7 @@ struct sof_ipc_dai_acp_params {
uint32_t fsync_rate; /* FSYNC frequency in Hz */
uint32_t tdm_slots;
uint32_t tdm_mode;
+ uint32_t format;
} __packed;
/* ACPDMIC Configuration Request - SOF_IPC_DAI_AMD_CONFIG */
diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h
index 36809f712723..e3fe492e78f5 100644
--- a/include/sound/sof/dai.h
+++ b/include/sound/sof/dai.h
@@ -90,6 +90,8 @@ enum sof_ipc_dai_type {
SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */
SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */
SOF_DAI_AMD_SDW, /**< AMD ACP SDW */
+ SOF_DAI_INTEL_UAOL, /**< Intel UAOL */
+ SOF_DAI_AMD_I2S, /**< AMD ACP I2S */
};
/* general purpose DAI configuration */
@@ -121,6 +123,7 @@ struct sof_ipc_dai_config {
struct sof_ipc_dai_mtk_afe_params afe;
struct sof_ipc_dai_micfil_params micfil;
struct sof_ipc_dai_acp_sdw_params acp_sdw;
+ struct sof_ipc_dai_acp_params acp_i2s;
};
} __packed;
diff --git a/include/sound/sof/header.h b/include/sound/sof/header.h
index 4e406dc22f31..6c2c3a5fc90d 100644
--- a/include/sound/sof/header.h
+++ b/include/sound/sof/header.h
@@ -179,7 +179,7 @@ struct sof_ipc_compound_hdr {
uint32_t count; /**< count of 0 means end of compound sequence */
} __packed;
-/**
+/*
* OOPS header architecture specific data.
*/
struct sof_ipc_dsp_oops_arch_hdr {
@@ -187,7 +187,7 @@ struct sof_ipc_dsp_oops_arch_hdr {
uint32_t totalsize; /* Total size of oops message */
} __packed;
-/**
+/*
* OOPS header platform specific data.
*/
struct sof_ipc_dsp_oops_plat_hdr {
diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index 4554e5e8cab5..cea3d9453b84 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -187,6 +187,10 @@ enum sof_ipc4_pipeline_state {
#define SOF_IPC4_GLB_PIPE_EXT_CORE_ID_MASK GENMASK(23, 20)
#define SOF_IPC4_GLB_PIPE_EXT_CORE_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_CORE_ID_SHIFT)
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT 29
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_MASK BIT(29)
+#define SOF_IPC4_GLB_PIPE_PAYLOAD(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_SHIFT)
+
/* pipeline set state ipc msg */
#define SOF_IPC4_GLB_PIPE_STATE_ID_SHIFT 16
#define SOF_IPC4_GLB_PIPE_STATE_ID_MASK GENMASK(23, 16)
@@ -536,12 +540,63 @@ enum sof_ipc4_notification_type {
SOF_IPC4_NOTIFY_TYPE_LAST,
};
+enum sof_ipc4_resource_type {
+ SOF_IPC4_MODULE_INSTANCE,
+ SOF_IPC4_PIPELINE,
+ SOF_IPC4_GATEWAY,
+ SOF_IPC4_EDF_TASK,
+ SOF_IPC4_INVALID_RESOURCE_TYPE,
+};
+
+enum sof_ipc4_event_type {
+ /* Underrun detected by the Mixer */
+ SOF_IPC4_MIXER_UNDERRUN_DETECTED = 1,
+ /* Error caught during data processing */
+ SOF_IPC4_PROCESS_DATA_ERROR = 3,
+ /* Underrun detected by gateway. */
+ SOF_IPC4_GATEWAY_UNDERRUN_DETECTED = 6,
+ /* Overrun detected by gateway */
+ SOF_IPC4_GATEWAY_OVERRUN_DETECTED,
+};
+
+/**
+ * struct sof_ipc4_process_data_error_event_data - process data error event payload
+ * @error_code: Error code returned by data processing function
+ */
+struct sof_ipc4_process_data_error_event_data {
+ uint32_t error_code;
+};
+
+/**
+ * struct sof_ipc4_mixer_underrun_event_data - mixer underrun event payload
+ * @eos_flag: Indicates EndOfStream
+ * @data_mixed: Data processed by module (in bytes)
+ * @expected_data_mixed: Expected data to be processed (in bytes)
+ */
+struct sof_ipc4_mixer_underrun_event_data {
+ uint32_t eos_flag;
+ uint32_t data_mixed;
+ uint32_t expected_data_mixed;
+};
+
+/**
+ * union sof_ipc4_resource_event_data - resource event specific payload
+ * @dws: Raw event data payload as six dwords
+ * @process_data_error: SOF_IPC4_PROCESS_DATA_ERROR payload
+ * @mixer_underrun: SOF_IPC4_MIXER_UNDERRUN_DETECTED payload
+ */
+union sof_ipc4_resource_event_data {
+ uint32_t dws[6];
+ struct sof_ipc4_process_data_error_event_data process_data_error;
+ struct sof_ipc4_mixer_underrun_event_data mixer_underrun;
+};
+
struct sof_ipc4_notify_resource_data {
uint32_t resource_type;
uint32_t resource_id;
uint32_t event_type;
uint32_t reserved;
- uint32_t data[6];
+ union sof_ipc4_resource_event_data data;
} __packed __aligned(4);
#define SOF_IPC4_DEBUG_DESCRIPTOR_SIZE 12 /* 3 x u32 */
@@ -654,11 +709,81 @@ enum sof_ipc4_mod_init_ext_obj_id {
SOF_IPC4_MOD_INIT_DATA_ID_MAX = SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA,
};
-/* DP module memory configuration data object for ext_init object array */
+/* DP module memory configuration data object for object array */
struct sof_ipc4_mod_init_ext_dp_memory_data {
+ u32 domain_id; /* userspace domain ID */
+ u32 stack_bytes; /* required stack size in bytes */
+ u32 heap_bytes; /* required heap size in bytes */
+} __packed __aligned(4);
+
+/*
+ * This set of macros are very similar to the set above, but these are
+ * for building payload to SOF_IPC4_GLB_CREATE_PIPELINE message.
+ *
+ * Macros for creating struct sof_ipc4_glb_pipe_payload payload with
+ * its associated data. struct sof_ipc4_glb_pipe_payload should be the
+ * first piece of payload following SOF_IPC4_GLB_CREATE_PIPELINE msg,
+ * and its existence is indicated with SOF_IPC4_GLB_PIPE_PAYLOAD bit.
+ *
+ * The macros below apply to sof_ipc4_glb_pipe_payload.word0
+ */
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT 0
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_MASK GENMASK(23, 0)
+#define SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS_SHIFT)
+
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT 24
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK BIT(24)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_SHIFT)
+
+struct sof_ipc4_glb_pipe_payload {
+ u32 word0;
+ u32 rsvd1;
+ u32 rsvd2;
+} __packed __aligned(4);
+
+/*
+ * SOF_IPC4_GLB_CREATE_PIPELINE payload may be followed by arbitrary
+ * number of object array objects. SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY-bit
+ * indicates that an array object follows struct
+ * sof_ipc4_glb_pipe_payload.
+ *
+ * The object header's SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST-bit in struct
+ * sof_ipc4_glb_pipe_ext_object indicates if the array is continued
+ * with another object. The header has also fields to identify the
+ * object, SOF_IPC4_GLB_PIPE_EXT_OBJ_ID, and to indicate the object's
+ * size in 32-bit words, SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS, not
+ * including the header itself.
+ *
+ * The macros below apply to sof_ipc4_glb_pipe_ext_object.header
+ */
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT 0
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK BIT(0)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_SHIFT)
+
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT 1
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_MASK GENMASK(15, 1)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_ID_SHIFT)
+
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT 16
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_MASK GENMASK(31, 16)
+#define SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(x) ((x) << SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS_SHIFT)
+
+struct sof_ipc4_glb_pipe_ext_object {
+ u32 header;
+ u32 data[];
+} __packed __aligned(4);
+
+enum sof_ipc4_glb_pipe_ext_obj_id {
+ SOF_IPC4_GLB_PIPE_DATA_ID_INVALID = 0,
+ SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA,
+ SOF_IPC4_GLB_PIPE_DATA_ID_MAX = SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA,
+};
+
+/* Pipeline memory configuration data object for ext_init object array */
+struct sof_ipc4_glb_pipe_ext_obj_memory_data {
u32 domain_id; /* userspace domain ID */
- u32 stack_bytes; /* stack size in bytes, 0 means default size */
- u32 heap_bytes; /* stack size in bytes, 0 means default size */
+ u32 stack_bytes; /* stack size in bytes */
+ u32 heap_bytes; /* heap size in bytes */
} __packed __aligned(4);
/** @}*/
diff --git a/include/sound/tas2781-dsp.h b/include/sound/tas2781-dsp.h
index dd6ee45ad096..e845687decf9 100644
--- a/include/sound/tas2781-dsp.h
+++ b/include/sound/tas2781-dsp.h
@@ -202,6 +202,11 @@ struct tasdevice_rca {
struct tasdevice_config_info **cfg_info;
int profile_cfg_id;
/*
+ * Used among SmartAMP for PDM microphone recording or IV data
+ * capture.
+ */
+ int capture_profile_id;
+ /*
* Since version 0x105, the keyword 'init' was introduced into the
* profile, which is used for chip initialization, particularly to
* store common settings for other non-initialization profiles.
@@ -222,7 +227,7 @@ void tasdevice_calbin_remove(void *context);
int tasdevice_select_tuningprm_cfg(void *context, int prm,
int cfg_no, int rca_conf_no);
int tasdevice_prmg_load(void *context, int prm_no);
-void tasdevice_tuning_switch(void *context, int state);
+void tasdevice_tuning_switch(void *context, int state, bool is_cap);
int tas2781_load_calibration(void *context, char *file_name,
unsigned short i);
diff --git a/include/sound/tlv320aic32x4.h b/include/sound/tlv320aic32x4.h
deleted file mode 100644
index b779d671a995..000000000000
--- a/include/sound/tlv320aic32x4.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * tlv320aic32x4.h -- TLV320AIC32X4 Soc Audio driver platform data
- *
- * Copyright 2011 Vista Silicon S.L.
- *
- * Author: Javier Martin <javier.martin@vista-silicon.com>
- */
-
-#ifndef _AIC32X4_PDATA_H
-#define _AIC32X4_PDATA_H
-
-#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001
-#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002
-#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004
-#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008
-#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010
-
-#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001
-#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002
-
-/* GPIO API */
-#define AIC32X4_MFPX_DEFAULT_VALUE 0xff
-
-#define AIC32X4_MFP1_DIN_DISABLED 0
-#define AIC32X4_MFP1_DIN_ENABLED 0x2
-#define AIC32X4_MFP1_GPIO_IN 0x4
-
-#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0
-#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1
-
-#define AIC32X4_MFP_GPIO_ENABLED 0x4
-
-#define AIC32X4_MFP5_GPIO_DISABLED 0x0
-#define AIC32X4_MFP5_GPIO_INPUT 0x8
-#define AIC32X4_MFP5_GPIO_OUTPUT 0xc
-#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0
-#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1
-
-struct aic32x4_setup_data {
- unsigned int gpio_func[5];
-};
-#endif
diff --git a/include/sound/wm8904.h b/include/sound/wm8904.h
index 8b2c16b524f7..151a05b13dfc 100644
--- a/include/sound/wm8904.h
+++ b/include/sound/wm8904.h
@@ -116,7 +116,7 @@
#define WM8904_DRC_REGS 4
#define WM8904_EQ_REGS 24
-/**
+/*
* DRC configurations are specified with a label and a set of register
* values to write (the enable bits will be ignored). At runtime an
* enumerated control will be presented for each DRC block allowing
@@ -131,7 +131,7 @@ struct wm8904_drc_cfg {
u16 regs[WM8904_DRC_REGS];
};
-/**
+/*
* ReTune Mobile configurations are specified with a label, sample
* rate and set of values to write (the enable bits will be ignored).
*
diff --git a/include/uapi/sound/asequencer.h b/include/uapi/sound/asequencer.h
index a5c41f771e05..c2e3d079c51e 100644
--- a/include/uapi/sound/asequencer.h
+++ b/include/uapi/sound/asequencer.h
@@ -308,16 +308,6 @@ struct snd_seq_ump_event {
};
};
-/*
- * bounce event - stored as variable size data
- */
-struct snd_seq_event_bounce {
- int err;
- struct snd_seq_event event;
- /* external data follows here. */
-};
-
-
/* system information */
struct snd_seq_system_info {
int queues; /* maximum queues count */
@@ -348,10 +338,10 @@ struct snd_seq_running_info {
/* client types */
-typedef int __bitwise snd_seq_client_type_t;
-#define NO_CLIENT ((__force snd_seq_client_type_t) 0)
-#define USER_CLIENT ((__force snd_seq_client_type_t) 1)
-#define KERNEL_CLIENT ((__force snd_seq_client_type_t) 2)
+typedef int snd_seq_client_type_t;
+#define NO_CLIENT 0
+#define USER_CLIENT 1
+#define KERNEL_CLIENT 2
/* event filter flags */
#define SNDRV_SEQ_FILTER_BROADCAST (1U<<0) /* accept broadcast messages */
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index d3ce75ba938a..c11da9656e38 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -169,72 +169,72 @@ enum {
SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
};
-typedef int __bitwise snd_pcm_access_t;
-#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) /* interleaved mmap */
-#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) /* noninterleaved mmap */
-#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) /* complex mmap */
-#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) /* readi/writei */
-#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) /* readn/writen */
+typedef int snd_pcm_access_t;
+#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED 0 /* interleaved mmap */
+#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED 1 /* noninterleaved mmap */
+#define SNDRV_PCM_ACCESS_MMAP_COMPLEX 2 /* complex mmap */
+#define SNDRV_PCM_ACCESS_RW_INTERLEAVED 3 /* readi/writei */
+#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED 4 /* readn/writen */
#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
-typedef int __bitwise snd_pcm_format_t;
-#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
-#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
-#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
-#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
-#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
-#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
-#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) /* low three bytes */
-#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) /* low three bytes */
-#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) /* low three bytes */
-#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) /* low three bytes */
+typedef int snd_pcm_format_t;
+#define SNDRV_PCM_FORMAT_S8 0
+#define SNDRV_PCM_FORMAT_U8 1
+#define SNDRV_PCM_FORMAT_S16_LE 2
+#define SNDRV_PCM_FORMAT_S16_BE 3
+#define SNDRV_PCM_FORMAT_U16_LE 4
+#define SNDRV_PCM_FORMAT_U16_BE 5
+#define SNDRV_PCM_FORMAT_S24_LE 6 /* low three bytes */
+#define SNDRV_PCM_FORMAT_S24_BE 7 /* low three bytes */
+#define SNDRV_PCM_FORMAT_U24_LE 8 /* low three bytes */
+#define SNDRV_PCM_FORMAT_U24_BE 9 /* low three bytes */
/*
* For S32/U32 formats, 'msbits' hardware parameter is often used to deliver information about the
* available bit count in most significant bit. It's for the case of so-called 'left-justified' or
* `right-padding` sample which has less width than 32 bit.
*/
-#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
-#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
-#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
-#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
-#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
-#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) /* IEC-958 subframe, Little Endian */
-#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) /* IEC-958 subframe, Big Endian */
-#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
-#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
-#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
-#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
-#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
-#define SNDRV_PCM_FORMAT_S20_LE ((__force snd_pcm_format_t) 25) /* in four bytes, LSB justified */
-#define SNDRV_PCM_FORMAT_S20_BE ((__force snd_pcm_format_t) 26) /* in four bytes, LSB justified */
-#define SNDRV_PCM_FORMAT_U20_LE ((__force snd_pcm_format_t) 27) /* in four bytes, LSB justified */
-#define SNDRV_PCM_FORMAT_U20_BE ((__force snd_pcm_format_t) 28) /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_S32_LE 10
+#define SNDRV_PCM_FORMAT_S32_BE 11
+#define SNDRV_PCM_FORMAT_U32_LE 12
+#define SNDRV_PCM_FORMAT_U32_BE 13
+#define SNDRV_PCM_FORMAT_FLOAT_LE 14 /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_FLOAT_BE 15 /* 4-byte float, IEEE-754 32-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_FLOAT64_LE 16 /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_FLOAT64_BE 17 /* 8-byte float, IEEE-754 64-bit, range -1.0 to 1.0 */
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE 18 /* IEC-958 subframe, Little Endian */
+#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE 19 /* IEC-958 subframe, Big Endian */
+#define SNDRV_PCM_FORMAT_MU_LAW 20
+#define SNDRV_PCM_FORMAT_A_LAW 21
+#define SNDRV_PCM_FORMAT_IMA_ADPCM 22
+#define SNDRV_PCM_FORMAT_MPEG 23
+#define SNDRV_PCM_FORMAT_GSM 24
+#define SNDRV_PCM_FORMAT_S20_LE 25 /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_S20_BE 26 /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_U20_LE 27 /* in four bytes, LSB justified */
+#define SNDRV_PCM_FORMAT_U20_BE 28 /* in four bytes, LSB justified */
/* gap in the numbering for a future standard linear format */
-#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
-#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) /* in three bytes */
-#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */
-#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */
-#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */
-#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
-#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
-#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
-#define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */
-#define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */
-#define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */
-#define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */
-#define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */
+#define SNDRV_PCM_FORMAT_SPECIAL 31
+#define SNDRV_PCM_FORMAT_S24_3LE 32 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S24_3BE 33 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U24_3LE 34 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U24_3BE 35 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S20_3LE 36 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S20_3BE 37 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U20_3LE 38 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U20_3BE 39 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S18_3LE 40 /* in three bytes */
+#define SNDRV_PCM_FORMAT_S18_3BE 41 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U18_3LE 42 /* in three bytes */
+#define SNDRV_PCM_FORMAT_U18_3BE 43 /* in three bytes */
+#define SNDRV_PCM_FORMAT_G723_24 44 /* 8 samples in 3 bytes */
+#define SNDRV_PCM_FORMAT_G723_24_1B 45 /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_G723_40 46 /* 8 Samples in 5 bytes */
+#define SNDRV_PCM_FORMAT_G723_40_1B 47 /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_DSD_U8 48 /* DSD, 1-byte samples DSD (x8) */
+#define SNDRV_PCM_FORMAT_DSD_U16_LE 49 /* DSD, 2-byte samples DSD (x16), little endian */
+#define SNDRV_PCM_FORMAT_DSD_U32_LE 50 /* DSD, 4-byte samples DSD (x32), little endian */
+#define SNDRV_PCM_FORMAT_DSD_U16_BE 51 /* DSD, 2-byte samples DSD (x16), big endian */
+#define SNDRV_PCM_FORMAT_DSD_U32_BE 52 /* DSD, 4-byte samples DSD (x32), big endian */
#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE
#define SNDRV_PCM_FORMAT_FIRST SNDRV_PCM_FORMAT_S8
@@ -265,11 +265,11 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_U20 SNDRV_PCM_FORMAT_U20_BE
#endif
-typedef int __bitwise snd_pcm_subformat_t;
-#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
-#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX ((__force snd_pcm_subformat_t) 1)
-#define SNDRV_PCM_SUBFORMAT_MSBITS_20 ((__force snd_pcm_subformat_t) 2)
-#define SNDRV_PCM_SUBFORMAT_MSBITS_24 ((__force snd_pcm_subformat_t) 3)
+typedef int snd_pcm_subformat_t;
+#define SNDRV_PCM_SUBFORMAT_STD 0
+#define SNDRV_PCM_SUBFORMAT_MSBITS_MAX 1
+#define SNDRV_PCM_SUBFORMAT_MSBITS_20 2
+#define SNDRV_PCM_SUBFORMAT_MSBITS_24 3
#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_MSBITS_24
#define SNDRV_PCM_INFO_MMAP 0x00000001 /* hardware supports mmap */
@@ -303,16 +303,16 @@ typedef int __bitwise snd_pcm_subformat_t;
#define __SND_STRUCT_TIME64
#endif
-typedef int __bitwise snd_pcm_state_t;
-#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
-#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) /* stream has a setup */
-#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */
-#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) /* stream is running */
-#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) /* stream reached an xrun */
-#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */
-#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) /* stream is paused */
-#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */
-#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */
+typedef int snd_pcm_state_t;
+#define SNDRV_PCM_STATE_OPEN 0 /* stream is open */
+#define SNDRV_PCM_STATE_SETUP 1 /* stream has a setup */
+#define SNDRV_PCM_STATE_PREPARED 2 /* stream is ready to start */
+#define SNDRV_PCM_STATE_RUNNING 3 /* stream is running */
+#define SNDRV_PCM_STATE_XRUN 4 /* stream reached an xrun */
+#define SNDRV_PCM_STATE_DRAINING 5 /* stream is draining */
+#define SNDRV_PCM_STATE_PAUSED 6 /* stream is paused */
+#define SNDRV_PCM_STATE_SUSPENDED 7 /* hardware is suspended */
+#define SNDRV_PCM_STATE_DISCONNECTED 8 /* hardware is disconnected */
#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
enum {
@@ -1058,7 +1058,7 @@ struct snd_timer_tread {
* *
****************************************************************************/
-#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9)
+#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
struct snd_ctl_card_info {
int card; /* card number */
@@ -1072,24 +1072,43 @@ struct snd_ctl_card_info {
unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */
};
-typedef int __bitwise snd_ctl_elem_type_t;
-#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) /* invalid */
-#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) /* boolean type */
-#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) /* integer type */
-#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) /* enumerated type */
-#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) /* byte array */
-#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) /* IEC958 (S/PDIF) setup */
-#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) /* 64-bit integer type */
+/*
+ * Card components can exceed the fixed 128 bytes in snd_ctl_card_info.
+ * Use SNDRV_CTL_IOCTL_CARD_BYTES with type SND_CTL_CARD_BTYPE_COMPONENTS
+ * to retrieve the full string.
+ */
+
+/* Type values for struct snd_ctl_card_bytes::type */
+enum {
+ SND_CTL_CARD_BTYPE_COMPONENTS = 1, /* full card components string */
+};
+
+struct snd_ctl_card_bytes {
+ __u32 type; /* SND_CTL_CARD_BTYPE_* */
+ __u32 data_allocated; /* size of @data buffer in bytes */
+ __u32 data_len; /* in/out: actual data length in bytes */
+ __u32 reserved; /* explicit pad */
+ __u64 data; /* user buffer (pointer stored as __u64) */
+};
+
+typedef int snd_ctl_elem_type_t;
+#define SNDRV_CTL_ELEM_TYPE_NONE 0 /* invalid */
+#define SNDRV_CTL_ELEM_TYPE_BOOLEAN 1 /* boolean type */
+#define SNDRV_CTL_ELEM_TYPE_INTEGER 2 /* integer type */
+#define SNDRV_CTL_ELEM_TYPE_ENUMERATED 3 /* enumerated type */
+#define SNDRV_CTL_ELEM_TYPE_BYTES 4 /* byte array */
+#define SNDRV_CTL_ELEM_TYPE_IEC958 5 /* IEC958 (S/PDIF) setup */
+#define SNDRV_CTL_ELEM_TYPE_INTEGER64 6 /* 64-bit integer type */
#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
-typedef int __bitwise snd_ctl_elem_iface_t;
-#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) /* global control */
-#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) /* hardware dependent device */
-#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) /* virtual mixer device */
-#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) /* PCM device */
-#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) /* RawMidi device */
-#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) /* timer device */
-#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) /* sequencer client */
+typedef int snd_ctl_elem_iface_t;
+#define SNDRV_CTL_ELEM_IFACE_CARD 0 /* global control */
+#define SNDRV_CTL_ELEM_IFACE_HWDEP 1 /* hardware dependent device */
+#define SNDRV_CTL_ELEM_IFACE_MIXER 2 /* virtual mixer device */
+#define SNDRV_CTL_ELEM_IFACE_PCM 3 /* PCM device */
+#define SNDRV_CTL_ELEM_IFACE_RAWMIDI 4 /* RawMidi device */
+#define SNDRV_CTL_ELEM_IFACE_TIMER 5 /* timer device */
+#define SNDRV_CTL_ELEM_IFACE_SEQUENCER 6 /* sequencer client */
#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
@@ -1198,6 +1217,7 @@ struct snd_ctl_tlv {
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
+#define SNDRV_CTL_IOCTL_CARD_BYTES _IOWR('U', 0x02, struct snd_ctl_card_bytes)
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
index 1e86872c151f..1235d89d2bff 100644
--- a/include/uapi/sound/firewire.h
+++ b/include/uapi/sound/firewire.h
@@ -79,11 +79,12 @@ struct snd_firewire_event_motu_register_dsp_change {
*
* @type: Fixed to SNDRV_FIREWIRE_EVENT_FF400_MESSAGE.
* @message_count: The number of messages.
+ * @messages: Array of @message_count messages
* @messages.message: The messages expressing hardware knob operation.
* @messages.tstamp: The isochronous cycle at which the request subaction of asynchronous
- * transaction was sent to deliver the message. It has 16 bit unsigned integer
+ * transaction was sent to deliver the message. It has 16-bit unsigned integer
* value. The higher 3 bits of value expresses the lower three bits of second
- * field in the format of CYCLE_TIME, up to 7. The rest 13 bits expresses cycle
+ * field in the format of CYCLE_TIME, up to 7. The remaining 13 bits express cycle
* field up to 7999.
*
* The structure expresses message transmitted by Fireface 400 when operating hardware knob.
@@ -191,8 +192,9 @@ struct snd_firewire_motu_register_dsp_meter {
#define SNDRV_FIREWIRE_MOTU_REGISTER_DSP_ALIGNED_INPUT_COUNT (SNDRV_FIREWIRE_MOTU_REGISTER_DSP_INPUT_COUNT + 2)
/**
- * snd_firewire_motu_register_dsp_parameter - the container for parameters of DSP controlled
- * by register access.
+ * struct snd_firewire_motu_register_dsp_parameter - the container for parameters
+ * of DSP controlled by register access.
+ * @mixer: aggregate of @mixer.source and @mixer.output
* @mixer.source.gain: The gain of source to mixer.
* @mixer.source.pan: The L/R balance of source to mixer.
* @mixer.source.flag: The flag of source to mixer, including mute, solo.
@@ -200,21 +202,25 @@ struct snd_firewire_motu_register_dsp_meter {
* Audio Express.
* @mixer.source.paired_width: The width of paired source to mixer, only for 4 pre and
* Audio Express.
+ * @mixer.output: FIXME
* @mixer.output.paired_volume: The volume of paired output from mixer.
* @mixer.output.paired_flag: The flag of paired output from mixer.
+ * @output: output parameters
* @output.main_paired_volume: The volume of paired main output.
* @output.hp_paired_volume: The volume of paired hp output.
* @output.hp_paired_assignment: The source assigned to paired hp output.
- * @output.reserved: Padding for 32 bit alignment for future extension.
+ * @output.reserved: Padding for 32-bit alignment for future extension.
+ * @line_input: line input parameters
* @line_input.boost_flag: The flags of boost for line inputs, only for 828mk2 and Traveler.
* @line_input.nominal_level_flag: The flags of nominal level for line inputs, only for 828mk2 and
* Traveler.
- * @line_input.reserved: Padding for 32 bit alignment for future extension.
+ * @line_input.reserved: Padding for 32-bit alignment for future extension.
+ * @input: input parameters
* @input.gain_and_invert: The value including gain and invert for input, only for Ultralite, 4 pre
* and Audio Express.
* @input.flag: The flag of input; e.g. jack detection, phantom power, and pad, only for Ultralite,
* 4 pre and Audio express.
- * @reserved: Padding so that the size of structure is kept to 512 byte, but for future extension.
+ * @reserved: Padding so that the size of structure is kept to 512 bytes, but for future extension.
*
* The structure expresses the set of parameters for DSP controlled by register access.
*/
@@ -272,8 +278,8 @@ struct snd_firewire_motu_register_dsp_parameter {
* controlled by command
* @data: Signal level meters. The mapping between position and signal channel is model-dependent.
*
- * The structure expresses the part of DSP status for hardware meter. The 32 bit storage is
- * estimated to include IEEE 764 32 bit single precision floating point (binary32) value. It is
+ * The structure expresses the part of DSP status for hardware meter. The 32-bit storage is
+ * estimated to include IEEE 764 32-bit single precision floating point (binary32) value. It is
* expected to be linear value (not logarithm) for audio signal level between 0.0 and +1.0.
*/
struct snd_firewire_motu_command_dsp_meter {
diff --git a/include/uapi/sound/skl-tplg-interface.h b/include/uapi/sound/skl-tplg-interface.h
deleted file mode 100644
index 940c4269322b..000000000000
--- a/include/uapi/sound/skl-tplg-interface.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * skl-tplg-interface.h - Intel DSP FW private data interface
- *
- * Copyright (C) 2015 Intel Corp
- * Author: Jeeja KP <jeeja.kp@intel.com>
- * Nilofer, Samreen <samreen.nilofer@intel.com>
- */
-
-#ifndef __HDA_TPLG_INTERFACE_H__
-#define __HDA_TPLG_INTERFACE_H__
-
-#include <linux/types.h>
-
-/*
- * Default types range from 0~12. type can range from 0 to 0xff
- * SST types start at higher to avoid any overlapping in future
- */
-#define SKL_CONTROL_TYPE_BYTE_TLV 0x100
-#define SKL_CONTROL_TYPE_MIC_SELECT 0x102
-#define SKL_CONTROL_TYPE_MULTI_IO_SELECT 0x103
-#define SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC 0x104
-
-#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/
-#define MAX_IN_QUEUE 8
-#define MAX_OUT_QUEUE 8
-
-#define SKL_UUID_STR_SZ 40
-/* Event types goes here */
-/* Reserve event type 0 for no event handlers */
-enum skl_event_types {
- SKL_EVENT_NONE = 0,
- SKL_MIXER_EVENT,
- SKL_MUX_EVENT,
- SKL_VMIXER_EVENT,
- SKL_PGA_EVENT
-};
-
-/**
- * enum skl_ch_cfg - channel configuration
- *
- * @SKL_CH_CFG_MONO: One channel only
- * @SKL_CH_CFG_STEREO: L & R
- * @SKL_CH_CFG_2_1: L, R & LFE
- * @SKL_CH_CFG_3_0: L, C & R
- * @SKL_CH_CFG_3_1: L, C, R & LFE
- * @SKL_CH_CFG_QUATRO: L, R, Ls & Rs
- * @SKL_CH_CFG_4_0: L, C, R & Cs
- * @SKL_CH_CFG_5_0: L, C, R, Ls & Rs
- * @SKL_CH_CFG_5_1: L, C, R, Ls, Rs & LFE
- * @SKL_CH_CFG_DUAL_MONO: One channel replicated in two
- * @SKL_CH_CFG_I2S_DUAL_STEREO_0: Stereo(L,R) in 4 slots, 1st stream:[ L, R, -, - ]
- * @SKL_CH_CFG_I2S_DUAL_STEREO_1: Stereo(L,R) in 4 slots, 2nd stream:[ -, -, L, R ]
- * @SKL_CH_CFG_INVALID: Invalid
- */
-enum skl_ch_cfg {
- SKL_CH_CFG_MONO = 0,
- SKL_CH_CFG_STEREO = 1,
- SKL_CH_CFG_2_1 = 2,
- SKL_CH_CFG_3_0 = 3,
- SKL_CH_CFG_3_1 = 4,
- SKL_CH_CFG_QUATRO = 5,
- SKL_CH_CFG_4_0 = 6,
- SKL_CH_CFG_5_0 = 7,
- SKL_CH_CFG_5_1 = 8,
- SKL_CH_CFG_DUAL_MONO = 9,
- SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
- SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
- SKL_CH_CFG_7_1 = 12,
- SKL_CH_CFG_4_CHANNEL = SKL_CH_CFG_7_1,
- SKL_CH_CFG_INVALID
-};
-
-enum skl_module_type {
- SKL_MODULE_TYPE_MIXER = 0,
- SKL_MODULE_TYPE_COPIER,
- SKL_MODULE_TYPE_UPDWMIX,
- SKL_MODULE_TYPE_SRCINT,
- SKL_MODULE_TYPE_ALGO,
- SKL_MODULE_TYPE_BASE_OUTFMT,
- SKL_MODULE_TYPE_KPB,
- SKL_MODULE_TYPE_MIC_SELECT,
-};
-
-enum skl_core_affinity {
- SKL_AFFINITY_CORE_0 = 0,
- SKL_AFFINITY_CORE_1,
- SKL_AFFINITY_CORE_MAX
-};
-
-enum skl_pipe_conn_type {
- SKL_PIPE_CONN_TYPE_NONE = 0,
- SKL_PIPE_CONN_TYPE_FE,
- SKL_PIPE_CONN_TYPE_BE
-};
-
-enum skl_hw_conn_type {
- SKL_CONN_NONE = 0,
- SKL_CONN_SOURCE = 1,
- SKL_CONN_SINK = 2
-};
-
-enum skl_dev_type {
- SKL_DEVICE_BT = 0x0,
- SKL_DEVICE_DMIC = 0x1,
- SKL_DEVICE_I2S = 0x2,
- SKL_DEVICE_SLIMBUS = 0x3,
- SKL_DEVICE_HDALINK = 0x4,
- SKL_DEVICE_HDAHOST = 0x5,
- SKL_DEVICE_NONE
-};
-
-/**
- * enum skl_interleaving - interleaving style
- *
- * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN]
- * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN]
- */
-enum skl_interleaving {
- SKL_INTERLEAVING_PER_CHANNEL = 0,
- SKL_INTERLEAVING_PER_SAMPLE = 1,
-};
-
-enum skl_sample_type {
- SKL_SAMPLE_TYPE_INT_MSB = 0,
- SKL_SAMPLE_TYPE_INT_LSB = 1,
- SKL_SAMPLE_TYPE_INT_SIGNED = 2,
- SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
- SKL_SAMPLE_TYPE_FLOAT = 4
-};
-
-enum module_pin_type {
- /* All pins of the module takes same PCM inputs or outputs
- * e.g. mixout
- */
- SKL_PIN_TYPE_HOMOGENEOUS,
- /* All pins of the module takes different PCM inputs or outputs
- * e.g mux
- */
- SKL_PIN_TYPE_HETEROGENEOUS,
-};
-
-enum skl_module_param_type {
- SKL_PARAM_DEFAULT = 0,
- SKL_PARAM_INIT,
- SKL_PARAM_SET,
- SKL_PARAM_BIND
-};
-
-struct skl_dfw_algo_data {
- __u32 set_params:2;
- __u32 rsvd:30;
- __u32 param_id;
- __u32 max;
- char params[];
-} __packed;
-
-enum skl_tkn_dir {
- SKL_DIR_IN,
- SKL_DIR_OUT
-};
-
-enum skl_tuple_type {
- SKL_TYPE_TUPLE,
- SKL_TYPE_DATA
-};
-
-#endif
diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h
index 6b8102eaa121..cf8ab6b85e34 100644
--- a/include/uapi/sound/snd_ar_tokens.h
+++ b/include/uapi/sound/snd_ar_tokens.h
@@ -58,7 +58,7 @@ enum ar_event_types {
#define SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX 256
#define SND_SOC_AR_TPLG_VOL_CTL 257
-/**
+/*
* %AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: Sub Graph Instance Id
*
* %AR_TKN_U32_SUB_GRAPH_PERF_MODE: Performance mode of subgraph
@@ -168,6 +168,60 @@ enum ar_event_types {
* LOG_WAIT = 0,
* LOG_IMMEDIATELY = 1
*
+ * %AR_TKN_U16_MODULE_SYNC_SRC: Frame sync source
+ * AR_AUDIO_IF_SYNC_SRC_EXTERNAL = 0,
+ * AR_AUDIO_IF_SYNC_SRC_INTERNAL = 1
+ *
+ * %AR_TKN_U16_MODULE_CTRL_DATA_OUT_ENABLE: Enable data-out tri-state control
+ * AR_AUDIO_IF_CTRL_DATA_OE_DISABLE = 0,
+ * AR_AUDIO_IF_CTRL_DATA_OE_ENABLE = 1
+ *
+ * %AR_TKN_U32_MODULE_SLOT_MASK: Active TDM slot bitmask
+ *
+ * %AR_TKN_U16_MODULE_NSLOTS_PER_FRAME: Number of slots per TDM frame
+ *
+ * %AR_TKN_U16_MODULE_SLOT_WIDTH: Slot width in bits (16 or 32)
+ *
+ * %AR_TKN_U16_MODULE_SYNC_MODE: Frame sync mode
+ * AR_AUDIO_IF_FRAME_SYNC_MODE_SHORT = 0,
+ * AR_AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT = 1,
+ * AR_AUDIO_IF_FRAME_SYNC_MODE_LONG = 2
+ *
+ * %AR_TKN_U16_MODULE_CTRL_INVERT_SYNC_PULSE: Invert frame sync pulse polarity
+ * AR_AUDIO_IF_SYNC_NORMAL = 0,
+ * AR_AUDIO_IF_SYNC_INVERTED = 1
+ *
+ * %AR_TKN_U16_MODULE_CTRL_SYNC_DATA_DELAY: Data delay relative to frame sync
+ * AR_AUDIO_IF_DATA_DELAY_NONE = 0,
+ * AR_AUDIO_IF_DATA_DELAY_1_CYCLE = 1,
+ * AR_AUDIO_IF_DATA_DELAY_2_CYCLE = 2
+ *
+ * %AR_TKN_U16_MODULE_INTF_MODE: Audio IF interface mode
+ * AR_AUDIO_IF_INTF_MODE_TDM = 0,
+ * AR_AUDIO_IF_INTF_MODE_PCM = 1,
+ * AR_AUDIO_IF_INTF_MODE_I2S = 2
+ *
+ * %AR_TKN_U16_MODULE_QAIF_TYPE: QAIF hardware port type index
+ * AR_AUDIO_IF_QAIF = 0,
+ * AR_AUDIO_IF_QAIF_VA = 1
+ *
+ * %AR_TKN_U32_MODULE_ACTIVE_LANE_MASK: Active lane bitmask for multi-lane
+ *
+ * %AR_TKN_U32_MODULE_FRAME_SYNC_RATE: Frame sync rate in Hz
+ *
+ * %AR_TKN_U16_MODULE_BIT_CLK_TYPE: Bit clock type
+ * AR_AUDIO_IF_BIT_CLK_INTERNAL = 0,
+ * AR_AUDIO_IF_BIT_CLK_EXTERNAL = 1,
+ * AR_AUDIO_IF_BIT_CLK_SKIP = 2
+ *
+ * %AR_TKN_U8_MODULE_INV_INT_BIT_CLK: Invert internal bit clock
+ * AR_AUDIO_IF_CLK_NORMAL = 0,
+ * AR_AUDIO_IF_CLK_INVERTED = 1
+ *
+ * %AR_TKN_U8_MODULE_INV_EXT_BIT_CLK: Invert external bit clock
+ * AR_AUDIO_IF_CLK_NORMAL = 0,
+ * AR_AUDIO_IF_CLK_INVERTED = 1
+ *
* %AR_TKN_DAI_INDEX: dai index
*
*/
@@ -240,6 +294,45 @@ enum ar_event_types {
#define AR_TKN_U32_MODULE_LOG_TAP_POINT_ID 260
#define AR_TKN_U32_MODULE_LOG_MODE 261
+#define AR_TKN_U16_MODULE_SYNC_SRC 262
+#define AR_TKN_U16_MODULE_CTRL_DATA_OUT_ENABLE 263
+#define AR_TKN_U32_MODULE_SLOT_MASK 264
+#define AR_TKN_U16_MODULE_NSLOTS_PER_FRAME 265
+#define AR_TKN_U16_MODULE_SLOT_WIDTH 266
+#define AR_TKN_U16_MODULE_SYNC_MODE 267
+#define AR_TKN_U16_MODULE_CTRL_INVERT_SYNC_PULSE 268
+#define AR_TKN_U16_MODULE_CTRL_SYNC_DATA_DELAY 269
+#define AR_TKN_U16_MODULE_INTF_MODE 270
+#define AR_TKN_U16_MODULE_QAIF_TYPE 271
+#define AR_TKN_U32_MODULE_ACTIVE_LANE_MASK 272
+#define AR_TKN_U32_MODULE_FRAME_SYNC_RATE 273
+#define AR_TKN_U16_MODULE_BIT_CLK_TYPE 274
+#define AR_TKN_U8_MODULE_INV_INT_BIT_CLK 275
+#define AR_TKN_U8_MODULE_INV_EXT_BIT_CLK 276
+
+#define AR_AUDIO_IF_SYNC_SRC_EXTERNAL 0
+#define AR_AUDIO_IF_SYNC_SRC_INTERNAL 1
+#define AR_AUDIO_IF_CTRL_DATA_OE_DISABLE 0
+#define AR_AUDIO_IF_CTRL_DATA_OE_ENABLE 1
+#define AR_AUDIO_IF_INTF_MODE_TDM 0
+#define AR_AUDIO_IF_INTF_MODE_PCM 1
+#define AR_AUDIO_IF_INTF_MODE_I2S 2
+#define AR_AUDIO_IF_QAIF 0
+#define AR_AUDIO_IF_QAIF_VA 1
+#define AR_AUDIO_IF_FRAME_SYNC_MODE_SHORT 0
+#define AR_AUDIO_IF_FRAME_SYNC_MODE_ONE_SLOT 1
+#define AR_AUDIO_IF_FRAME_SYNC_MODE_LONG 2
+#define AR_AUDIO_IF_SYNC_NORMAL 0
+#define AR_AUDIO_IF_SYNC_INVERTED 1
+#define AR_AUDIO_IF_DATA_DELAY_NONE 0
+#define AR_AUDIO_IF_DATA_DELAY_1_CYCLE 1
+#define AR_AUDIO_IF_DATA_DELAY_2_CYCLE 2
+#define AR_AUDIO_IF_BIT_CLK_INTERNAL 0
+#define AR_AUDIO_IF_BIT_CLK_EXTERNAL 1
+#define AR_AUDIO_IF_BIT_CLK_SKIP 2
+#define AR_AUDIO_IF_CLK_NORMAL 0
+#define AR_AUDIO_IF_CLK_INVERTED 1
+
#define SND_SOC_AR_TPLG_MODULE_CFG_TYPE 0x01001006
struct audioreach_module_priv_data {
__le32 size; /* size in bytes of the array, including all elements */
diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h
deleted file mode 100644
index defeb0c6ed20..000000000000
--- a/include/uapi/sound/snd_sst_tokens.h
+++ /dev/null
@@ -1,324 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- * snd_sst_tokens.h - Intel SST tokens definition
- *
- * Copyright (C) 2016 Intel Corp
- * Author: Shreyas NC <shreyas.nc@intel.com>
- */
-#ifndef __SND_SST_TOKENS_H__
-#define __SND_SST_TOKENS_H__
-
-/**
- * %SKL_TKN_UUID: Module UUID
- *
- * %SKL_TKN_U8_BLOCK_TYPE: Type of the private data block.Can be:
- * tuples, bytes, short and words
- *
- * %SKL_TKN_U8_IN_PIN_TYPE: Input pin type,
- * homogenous=0, heterogenous=1
- *
- * %SKL_TKN_U8_OUT_PIN_TYPE: Output pin type,
- * homogenous=0, heterogenous=1
- * %SKL_TKN_U8_DYN_IN_PIN: Configure Input pin dynamically
- * if true
- *
- * %SKL_TKN_U8_DYN_OUT_PIN: Configure Output pin dynamically
- * if true
- *
- * %SKL_TKN_U8_IN_QUEUE_COUNT: Store the number of Input pins
- *
- * %SKL_TKN_U8_OUT_QUEUE_COUNT: Store the number of Output pins
- *
- * %SKL_TKN_U8_TIME_SLOT: TDM slot number
- *
- * %SKL_TKN_U8_CORE_ID: Stores module affinity value.Can take
- * the values:
- * SKL_AFFINITY_CORE_0 = 0,
- * SKL_AFFINITY_CORE_1,
- * SKL_AFFINITY_CORE_MAX
- *
- * %SKL_TKN_U8_MOD_TYPE: Module type value.
- *
- * %SKL_TKN_U8_CONN_TYPE: Module connection type can be a FE,
- * BE or NONE as defined :
- * SKL_PIPE_CONN_TYPE_NONE = 0,
- * SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA)
- * SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA)
- *
- * %SKL_TKN_U8_DEV_TYPE: Type of device to which the module is
- * connected
- * Can take the values:
- * SKL_DEVICE_BT = 0x0,
- * SKL_DEVICE_DMIC = 0x1,
- * SKL_DEVICE_I2S = 0x2,
- * SKL_DEVICE_SLIMBUS = 0x3,
- * SKL_DEVICE_HDALINK = 0x4,
- * SKL_DEVICE_HDAHOST = 0x5,
- * SKL_DEVICE_NONE
- *
- * %SKL_TKN_U8_HW_CONN_TYPE: Connection type of the HW to which the
- * module is connected
- * SKL_CONN_NONE = 0,
- * SKL_CONN_SOURCE = 1,
- * SKL_CONN_SINK = 2
- *
- * %SKL_TKN_U16_PIN_INST_ID: Stores the pin instance id
- *
- * %SKL_TKN_U16_MOD_INST_ID: Stores the mdule instance id
- *
- * %SKL_TKN_U32_MAX_MCPS: Module max mcps value
- *
- * %SKL_TKN_U32_MEM_PAGES: Module resource pages
- *
- * %SKL_TKN_U32_OBS: Stores Output Buffer size
- *
- * %SKL_TKN_U32_IBS: Stores input buffer size
- *
- * %SKL_TKN_U32_VBUS_ID: Module VBUS_ID. PDM=0, SSP0=0,
- * SSP1=1,SSP2=2,
- * SSP3=3, SSP4=4,
- * SSP5=5, SSP6=6,INVALID
- *
- * %SKL_TKN_U32_PARAMS_FIXUP: Module Params fixup mask
- * %SKL_TKN_U32_CONVERTER: Module params converter mask
- * %SKL_TKN_U32_PIPE_ID: Stores the pipe id
- *
- * %SKL_TKN_U32_PIPE_CONN_TYPE: Type of the token to which the pipe is
- * connected to. It can be
- * SKL_PIPE_CONN_TYPE_NONE = 0,
- * SKL_PIPE_CONN_TYPE_FE = 1 (HOST_DMA),
- * SKL_PIPE_CONN_TYPE_BE = 2 (LINK_DMA),
- *
- * %SKL_TKN_U32_PIPE_PRIORITY: Pipe priority value
- * %SKL_TKN_U32_PIPE_MEM_PGS: Pipe resource pages
- *
- * %SKL_TKN_U32_DIR_PIN_COUNT: Value for the direction to set input/output
- * formats and the pin count.
- * The first 4 bits have the direction
- * value and the next 4 have
- * the pin count value.
- * SKL_DIR_IN = 0, SKL_DIR_OUT = 1.
- * The input and output formats
- * share the same set of tokens
- * with the distinction between input
- * and output made by reading direction
- * token.
- *
- * %SKL_TKN_U32_FMT_CH: Supported channel count
- *
- * %SKL_TKN_U32_FMT_FREQ: Supported frequency/sample rate
- *
- * %SKL_TKN_U32_FMT_BIT_DEPTH: Supported container size
- *
- * %SKL_TKN_U32_FMT_SAMPLE_SIZE:Number of samples in the container
- *
- * %SKL_TKN_U32_FMT_CH_CONFIG: Supported channel configurations for the
- * input/output.
- *
- * %SKL_TKN_U32_FMT_INTERLEAVE: Interleaving style which can be per
- * channel or per sample. The values can be :
- * SKL_INTERLEAVING_PER_CHANNEL = 0,
- * SKL_INTERLEAVING_PER_SAMPLE = 1,
- *
- * %SKL_TKN_U32_FMT_SAMPLE_TYPE:
- * Specifies the sample type. Can take the
- * values: SKL_SAMPLE_TYPE_INT_MSB = 0,
- * SKL_SAMPLE_TYPE_INT_LSB = 1,
- * SKL_SAMPLE_TYPE_INT_SIGNED = 2,
- * SKL_SAMPLE_TYPE_INT_UNSIGNED = 3,
- * SKL_SAMPLE_TYPE_FLOAT = 4
- *
- * %SKL_TKN_U32_CH_MAP: Channel map values
- * %SKL_TKN_U32_MOD_SET_PARAMS: It can take these values:
- * SKL_PARAM_DEFAULT, SKL_PARAM_INIT,
- * SKL_PARAM_SET, SKL_PARAM_BIND
- *
- * %SKL_TKN_U32_MOD_PARAM_ID: ID of the module params
- *
- * %SKL_TKN_U32_CAPS_SET_PARAMS:
- * Set params value
- *
- * %SKL_TKN_U32_CAPS_PARAMS_ID: Params ID
- *
- * %SKL_TKN_U32_CAPS_SIZE: Caps size
- *
- * %SKL_TKN_U32_PROC_DOMAIN: Specify processing domain
- *
- * %SKL_TKN_U32_LIB_COUNT: Specifies the number of libraries
- *
- * %SKL_TKN_STR_LIB_NAME: Specifies the library name
- *
- * %SKL_TKN_U32_PMODE: Specifies the power mode for pipe
- *
- * %SKL_TKL_U32_D0I3_CAPS: Specifies the D0i3 capability for module
- *
- * %SKL_TKN_U32_DMA_BUF_SIZE: DMA buffer size in millisec
- *
- * %SKL_TKN_U32_PIPE_DIR: Specifies pipe direction. Can be
- * playback/capture.
- *
- * %SKL_TKN_U32_NUM_CONFIGS: Number of pipe configs
- *
- * %SKL_TKN_U32_PATH_MEM_PGS: Size of memory (in pages) required for pipeline
- * and its data
- *
- * %SKL_TKN_U32_PIPE_CONFIG_ID: Config id for the modules in the pipe
- * and PCM params supported by that pipe
- * config. This is used as index to fill
- * up the pipe config and module config
- * structure.
- *
- * %SKL_TKN_U32_CFG_FREQ:
- * %SKL_TKN_U8_CFG_CHAN:
- * %SKL_TKN_U8_CFG_BPS: PCM params (freq, channels, bits per sample)
- * supported for each of the pipe configs.
- *
- * %SKL_TKN_CFG_MOD_RES_ID: Module's resource index for each of the
- * pipe config
- *
- * %SKL_TKN_CFG_MOD_FMT_ID: Module's interface index for each of the
- * pipe config
- *
- * %SKL_TKN_U8_NUM_MOD: Number of modules in the manifest
- *
- * %SKL_TKN_MM_U8_MOD_IDX: Current index of the module in the manifest
- *
- * %SKL_TKN_MM_U8_NUM_RES: Number of resources for the module
- *
- * %SKL_TKN_MM_U8_NUM_INTF: Number of interfaces for the module
- *
- * %SKL_TKN_MM_U32_RES_ID: Resource index for the resource info to
- * be filled into.
- * A module can support multiple resource
- * configuration and is represnted as a
- * resource table. This index is used to
- * fill information into appropriate index.
- *
- * %SKL_TKN_MM_U32_CPS: DSP cycles per second
- *
- * %SKL_TKN_MM_U32_DMA_SIZE: Allocated buffer size for gateway DMA
- *
- * %SKL_TKN_MM_U32_CPC: DSP cycles allocated per frame
- *
- * %SKL_TKN_MM_U32_RES_PIN_ID: Resource pin index in the module
- *
- * %SKL_TKN_MM_U32_INTF_PIN_ID: Interface index in the module
- *
- * %SKL_TKN_MM_U32_PIN_BUF: Buffer size of the module pin
- *
- * %SKL_TKN_MM_U32_FMT_ID: Format index for each of the interface/
- * format information to be filled into.
- *
- * %SKL_TKN_MM_U32_NUM_IN_FMT: Number of input formats
- * %SKL_TKN_MM_U32_NUM_OUT_FMT: Number of output formats
- *
- * %SKL_TKN_U32_ASTATE_IDX: Table Index for the A-State entry to be filled
- * with kcps and clock source
- *
- * %SKL_TKN_U32_ASTATE_COUNT: Number of valid entries in A-State table
- *
- * %SKL_TKN_U32_ASTATE_KCPS: Specifies the core load threshold (in kilo
- * cycles per second) below which DSP is clocked
- * from source specified by clock source.
- *
- * %SKL_TKN_U32_ASTATE_CLK_SRC: Clock source for A-State entry
- *
- * %SKL_TKN_U32_FMT_CFG_IDX: Format config index
- *
- * module_id and loadable flags dont have tokens as these values will be
- * read from the DSP FW manifest
- *
- * Tokens defined can be used either in the manifest or widget private data.
- *
- * SKL_TKN_MM is used as a suffix for all tokens that represent
- * module data in the manifest.
- */
-enum SKL_TKNS {
- SKL_TKN_UUID = 1,
- SKL_TKN_U8_NUM_BLOCKS,
- SKL_TKN_U8_BLOCK_TYPE,
- SKL_TKN_U8_IN_PIN_TYPE,
- SKL_TKN_U8_OUT_PIN_TYPE,
- SKL_TKN_U8_DYN_IN_PIN,
- SKL_TKN_U8_DYN_OUT_PIN,
- SKL_TKN_U8_IN_QUEUE_COUNT,
- SKL_TKN_U8_OUT_QUEUE_COUNT,
- SKL_TKN_U8_TIME_SLOT,
- SKL_TKN_U8_CORE_ID,
- SKL_TKN_U8_MOD_TYPE,
- SKL_TKN_U8_CONN_TYPE,
- SKL_TKN_U8_DEV_TYPE,
- SKL_TKN_U8_HW_CONN_TYPE,
- SKL_TKN_U16_MOD_INST_ID,
- SKL_TKN_U16_BLOCK_SIZE,
- SKL_TKN_U32_MAX_MCPS,
- SKL_TKN_U32_MEM_PAGES,
- SKL_TKN_U32_OBS,
- SKL_TKN_U32_IBS,
- SKL_TKN_U32_VBUS_ID,
- SKL_TKN_U32_PARAMS_FIXUP,
- SKL_TKN_U32_CONVERTER,
- SKL_TKN_U32_PIPE_ID,
- SKL_TKN_U32_PIPE_CONN_TYPE,
- SKL_TKN_U32_PIPE_PRIORITY,
- SKL_TKN_U32_PIPE_MEM_PGS,
- SKL_TKN_U32_DIR_PIN_COUNT,
- SKL_TKN_U32_FMT_CH,
- SKL_TKN_U32_FMT_FREQ,
- SKL_TKN_U32_FMT_BIT_DEPTH,
- SKL_TKN_U32_FMT_SAMPLE_SIZE,
- SKL_TKN_U32_FMT_CH_CONFIG,
- SKL_TKN_U32_FMT_INTERLEAVE,
- SKL_TKN_U32_FMT_SAMPLE_TYPE,
- SKL_TKN_U32_FMT_CH_MAP,
- SKL_TKN_U32_PIN_MOD_ID,
- SKL_TKN_U32_PIN_INST_ID,
- SKL_TKN_U32_MOD_SET_PARAMS,
- SKL_TKN_U32_MOD_PARAM_ID,
- SKL_TKN_U32_CAPS_SET_PARAMS,
- SKL_TKN_U32_CAPS_PARAMS_ID,
- SKL_TKN_U32_CAPS_SIZE,
- SKL_TKN_U32_PROC_DOMAIN,
- SKL_TKN_U32_LIB_COUNT,
- SKL_TKN_STR_LIB_NAME,
- SKL_TKN_U32_PMODE,
- SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
- SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
- SKL_TKN_U32_DMA_BUF_SIZE,
-
- SKL_TKN_U32_PIPE_DIRECTION,
- SKL_TKN_U32_PIPE_CONFIG_ID,
- SKL_TKN_U32_NUM_CONFIGS,
- SKL_TKN_U32_PATH_MEM_PGS,
-
- SKL_TKN_U32_CFG_FREQ,
- SKL_TKN_U8_CFG_CHAN,
- SKL_TKN_U8_CFG_BPS,
- SKL_TKN_CFG_MOD_RES_ID,
- SKL_TKN_CFG_MOD_FMT_ID,
- SKL_TKN_U8_NUM_MOD,
-
- SKL_TKN_MM_U8_MOD_IDX,
- SKL_TKN_MM_U8_NUM_RES,
- SKL_TKN_MM_U8_NUM_INTF,
- SKL_TKN_MM_U32_RES_ID,
- SKL_TKN_MM_U32_CPS,
- SKL_TKN_MM_U32_DMA_SIZE,
- SKL_TKN_MM_U32_CPC,
- SKL_TKN_MM_U32_RES_PIN_ID,
- SKL_TKN_MM_U32_INTF_PIN_ID,
- SKL_TKN_MM_U32_PIN_BUF,
- SKL_TKN_MM_U32_FMT_ID,
- SKL_TKN_MM_U32_NUM_IN_FMT,
- SKL_TKN_MM_U32_NUM_OUT_FMT,
-
- SKL_TKN_U32_ASTATE_IDX,
- SKL_TKN_U32_ASTATE_COUNT,
- SKL_TKN_U32_ASTATE_KCPS,
- SKL_TKN_U32_ASTATE_CLK_SRC,
-
- SKL_TKN_U32_FMT_CFG_IDX = 96,
- SKL_TKN_MAX = SKL_TKN_U32_FMT_CFG_IDX,
-};
-
-#endif
diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h
index f4a7baadb44d..d42adbef0478 100644
--- a/include/uapi/sound/sof/tokens.h
+++ b/include/uapi/sound/sof/tokens.h
@@ -111,8 +111,8 @@
#define SOF_TKN_COMP_SCHED_DOMAIN 418
#define SOF_TKN_COMP_DOMAIN_ID 419
-#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 420
-#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 421
+#define SOF_TKN_COMP_STACK_BYTES_REQUIREMENT 420
+#define SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT 421
/* SSP */
#define SOF_TKN_INTEL_SSP_CLKS_CONTROL 500
@@ -223,6 +223,7 @@
#define SOF_TKN_AMD_ACPI2S_RATE 1700
#define SOF_TKN_AMD_ACPI2S_CH 1701
#define SOF_TKN_AMD_ACPI2S_TDM_MODE 1702
+#define SOF_TKN_AMD_ACPI2S_FORMAT 1703
/* MICFIL PDM */
#define SOF_TKN_IMX_MICFIL_RATE 2000
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index e394205f469b..234549e17351 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -693,7 +693,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct snd_card *card;
struct atmel_ac97c *chip;
- struct resource *regs;
+ void __iomem *regs;
struct clk *pclk;
static const struct snd_ac97_bus_ops ops = {
.write = atmel_ac97c_write,
@@ -702,42 +702,34 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
int retval;
int irq;
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_dbg(&pdev->dev, "no memory resource\n");
- return -ENXIO;
- }
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_dbg(&pdev->dev, "could not get irq: %d\n", irq);
+ if (irq < 0)
return irq;
- }
- pclk = clk_get(&pdev->dev, "ac97_clk");
+ pclk = devm_clk_get_enabled(&pdev->dev, "ac97_clk");
if (IS_ERR(pclk)) {
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
- retval = clk_prepare_enable(pclk);
- if (retval)
- goto err_prepare_enable;
- retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
+ retval = snd_devm_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
sizeof(struct atmel_ac97c), &card);
if (retval) {
dev_dbg(&pdev->dev, "could not create sound card device\n");
- goto err_snd_card_new;
+ return retval;
}
chip = get_chip(card);
- retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
- if (retval) {
- dev_dbg(&pdev->dev, "unable to request irq %d\n", irq);
- goto err_request_irq;
- }
+ retval = devm_request_irq(&pdev->dev, irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
+ if (retval)
+ return retval;
+
chip->irq = irq;
spin_lock_init(&chip->lock);
@@ -749,13 +741,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
chip->card = card;
chip->pclk = pclk;
chip->pdev = pdev;
- chip->regs = ioremap(regs->start, resource_size(regs));
-
- if (!chip->regs) {
- dev_dbg(&pdev->dev, "could not remap register memory\n");
- retval = -ENOMEM;
- goto err_ioremap;
- }
+ chip->regs = regs;
chip->reset_pin = devm_gpiod_get_index(dev, "ac97", 2, GPIOD_OUT_HIGH);
if (IS_ERR(chip->reset_pin))
@@ -770,25 +756,25 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
if (retval) {
dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
- goto err_ac97_bus;
+ return retval;
}
retval = atmel_ac97c_mixer_new(chip);
if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
- goto err_ac97_bus;
+ return retval;
}
retval = atmel_ac97c_pcm_new(chip);
if (retval) {
dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
- goto err_ac97_bus;
+ return retval;
}
retval = snd_card_register(card);
if (retval) {
dev_dbg(&pdev->dev, "could not register sound card\n");
- goto err_ac97_bus;
+ return retval;
}
platform_set_drvdata(pdev, card);
@@ -797,18 +783,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
chip->regs, irq);
return 0;
-
-err_ac97_bus:
- iounmap(chip->regs);
-err_ioremap:
- free_irq(irq, chip);
-err_request_irq:
- snd_card_free(card);
-err_snd_card_new:
- clk_disable_unprepare(pclk);
-err_prepare_enable:
- clk_put(pclk);
- return retval;
}
static int atmel_ac97c_suspend(struct device *pdev)
@@ -839,13 +813,6 @@ static void atmel_ac97c_remove(struct platform_device *pdev)
ac97c_writel(chip, CAMR, 0);
ac97c_writel(chip, COMR, 0);
ac97c_writel(chip, MR, 0);
-
- clk_disable_unprepare(chip->pclk);
- clk_put(chip->pclk);
- iounmap(chip->regs);
- free_irq(chip->irq, chip);
-
- snd_card_free(card);
}
static struct platform_driver atmel_ac97c_driver = {
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index ea699491f0c3..23d62fede06e 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -1393,17 +1393,17 @@ static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd,
#endif
static const struct file_operations snd_compr_file_ops = {
- .owner = THIS_MODULE,
- .open = snd_compr_open,
- .release = snd_compr_free,
- .write = snd_compr_write,
- .read = snd_compr_read,
- .unlocked_ioctl = snd_compr_ioctl,
+ .owner = THIS_MODULE,
+ .open = snd_compr_open,
+ .release = snd_compr_free,
+ .write = snd_compr_write,
+ .read = snd_compr_read,
+ .unlocked_ioctl = snd_compr_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = snd_compr_ioctl_compat,
+ .compat_ioctl = snd_compr_ioctl_compat,
#endif
- .mmap = snd_compr_mmap,
- .poll = snd_compr_poll,
+ .mmap = snd_compr_mmap,
+ .poll = snd_compr_poll,
};
static int snd_compress_dev_register(struct snd_device *device)
diff --git a/sound/core/control.c b/sound/core/control.c
index 7a8dc506221e..78ce7bc936d2 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -38,7 +38,7 @@ struct snd_kctl_ioctl {
snd_kctl_ioctl_func_t fioctl;
};
-static DECLARE_RWSEM(snd_ioctl_rwsem);
+DECLARE_RWSEM(snd_ioctl_rwsem);
static DECLARE_RWSEM(snd_ctl_layer_rwsem);
static LIST_HEAD(snd_control_ioctls);
#ifdef CONFIG_COMPAT
@@ -55,9 +55,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
struct snd_ctl_file *ctl;
int i, err;
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
if (!card) {
@@ -65,12 +63,10 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
goto __error1;
}
err = snd_card_file_add(card, file);
- if (err < 0) {
- err = -ENODEV;
+ if (err < 0)
goto __error1;
- }
if (!try_module_get(card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
@@ -876,23 +872,81 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
{
struct snd_ctl_card_info *info __free(kfree) =
kzalloc(sizeof(*info), GFP_KERNEL);
+ ssize_t n;
if (! info)
return -ENOMEM;
+
+ static_assert(sizeof(info->components) >= 2);
+
scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+ const char *components = card->components;
+
+ if (!components)
+ components = "";
+
info->card = card->number;
strscpy(info->id, card->id, sizeof(info->id));
strscpy(info->driver, card->driver, sizeof(info->driver));
strscpy(info->name, card->shortname, sizeof(info->name));
strscpy(info->longname, card->longname, sizeof(info->longname));
strscpy(info->mixername, card->mixername, sizeof(info->mixername));
- strscpy(info->components, card->components, sizeof(info->components));
+ n = strscpy(info->components, components, sizeof(info->components));
+ if (n < 0) // mark the truncation with '>' before NULL terminator
+ info->components[sizeof(info->components) - 2] = '>';
}
if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info)))
return -EFAULT;
return 0;
}
+static int snd_ctl_card_bytes(struct snd_card *card,
+ struct snd_ctl_card_bytes *info,
+ unsigned int __user *data_len_out)
+{
+ unsigned int data_len;
+
+ switch (info->type) {
+ case SND_CTL_CARD_BTYPE_COMPONENTS:
+ scoped_guard(rwsem_read, &snd_ioctl_rwsem) {
+ const char *components = card->components;
+
+ if (!components)
+ components = "";
+
+ data_len = strlen(components) + 1;
+
+ if (!info->data || info->data_allocated == 0)
+ break;
+
+ if (info->data_allocated < data_len)
+ return -ENOMEM;
+
+ if (copy_to_user(u64_to_user_ptr(info->data), components, data_len))
+ return -EFAULT;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (put_user(data_len, data_len_out))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int snd_ctl_card_bytes_user(struct snd_card *card,
+ struct snd_ctl_card_bytes __user *_info)
+{
+ struct snd_ctl_card_bytes info;
+
+ if (copy_from_user(&info, _info, sizeof(info)))
+ return -EFAULT;
+
+ return snd_ctl_card_bytes(card, &info, &_info->data_len);
+}
+
static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list *list)
{
@@ -1990,6 +2044,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
case SNDRV_CTL_IOCTL_CARD_INFO:
return snd_ctl_card_info(card, ctl, cmd, argp);
+ case SNDRV_CTL_IOCTL_CARD_BYTES:
+ return snd_ctl_card_bytes_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_LIST:
return snd_ctl_elem_list_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_INFO:
@@ -2339,16 +2395,15 @@ EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer);
* INIT PART
*/
-static const struct file_operations snd_ctl_f_ops =
-{
- .owner = THIS_MODULE,
- .read = snd_ctl_read,
- .open = snd_ctl_open,
- .release = snd_ctl_release,
- .poll = snd_ctl_poll,
- .unlocked_ioctl = snd_ctl_ioctl,
- .compat_ioctl = snd_ctl_ioctl_compat,
- .fasync = snd_ctl_fasync,
+static const struct file_operations snd_ctl_f_ops = {
+ .owner = THIS_MODULE,
+ .read = snd_ctl_read,
+ .open = snd_ctl_open,
+ .release = snd_ctl_release,
+ .poll = snd_ctl_poll,
+ .unlocked_ioctl = snd_ctl_ioctl,
+ .compat_ioctl = snd_ctl_ioctl_compat,
+ .fasync = snd_ctl_fasync,
};
/* call lops under rwsems; called from snd_ctl_dev_*() below() */
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index 16bc80555f26..87f7ad5ab739 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -226,8 +226,8 @@ static int copy_ctl_value_from_user(struct snd_card *card,
if (type < 0)
return type;
- if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -236,7 +236,7 @@ static int copy_ctl_value_from_user(struct snd_card *card,
data->value.integer.value[i] = val;
}
} else {
- size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
+ size = get_elem_size(type, count);
if (size < 0) {
dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
return -EINVAL;
@@ -259,8 +259,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
struct snd_ctl_elem_value32 __user *data32 = userdata;
int i, size;
- if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
- type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
+ if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+ type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
for (i = 0; i < count; i++) {
s32 __user *intp = valuep;
int val;
@@ -269,7 +269,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
return -EFAULT;
}
} else {
- size = get_elem_size((__force snd_ctl_elem_type_t)type, count);
+ size = get_elem_size(type, count);
if (copy_to_user(valuep, data->value.bytes.data, size))
return -EFAULT;
}
@@ -417,7 +417,7 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
break;
}
return snd_ctl_elem_add(file, data, replace);
-}
+}
enum {
SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
@@ -446,6 +446,7 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns
switch (cmd) {
case SNDRV_CTL_IOCTL_PVERSION:
case SNDRV_CTL_IOCTL_CARD_INFO:
+ case SNDRV_CTL_IOCTL_CARD_BYTES:
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
case SNDRV_CTL_IOCTL_POWER:
case SNDRV_CTL_IOCTL_POWER_STATE:
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 973d11732bfd..c6de5345e946 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -87,7 +87,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
if (!try_module_get(hw->card->module)) {
snd_card_unref(hw->card);
- return -EFAULT;
+ return -ENODEV;
}
init_waitqueue_entry(&wait, current);
@@ -323,18 +323,17 @@ static int snd_hwdep_control_ioctl(struct snd_card *card,
*/
-static const struct file_operations snd_hwdep_f_ops =
-{
- .owner = THIS_MODULE,
- .llseek = snd_hwdep_llseek,
- .read = snd_hwdep_read,
- .write = snd_hwdep_write,
- .open = snd_hwdep_open,
- .release = snd_hwdep_release,
- .poll = snd_hwdep_poll,
- .unlocked_ioctl = snd_hwdep_ioctl,
- .compat_ioctl = snd_hwdep_ioctl_compat,
- .mmap = snd_hwdep_mmap,
+static const struct file_operations snd_hwdep_f_ops = {
+ .owner = THIS_MODULE,
+ .llseek = snd_hwdep_llseek,
+ .read = snd_hwdep_read,
+ .write = snd_hwdep_write,
+ .open = snd_hwdep_open,
+ .release = snd_hwdep_release,
+ .poll = snd_hwdep_poll,
+ .unlocked_ioctl = snd_hwdep_ioctl,
+ .compat_ioctl = snd_hwdep_ioctl_compat,
+ .mmap = snd_hwdep_mmap,
};
static void snd_hwdep_free(struct snd_hwdep *hwdep)
diff --git a/sound/core/info.c b/sound/core/info.c
index 54834dbe6b59..3b8ccda04e1a 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -78,7 +78,7 @@ static int alloc_info_private(struct snd_info_entry *entry,
if (!entry || !entry->p)
return -ENODEV;
if (!try_module_get(entry->module))
- return -EFAULT;
+ return -ENODEV;
data = kzalloc_obj(*data);
if (!data) {
module_put(entry->module);
diff --git a/sound/core/init.c b/sound/core/init.c
index 56dde5bd73c4..2f7f83a7611b 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -466,20 +466,19 @@ static int snd_disconnect_fasync(int fd, struct file *file, int on)
return -ENODEV;
}
-static const struct file_operations snd_shutdown_f_ops =
-{
- .owner = THIS_MODULE,
- .llseek = snd_disconnect_llseek,
- .read = snd_disconnect_read,
- .write = snd_disconnect_write,
- .release = snd_disconnect_release,
- .poll = snd_disconnect_poll,
- .unlocked_ioctl = snd_disconnect_ioctl,
+static const struct file_operations snd_shutdown_f_ops = {
+ .owner = THIS_MODULE,
+ .llseek = snd_disconnect_llseek,
+ .read = snd_disconnect_read,
+ .write = snd_disconnect_write,
+ .release = snd_disconnect_release,
+ .poll = snd_disconnect_poll,
+ .unlocked_ioctl = snd_disconnect_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = snd_disconnect_ioctl,
+ .compat_ioctl = snd_disconnect_ioctl,
#endif
- .mmap = snd_disconnect_mmap,
- .fasync = snd_disconnect_fasync
+ .mmap = snd_disconnect_mmap,
+ .fasync = snd_disconnect_fasync
};
/**
@@ -584,12 +583,17 @@ EXPORT_SYMBOL_GPL(snd_card_disconnect_sync);
static int snd_card_do_free(struct snd_card *card)
{
+ bool managed = card->managed;
+
card->releasing = true;
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
snd_device_free_all(card);
+ kfree(card->components);
+ card->components = NULL;
+ card->components_alloc_size = 0;
if (card->private_free)
card->private_free(card);
#ifdef CONFIG_SND_CTL_DEBUG
@@ -601,7 +605,7 @@ static int snd_card_do_free(struct snd_card *card)
}
if (card->release_completion)
complete(card->release_completion);
- if (!card->managed)
+ if (!managed)
kfree(card);
return 0;
}
@@ -722,7 +726,7 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
int len, loops;
bool is_default = false;
char *id;
-
+
copy_valid_id_string(card, src, nid);
id = card->id;
@@ -1031,21 +1035,44 @@ int __init snd_card_info_init(void)
*
* Return: Zero otherwise a negative error code.
*/
-
+
int snd_component_add(struct snd_card *card, const char *component)
{
char *ptr;
int len = strlen(component);
+ unsigned int cur_len, need_len;
+
+ guard(rwsem_write)(&snd_ioctl_rwsem);
- ptr = strstr(card->components, component);
- if (ptr != NULL) {
- if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */
- return 1;
+ if (card->components) {
+ ptr = strstr(card->components, component);
+ if (ptr) {
+ if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */
+ return 1;
+ }
+ cur_len = strlen(card->components) + 1;
+ } else {
+ cur_len = 0;
}
- if (strlen(card->components) + 1 + len + 1 > sizeof(card->components)) {
+
+ need_len = cur_len + len + 1;
+ if (need_len > 512) {
snd_BUG();
return -ENOMEM;
}
+
+ if (need_len > card->components_alloc_size) {
+ unsigned int new_alloc = roundup(need_len, 32);
+
+ ptr = krealloc(card->components, new_alloc, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+ if (!card->components)
+ ptr[0] = '\0';
+ card->components = ptr;
+ card->components_alloc_size = new_alloc;
+ }
+
if (card->components[0] != '\0')
strcat(card->components, " ");
strcat(card->components, component);
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 96e0733ede77..0f04018181ac 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -303,41 +303,41 @@ static ssize_t jack_type_read(struct file *file,
}
static const struct file_operations jack_type_fops = {
- .open = simple_open,
- .read = jack_type_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_type_read,
+ .llseek = default_llseek,
};
#endif
static const struct file_operations sw_inject_enable_fops = {
- .open = simple_open,
- .read = sw_inject_enable_read,
- .write = sw_inject_enable_write,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = sw_inject_enable_read,
+ .write = sw_inject_enable_write,
+ .llseek = default_llseek,
};
static const struct file_operations jackin_inject_fops = {
- .open = simple_open,
- .write = jackin_inject_write,
- .llseek = default_llseek,
+ .open = simple_open,
+ .write = jackin_inject_write,
+ .llseek = default_llseek,
};
static const struct file_operations jack_kctl_id_fops = {
- .open = simple_open,
- .read = jack_kctl_id_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_kctl_id_read,
+ .llseek = default_llseek,
};
static const struct file_operations jack_kctl_mask_bits_fops = {
- .open = simple_open,
- .read = jack_kctl_mask_bits_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_kctl_mask_bits_read,
+ .llseek = default_llseek,
};
static const struct file_operations jack_kctl_status_fops = {
- .open = simple_open,
- .read = jack_kctl_status_read,
- .llseek = default_llseek,
+ .open = simple_open,
+ .read = jack_kctl_status_read,
+ .llseek = default_llseek,
};
static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack,
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 591cff800329..ff9d7fd60a7e 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -30,9 +30,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
struct snd_mixer_oss_file *fmixer;
int err;
- err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ nonseekable_open(inode, file);
card = snd_lookup_oss_minor_data(iminor(inode),
SNDRV_OSS_DEVICE_TYPE_MIXER);
@@ -60,7 +58,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
kfree(fmixer);
snd_card_file_remove(card, file);
snd_card_unref(card);
- return -EFAULT;
+ return -ENODEV;
}
snd_card_unref(card);
return 0;
@@ -407,13 +405,12 @@ static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
* REGISTRATION PART
*/
-static const struct file_operations snd_mixer_oss_f_ops =
-{
- .owner = THIS_MODULE,
- .open = snd_mixer_oss_open,
- .release = snd_mixer_oss_release,
- .unlocked_ioctl = snd_mixer_oss_ioctl,
- .compat_ioctl = snd_mixer_oss_ioctl_compat,
+static const struct file_operations snd_mixer_oss_f_ops = {
+ .owner = THIS_MODULE,
+ .open = snd_mixer_oss_open,
+ .release = snd_mixer_oss_release,
+ .unlocked_ioctl = snd_mixer_oss_ioctl,
+ .compat_ioctl = snd_mixer_oss_ioctl_compat,
};
/*
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 9826d9a0be6d..bd19328dca9e 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -879,11 +879,11 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
_snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
snd_mask_none(&mask);
if (atomic_read(&substream->mmap_count))
- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
else {
- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
if (!direct)
- snd_mask_set(&mask, (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
+ snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
}
err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
if (err < 0) {
@@ -909,7 +909,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
else
sformat = snd_pcm_plug_slave_format(format, sformat_mask);
- if ((__force int)sformat < 0 ||
+ if (sformat < 0 ||
!snd_mask_test_format(sformat_mask, sformat)) {
pcm_for_each_format(sformat) {
if (snd_mask_test_format(sformat_mask, sformat) &&
@@ -921,7 +921,7 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
goto failure;
}
format_found:
- err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, (__force int)sformat, 0);
+ err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
if (err < 0)
goto failure;
@@ -930,9 +930,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
} else {
_snd_pcm_hw_params_any(params);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
- (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
+ SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
- (__force int)snd_pcm_oss_format_from(runtime->oss.format), 0);
+ snd_pcm_oss_format_from(runtime->oss.format), 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
runtime->oss.channels, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
@@ -1875,7 +1875,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((__force snd_pcm_format_t)fmt);
+ int f = snd_pcm_oss_format_to(fmt);
if (f >= 0)
formats |= f;
}
@@ -2495,9 +2495,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
int nonblock;
wait_queue_entry_t wait;
- err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ nonseekable_open(inode, file);
pcm = snd_lookup_oss_minor_data(iminor(inode),
SNDRV_OSS_DEVICE_TYPE_PCM);
@@ -2509,7 +2507,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
if (err < 0)
goto __error1;
if (!try_module_get(pcm->card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
@@ -3129,17 +3127,16 @@ static inline void snd_pcm_oss_proc_done(struct snd_pcm *pcm)
* ENTRY functions
*/
-static const struct file_operations snd_pcm_oss_f_reg =
-{
- .owner = THIS_MODULE,
- .read = snd_pcm_oss_read,
- .write = snd_pcm_oss_write,
- .open = snd_pcm_oss_open,
- .release = snd_pcm_oss_release,
- .poll = snd_pcm_oss_poll,
- .unlocked_ioctl = snd_pcm_oss_ioctl,
- .compat_ioctl = snd_pcm_oss_ioctl_compat,
- .mmap = snd_pcm_oss_mmap,
+static const struct file_operations snd_pcm_oss_f_reg = {
+ .owner = THIS_MODULE,
+ .read = snd_pcm_oss_read,
+ .write = snd_pcm_oss_write,
+ .open = snd_pcm_oss_open,
+ .release = snd_pcm_oss_release,
+ .poll = snd_pcm_oss_poll,
+ .unlocked_ioctl = snd_pcm_oss_ioctl,
+ .compat_ioctl = snd_pcm_oss_ioctl_compat,
+ .mmap = snd_pcm_oss_mmap,
};
static void register_oss_dsp(struct snd_pcm *pcm, int index)
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 5f4d6945a7df..acf5ca663ba8 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -272,13 +272,13 @@ static int snd_pcm_plug_formats(const struct snd_mask *mask,
SNDRV_PCM_FMTBIT_U24_3BE | SNDRV_PCM_FMTBIT_S24_3BE |
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
- snd_mask_set(&formats, (__force int)SNDRV_PCM_FORMAT_MU_LAW);
+ snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
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);
+ return snd_mask_test(&formats, format);
}
static const snd_pcm_format_t preferred_formats[] = {
@@ -307,20 +307,20 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
{
int i;
- if (snd_mask_test(format_mask, (__force int)format))
+ if (snd_mask_test(format_mask, format))
return format;
if (!snd_pcm_plug_formats(format_mask, format))
- return (__force snd_pcm_format_t)-EINVAL;
+ return -EINVAL;
if (snd_pcm_format_linear(format)) {
unsigned int width = snd_pcm_format_width(format);
int unsignd = snd_pcm_format_unsigned(format) > 0;
int big = snd_pcm_format_big_endian(format) > 0;
unsigned int badness, best = -1;
- snd_pcm_format_t best_format = (__force snd_pcm_format_t)-1;
+ snd_pcm_format_t best_format = -1;
for (i = 0; i < ARRAY_SIZE(preferred_formats); i++) {
snd_pcm_format_t f = preferred_formats[i];
unsigned int w;
- if (!snd_mask_test(format_mask, (__force int)f))
+ if (!snd_mask_test(format_mask, f))
continue;
w = snd_pcm_format_width(f);
if (w >= width)
@@ -334,21 +334,21 @@ snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
best = badness;
}
}
- if ((__force int)best_format >= 0)
+ if (best_format >= 0)
return best_format;
else
- return (__force snd_pcm_format_t)-EINVAL;
+ return -EINVAL;
} else {
switch (format) {
case SNDRV_PCM_FORMAT_MU_LAW:
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
snd_pcm_format_t format1 = preferred_formats[i];
- if (snd_mask_test(format_mask, (__force int)format1))
+ if (snd_mask_test(format_mask, format1))
return format1;
}
fallthrough;
default:
- return (__force snd_pcm_format_t)-EINVAL;
+ return -EINVAL;
}
}
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index bfedf571e021..41c2cab7a52c 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -211,11 +211,9 @@ static const char * const snd_pcm_format_names[] = {
*/
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
- unsigned int format_num = (__force unsigned int)format;
-
- if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num])
+ if (format >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format])
return "Unknown";
- return snd_pcm_format_names[format_num];
+ return snd_pcm_format_names[format];
}
EXPORT_SYMBOL_GPL(snd_pcm_format_name);
@@ -275,12 +273,12 @@ static const char *snd_pcm_stream_name(int stream)
static const char *snd_pcm_access_name(snd_pcm_access_t access)
{
- return snd_pcm_access_names[(__force int)access];
+ return snd_pcm_access_names[access];
}
static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
{
- return snd_pcm_subformat_names[(__force int)subformat];
+ return snd_pcm_subformat_names[subformat];
}
static const char *snd_pcm_tstamp_mode_name(int mode)
@@ -290,7 +288,7 @@ static const char *snd_pcm_tstamp_mode_name(int mode)
static const char *snd_pcm_state_name(snd_pcm_state_t state)
{
- return snd_pcm_state_names[(__force int)state];
+ return snd_pcm_state_names[state];
}
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 180b6b64a448..13de3b02aa34 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -24,15 +24,12 @@ struct pcm_format_data {
unsigned char silence[8]; /* silence data to fill */
};
-/* we do lots of calculations on snd_pcm_format_t; shut up sparse */
-#define INT __force int
-
static bool valid_format(snd_pcm_format_t format)
{
- return (INT)format >= 0 && (INT)format <= (INT)SNDRV_PCM_FORMAT_LAST;
+ return format >= 0 && format <= SNDRV_PCM_FORMAT_LAST;
}
-static const struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = {
+static const struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
[SNDRV_PCM_FORMAT_S8] = {
.width = 8, .phys = 8, .le = -1, .signd = 1,
.silence = {},
@@ -251,7 +248,7 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].signd;
+ val = pcm_formats[format].signd;
if (val < 0)
return -EINVAL;
return val;
@@ -300,7 +297,7 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].le;
+ val = pcm_formats[format].le;
if (val < 0)
return -EINVAL;
return val;
@@ -337,7 +334,7 @@ int snd_pcm_format_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].width;
+ val = pcm_formats[format].width;
if (!val)
return -EINVAL;
return val;
@@ -356,7 +353,7 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
- val = pcm_formats[(INT)format].phys;
+ val = pcm_formats[format].phys;
if (!val)
return -EINVAL;
return val;
@@ -390,9 +387,9 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
{
if (!valid_format(format))
return NULL;
- if (! pcm_formats[(INT)format].phys)
+ if (! pcm_formats[format].phys)
return NULL;
- return pcm_formats[(INT)format].silence;
+ return pcm_formats[format].silence;
}
EXPORT_SYMBOL(snd_pcm_format_silence_64);
@@ -416,12 +413,12 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
return -EINVAL;
if (samples == 0)
return 0;
- width = pcm_formats[(INT)format].phys; /* physical width */
+ width = pcm_formats[format].phys; /* physical width */
if (!width)
return -EINVAL;
- pat = pcm_formats[(INT)format].silence;
+ pat = pcm_formats[format].silence;
/* signed or 1 byte data */
- if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
+ if (pcm_formats[format].signd == 1 || width <= 8) {
unsigned int bytes = samples * width / 8;
memset(data, *pat, bytes);
return 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index c9d0c2bb55b2..4a5057e7629d 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -257,7 +257,7 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
}
/* macro for simplified cast */
-#define PARAM_MASK_BIT(b) (1U << (__force int)(b))
+#define PARAM_MASK_BIT(b) (1U << (b))
static bool hw_support_mmap(struct snd_pcm_substream *substream)
{
@@ -489,7 +489,7 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
params->msbits = snd_interval_value(i);
m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
if (snd_mask_single(m)) {
- snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+ snd_pcm_format_t format = snd_mask_min(m);
params->msbits = snd_pcm_format_width(format);
}
}
@@ -497,13 +497,13 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
if (params->msbits) {
m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
if (snd_mask_single(m)) {
- snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m);
+ snd_pcm_format_t format = snd_mask_min(m);
if (snd_pcm_format_linear(format) &&
snd_pcm_format_width(format) != params->msbits) {
m_rw = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT);
snd_mask_reset(m_rw,
- (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
+ SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
if (snd_mask_empty(m_rw))
return -EINVAL;
}
@@ -1252,7 +1252,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
runtime->trigger_master = NULL;
}
-#define ACTION_ARG_IGNORE (__force snd_pcm_state_t)0
+#define ACTION_ARG_IGNORE 0
struct action_ops {
int (*pre_action)(struct snd_pcm_substream *substream,
@@ -1635,7 +1635,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
/*
* pause callbacks: pass boolean (to start pause or resume) as state argument
*/
-#define pause_pushed(state) (__force bool)(state)
+#define pause_pushed(state) (bool)(state)
static int snd_pcm_pre_pause(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
@@ -1707,14 +1707,14 @@ static const struct action_ops snd_pcm_action_pause = {
static int snd_pcm_pause(struct snd_pcm_substream *substream, bool push)
{
return snd_pcm_action(&snd_pcm_action_pause, substream,
- (__force snd_pcm_state_t)push);
+ (snd_pcm_state_t)push);
}
static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream,
bool push)
{
return snd_pcm_action_lock_irq(&snd_pcm_action_pause, substream,
- (__force snd_pcm_state_t)push);
+ (snd_pcm_state_t)push);
}
#ifdef CONFIG_PM
@@ -1982,7 +1982,7 @@ static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
snd_pcm_state_t state)
{
snd_pcm_state_t cur_state = snd_pcm_get_state(substream);
- int f_flags = (__force int)state;
+ int f_flags = state;
if (cur_state == SNDRV_PCM_STATE_OPEN ||
cur_state == SNDRV_PCM_STATE_DISCONNECTED)
@@ -2050,7 +2050,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
substream,
- (__force snd_pcm_state_t)f_flags);
+ (snd_pcm_state_t)f_flags);
}
/*
@@ -2461,7 +2461,7 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
if (bits <= 0)
continue; /* ignore invalid formats */
if ((unsigned)bits < i->min || (unsigned)bits > i->max)
- snd_mask_reset(&m, (__force unsigned)k);
+ snd_mask_reset(&m, k);
}
return snd_mask_refine(mask, &m);
}
@@ -2543,16 +2543,16 @@ static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params,
snd_mask_none(&m);
/* All PCMs support at least the default STD subformat. */
- snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_STD);
+ snd_mask_set(&m, SNDRV_PCM_SUBFORMAT_STD);
pcm_for_each_format(f) {
- if (!snd_mask_test(fmask, (__force unsigned)f))
+ if (!snd_mask_test(fmask, f))
continue;
if (f == SNDRV_PCM_FORMAT_S32_LE && *subformats)
m.bits[0] |= *subformats;
else if (snd_pcm_format_linear(f))
- snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
+ snd_mask_set(&m, SNDRV_PCM_SUBFORMAT_MSBITS_MAX);
}
return snd_mask_refine(sfmask, &m);
@@ -2880,9 +2880,10 @@ static int snd_pcm_open_file(struct file *file,
static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
- int err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ int err;
+
+ nonseekable_open(inode, file);
+
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
@@ -2894,9 +2895,10 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
static int snd_pcm_capture_open(struct inode *inode, struct file *file)
{
struct snd_pcm *pcm;
- int err = nonseekable_open(inode, file);
- if (err < 0)
- return err;
+ int err;
+
+ nonseekable_open(inode, file);
+
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_CAPTURE);
err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
@@ -2918,7 +2920,7 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
if (err < 0)
goto __error1;
if (!try_module_get(pcm->card->module)) {
- err = -EFAULT;
+ err = -ENODEV;
goto __error2;
}
init_waitqueue_entry(&wait, current);
@@ -3914,6 +3916,8 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
if (substream == NULL)
return VM_FAULT_SIGBUS;
runtime = substream->runtime;
+ if (runtime->state == SNDRV_PCM_STATE_DISCONNECTED)
+ return VM_FAULT_SIGBUS;
offset = vmf->pgoff << PAGE_SHIFT;
dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
if (offset > dma_bytes - PAGE_SIZE)
@@ -4239,29 +4243,29 @@ static unsigned long snd_pcm_get_unmapped_area(struct file *file,
const struct file_operations snd_pcm_f_ops[2] = {
{
- .owner = THIS_MODULE,
- .write = snd_pcm_write,
- .write_iter = snd_pcm_writev,
- .open = snd_pcm_playback_open,
- .release = snd_pcm_release,
- .poll = snd_pcm_poll,
- .unlocked_ioctl = snd_pcm_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
- .mmap = snd_pcm_mmap,
- .fasync = snd_pcm_fasync,
- .get_unmapped_area = snd_pcm_get_unmapped_area,
+ .owner = THIS_MODULE,
+ .write = snd_pcm_write,
+ .write_iter = snd_pcm_writev,
+ .open = snd_pcm_playback_open,
+ .release = snd_pcm_release,
+ .poll = snd_pcm_poll,
+ .unlocked_ioctl = snd_pcm_ioctl,
+ .compat_ioctl = snd_pcm_ioctl_compat,
+ .mmap = snd_pcm_mmap,
+ .fasync = snd_pcm_fasync,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
- .owner = THIS_MODULE,
- .read = snd_pcm_read,
- .read_iter = snd_pcm_readv,
- .open = snd_pcm_capture_open,
- .release = snd_pcm_release,
- .poll = snd_pcm_poll,
- .unlocked_ioctl = snd_pcm_ioctl,
- .compat_ioctl = snd_pcm_ioctl_compat,
- .mmap = snd_pcm_mmap,
- .fasync = snd_pcm_fasync,
- .get_unmapped_area = snd_pcm_get_unmapped_area,
+ .owner = THIS_MODULE,
+ .read = snd_pcm_read,
+ .read_iter = snd_pcm_readv,
+ .open = snd_pcm_capture_open,
+ .release = snd_pcm_release,
+ .poll = snd_pcm_poll,
+ .unlocked_ioctl = snd_pcm_ioctl,
+ .compat_ioctl = snd_pcm_ioctl_compat,
+ .mmap = snd_pcm_mmap,
+ .fasync = snd_pcm_fasync,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
}
};
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 4dfd9d53e6d3..bf504e27f73e 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -408,9 +408,10 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode,
return 0;
}
-/* called from sound/core/seq/seq_midi.c */
-int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
- int mode, struct snd_rawmidi_file *rfile)
+/* called from sound/core/seq/seq_midi.c and sound/core/ump.c */
+int snd_rawmidi_kernel_open_nested(struct snd_rawmidi *rmidi, int subdevice,
+ int mode, struct snd_rawmidi_file *rfile,
+ int depth)
{
int err;
@@ -419,13 +420,14 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice,
if (!try_module_get(rmidi->card->module))
return -ENXIO;
- guard(mutex)(&rmidi->open_mutex);
+ mutex_lock_nested(&rmidi->open_mutex, depth);
err = rawmidi_open_priv(rmidi, subdevice, mode, rfile);
if (err < 0)
module_put(rmidi->card->module);
+ mutex_unlock(&rmidi->open_mutex);
return err;
}
-EXPORT_SYMBOL(snd_rawmidi_kernel_open);
+EXPORT_SYMBOL(snd_rawmidi_kernel_open_nested);
static int snd_rawmidi_open(struct inode *inode, struct file *file)
{
@@ -441,9 +443,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
return -EINVAL; /* invalid combination */
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
if (maj == snd_major) {
rmidi = snd_lookup_minor_data(iminor(inode),
@@ -1784,14 +1784,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
*/
static const struct file_operations snd_rawmidi_f_ops = {
- .owner = THIS_MODULE,
- .read = snd_rawmidi_read,
- .write = snd_rawmidi_write,
- .open = snd_rawmidi_open,
- .release = snd_rawmidi_release,
- .poll = snd_rawmidi_poll,
- .unlocked_ioctl = snd_rawmidi_ioctl,
- .compat_ioctl = snd_rawmidi_ioctl_compat,
+ .owner = THIS_MODULE,
+ .read = snd_rawmidi_read,
+ .write = snd_rawmidi_write,
+ .open = snd_rawmidi_open,
+ .release = snd_rawmidi_release,
+ .poll = snd_rawmidi_poll,
+ .unlocked_ioctl = snd_rawmidi_ioctl,
+ .compat_ioctl = snd_rawmidi_ioctl_compat,
};
static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 021cd70f90db..2835576040ed 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -206,17 +206,16 @@ odev_poll(struct file *file, poll_table * wait)
* registration of sequencer minor device
*/
-static const struct file_operations seq_oss_f_ops =
-{
- .owner = THIS_MODULE,
- .read = odev_read,
- .write = odev_write,
- .open = odev_open,
- .release = odev_release,
- .poll = odev_poll,
- .unlocked_ioctl = odev_ioctl,
- .compat_ioctl = odev_ioctl_compat,
- .llseek = noop_llseek,
+static const struct file_operations seq_oss_f_ops = {
+ .owner = THIS_MODULE,
+ .read = odev_read,
+ .write = odev_write,
+ .open = odev_open,
+ .release = odev_release,
+ .poll = odev_poll,
+ .unlocked_ioctl = odev_ioctl,
+ .compat_ioctl = odev_ioctl_compat,
+ .llseek = noop_llseek,
};
static int __init
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 28782e1776fa..5b86e75c2658 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -59,7 +59,7 @@ static DEFINE_MUTEX(register_mutex);
* client table
*/
static char clienttablock[SNDRV_SEQ_MAX_CLIENTS];
-static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS];
+static struct snd_seq_client __rcu *clienttab[SNDRV_SEQ_MAX_CLIENTS];
static struct snd_seq_usage client_usage;
/*
@@ -95,15 +95,23 @@ static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
return snd_seq_total_cells(client->pool) > 0;
}
-/* return pointer to client structure for specified id */
-static struct snd_seq_client *clientptr(int clientid)
+/* return pointer to client structure for specified id; call under RCU read-lock */
+static struct snd_seq_client *__clientptr(int clientid)
{
if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
clientid);
return NULL;
}
- return clienttab[clientid];
+ return rcu_dereference_check(clienttab[clientid],
+ lockdep_is_held(&clients_lock));
+}
+
+/* return pointer to client structure for specified id */
+static struct snd_seq_client *clientptr(int clientid)
+{
+ guard(rcu)();
+ return __clientptr(clientid);
}
static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
@@ -115,8 +123,8 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
clientid);
return NULL;
}
- scoped_guard(spinlock_irqsave, &clients_lock) {
- client = clientptr(clientid);
+ scoped_guard(rcu) {
+ client = __clientptr(clientid);
if (client)
return snd_seq_client_ref(client);
if (clienttablock[clientid])
@@ -150,8 +158,8 @@ static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
snd_seq_device_load_drivers();
}
}
- scoped_guard(spinlock_irqsave, &clients_lock) {
- client = clientptr(clientid);
+ scoped_guard(rcu) {
+ client = __clientptr(clientid);
if (client)
return snd_seq_client_ref(client);
}
@@ -212,7 +220,6 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
}
client->type = NO_CLIENT;
snd_use_lock_init(&client->use_lock);
- rwlock_init(&client->ports_lock);
mutex_init(&client->ports_mutex);
INIT_LIST_HEAD(&client->ports_list_head);
mutex_init(&client->ioctl_mutex);
@@ -224,14 +231,17 @@ static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
c < SNDRV_SEQ_MAX_CLIENTS;
c++) {
- if (clienttab[c] || clienttablock[c])
+ if (rcu_access_pointer(clienttab[c]) || clienttablock[c])
continue;
- clienttab[client->number = c] = client;
+ client->number = c;
+ rcu_assign_pointer(clienttab[c], client);
return client;
}
} else {
- if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
- clienttab[client->number = client_index] = client;
+ if (rcu_access_pointer(clienttab[client_index]) == NULL &&
+ !clienttablock[client_index]) {
+ client->number = client_index;
+ rcu_assign_pointer(clienttab[client_index], client);
return client;
}
}
@@ -249,10 +259,16 @@ static int seq_free_client1(struct snd_seq_client *client)
return 0;
scoped_guard(spinlock_irq, &clients_lock) {
clienttablock[client->number] = 1;
- clienttab[client->number] = NULL;
+ rcu_assign_pointer(clienttab[client->number], NULL);
}
snd_seq_delete_all_ports(client);
snd_seq_queue_client_leave(client->number);
+ /* the client has been unpublished from the table; wait for a grace
+ * period so that lockless readers (snd_seq_client_use_ptr()) that
+ * observed the old pointer can no longer take a new use_lock
+ * reference, then drain the outstanding references before freeing
+ */
+ synchronize_rcu();
snd_use_lock_sync(&client->use_lock);
if (client->pool)
snd_seq_pool_delete(&client->pool);
@@ -296,11 +312,8 @@ static int snd_seq_open(struct inode *inode, struct file *file)
int c, mode; /* client id */
struct snd_seq_client *client;
struct snd_seq_user_client *user;
- int err;
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
scoped_guard(mutex, &register_mutex) {
client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
@@ -517,9 +530,8 @@ static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event)
* Return the error event.
*
* If the receiver client is a user client, the original event is
- * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. If
- * the original event is also variable length, the external data is
- * copied after the event record.
+ * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. The
+ * external data of a variable length event is not copied along.
* If the receiver client is a kernel client, the original event is
* quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra
* kmalloc.
@@ -528,7 +540,7 @@ static int bounce_error_event(struct snd_seq_client *client,
struct snd_seq_event *event,
int err, int atomic, int hop)
{
- struct snd_seq_event bounce_ev;
+ struct snd_seq_event bounce_ev, quoted;
int result;
if (client == NULL ||
@@ -548,15 +560,19 @@ static int bounce_error_event(struct snd_seq_client *client,
* For user clients, send SNDRV_SEQ_EVENT_BOUNCE with the
* original event embedded as variable-length data. This
* avoids exposing data.quote.event (a kernel pointer) to
- * userspace. The variable-length path in snd_seq_event_dup()
- * copies the event data from data.ext.ptr into chained cells,
- * and snd_seq_expand_var_event() copies only the data content
- * -- never the pointer -- to userspace.
+ * userspace. Sanitise the embedded copy too - a queued
+ * variable-length event carries the address of its own
+ * extension cell, and the payload goes out verbatim.
*/
+ quoted = *event;
+ if (snd_seq_ev_is_variable(&quoted)) {
+ quoted.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
+ quoted.data.ext.ptr = NULL;
+ }
bounce_ev.type = SNDRV_SEQ_EVENT_BOUNCE;
bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
bounce_ev.data.ext.len = sizeof(struct snd_seq_event);
- bounce_ev.data.ext.ptr = (char *)event;
+ bounce_ev.data.ext.ptr = (char *)&quoted;
} else {
/*
* For kernel clients, quote the event pointer directly.
@@ -720,10 +736,11 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
/* lock list */
if (atomic)
- read_lock(&grp->list_lock);
+ rcu_read_lock();
else
down_read_nested(&grp->list_mutex, hop);
- list_for_each_entry(subs, &grp->list_head, src_list) {
+ hlist_for_each_entry_rcu(subs, &grp->list_head, src_list,
+ lockdep_is_held(&grp->list_mutex)) {
/* both ports ready? */
if (atomic_read(&subs->ref_count) != 2)
continue;
@@ -744,7 +761,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
memcpy(event, &event_saved, saved_size);
}
if (atomic)
- read_unlock(&grp->list_lock);
+ rcu_read_unlock();
else
up_read(&grp->list_mutex);
memcpy(event, &event_saved, saved_size);
@@ -1941,7 +1958,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
{
struct snd_seq_query_subs *subs = arg;
struct snd_seq_port_subs_info *group;
- struct list_head *p;
+ struct hlist_node *p;
int i;
struct snd_seq_client *cptr __free(snd_seq_client) =
@@ -1968,15 +1985,15 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
/* search for the subscriber */
subs->num_subs = group->count;
i = 0;
- list_for_each(p, &group->list_head) {
+ hlist_for_each(p, &group->list_head) {
if (i++ == subs->index) {
/* found! */
struct snd_seq_subscribers *s;
if (subs->type == SNDRV_SEQ_QUERY_SUBS_READ) {
- s = list_entry(p, struct snd_seq_subscribers, src_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, src_list);
subs->addr = s->info.dest;
} else {
- s = list_entry(p, struct snd_seq_subscribers, dest_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, dest_list);
subs->addr = s->info.sender;
}
subs->flags = s->info.flags;
@@ -2532,19 +2549,19 @@ static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
struct snd_seq_port_subs_info *group,
int is_src, char *msg)
{
- struct list_head *p;
+ struct hlist_node *p;
struct snd_seq_subscribers *s;
int count = 0;
guard(rwsem_read)(&group->list_mutex);
- if (list_empty(&group->list_head))
+ if (hlist_empty(&group->list_head))
return;
snd_iprintf(buffer, msg);
- list_for_each(p, &group->list_head) {
+ hlist_for_each(p, &group->list_head) {
if (is_src)
- s = list_entry(p, struct snd_seq_subscribers, src_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, src_list);
else
- s = list_entry(p, struct snd_seq_subscribers, dest_list);
+ s = hlist_entry(p, struct snd_seq_subscribers, dest_list);
if (count++)
snd_iprintf(buffer, ", ");
snd_iprintf(buffer, "%d:%d",
@@ -2666,16 +2683,15 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
* REGISTRATION PART
*/
-static const struct file_operations snd_seq_f_ops =
-{
- .owner = THIS_MODULE,
- .read = snd_seq_read,
- .write = snd_seq_write,
- .open = snd_seq_open,
- .release = snd_seq_release,
- .poll = snd_seq_poll,
- .unlocked_ioctl = snd_seq_ioctl,
- .compat_ioctl = snd_seq_ioctl_compat,
+static const struct file_operations snd_seq_f_ops = {
+ .owner = THIS_MODULE,
+ .read = snd_seq_read,
+ .write = snd_seq_write,
+ .open = snd_seq_open,
+ .release = snd_seq_release,
+ .poll = snd_seq_poll,
+ .unlocked_ioctl = snd_seq_ioctl,
+ .compat_ioctl = snd_seq_ioctl_compat,
};
static struct device *seq_dev;
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index feea8bb7d987..d7ffc5c1ed61 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -49,7 +49,6 @@ struct snd_seq_client {
/* ports */
int num_ports; /* number of ports */
struct list_head ports_list_head;
- rwlock_t ports_lock;
struct mutex ports_mutex;
struct mutex ioctl_mutex;
int convert32; /* convert 32->64bit */
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 2eb12199c92f..a16a5debf339 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -42,9 +42,11 @@ struct seq_midisynth {
struct snd_rawmidi *rmidi;
int device;
int subdevice;
+ struct snd_rawmidi_substream __rcu *input_substream;
+ snd_use_lock_t input_use_lock; /* in-flight event_input users */
struct snd_rawmidi_file input_rfile;
- spinlock_t output_lock; /* protects output_rfile publication */
snd_use_lock_t output_use_lock; /* in-flight event_input users */
+ struct snd_rawmidi_substream __rcu *output_substream;
struct snd_rawmidi_file output_rfile;
int seq_client;
int seq_port;
@@ -76,6 +78,14 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
msynth = runtime->private_data;
if (msynth == NULL)
return;
+
+ scoped_guard(rcu) {
+ if (rcu_dereference(msynth->input_substream) != substream)
+ return;
+
+ snd_use_lock_use(&msynth->input_use_lock);
+ }
+
memset(&ev, 0, sizeof(ev));
while (runtime->avail > 0) {
res = snd_rawmidi_kernel_read(substream, buf, sizeof(buf));
@@ -95,6 +105,8 @@ static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
memset(&ev, 0, sizeof(ev));
}
}
+
+ snd_use_lock_free(&msynth->input_use_lock);
}
static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count)
@@ -134,8 +146,8 @@ static int event_process_midi(struct snd_seq_event *ev, int direct,
if (snd_BUG_ON(!msynth))
return -EINVAL;
- scoped_guard(spinlock_irqsave, &msynth->output_lock) {
- substream = msynth->output_rfile.output;
+ scoped_guard(rcu) {
+ substream = rcu_dereference(msynth->output_substream);
if (!substream)
return -ENODEV;
snd_use_lock_use(&msynth->output_use_lock);
@@ -177,7 +189,7 @@ static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
msynth->card = card;
msynth->device = device;
msynth->subdevice = subdevice;
- spin_lock_init(&msynth->output_lock);
+ snd_use_lock_init(&msynth->input_use_lock);
snd_use_lock_init(&msynth->output_use_lock);
return 0;
}
@@ -188,28 +200,31 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
int err;
struct seq_midisynth *msynth = private_data;
struct snd_rawmidi_runtime *runtime;
+ struct snd_rawmidi_file rfile = {};
struct snd_rawmidi_params params;
/* open midi port */
err = snd_rawmidi_kernel_open(msynth->rmidi, msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
- &msynth->input_rfile);
+ &rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
return err;
}
- runtime = msynth->input_rfile.input->runtime;
+ runtime = rfile.input->runtime;
memset(&params, 0, sizeof(params));
params.avail_min = 1;
params.buffer_size = input_buffer_size;
- err = snd_rawmidi_input_params(msynth->input_rfile.input, &params);
+ err = snd_rawmidi_input_params(rfile.input, &params);
if (err < 0) {
- snd_rawmidi_kernel_release(&msynth->input_rfile);
+ snd_rawmidi_kernel_release(&rfile);
return err;
}
snd_midi_event_reset_encode(msynth->parser);
runtime->event = snd_midi_input_event;
runtime->private_data = msynth;
+ msynth->input_rfile = rfile;
+ rcu_assign_pointer(msynth->input_substream, rfile.input);
snd_rawmidi_kernel_read(msynth->input_rfile.input, NULL, 0);
return 0;
}
@@ -219,10 +234,19 @@ static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscri
{
int err;
struct seq_midisynth *msynth = private_data;
+ struct snd_rawmidi_file rfile;
- if (snd_BUG_ON(!msynth->input_rfile.input))
+ rcu_assign_pointer(msynth->input_substream, NULL);
+ synchronize_rcu();
+ snd_use_lock_sync(&msynth->input_use_lock);
+
+ rfile = msynth->input_rfile;
+ msynth->input_rfile = (struct snd_rawmidi_file){};
+
+ if (snd_BUG_ON(!rfile.input))
return -EINVAL;
- err = snd_rawmidi_kernel_release(&msynth->input_rfile);
+
+ err = snd_rawmidi_kernel_release(&rfile);
return err;
}
@@ -252,8 +276,8 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
return err;
}
snd_midi_event_reset_decode(msynth->parser);
- scoped_guard(spinlock_irqsave, &msynth->output_lock)
- msynth->output_rfile = rfile;
+ msynth->output_rfile = rfile;
+ rcu_assign_pointer(msynth->output_substream, rfile.output);
return 0;
}
@@ -261,17 +285,16 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
{
struct seq_midisynth *msynth = private_data;
- struct snd_rawmidi_file rfile = {};
+ struct snd_rawmidi_file rfile;
- scoped_guard(spinlock_irqsave, &msynth->output_lock) {
- rfile = msynth->output_rfile;
- msynth->output_rfile = (struct snd_rawmidi_file){};
- }
+ rcu_assign_pointer(msynth->output_substream, NULL);
+ synchronize_rcu();
+ snd_use_lock_sync(&msynth->output_use_lock);
+ rfile = msynth->output_rfile;
+ msynth->output_rfile = (struct snd_rawmidi_file){};
if (snd_BUG_ON(!rfile.output))
return -EINVAL;
-
- snd_use_lock_sync(&msynth->output_use_lock);
snd_rawmidi_drain_output(rfile.output);
return snd_rawmidi_kernel_release(&rfile);
}
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 6612e92d801f..eb67eb0eeb14 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -48,8 +48,8 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client,
if (client == NULL)
return NULL;
- guard(read_lock)(&client->ports_lock);
- list_for_each_entry(port, &client->ports_list_head, list) {
+ guard(rcu)();
+ list_for_each_entry_rcu(port, &client->ports_list_head, list) {
if (port->addr.port == num) {
if (port->closing)
break; /* deleting now */
@@ -71,8 +71,8 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
num = pinfo->addr.port;
found = NULL;
- guard(read_lock)(&client->ports_lock);
- list_for_each_entry(port, &client->ports_list_head, list) {
+ guard(rcu)();
+ list_for_each_entry_rcu(port, &client->ports_list_head, list) {
if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) &&
!check_inactive)
continue; /* skip inactive ports */
@@ -98,10 +98,9 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl
/* initialize snd_seq_port_subs_info */
static void port_subs_info_init(struct snd_seq_port_subs_info *grp)
{
- INIT_LIST_HEAD(&grp->list_head);
+ INIT_HLIST_HEAD(&grp->list_head);
grp->count = 0;
grp->exclusive = 0;
- rwlock_init(&grp->list_lock);
init_rwsem(&grp->list_mutex);
grp->open = NULL;
grp->close = NULL;
@@ -154,7 +153,6 @@ int snd_seq_insert_port(struct snd_seq_client *client, int port,
num = max(port, 0);
guard(mutex)(&client->ports_mutex);
- guard(write_lock_irq)(&client->ports_lock);
struct list_head *insert_before = &client->ports_list_head;
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port)
@@ -166,12 +164,13 @@ int snd_seq_insert_port(struct snd_seq_client *client, int port,
if (port < 0) /* auto-probe mode */
num = p->addr.port + 1;
}
- /* insert the new port */
- list_add_tail(&new_port->list, insert_before);
- client->num_ports++;
+ /* finish initializing the port before publishing it to RCU readers */
new_port->addr.port = num; /* store the port number in the port */
if (!new_port->name[0])
sprintf(new_port->name, "port-%d", num);
+ /* insert the new port */
+ list_add_tail_rcu(&new_port->list, insert_before);
+ client->num_ports++;
return num;
}
@@ -202,12 +201,12 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client,
bool is_src, bool ack);
static inline struct snd_seq_subscribers *
-get_subscriber(struct list_head *p, bool is_src)
+get_subscriber(struct hlist_node *p, bool is_src)
{
if (is_src)
- return list_entry(p, struct snd_seq_subscribers, src_list);
+ return hlist_entry(p, struct snd_seq_subscribers, src_list);
else
- return list_entry(p, struct snd_seq_subscribers, dest_list);
+ return hlist_entry(p, struct snd_seq_subscribers, dest_list);
}
/*
@@ -219,9 +218,9 @@ static void clear_subscriber_list(struct snd_seq_client *client,
struct snd_seq_port_subs_info *grp,
int is_src)
{
- struct list_head *p, *n;
+ struct hlist_node *p, *n;
- list_for_each_safe(p, n, &grp->list_head) {
+ hlist_for_each_safe(p, n, &grp->list_head) {
struct snd_seq_subscribers *subs;
subs = get_subscriber(p, is_src);
@@ -238,13 +237,13 @@ static void clear_subscriber_list(struct snd_seq_client *client,
* remove the subscriber info
*/
if (atomic_dec_and_test(&subs->ref_count))
- kfree(subs);
+ kfree_rcu(subs, rcu);
continue;
}
/* ok we got the connected port */
delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
- kfree(subs);
+ kfree_rcu(subs, rcu);
}
}
@@ -254,7 +253,13 @@ static int port_delete(struct snd_seq_client *client,
{
/* set closing flag and wait for all port access are gone */
port->closing = 1;
- snd_use_lock_sync(&port->use_lock);
+ /* the port has already been unlinked from the client's port list;
+ * wait for a grace period so that RCU readers still traversing the
+ * list can no longer take a new use_lock reference, then drain the
+ * outstanding references before freeing
+ */
+ synchronize_rcu();
+ snd_use_lock_sync(&port->use_lock);
/* clear subscribers info */
clear_subscriber_list(client, port, &port->c_src, true);
@@ -277,11 +282,10 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
struct snd_seq_client_port *found = NULL, *p;
scoped_guard(mutex, &client->ports_mutex) {
- guard(write_lock_irq)(&client->ports_lock);
list_for_each_entry(p, &client->ports_list_head, list) {
if (p->addr.port == port) {
/* ok found. delete from the list at first */
- list_del(&p->list);
+ list_del_rcu(&p->list);
client->num_ports--;
found = p;
break;
@@ -297,26 +301,16 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port)
/* delete the all ports belonging to the given client */
int snd_seq_delete_all_ports(struct snd_seq_client *client)
{
- struct list_head deleted_list;
struct snd_seq_client_port *port, *tmp;
-
- /* move the port list to deleted_list, and
- * clear the port list in the client data.
+
+ /* unlink and delete each port; port_delete() waits for an RCU grace
+ * period before draining the port, so concurrent lockless readers can
+ * no longer take a new use_lock reference on it
*/
guard(mutex)(&client->ports_mutex);
- scoped_guard(write_lock_irq, &client->ports_lock) {
- if (!list_empty(&client->ports_list_head)) {
- list_add(&deleted_list, &client->ports_list_head);
- list_del_init(&client->ports_list_head);
- } else {
- INIT_LIST_HEAD(&deleted_list);
- }
- client->num_ports = 0;
- }
-
- /* remove each port in deleted_list */
- list_for_each_entry_safe(port, tmp, &deleted_list, list) {
- list_del(&port->list);
+ list_for_each_entry_safe(port, tmp, &client->ports_list_head, list) {
+ list_del_rcu(&port->list);
+ client->num_ports--;
snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
port_delete(client, port);
}
@@ -499,20 +493,20 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
bool is_src, bool exclusive, bool ack)
{
struct snd_seq_port_subs_info *grp;
- struct list_head *p;
+ struct hlist_node *p;
struct snd_seq_subscribers *s;
int err;
grp = is_src ? &port->c_src : &port->c_dest;
guard(rwsem_write)(&grp->list_mutex);
if (exclusive) {
- if (!list_empty(&grp->list_head))
+ if (!hlist_empty(&grp->list_head))
return -EBUSY;
} else {
if (grp->exclusive)
return -EBUSY;
/* check whether already exists */
- list_for_each(p, &grp->list_head) {
+ hlist_for_each(p, &grp->list_head) {
s = get_subscriber(p, is_src);
if (match_subs_info(&subs->info, &s->info))
return -EBUSY;
@@ -526,11 +520,10 @@ static int check_and_subscribe_port(struct snd_seq_client *client,
}
/* add to list */
- guard(write_lock_irq)(&grp->list_lock);
if (is_src)
- list_add_tail(&subs->src_list, &grp->list_head);
+ hlist_add_tail_rcu(&subs->src_list, &grp->list_head);
else
- list_add_tail(&subs->dest_list, &grp->list_head);
+ hlist_add_tail_rcu(&subs->dest_list, &grp->list_head);
grp->exclusive = exclusive;
atomic_inc(&subs->ref_count);
@@ -544,17 +537,15 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client,
bool is_src, bool ack)
{
struct snd_seq_port_subs_info *grp;
- struct list_head *list;
+ struct hlist_node *list;
bool empty;
grp = is_src ? &port->c_src : &port->c_dest;
list = is_src ? &subs->src_list : &subs->dest_list;
- scoped_guard(write_lock_irq, &grp->list_lock) {
- empty = list_empty(list);
- if (!empty)
- list_del_init(list);
- grp->exclusive = 0;
- }
+ empty = hlist_unhashed(list);
+ if (!empty)
+ hlist_del_init_rcu(list);
+ grp->exclusive = 0;
if (!empty)
unsubscribe_port(client, port, grp, &subs->info, ack);
@@ -590,8 +581,8 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
subs->info = *info;
atomic_set(&subs->ref_count, 0);
- INIT_LIST_HEAD(&subs->src_list);
- INIT_LIST_HEAD(&subs->dest_list);
+ INIT_HLIST_NODE(&subs->src_list);
+ INIT_HLIST_NODE(&subs->dest_list);
exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE);
@@ -612,7 +603,7 @@ int snd_seq_port_connect(struct snd_seq_client *connector,
delete_and_unsubscribe_port(src_client, src_port, subs, true,
connector->number != src_client->number);
error:
- kfree(subs);
+ kfree_rcu(subs, rcu);
return err;
}
@@ -633,7 +624,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
*/
scoped_guard(rwsem_write, &dest->list_mutex) {
/* look for the connection */
- list_for_each_entry(subs, &dest->list_head, dest_list) {
+ hlist_for_each_entry(subs, &dest->list_head, dest_list) {
if (match_subs_info(info, &subs->info)) {
__delete_and_unsubscribe_port(dest_client, dest_port,
subs, false,
@@ -648,7 +639,7 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector,
delete_and_unsubscribe_port(src_client, src_port, subs, true,
connector->number != src_client->number);
- kfree(subs);
+ kfree_rcu(subs, rcu);
return 0;
}
@@ -662,7 +653,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp,
int err = -ENOENT;
guard(rwsem_read)(&src_grp->list_mutex);
- list_for_each_entry(s, &src_grp->list_head, src_list) {
+ hlist_for_each_entry(s, &src_grp->list_head, src_list) {
if (addr_match(dest_addr, &s->info.dest)) {
*subs = s->info;
err = 0;
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
index b689c0f4867c..12ad86bf1489 100644
--- a/sound/core/seq/seq_ports.h
+++ b/sound/core/seq/seq_ports.h
@@ -28,17 +28,17 @@
struct snd_seq_subscribers {
struct snd_seq_port_subscribe info; /* additional info */
- struct list_head src_list; /* link of sources */
- struct list_head dest_list; /* link of destinations */
+ struct hlist_node src_list; /* link of sources */
+ struct hlist_node dest_list; /* link of destinations */
atomic_t ref_count;
+ struct rcu_head rcu; /* for deferred free */
};
struct snd_seq_port_subs_info {
- struct list_head list_head; /* list of subscribed ports */
+ struct hlist_head list_head; /* list of subscribed ports */
unsigned int count; /* count of subscribers */
unsigned int exclusive: 1; /* exclusive mode */
struct rw_semaphore list_mutex;
- rwlock_t list_lock;
int (*open)(void *private_data, struct snd_seq_port_subscribe *info);
int (*close)(void *private_data, struct snd_seq_port_subscribe *info);
};
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
index ccd93599b493..4c1e81db376f 100644
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -37,8 +37,11 @@ struct seq_ump_client {
struct snd_ump_endpoint *ump; /* assigned endpoint */
int seq_client; /* sequencer client id */
int opened[2]; /* current opens for each direction */
- rwlock_t output_lock; /* protects out_rfile output access */
struct snd_rawmidi_file out_rfile; /* rawmidi for output */
+ /* RCU-protected shadow of out_rfile.output for the delivery hot path;
+ * out_rfile itself is only touched by open/close under open_mutex
+ */
+ struct snd_rawmidi_substream __rcu *out_substream;
struct seq_ump_input_buffer input; /* input parser context */
void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
struct work_struct group_notify_work; /* FB change notification */
@@ -89,8 +92,8 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
unsigned char type;
int len;
- guard(read_lock_irqsave)(&client->output_lock);
- substream = client->out_rfile.output;
+ guard(rcu)();
+ substream = rcu_dereference(client->out_substream);
if (!substream)
return -ENODEV;
if (!snd_seq_ev_is_ump(ev))
@@ -108,19 +111,22 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct,
static int seq_ump_client_open(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
- struct snd_rawmidi_file rfile = {};
int err;
guard(mutex)(&ump->open_mutex);
if (dir == STR_OUT && !client->opened[dir]) {
+ /* out_rfile is only accessed under open_mutex; the delivery
+ * path reads out_substream via RCU, so open into out_rfile
+ * directly and publish the substream afterwards
+ */
err = snd_rawmidi_kernel_open(&ump->core, 0,
SNDRV_RAWMIDI_LFLG_OUTPUT |
SNDRV_RAWMIDI_LFLG_APPEND,
- &rfile);
+ &client->out_rfile);
if (err < 0)
return err;
- scoped_guard(write_lock_irqsave, &client->output_lock)
- client->out_rfile = rfile;
+ rcu_assign_pointer(client->out_substream,
+ client->out_rfile.output);
}
client->opened[dir]++;
return 0;
@@ -130,17 +136,18 @@ static int seq_ump_client_open(struct seq_ump_client *client, int dir)
static int seq_ump_client_close(struct seq_ump_client *client, int dir)
{
struct snd_ump_endpoint *ump = client->ump;
- struct snd_rawmidi_file rfile = {};
guard(mutex)(&ump->open_mutex);
if (!--client->opened[dir]) {
- if (dir == STR_OUT) {
- scoped_guard(write_lock_irqsave, &client->output_lock) {
- rfile = client->out_rfile;
- client->out_rfile = (struct snd_rawmidi_file){};
- }
- if (rfile.rmidi)
- snd_rawmidi_kernel_release(&rfile);
+ if (dir == STR_OUT && client->out_rfile.rmidi) {
+ rcu_assign_pointer(client->out_substream, NULL);
+ /* wait for a grace period so that no reader in the
+ * delivery path is still writing to the substream
+ * before it is released
+ */
+ synchronize_rcu();
+ snd_rawmidi_kernel_release(&client->out_rfile);
+ client->out_rfile = (struct snd_rawmidi_file){};
}
}
return 0;
@@ -480,7 +487,6 @@ static int snd_seq_ump_probe(struct snd_seq_device *dev)
INIT_WORK(&client->group_notify_work, handle_group_notify);
client->ump = ump;
- rwlock_init(&client->output_lock);
client->seq_client =
snd_seq_create_kernel_client(card, ump->core.device,
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 982828650d41..6208bf7f57bf 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -78,10 +78,11 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
int len;
if (atomic)
- read_lock(&rdev->filelist_lock);
+ rcu_read_lock();
else
down_read(&rdev->filelist_sem);
- list_for_each_entry(vmidi, &rdev->filelist, list) {
+ list_for_each_entry_rcu(vmidi, &rdev->filelist, list,
+ lockdep_is_held(&rdev->filelist_sem)) {
if (!READ_ONCE(vmidi->trigger))
continue;
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
@@ -96,7 +97,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
}
}
if (atomic)
- read_unlock(&rdev->filelist_lock);
+ rcu_read_unlock();
else
up_read(&rdev->filelist_sem);
@@ -200,8 +201,7 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
vmidi->port = rdev->port;
runtime->private_data = vmidi;
scoped_guard(rwsem_write, &rdev->filelist_sem) {
- guard(write_lock_irq)(&rdev->filelist_lock);
- list_add_tail(&vmidi->list, &rdev->filelist);
+ list_add_tail_rcu(&vmidi->list, &rdev->filelist);
}
vmidi->rdev = rdev;
return 0;
@@ -243,9 +243,13 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
struct snd_virmidi *vmidi = substream->runtime->private_data;
scoped_guard(rwsem_write, &rdev->filelist_sem) {
- guard(write_lock_irq)(&rdev->filelist_lock);
- list_del(&vmidi->list);
+ list_del_rcu(&vmidi->list);
}
+ /* wait for a grace period so that lockless readers in the atomic
+ * delivery path (snd_virmidi_dev_receive_event()) are no longer
+ * traversing this entry before its parser and memory are freed
+ */
+ synchronize_rcu();
snd_midi_event_free(vmidi->parser);
substream->runtime->private_data = NULL;
kfree(vmidi);
@@ -508,7 +512,6 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
rdev->device = device;
rdev->client = -1;
init_rwsem(&rdev->filelist_sem);
- rwlock_init(&rdev->filelist_lock);
INIT_LIST_HEAD(&rdev->filelist);
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
rmidi->private_data = rdev;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 8d05fe0d263b..24f40763a20c 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -167,11 +167,10 @@ static int snd_open(struct inode *inode, struct file *file)
return err;
}
-static const struct file_operations snd_fops =
-{
- .owner = THIS_MODULE,
- .open = snd_open,
- .llseek = noop_llseek,
+static const struct file_operations snd_fops = {
+ .owner = THIS_MODULE,
+ .open = snd_open,
+ .llseek = noop_llseek,
};
#ifdef CONFIG_SND_DYNAMIC_MINORS
@@ -358,7 +357,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
struct snd_minor *mptr;
guard(mutex)(&sound_mutex);
- for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
+ for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
mptr = snd_minors[minor];
if (!mptr)
continue;
@@ -395,15 +394,21 @@ int __init snd_minor_info_init(void)
static int __init alsa_sound_init(void)
{
+ int err;
+
snd_major = major;
snd_ecards_limit = cards_limit;
- if (register_chrdev(major, "alsa", &snd_fops)) {
+
+ err = register_chrdev(major, "alsa", &snd_fops);
+ if (err < 0) {
pr_err("ALSA core: unable to register native major device number %d\n", major);
- return -EIO;
+ return err;
}
- if (snd_info_init() < 0) {
+
+ err = snd_info_init();
+ if (err < 0) {
unregister_chrdev(major, "alsa");
- return -ENOMEM;
+ return err;
}
#ifdef CONFIG_SND_DEBUG
diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c
index 84e337ecbddd..0376112cc67e 100644
--- a/sound/core/sound_kunit.c
+++ b/sound/core/sound_kunit.c
@@ -17,8 +17,8 @@
.name = #fmt, \
}
-#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1)
-#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1
+#define WRONG_FORMAT_1 (SNDRV_PCM_FORMAT_LAST + 1)
+#define WRONG_FORMAT_2 -1
#define VALID_NAME "ValidName"
#define NAME_W_SPEC_CHARS "In%v@1id name"
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 9407954034cf..f666f05e9d45 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1546,11 +1546,8 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size)
static int snd_timer_user_open(struct inode *inode, struct file *file)
{
struct snd_timer_user *tu;
- int err;
- err = stream_open(inode, file);
- if (err < 0)
- return err;
+ stream_open(inode, file);
tu = kzalloc_obj(*tu);
if (tu == NULL)
@@ -2176,9 +2173,9 @@ static long snd_utimer_ioctl(struct file *file, unsigned int ioctl, unsigned lon
}
static const struct file_operations snd_utimer_fops = {
- .llseek = noop_llseek,
- .release = snd_utimer_release,
- .unlocked_ioctl = snd_utimer_ioctl,
+ .llseek = noop_llseek,
+ .release = snd_utimer_release,
+ .unlocked_ioctl = snd_utimer_ioctl,
};
static int snd_utimer_start(struct snd_timer *t)
@@ -2530,16 +2527,15 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait)
#define snd_timer_user_ioctl_compat NULL
#endif
-static const struct file_operations snd_timer_f_ops =
-{
- .owner = THIS_MODULE,
- .read = snd_timer_user_read,
- .open = snd_timer_user_open,
- .release = snd_timer_user_release,
- .poll = snd_timer_user_poll,
- .unlocked_ioctl = snd_timer_user_ioctl,
- .compat_ioctl = snd_timer_user_ioctl_compat,
- .fasync = snd_timer_user_fasync,
+static const struct file_operations snd_timer_f_ops = {
+ .owner = THIS_MODULE,
+ .read = snd_timer_user_read,
+ .open = snd_timer_user_open,
+ .release = snd_timer_user_release,
+ .poll = snd_timer_user_poll,
+ .unlocked_ioctl = snd_timer_user_ioctl,
+ .compat_ioctl = snd_timer_user_ioctl_compat,
+ .fasync = snd_timer_user_fasync,
};
/* unregister the system timer */
diff --git a/sound/core/ump.c b/sound/core/ump.c
index 632c13baf21e..82ad155c56e6 100644
--- a/sound/core/ump.c
+++ b/sound/core/ump.c
@@ -1157,10 +1157,11 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream)
return -ENODEV;
if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) {
if (!ump->legacy_out_opens) {
- err = snd_rawmidi_kernel_open(&ump->core, 0,
- SNDRV_RAWMIDI_LFLG_OUTPUT |
- SNDRV_RAWMIDI_LFLG_APPEND,
- &ump->legacy_out_rfile);
+ err = snd_rawmidi_kernel_open_nested(&ump->core, 0,
+ SNDRV_RAWMIDI_LFLG_OUTPUT |
+ SNDRV_RAWMIDI_LFLG_APPEND,
+ &ump->legacy_out_rfile,
+ SINGLE_DEPTH_NESTING);
if (err < 0)
return err;
}
diff --git a/sound/core/ump_convert.c b/sound/core/ump_convert.c
index 0fe13d031656..85cc67de6330 100644
--- a/sound/core/ump_convert.c
+++ b/sound/core/ump_convert.c
@@ -258,6 +258,7 @@ static int cvt_legacy_sysex_to_ump(struct ump_cvt_to_ump *cvt,
else
status = UMP_SYSEX_STATUS_CONTINUE;
*data = ump_compose(UMP_MSG_TYPE_DATA, group, status, cvt->len);
+ data[1] = 0;
offset = 8;
for (i = 0; i < cvt->len; i++) {
*data |= cvt->buf[i] << offset;
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 06bfe09eae1a..4e3ea23ca913 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -23,6 +23,7 @@
#include <linux/wait.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/hrtimer.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -55,7 +56,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
module_param_array(pcm_notify, int, NULL, 0444);
MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
module_param_array(timer_source, charp, NULL, 0444);
-MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default].");
+MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default], 'hrtimer' for high-resolution timer.");
#define NO_PITCH 100000
@@ -161,8 +162,11 @@ struct loopback_pcm {
unsigned int period_size_frac; /* period size in jiffies ticks */
unsigned int last_drift;
unsigned long last_jiffies;
- /* If jiffies timer is used */
+ /* If jiffies / hrtimer is used */
struct timer_list timer;
+#ifdef CONFIG_HIGH_RES_TIMERS
+ struct hrtimer hrtimer;
+#endif
/* size of per channel buffer in case of non-interleaved access */
unsigned int channel_buf_n;
@@ -232,6 +236,31 @@ static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/* call in cable->lock */
+static int loopback_hrtimer_start(struct loopback_pcm *dpcm)
+{
+ unsigned long tick;
+ unsigned int rate_shift = get_rate_shift(dpcm);
+
+ if (rate_shift != dpcm->pcm_rate_shift) {
+ dpcm->pcm_rate_shift = rate_shift;
+ dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
+ }
+ if (dpcm->period_size_frac <= dpcm->irq_pos) {
+ dpcm->irq_pos %= dpcm->period_size_frac;
+ dpcm->period_update_pending = 1;
+ }
+ tick = dpcm->period_size_frac - dpcm->irq_pos;
+ tick = DIV_ROUND_UP(tick, dpcm->pcm_bps);
+ hrtimer_start(&dpcm->hrtimer,
+ ns_to_ktime(div_u64((u64)tick * NSEC_PER_SEC, HZ)),
+ HRTIMER_MODE_REL_SOFT);
+
+ return 0;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_start(struct loopback_pcm *dpcm)
{
@@ -270,6 +299,16 @@ static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+/* call in cable->lock */
+static inline int loopback_hrtimer_stop(struct loopback_pcm *dpcm)
+{
+ hrtimer_try_to_cancel(&dpcm->hrtimer);
+
+ return 0;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_stop(struct loopback_pcm *dpcm)
{
@@ -300,6 +339,15 @@ static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm)
return 0;
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static inline int loopback_hrtimer_stop_sync(struct loopback_pcm *dpcm)
+{
+ hrtimer_cancel(&dpcm->hrtimer);
+
+ return 0;
+}
+#endif
+
/* call in loopback->cable_lock */
static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
{
@@ -734,6 +782,30 @@ static void loopback_jiffies_timer_function(struct timer_list *t)
snd_pcm_period_elapsed(dpcm->substream);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart loopback_hrtimer_function(struct hrtimer *t)
+{
+ struct loopback_pcm *dpcm = container_of(t, struct loopback_pcm, hrtimer);
+ bool period_elapsed = false;
+
+ scoped_guard(spinlock_irqsave, &dpcm->cable->lock) {
+ if (loopback_jiffies_timer_pos_update(dpcm->cable) &
+ (1 << dpcm->substream->stream)) {
+ loopback_hrtimer_start(dpcm);
+ if (dpcm->period_update_pending) {
+ dpcm->period_update_pending = 0;
+ period_elapsed = true;
+ }
+ }
+ }
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(dpcm->substream);
+
+ return HRTIMER_NORESTART;
+}
+#endif
+
/* call in cable->lock */
static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime,
unsigned long resolution)
@@ -907,6 +979,21 @@ static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm,
snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+static void loopback_hrtimer_dpcm_info(struct loopback_pcm *dpcm,
+ struct snd_info_buffer *buffer)
+{
+ snd_iprintf(buffer, " update_pending:\t%u\n",
+ dpcm->period_update_pending);
+ snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
+ snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
+ snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
+ dpcm->last_jiffies, jiffies);
+ snd_iprintf(buffer, " timer_expires:\t%llu\n",
+ ktime_to_ns(hrtimer_get_expires(&dpcm->hrtimer)));
+}
+#endif
+
static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
struct snd_info_buffer *buffer)
{
@@ -1097,6 +1184,26 @@ static const struct loopback_ops loopback_jiffies_timer_ops = {
.dpcm_info = loopback_jiffies_timer_dpcm_info,
};
+#ifdef CONFIG_HIGH_RES_TIMERS
+static int loopback_hrtimer_open(struct loopback_pcm *dpcm)
+{
+ hrtimer_setup(&dpcm->hrtimer, loopback_hrtimer_function,
+ CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+
+ return 0;
+}
+
+static const struct loopback_ops loopback_hrtimer_ops = {
+ .open = loopback_hrtimer_open,
+ .start = loopback_hrtimer_start,
+ .stop = loopback_hrtimer_stop,
+ .stop_sync = loopback_hrtimer_stop_sync,
+ .close_substream = loopback_hrtimer_stop_sync,
+ .pos_update = loopback_jiffies_timer_pos_update,
+ .dpcm_info = loopback_hrtimer_dpcm_info,
+};
+#endif
+
static int loopback_parse_timer_id(const char *str,
struct snd_timer_id *tid)
{
@@ -1274,7 +1381,12 @@ static int loopback_open(struct snd_pcm_substream *substream)
spin_lock_init(&cable->lock);
snd_refcount_init(&cable->stop_count);
cable->hw = loopback_pcm_hardware;
- if (loopback->timer_source)
+#ifdef CONFIG_HIGH_RES_TIMERS
+ if (loopback->timer_source && !strcmp(loopback->timer_source, "hrtimer"))
+ cable->ops = &loopback_hrtimer_ops;
+ else
+#endif
+ if (loopback->timer_source && loopback->timer_source[0])
cable->ops = &loopback_snd_timer_ops;
else
cable->ops = &loopback_jiffies_timer_ops;
@@ -1491,7 +1603,7 @@ static int loopback_format_info(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = (__force int)SNDRV_PCM_FORMAT_LAST;
+ uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST;
uinfo->value.integer.step = 1;
return 0;
}
@@ -1502,7 +1614,7 @@ static int loopback_format_get(struct snd_kcontrol *kcontrol,
struct loopback *loopback = snd_kcontrol_chip(kcontrol);
ucontrol->value.integer.value[0] =
- (__force int)loopback->setup[kcontrol->id.subdevice]
+ loopback->setup[kcontrol->id.subdevice]
[kcontrol->id.device].format;
return 0;
}
@@ -1556,7 +1668,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol,
static int loopback_access_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- const char * const texts[] = {"Interleaved", "Non-interleaved"};
+ static const char * const texts[] = {"Interleaved", "Non-interleaved"};
return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
@@ -1802,6 +1914,12 @@ static int loopback_probe(struct platform_device *devptr)
int dev = devptr->id;
int err;
+ if (dev < 0 || dev >= SNDRV_CARDS) {
+ dev_warn(&devptr->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
sizeof(struct loopback), &card);
if (err < 0)
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index ce7ab986dee6..b908d2564aee 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -101,6 +101,7 @@ struct dummy_timer_ops {
int (*prepare)(struct snd_pcm_substream *);
int (*start)(struct snd_pcm_substream *);
int (*stop)(struct snd_pcm_substream *);
+ int (*sync_stop)(struct snd_pcm_substream *);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
};
@@ -286,6 +287,14 @@ static int dummy_systimer_stop(struct snd_pcm_substream *substream)
return 0;
}
+static int dummy_systimer_sync_stop(struct snd_pcm_substream *substream)
+{
+ struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
+
+ timer_delete_sync(&dpcm->timer);
+ return 0;
+}
+
static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -342,7 +351,10 @@ static int dummy_systimer_create(struct snd_pcm_substream *substream)
static void dummy_systimer_free(struct snd_pcm_substream *substream)
{
- kfree(substream->runtime->private_data);
+ struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
+
+ timer_shutdown_sync(&dpcm->timer);
+ kfree(dpcm);
}
static const struct dummy_timer_ops dummy_systimer_ops = {
@@ -351,6 +363,7 @@ static const struct dummy_timer_ops dummy_systimer_ops = {
.prepare = dummy_systimer_prepare,
.start = dummy_systimer_start,
.stop = dummy_systimer_stop,
+ .sync_stop = dummy_systimer_sync_stop,
.pointer = dummy_systimer_pointer,
};
@@ -408,9 +421,12 @@ static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)
return 0;
}
-static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
+static int dummy_hrtimer_sync_stop(struct snd_pcm_substream *substream)
{
+ struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
+
hrtimer_cancel(&dpcm->timer);
+ return 0;
}
static snd_pcm_uframes_t
@@ -436,7 +452,6 @@ static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream)
long sec;
unsigned long nsecs;
- dummy_hrtimer_sync(dpcm);
period = runtime->period_size;
rate = runtime->rate;
sec = period / rate;
@@ -464,7 +479,7 @@ static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
static void dummy_hrtimer_free(struct snd_pcm_substream *substream)
{
struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
- dummy_hrtimer_sync(dpcm);
+
kfree(dpcm);
}
@@ -474,6 +489,7 @@ static const struct dummy_timer_ops dummy_hrtimer_ops = {
.prepare = dummy_hrtimer_prepare,
.start = dummy_hrtimer_start,
.stop = dummy_hrtimer_stop,
+ .sync_stop = dummy_hrtimer_sync_stop,
.pointer = dummy_hrtimer_pointer,
};
@@ -496,6 +512,13 @@ static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return -EINVAL;
}
+static int dummy_pcm_sync_stop(struct snd_pcm_substream *substream)
+{
+ if (get_dummy_ops(substream)->sync_stop)
+ return get_dummy_ops(substream)->sync_stop(substream);
+ return 0;
+}
+
static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
{
return get_dummy_ops(substream)->prepare(substream);
@@ -647,6 +670,7 @@ static const struct snd_pcm_ops dummy_pcm_ops = {
.hw_params = dummy_pcm_hw_params,
.prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger,
+ .sync_stop = dummy_pcm_sync_stop,
.pointer = dummy_pcm_pointer,
};
@@ -656,6 +680,7 @@ static const struct snd_pcm_ops dummy_pcm_ops_no_buf = {
.hw_params = dummy_pcm_hw_params,
.prepare = dummy_pcm_prepare,
.trigger = dummy_pcm_trigger,
+ .sync_stop = dummy_pcm_sync_stop,
.pointer = dummy_pcm_pointer,
.copy = dummy_pcm_copy,
.fill_silence = dummy_pcm_silence,
@@ -1018,6 +1043,12 @@ static int snd_dummy_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
+ if (dev < 0 || dev >= SNDRV_CARDS) {
+ dev_warn(&devptr->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_dummy), &card);
if (err < 0)
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index c217c427bf1e..b93291ad067a 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -89,6 +89,12 @@ static int snd_mpu401_probe(struct platform_device *devptr)
int err;
struct snd_card *card;
+ if (dev < 0 || dev >= SNDRV_CARDS) {
+ dev_warn(&devptr->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
if (port[dev] == SNDRV_AUTO_PORT) {
dev_err(&devptr->dev, "specify port\n");
return -EINVAL;
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index 36e9eab204ca..cefaa00b83e7 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -900,6 +900,12 @@ static int snd_mts64_probe(struct platform_device *pdev)
p = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
+ if (dev < 0) {
+ dev_warn(&pdev->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev])
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index dcc0899cfb99..03ed3c3c27fb 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -697,6 +697,12 @@ static int snd_portman_probe(struct platform_device *pdev)
p = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
+ if (dev < 0) {
+ dev_warn(&pdev->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev])
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 3c28961091b1..cc9c325df910 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -846,6 +846,12 @@ static int snd_serial_probe(struct platform_device *devptr)
int err;
int dev = devptr->id;
+ if (dev < 0 || dev >= SNDRV_CARDS) {
+ dev_warn(&devptr->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
switch (adaptor[dev]) {
case SNDRV_SERIAL_SOUNDCANVAS:
ins[dev] = 1;
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index a204f42d1026..70e16105f1c4 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -75,6 +75,12 @@ static int snd_virmidi_probe(struct platform_device *devptr)
int idx, err;
int dev = devptr->id;
+ if (dev < 0 || dev >= SNDRV_CARDS) {
+ dev_warn(&devptr->dev,
+ "Invalid card index %d, using default 0\n", dev);
+ dev = 0;
+ }
+
err = snd_devm_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
sizeof(struct snd_card_virmidi), &card);
if (err < 0)
diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
index 3fe11983d6ca..0f8fb62f021d 100644
--- a/sound/hda/codecs/ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -5788,7 +5788,8 @@ static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS;
if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS)
uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1;
- sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx);
+ snprintf(namestr, sizeof(namestr), "%d %s",
+ (uinfo->value.enumerated.item * 10), sfx);
strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5840,9 +5841,9 @@ static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
- sprintf(namestr, "%s %s",
- ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
- sfx);
+ snprintf(namestr, sizeof(namestr), "%s %s",
+ ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
+ sfx);
strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -5894,8 +5895,8 @@ static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
- sprintf(namestr, "%s",
- ae5_filter_presets[uinfo->value.enumerated.item].name);
+ snprintf(namestr, sizeof(namestr), "%s",
+ ae5_filter_presets[uinfo->value.enumerated.item].name);
strscpy(uinfo->value.enumerated.name, namestr);
return 0;
}
@@ -6632,7 +6633,7 @@ static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid,
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
- sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "FX: %s %s Volume", pfx, dirstr[dir]);
knew.tlv.c = NULL;
@@ -6671,9 +6672,9 @@ static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
* prefix to OutFX or InFX enable controls.
*/
if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
- sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "FX: %s %s Switch", pfx, dirstr[dir]);
else
- sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+ snprintf(namestr, sizeof(namestr), "%s %s Switch", pfx, dirstr[dir]);
return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
}
@@ -8530,10 +8531,9 @@ static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k)
static bool ca0132_download_dsp_images(struct hda_codec *codec)
{
- bool dsp_loaded = false;
struct ca0132_spec *spec = codec->spec;
const struct dsp_image_seg *dsp_os_image;
- const struct firmware *fw_entry = NULL;
+ const struct firmware *fw_entry __free(firmware) = NULL;
/*
* Alternate firmwares for different variants. The Recon3Di apparently
* can use the default firmware, but I'll leave the option in case
@@ -8573,15 +8573,10 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
codec_err(codec, "ca0132 DSP load image failed\n");
- goto exit_download;
+ return false;
}
- dsp_loaded = dspload_wait_loaded(codec);
-
-exit_download:
- release_firmware(fw_entry);
-
- return dsp_loaded;
+ return dspload_wait_loaded(codec);
}
static void ca0132_download_dsp(struct hda_codec *codec)
@@ -9634,6 +9629,7 @@ static void ca0132_free(struct hda_codec *codec)
#endif
kfree(spec->spec_init_verbs);
kfree(codec->spec);
+ codec->spec = NULL;
}
static void dbpro_free(struct hda_codec *codec)
@@ -9644,6 +9640,7 @@ static void dbpro_free(struct hda_codec *codec)
kfree(spec->spec_init_verbs);
kfree(codec->spec);
+ codec->spec = NULL;
}
static void ca0132_config(struct hda_codec *codec)
diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
index eeb9ca38d2d8..8a74862d8a81 100644
--- a/sound/hda/codecs/cm9825.c
+++ b/sound/hda/codecs/cm9825.c
@@ -15,7 +15,8 @@
enum {
QUIRK_CM_STD = 0x0,
- QUIRK_GENE_TWL7_SSID = 0x160dc000
+ QUIRK_GENE_TWL7_SSID = 0x160dc000,
+ QUIRK_IBP_SSID = 0x15bd3275
};
/* CM9825 Offset Definitions */
@@ -40,13 +41,19 @@ enum {
#define CM9825_VERB_SET_GAD 0x7b4
#define CM9825_VERB_SET_TMOD 0x7b5
#define CM9825_VERB_SET_SNR 0x7b6
+#define CM9825_VERB_SET_OMTP 0x7ef
+#define CM9825_VERB_READ_OMTP 0xfec
struct cmi_spec {
struct hda_gen_spec gen;
const struct hda_verb *chip_d0_verbs;
const struct hda_verb *chip_d3_verbs;
+ const struct hda_verb *chip_playback_start_verbs;
+ const struct hda_verb *chip_playback_stop_verbs;
const struct hda_verb *chip_hp_present_verbs;
const struct hda_verb *chip_hp_remove_verbs;
+ const struct hda_verb *chip_lineout_present_verbs;
+ const struct hda_verb *chip_lineout_remove_verbs;
struct hda_codec *codec;
struct delayed_work unsol_inputs_work;
struct delayed_work unsol_lineout_work;
@@ -193,6 +200,94 @@ static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
{}
};
+/*
+ * To save power, AD/CLK is turned off.
+ */
+static const struct hda_verb cm9825_ibp_d3_verbs[] = {
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_PLL, 0x01},
+ {0x43, CM9825_VERB_SET_NEG, 0xc2},
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_VNEG, 0x50},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {0x43, CM9825_VERB_SET_PDNEG, 0x04},
+ {0x43, CM9825_VERB_SET_CDALR, 0xf6},
+ {0x43, CM9825_VERB_SET_OTP, 0xcd},
+ {}
+};
+
+/*
+ * D0 configuration: enable PLL/CLK/ADC/DAC and optimize performance
+ */
+static const struct hda_verb cm9825_ibp_d0_verbs[] = {
+ {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+ {0x43, CM9825_VERB_SET_SNR, 0x38},
+ {0x43, CM9825_VERB_SET_PLL, 0x00},
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {0x43, CM9825_VERB_SET_VNEG, 0x56},
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_DACTRL, 0x00},
+ {0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+ {0x43, CM9825_VERB_SET_CDALR, 0xf4},
+ {0x43, CM9825_VERB_SET_OTP, 0xcd},
+ {0x43, CM9825_VERB_SET_MTCBA, 0x61},
+ {0x43, CM9825_VERB_SET_OCP, 0x33},
+ {0x43, CM9825_VERB_SET_GAD, 0x07},
+ {0x43, CM9825_VERB_SET_TMOD, 0x26},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},
+ {0x43, CM9825_VERB_SET_HPF_1, 0x40},
+ {0x43, CM9825_VERB_SET_HPF_2, 0x40},
+ {}
+};
+
+/*
+ * Enable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_present_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x8c},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x10},
+ {}
+};
+
+/*
+ * Disable mbias, ADC.
+ */
+static const struct hda_verb cm9825_ibp_lineout_remove_verbs[] = {
+ {0x43, CM9825_VERB_SET_ADCL, 0x00},
+ {0x43, CM9825_VERB_SET_MBIAS, 0x00},
+ {}
+};
+
+/*
+ * Turn on the DAC (widget NID 0x43) in the playback path by writing
+ * a sequence of vendor-specific verbs.
+ */
+static const struct hda_verb cm9825_ibp_playback_start_verbs[] = {
+ {0x43, CM9825_VERB_SET_DACL, 0xaa},
+ {0x43, CM9825_VERB_SET_D2S, 0xf2},
+ {0x43, CM9825_VERB_SET_VDO, 0xc4},
+ {0x43, CM9825_VERB_SET_SNR, 0x30},
+ {}
+};
+
+/*
+ * Shut down the playback path. The order differs slightly from the
+ * enable sequence, likely to avoid audible pop noise when powering
+ * down the output stage.
+ */
+static const struct hda_verb cm9825_ibp_playback_stop_verbs[] = {
+ {0x43, CM9825_VERB_SET_VDO, 0xc0},
+ {0x43, CM9825_VERB_SET_DACL, 0x02},
+ {0x43, CM9825_VERB_SET_D2S, 0x62},
+ {0x43, CM9825_VERB_SET_VDO, 0x80},
+ {0x43, CM9825_VERB_SET_SNR, 0x38},
+ {}
+};
+
static void cm9825_update_jk_plug_status(struct hda_codec *codec, hda_nid_t nid)
{
struct cmi_spec *spec = codec->spec;
@@ -232,6 +327,23 @@ static void cm9825_unsol_lineout_delayed(struct work_struct *work)
struct cmi_spec *spec =
container_of(to_delayed_work(work), struct cmi_spec,
unsol_lineout_work);
+ hda_nid_t line_out_pin = spec->gen.autocfg.line_out_pins[0];
+ bool line_out_jack_plugin = false;
+
+ line_out_jack_plugin = snd_hda_jack_detect(spec->codec, line_out_pin);
+
+ codec_dbg(spec->codec, "lineout_jack_plugin %d, lineout_pin 0x%X\n",
+ (int)line_out_jack_plugin, line_out_pin);
+
+ if (!line_out_jack_plugin) {
+ /* Jack plugout */
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_lineout_remove_verbs);
+ } else {
+ /* Jack plugin */
+ snd_hda_sequence_write(spec->codec,
+ spec->chip_lineout_present_verbs);
+ }
cm9825_update_jk_plug_status(spec->codec,
spec->gen.autocfg.line_out_pins[0]);
@@ -362,12 +474,10 @@ static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
switch (action) {
case HDA_GEN_PCM_ACT_PREPARE:
- snd_hda_sequence_write(spec->codec,
- cm9825_gene_twl7_playback_start_verbs);
+ snd_hda_sequence_write(codec, spec->chip_playback_start_verbs);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
- snd_hda_sequence_write(spec->codec,
- cm9825_gene_twl7_playback_stop_verbs);
+ snd_hda_sequence_write(codec, spec->chip_playback_stop_verbs);
break;
default:
return;
@@ -471,7 +581,8 @@ static int cm9825_resume(struct hda_codec *codec)
if (codec->core.subsystem_id == QUIRK_CM_STD)
cm9825_cm_std_resume(codec);
- else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+ else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID ||
+ codec->core.subsystem_id == QUIRK_IBP_SSID) {
snd_hda_codec_init(codec);
snd_hda_sequence_write(codec, spec->chip_d0_verbs);
}
@@ -487,6 +598,7 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
struct cmi_spec *spec;
struct auto_pin_cfg *cfg;
int err = 0;
+ unsigned int val;
spec = kzalloc_obj(*spec);
if (spec == NULL)
@@ -523,9 +635,33 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs;
spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs;
spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+ spec->chip_playback_start_verbs =
+ cm9825_gene_twl7_playback_start_verbs;
+ spec->chip_playback_stop_verbs =
+ cm9825_gene_twl7_playback_stop_verbs;
/* Internal fixed device, Rear, Mic-in, 3.5mm */
snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
break;
+ case QUIRK_IBP_SSID:
+ snd_hda_codec_set_name(codec, "CM9825 IBP");
+ spec->chip_d0_verbs = cm9825_ibp_d0_verbs;
+ spec->chip_d3_verbs = cm9825_ibp_d3_verbs;
+ spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+ spec->chip_lineout_present_verbs =
+ cm9825_ibp_lineout_present_verbs;
+ spec->chip_lineout_remove_verbs =
+ cm9825_ibp_lineout_remove_verbs;
+ spec->chip_playback_start_verbs =
+ cm9825_ibp_playback_start_verbs;
+ spec->chip_playback_stop_verbs = cm9825_ibp_playback_stop_verbs;
+
+ /* OMTP */
+ val =
+ snd_hda_codec_read(codec, 0x46, 0, CM9825_VERB_READ_OMTP,
+ 0x0);
+ snd_hda_codec_write(codec, 0x46, 0, CM9825_VERB_SET_OMTP,
+ (val >> 24) & 0x7f);
+ break;
default:
err = -ENXIO;
break;
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
index 40da2832ba66..c517334b56fd 100644
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -292,6 +292,7 @@ enum {
CXT_PINCFG_TOP_SPEAKER,
CXT_FIXUP_HP_A_U,
CXT_FIXUP_ACER_SWIFT_HP,
+ CXT_FIXUP_HUAWEI_MATEBOOK_HP,
};
/* for hda_fixup_thinkpad_acpi() */
@@ -451,7 +452,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec)
if (!spec->dc_enable) {
/* disable DC bias path and pin for port F */
update_mic_pin(codec, 0x1e, 0);
- snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
+ if (spec->dc_mode_path)
+ snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
/* update port B (ext mic) and C (int mic) */
/* OLPC defers mic widget control until when capture is
@@ -487,7 +489,8 @@ static void olpc_xo_update_mic_pins(struct hda_codec *codec)
update_mic_pin(codec, 0x1b, 0);
/* enable DC bias path and pin */
update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
- snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
+ if (spec->dc_mode_path)
+ snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
}
}
@@ -1033,6 +1036,13 @@ static const struct hda_fixup cxt_fixups[] = {
{ }
},
},
+ [CXT_FIXUP_HUAWEI_MATEBOOK_HP] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x18, 0x03211020 }, /* Headphone */
+ { }
+ },
+ },
};
static const struct hda_quirk cxt5045_fixups[] = {
@@ -1097,6 +1107,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x837b, "HP ProBook 440 G5", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
@@ -1133,6 +1144,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI),
+ SND_PCI_QUIRK(0x19e5, 0x3289, "Huawei Matebook", CXT_FIXUP_HUAWEI_MATEBOOK_HP),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
SND_PCI_QUIRK(0x1d05, 0x3012, "MECHREVO Wujie 15X Pro", CXT_FIXUP_HEADSET_MIC),
diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c
index 660a9f2c0ded..6120f797b45a 100644
--- a/sound/hda/codecs/generic.c
+++ b/sound/hda/codecs/generic.c
@@ -2695,30 +2695,13 @@ static const struct snd_kcontrol_new out_jack_mode_enum = {
.put = out_jack_mode_put,
};
-static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
-{
- struct hda_gen_spec *spec = codec->spec;
- const struct snd_kcontrol_new *kctl;
- int i;
-
- snd_array_for_each(&spec->kctls, i, kctl) {
- if (!strcmp(kctl->name, name) && kctl->index == idx)
- return true;
- }
- return false;
-}
-
static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
char *name, size_t name_len)
{
struct hda_gen_spec *spec = codec->spec;
- int idx = 0;
-
- snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
- strlcat(name, " Jack Mode", name_len);
- for (; find_kctl_name(codec, name, idx); idx++)
- ;
+ snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len);
+ hda_append_suffix(name, " Jack Mode", name_len);
}
static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
@@ -5695,7 +5678,7 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
break;
}
}
- strlcat(str, sfx, len);
+ hda_append_suffix(str, sfx, len);
}
/* copy PCM stream info from @default_str, and override non-NULL entries
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
index a4a2f2f0540c..1e7a05c87733 100644
--- a/sound/hda/codecs/hdmi/hdmi.c
+++ b/sound/hda/codecs/hdmi/hdmi.c
@@ -2236,8 +2236,10 @@ void snd_hda_hdmi_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
/* skip notification during system suspend (but not in runtime PM);
* the state will be updated at resume
*/
- if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+ if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ codec->acomp_requested_resume = 1;
return;
+ }
snd_hda_hdmi_check_presence_and_report(codec, pin_nid, dev_id);
}
@@ -2346,6 +2348,7 @@ static const struct hda_device_id snd_hda_id_generichdmi[] = {
HDA_CODEC_ID_MODEL(0x1d179f8e, "KX-7000 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x1d179f8f, "KX-7000 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x1d179f90, "KX-7000 HDMI/DP", MODEL_GF),
+ HDA_CODEC_ID_MODEL(0x4c545020, "Lisuan HDMI/DP", MODEL_GENERIC),
HDA_CODEC_ID_MODEL(0x67663d82, "Arise 82 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x67663d83, "Arise 83 HDMI/DP", MODEL_GF),
HDA_CODEC_ID_MODEL(0x67663d84, "Arise 84 HDMI/DP", MODEL_GF),
diff --git a/sound/hda/codecs/helpers/razer_blade16_2025.c b/sound/hda/codecs/helpers/razer_blade16_2025.c
new file mode 100644
index 000000000000..1f2e06d8fc13
--- /dev/null
+++ b/sound/hda/codecs/helpers/razer_blade16_2025.c
@@ -0,0 +1,820 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Razer Blade 16 (2025) external smart-amplifier programming and fixup,
+ * to be included from the codec driver.
+ *
+ * The internal speakers are driven by an external smart amplifier whose
+ * crossover, voicing and protection live in a DSP reached over a vendor
+ * coef mailbox on NID 0x20. These tables hold the programming captured
+ * from the Windows driver, reduced to the NID-0x20 traffic this machine
+ * needs (everything else the HDA parser rebuilds).
+ *
+ * Each entry is either a plain codec coef write or a mailbox write:
+ * strobe == 0: coef[addr] = lo
+ * strobe != 0: amp[addr] = (hi << 16) | lo, with the bank selected on
+ * port 0x89 and the write committed by the strobe opcode.
+ */
+
+struct alc298_razer_blade16_2025_op {
+ u16 bank; /* mailbox bank (port 0x89); unused for a plain coef */
+ u16 addr; /* mailbox register, or plain coef index */
+ u16 hi; /* mailbox high word; unused for a plain coef */
+ u16 lo; /* mailbox low word, or plain coef value */
+ u16 strobe; /* mailbox commit opcode; 0 marks a plain coef write */
+};
+
+/* program the external DSP at init; the amp is woken/parked separately */
+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_init[] = {
+ { 0x0000, 0xf102, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xf103, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc000, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xea00, 0x0000, 0x0047, 0xb031 },
+ { 0x0000, 0xf20d, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xf212, 0x0000, 0x003e, 0xb031 },
+ { 0x0000, 0xc001, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc003, 0x0000, 0x0022, 0xb031 },
+ { 0x0000, 0xc004, 0x0000, 0x0044, 0xb031 },
+ { 0x0000, 0xc005, 0x0000, 0x0044, 0xb031 },
+ { 0x0000, 0xc007, 0x0000, 0x0064, 0xb031 },
+ { 0x0000, 0xc00e, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xf223, 0x0000, 0x007f, 0xb031 },
+ { 0x0000, 0xf224, 0x0000, 0x00db, 0xb031 },
+ { 0x0000, 0xf225, 0x0000, 0x00ee, 0xb031 },
+ { 0x0000, 0xf226, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xf227, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xf21a, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xf242, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xc120, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xc125, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xc321, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xc200, 0x0000, 0x00d8, 0xb031 },
+ { 0x0000, 0xc201, 0x0000, 0x0027, 0xb031 },
+ { 0x0000, 0xc202, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xc400, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc401, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xc402, 0x0000, 0x00e0, 0xb031 },
+ { 0x0000, 0xc403, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc404, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xc406, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xc407, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc408, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xc300, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc125, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xdf00, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xdf5f, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xdf60, 0x0000, 0x00a7, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x0084, 0xb031 },
+ { 0x0000, 0xc206, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xf10a, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f4, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x00e0, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f4, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x0065, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f7, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xf104, 0x0000, 0x00f7, 0xb031 },
+ { 0x0000, 0xf105, 0x0000, 0x0031, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xf10b, 0x0000, 0x005c, 0xb031 },
+ { 0x0000, 0xe706, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xe707, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xe806, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xe807, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xce04, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xce05, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xce06, 0x0000, 0x0031, 0xb031 },
+ { 0x0000, 0xce07, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xcf04, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xcf05, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xcf06, 0x0000, 0x0031, 0xb031 },
+ { 0x0000, 0xcf07, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xc130, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xe000, 0x0000, 0x00a8, 0xb031 },
+ { 0x4100, 0x1888, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc121, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xea00, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xca00, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca02, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xca12, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xed00, 0x0000, 0x0090, 0xb031 },
+ { 0x0000, 0xcc2c, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc2d, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xcc2e, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xcc2f, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcd2c, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd2d, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xcd2e, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xcd2f, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcc24, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc25, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xcc26, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xcc27, 0x0000, 0x0085, 0xb031 },
+ { 0x0000, 0xcd24, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd25, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xcd26, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xcd27, 0x0000, 0x0085, 0xb031 },
+ { 0x0000, 0xcc20, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc21, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc22, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcd20, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd21, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd22, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xcc16, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xcc17, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd16, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xcd17, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc29, 0x0000, 0x005d, 0xb031 },
+ { 0x0000, 0xcc2a, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xcd29, 0x0000, 0x005d, 0xb031 },
+ { 0x0000, 0xcd2a, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xcc31, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xcc32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc33, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc34, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd31, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xcd32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd33, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd34, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc36, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xcc37, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcc38, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcc39, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcd36, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xcd37, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcd38, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcd39, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xcc09, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc0a, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xcc0b, 0x0000, 0x007c, 0xb031 },
+ { 0x0000, 0xcc0c, 0x0000, 0x005b, 0xb031 },
+ { 0x0000, 0xcd09, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd0a, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xcd0b, 0x0000, 0x007c, 0xb031 },
+ { 0x0000, 0xcd0c, 0x0000, 0x005b, 0xb031 },
+ { 0x0000, 0xcc0e, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcc0f, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xcc10, 0x0000, 0x003e, 0xb031 },
+ { 0x0000, 0xcc11, 0x0000, 0x002d, 0xb031 },
+ { 0x0000, 0xcd0e, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcd0f, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xcd10, 0x0000, 0x003e, 0xb031 },
+ { 0x0000, 0xcd11, 0x0000, 0x002d, 0xb031 },
+ { 0x0000, 0xccd6, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xccd7, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xcdd6, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcdd7, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xccd8, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xccd9, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xcdd8, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcdd9, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xccda, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xccdb, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xcdda, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xcddb, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xc320, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xc321, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xe604, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xdd00, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xdc19, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdc1a, 0x0000, 0x006a, 0xb031 },
+ { 0x0000, 0xdc1b, 0x0000, 0x00aa, 0xb031 },
+ { 0x0000, 0xdc1c, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xdc1d, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdc1e, 0x0000, 0x0027, 0xb031 },
+ { 0x0000, 0xdc1f, 0x0000, 0x0062, 0xb031 },
+ { 0x0000, 0xdc20, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xde19, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xde1a, 0x0000, 0x006a, 0xb031 },
+ { 0x0000, 0xde1b, 0x0000, 0x00aa, 0xb031 },
+ { 0x0000, 0xde1c, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xde1d, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xde1e, 0x0000, 0x0027, 0xb031 },
+ { 0x0000, 0xde1f, 0x0000, 0x0062, 0xb031 },
+ { 0x0000, 0xde20, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xdb32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdd32, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdb33, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xdd33, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xdb34, 0x0000, 0x001a, 0xb031 },
+ { 0x0000, 0xdd34, 0x0000, 0x001a, 0xb031 },
+ { 0x0000, 0xdb15, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xdd15, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xdb17, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xdd17, 0x0000, 0x003f, 0xb031 },
+ { 0x0000, 0xdb94, 0x0000, 0x0070, 0xb031 },
+ { 0x0000, 0xdd94, 0x0000, 0x0070, 0xb031 },
+ { 0x0000, 0xdb19, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xdd19, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x001c, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xdb04, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xdb05, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xdd04, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xdd05, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xdbbb, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xdbbc, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xdbbd, 0x0000, 0x00f3, 0xb031 },
+ { 0x0000, 0xdbbe, 0x0000, 0x00cf, 0xb031 },
+ { 0x0000, 0xddbb, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xddbc, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xddbd, 0x0000, 0x00f3, 0xb031 },
+ { 0x0000, 0xddbe, 0x0000, 0x00cf, 0xb031 },
+ { 0x0000, 0xdb01, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xdd01, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xdb08, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xdd08, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xdc52, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xde52, 0x0000, 0x00ef, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0xdf0a, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xdf0b, 0x0000, 0x007f, 0xb031 },
+ { 0x0000, 0xc851, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xc951, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xdf01, 0x0000, 0x0073, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xebcb, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeb10, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb11, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xeb12, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xeb13, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xeb14, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb15, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xeb16, 0x0000, 0x0069, 0xb031 },
+ { 0x0000, 0xeb21, 0x0000, 0x0011, 0xb031 },
+ { 0x0000, 0xeb22, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xeb23, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeb24, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb25, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xeb26, 0x0000, 0x0055, 0xb031 },
+ { 0x0000, 0xeb27, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xeb28, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb29, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xeb2a, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xeb2b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xeb30, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb31, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xeb32, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xeb33, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb34, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb35, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xeb36, 0x0000, 0x0024, 0xb031 },
+ { 0x0000, 0xeb37, 0x0000, 0x0068, 0xb031 },
+ { 0x0000, 0xeb40, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb41, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xeb42, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xeb43, 0x0000, 0x00e8, 0xb031 },
+ { 0x0000, 0xeb44, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb45, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xeb46, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xeb47, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb48, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb49, 0x0000, 0x00c5, 0xb031 },
+ { 0x0000, 0xeb4a, 0x0000, 0x0032, 0xb031 },
+ { 0x0000, 0xeb4b, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeb50, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb51, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xeb52, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xeb53, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb54, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb55, 0x0000, 0x007d, 0xb031 },
+ { 0x0000, 0xeb56, 0x0000, 0x00d9, 0xb031 },
+ { 0x0000, 0xeb57, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xeb60, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xeb61, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xeb62, 0x0000, 0x00b5, 0xb031 },
+ { 0x0000, 0xeb63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xeb64, 0x0000, 0x00fa, 0xb031 },
+ { 0x0000, 0xeb65, 0x0000, 0x0086, 0xb031 },
+ { 0x0000, 0xeb66, 0x0000, 0x00a8, 0xb031 },
+ { 0x0000, 0xeb67, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xeb68, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xeb69, 0x0000, 0x009a, 0xb031 },
+ { 0x0000, 0xeb6a, 0x0000, 0x002f, 0xb031 },
+ { 0x0000, 0xeb6b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xebb6, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeb70, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xeb71, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xeb72, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xeb73, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xeb74, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xeb75, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xeb76, 0x0000, 0x002c, 0xb031 },
+ { 0x0000, 0xeb77, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xeb80, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb81, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xeb82, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xeb83, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xeb84, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xeb85, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xeb86, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xeb87, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xeb88, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xeb89, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xeb8a, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xeb8b, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xebb8, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeb90, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xeb91, 0x0000, 0x008b, 0xb031 },
+ { 0x0000, 0xeb92, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xeb93, 0x0000, 0x0064, 0xb031 },
+ { 0x0000, 0xeb94, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xeb95, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xeb96, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xeb97, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xeba0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeba1, 0x0000, 0x0091, 0xb031 },
+ { 0x0000, 0xeba2, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xeba3, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeba4, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xeba5, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeba6, 0x0000, 0x0093, 0xb031 },
+ { 0x0000, 0xeba7, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xeba8, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xeba9, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xebaa, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xebab, 0x0000, 0x006c, 0xb031 },
+ { 0x0000, 0xebc3, 0x0000, 0x00ff, 0xb031 },
+ { 0x0000, 0xebc4, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xeb00, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xeb01, 0x0000, 0x00a9, 0xb031 },
+ { 0x0000, 0xeb02, 0x0000, 0x00df, 0xb031 },
+ { 0x0000, 0xeb03, 0x0000, 0x007b, 0xb031 },
+ { 0x0000, 0xeb05, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xeb06, 0x0000, 0x005a, 0xb031 },
+ { 0x0000, 0xeb07, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xebc0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xd0cb, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xd0b0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd010, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd011, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd012, 0x0000, 0x0092, 0xb031 },
+ { 0x0000, 0xd013, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd014, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd015, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xd016, 0x0000, 0x0072, 0xb031 },
+ { 0x0000, 0xd017, 0x0000, 0x00b0, 0xb031 },
+ { 0x0000, 0xd020, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd021, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd022, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd023, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd024, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd025, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd026, 0x0000, 0x0090, 0xb031 },
+ { 0x0000, 0xd027, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xd028, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd029, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd02a, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd02b, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c3, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c4, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd0c0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xce6a, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xce63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xce64, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xdb04, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xdb05, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xcc00, 0x0000, 0x00c1, 0xb031 },
+ { 0x0000, 0xca02, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xca00, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca62, 0x0000, 0x0077, 0xb031 },
+ { 0x0000, 0xca65, 0x0000, 0x0082, 0xb031 },
+ { 0x0000, 0xca68, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xca75, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xca7b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xca00, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xca02, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc860, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc861, 0x0000, 0x00e5, 0xb031 },
+ { 0x0000, 0xc862, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xc863, 0x0000, 0x00c6, 0xb031 },
+ { 0x0000, 0xc864, 0x0000, 0x00ba, 0xb031 },
+ { 0x0000, 0xc865, 0x0000, 0x0061, 0xb031 },
+ { 0x0000, 0xc867, 0x0000, 0x0017, 0xb031 },
+ { 0x0000, 0xc868, 0x0000, 0x00ed, 0xb031 },
+ { 0x0000, 0xc869, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xc86a, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xc86b, 0x0000, 0x00e2, 0xb031 },
+ { 0x0000, 0xc875, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xc87b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xc836, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc8a0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc833, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xc834, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc83f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc83e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc83a, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xc83b, 0x0000, 0x0089, 0xb031 },
+ { 0x0000, 0xc830, 0x0000, 0x0013, 0xb031 },
+ { 0x0000, 0xc826, 0x0000, 0x00d1, 0xb031 },
+ { 0x0000, 0xc890, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc823, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc824, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xc82f, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xc82e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc820, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc816, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc880, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xc813, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc814, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc81f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc81e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc81a, 0x0000, 0x0066, 0xb031 },
+ { 0x0000, 0xc81b, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc810, 0x0000, 0x000d, 0xb031 },
+ { 0x0000, 0xc846, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc8d0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc844, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc84f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc84e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc84a, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc84b, 0x0000, 0x0056, 0xb031 },
+ { 0x0000, 0xc800, 0x0000, 0x00b0, 0xb031 },
+ { 0x0000, 0xc851, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xc500, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc501, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc502, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc503, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc504, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc505, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc506, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc507, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc510, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc511, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc512, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc513, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc514, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc515, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc516, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc517, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc518, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc541, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xd250, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xd251, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xd264, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0xf800, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xecb0, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec10, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec11, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xec12, 0x0000, 0x00ab, 0xb031 },
+ { 0x0000, 0xec13, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xec14, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec15, 0x0000, 0x004c, 0xb031 },
+ { 0x0000, 0xec16, 0x0000, 0x0069, 0xb031 },
+ { 0x0000, 0xec21, 0x0000, 0x0011, 0xb031 },
+ { 0x0000, 0xec22, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xec23, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xec24, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec25, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xec26, 0x0000, 0x0055, 0xb031 },
+ { 0x0000, 0xec27, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xec28, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec29, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xec2a, 0x0000, 0x0051, 0xb031 },
+ { 0x0000, 0xec2b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xecb2, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec30, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec31, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xec32, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xec33, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec34, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec35, 0x0000, 0x00bb, 0xb031 },
+ { 0x0000, 0xec36, 0x0000, 0x0024, 0xb031 },
+ { 0x0000, 0xec37, 0x0000, 0x0068, 0xb031 },
+ { 0x0000, 0xec40, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec41, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xec42, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xec43, 0x0000, 0x00e8, 0xb031 },
+ { 0x0000, 0xec44, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec45, 0x0000, 0x004f, 0xb031 },
+ { 0x0000, 0xec46, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xec47, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec48, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec49, 0x0000, 0x00c5, 0xb031 },
+ { 0x0000, 0xec4a, 0x0000, 0x0032, 0xb031 },
+ { 0x0000, 0xec4b, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xecb4, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec50, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec51, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xec52, 0x0000, 0x00b4, 0xb031 },
+ { 0x0000, 0xec53, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec54, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec55, 0x0000, 0x007d, 0xb031 },
+ { 0x0000, 0xec56, 0x0000, 0x00d9, 0xb031 },
+ { 0x0000, 0xec57, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xec60, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xec61, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xec62, 0x0000, 0x00b5, 0xb031 },
+ { 0x0000, 0xec63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xec64, 0x0000, 0x00fa, 0xb031 },
+ { 0x0000, 0xec65, 0x0000, 0x0086, 0xb031 },
+ { 0x0000, 0xec66, 0x0000, 0x00a8, 0xb031 },
+ { 0x0000, 0xec67, 0x0000, 0x0040, 0xb031 },
+ { 0x0000, 0xec68, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xec69, 0x0000, 0x009a, 0xb031 },
+ { 0x0000, 0xec6a, 0x0000, 0x002f, 0xb031 },
+ { 0x0000, 0xec6b, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xecb6, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xec70, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xec71, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xec72, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xec73, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xec74, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xec75, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xec76, 0x0000, 0x002c, 0xb031 },
+ { 0x0000, 0xec77, 0x0000, 0x0050, 0xb031 },
+ { 0x0000, 0xec80, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec81, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xec82, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xec83, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xec84, 0x0000, 0x00f5, 0xb031 },
+ { 0x0000, 0xec85, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xec86, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xec87, 0x0000, 0x00d0, 0xb031 },
+ { 0x0000, 0xec88, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xec89, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xec8a, 0x0000, 0x0016, 0xb031 },
+ { 0x0000, 0xec8b, 0x0000, 0x0028, 0xb031 },
+ { 0x0000, 0xecb8, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xec90, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xec91, 0x0000, 0x008b, 0xb031 },
+ { 0x0000, 0xec92, 0x0000, 0x00bd, 0xb031 },
+ { 0x0000, 0xec93, 0x0000, 0x0064, 0xb031 },
+ { 0x0000, 0xec94, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xec95, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xec96, 0x0000, 0x00e7, 0xb031 },
+ { 0x0000, 0xec97, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xeca0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeca1, 0x0000, 0x0091, 0xb031 },
+ { 0x0000, 0xeca2, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xeca3, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xeca4, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xeca5, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xeca6, 0x0000, 0x0093, 0xb031 },
+ { 0x0000, 0xeca7, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xeca8, 0x0000, 0x0003, 0xb031 },
+ { 0x0000, 0xeca9, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xecaa, 0x0000, 0x0099, 0xb031 },
+ { 0x0000, 0xecab, 0x0000, 0x006c, 0xb031 },
+ { 0x0000, 0xebc3, 0x0000, 0x00ff, 0xb031 },
+ { 0x0000, 0xebc4, 0x0000, 0x00fc, 0xb031 },
+ { 0x0000, 0xec00, 0x0000, 0x0005, 0xb031 },
+ { 0x0000, 0xec01, 0x0000, 0x00a9, 0xb031 },
+ { 0x0000, 0xec02, 0x0000, 0x00df, 0xb031 },
+ { 0x0000, 0xec03, 0x0000, 0x007b, 0xb031 },
+ { 0x0000, 0xec05, 0x0000, 0x0079, 0xb031 },
+ { 0x0000, 0xec06, 0x0000, 0x005a, 0xb031 },
+ { 0x0000, 0xec07, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xebc0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xd1b0, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd110, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd111, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd112, 0x0000, 0x0092, 0xb031 },
+ { 0x0000, 0xd113, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd114, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd115, 0x0000, 0x00f6, 0xb031 },
+ { 0x0000, 0xd116, 0x0000, 0x0072, 0xb031 },
+ { 0x0000, 0xd117, 0x0000, 0x00b0, 0xb031 },
+ { 0x0000, 0xd120, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd121, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd122, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd123, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd124, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd125, 0x0000, 0x0009, 0xb031 },
+ { 0x0000, 0xd126, 0x0000, 0x0090, 0xb031 },
+ { 0x0000, 0xd127, 0x0000, 0x0020, 0xb031 },
+ { 0x0000, 0xd128, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xd129, 0x0000, 0x00fb, 0xb031 },
+ { 0x0000, 0xd12a, 0x0000, 0x0037, 0xb031 },
+ { 0x0000, 0xd12b, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c3, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd0c4, 0x0000, 0x000c, 0xb031 },
+ { 0x0000, 0xd0c0, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xce63, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xce64, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xdd04, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xdd05, 0x0000, 0x0006, 0xb031 },
+ { 0x0000, 0xca12, 0x0000, 0x000f, 0xb031 },
+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca82, 0x0000, 0x0077, 0xb031 },
+ { 0x0000, 0xca85, 0x0000, 0x0082, 0xb031 },
+ { 0x0000, 0xca88, 0x0000, 0x00c2, 0xb031 },
+ { 0x0000, 0xca95, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xca9b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xca10, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xca12, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc960, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc961, 0x0000, 0x00e5, 0xb031 },
+ { 0x0000, 0xc962, 0x0000, 0x00eb, 0xb031 },
+ { 0x0000, 0xc963, 0x0000, 0x00c6, 0xb031 },
+ { 0x0000, 0xc964, 0x0000, 0x00ba, 0xb031 },
+ { 0x0000, 0xc965, 0x0000, 0x0061, 0xb031 },
+ { 0x0000, 0xc967, 0x0000, 0x0017, 0xb031 },
+ { 0x0000, 0xc968, 0x0000, 0x00ed, 0xb031 },
+ { 0x0000, 0xc969, 0x0000, 0x003c, 0xb031 },
+ { 0x0000, 0xc96a, 0x0000, 0x008a, 0xb031 },
+ { 0x0000, 0xc96b, 0x0000, 0x00e2, 0xb031 },
+ { 0x0000, 0xc975, 0x0000, 0x003a, 0xb031 },
+ { 0x0000, 0xc97b, 0x0000, 0x006f, 0xb031 },
+ { 0x0000, 0xc936, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc9a0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc933, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xc934, 0x0000, 0x0002, 0xb031 },
+ { 0x0000, 0xc93f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc93e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc93a, 0x0000, 0x0076, 0xb031 },
+ { 0x0000, 0xc93b, 0x0000, 0x0089, 0xb031 },
+ { 0x0000, 0xc930, 0x0000, 0x0013, 0xb031 },
+ { 0x0000, 0xc926, 0x0000, 0x00d1, 0xb031 },
+ { 0x0000, 0xc990, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc923, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc924, 0x0000, 0x0004, 0xb031 },
+ { 0x0000, 0xc92f, 0x0000, 0x0018, 0xb031 },
+ { 0x0000, 0xc92e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc920, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc916, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc980, 0x0000, 0x00e1, 0xb031 },
+ { 0x0000, 0xc913, 0x0000, 0x0000, 0xb031 },
+ { 0x0000, 0xc914, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc91f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc91e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc91a, 0x0000, 0x0066, 0xb031 },
+ { 0x0000, 0xc91b, 0x0000, 0x0078, 0xb031 },
+ { 0x0000, 0xc910, 0x0000, 0x000d, 0xb031 },
+ { 0x0000, 0xc946, 0x0000, 0x00f9, 0xb031 },
+ { 0x0000, 0xc9d0, 0x0000, 0x00f1, 0xb031 },
+ { 0x0000, 0xc944, 0x0000, 0x0001, 0xb031 },
+ { 0x0000, 0xc94f, 0x0000, 0x0014, 0xb031 },
+ { 0x0000, 0xc94e, 0x0000, 0x0094, 0xb031 },
+ { 0x0000, 0xc94a, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc94b, 0x0000, 0x0056, 0xb031 },
+ { 0x0000, 0xc951, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xc600, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc601, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc602, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc603, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc604, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc605, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc606, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc607, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc610, 0x0000, 0x0007, 0xb031 },
+ { 0x0000, 0xc611, 0x0000, 0x00da, 0xb031 },
+ { 0x0000, 0xc612, 0x0000, 0x000e, 0xb031 },
+ { 0x0000, 0xc613, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc614, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xc615, 0x0000, 0x0026, 0xb031 },
+ { 0x0000, 0xc616, 0x0000, 0x004a, 0xb031 },
+ { 0x0000, 0xc617, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xc618, 0x0000, 0x0008, 0xb031 },
+ { 0x0000, 0xc541, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xc802, 0x0000, 0x00d2, 0xb031 },
+ { 0x0000, 0xc902, 0x0000, 0x00d2, 0xb031 },
+ { 0x0000, 0xc800, 0x0000, 0x00f0, 0xb031 },
+ { 0x0000, 0xd250, 0x0000, 0x0087, 0xb031 },
+ { 0x0000, 0xd252, 0x0000, 0x0030, 0xb031 },
+ { 0x0000, 0xd264, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xce60, 0x0000, 0x00e3, 0xb031 },
+ { 0x0000, 0xdf00, 0x0000, 0x0010, 0xb031 },
+ { 0x0000, 0xdbb5, 0x0041, 0xd27f, 0xb037 },
+ { 0x0000, 0xddb5, 0x0040, 0x6e3b, 0xb037 },
+ { 0x0000, 0xdb93, 0x0000, 0x009e, 0xb033 },
+ { 0x0000, 0xdd93, 0x0000, 0x009e, 0xb033 },
+ { 0x0000, 0xdb12, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xdd12, 0x0000, 0x00c0, 0xb031 },
+ { 0x0000, 0xdb08, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xdd08, 0x0000, 0x0080, 0xb031 },
+ { 0x0000, 0xdb00, 0x0000, 0x00cc, 0xb031 },
+ { 0x0000, 0xc203, 0x0000, 0x009c, 0xb031 },
+ { 0x0000, 0x0010, 0x0000, 0x0f21, 0x0000 },
+};
+
+/* wake the amp (ea00=0x43, c121=0x0b, f109=0xe0) */
+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_wake[] = {
+ { 0x0000, 0xea00, 0x0000, 0x0043, 0xb031 },
+ { 0x0000, 0xc121, 0x0000, 0x000b, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x00e0, 0xb031 },
+};
+
+/* park the amp (ea00=0x47, c121=0x0a, f109=0xa0) */
+static const struct alc298_razer_blade16_2025_op alc298_razer_blade16_2025_amp_sleep[] = {
+ { 0x0000, 0xea00, 0x0000, 0x0047, 0xb031 },
+ { 0x0000, 0xc121, 0x0000, 0x000a, 0xb031 },
+ { 0x0000, 0xf109, 0x0000, 0x00a0, 0xb031 },
+};
+
+/*
+ * Razer Blade 16 (2025): Realtek ALC298 driving an external smart amp.
+ * Crossover, voicing and speaker protection live in an external DSP
+ * reached over a vendor-coef mailbox on NID 0x20; the captured DSP
+ * programming is in the tables above. NID 0x14, the BIOS-disabled
+ * tweeter pin, is re-exposed via a pin-config override so the parser
+ * drives it as a normal internal speaker (shared volume/mute, auto-mute
+ * on headphone insertion).
+ *
+ * alc298_razer_blade16_2025_apply() runs one op-table: a plain coef write
+ * (strobe == 0) goes through alc_write_coef_idx(), while a mailbox op
+ * selects a bank and streams four PROC_COEF words (addr/hi/lo/commit)
+ * into a single coef index (0x23) on NID 0x20 to reach the external DSP
+ * -- that one-index/many-words form is why it cannot be expressed as an
+ * alc_process_coef_fw() table (one value per index).
+ */
+static void alc298_razer_blade16_2025_apply(struct hda_codec *codec,
+ const struct alc298_razer_blade16_2025_op *seq,
+ int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (!seq[i].strobe) {
+ alc_write_coef_idx(codec, seq[i].addr, seq[i].lo);
+ continue;
+ }
+ alc_write_coef_idx(codec, 0x89, seq[i].bank);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x23);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].addr);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].hi);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].lo);
+ snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, seq[i].strobe);
+ }
+}
+
+static void alc298_razer_blade16_2025_pcm_hook(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream,
+ int action)
+{
+ /* power the external amp only while a stream is running */
+ switch (action) {
+ case HDA_GEN_PCM_ACT_PREPARE:
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_wake,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_wake));
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_sleep,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_sleep));
+ break;
+ }
+}
+
+static void alc298_fixup_razer_blade16_2025(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /*
+ * Pin every output to a fixed converter so the routing does not
+ * rely on the generic parser's DAC-allocation heuristics: without
+ * a fixed assignment the parser brings up only one speaker pin and
+ * leaves the other silent, and the allocation could change between
+ * kernel versions. Both speaker pins share DAC 0x03 through mixer
+ * 0x0d: that is the only converter that drives the woofer (NID
+ * 0x17) on this machine -- feeding it from DAC 0x02 or the digital
+ * converter 0x06 leaves the woofer silent. Both pins carry the
+ * same stereo stream and the external amp does the crossover.
+ * Headphone NID 0x21 keeps DAC 0x02.
+ */
+ static const hda_nid_t preferred_pairs[] = {
+ 0x21, 0x02,
+ 0x14, 0x03,
+ 0x17, 0x03,
+ 0
+ };
+ struct alc_spec *spec = codec->spec;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.preferred_dacs = preferred_pairs;
+ break;
+ case HDA_FIXUP_ACT_PROBE:
+ spec->gen.pcm_playback_hook = alc298_razer_blade16_2025_pcm_hook;
+ break;
+ case HDA_FIXUP_ACT_INIT:
+ /*
+ * Wake the amp, program its DSP at boot and on resume, then
+ * park it. It is woken again for playback and parked
+ * afterwards from the pcm_playback_hook.
+ */
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_wake,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_wake));
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_init,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_init));
+ alc298_razer_blade16_2025_apply(codec, alc298_razer_blade16_2025_amp_sleep,
+ ARRAY_SIZE(alc298_razer_blade16_2025_amp_sleep));
+ break;
+ }
+}
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 48a2e7f2ebb1..cae327e1d90d 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -296,7 +296,8 @@ static void alc282_init(struct hda_codec *codec)
msleep(100);
/* Headphone capless set to normal mode */
- alc_write_coef_idx(codec, 0x78, coef78);
+ if (coef78 != -1)
+ alc_write_coef_idx(codec, 0x78, coef78);
}
static void alc282_shutup(struct hda_codec *codec)
@@ -333,7 +334,8 @@ static void alc282_shutup(struct hda_codec *codec)
alc_auto_setup_eapd(codec, false);
alc_shutup_pins(codec);
- alc_write_coef_idx(codec, 0x78, coef78);
+ if (coef78 != -1)
+ alc_write_coef_idx(codec, 0x78, coef78);
}
static const struct coef_fw alc283_coefs[] = {
@@ -585,15 +587,19 @@ static void alc285_hp_init(struct hda_codec *codec)
alc_write_coefex_idx(codec, 0x58, 0x00, 0xf888); /* HP depop procedure start */
val = alc_read_coefex_idx(codec, 0x58, 0x00);
- for (i = 0; i < 20 && val & 0x8000; i++) {
+ for (i = 0; i < 20 && val != -1 && val & 0x8000; i++) {
msleep(50);
val = alc_read_coefex_idx(codec, 0x58, 0x00);
} /* Wait for depop procedure finish */
- alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */
- alc_update_coef_idx(codec, 0x38, 1<<4, coef38);
- alc_update_coef_idx(codec, 0x0d, 0x110, coef0d);
- alc_update_coef_idx(codec, 0x36, 3<<13, coef36);
+ if (val != -1)
+ alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */
+ if (coef38 != -1)
+ alc_update_coef_idx(codec, 0x38, 1<<4, coef38);
+ if (coef0d != -1)
+ alc_update_coef_idx(codec, 0x0d, 0x110, coef0d);
+ if (coef36 != -1)
+ alc_update_coef_idx(codec, 0x36, 3<<13, coef36);
msleep(50);
alc_update_coef_idx(codec, 0x4a, 1<<15, 0);
@@ -858,7 +864,7 @@ static void alc294_hp_init(struct hda_codec *codec)
/* Wait for depop procedure finish */
val = alc_read_coefex_idx(codec, 0x58, 0x01);
- for (i = 0; i < 20 && val & 0x0080; i++) {
+ for (i = 0; i < 20 && val != -1 && val & 0x0080; i++) {
msleep(50);
val = alc_read_coefex_idx(codec, 0x58, 0x01);
}
@@ -1392,6 +1398,15 @@ static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
}
+static void alc245_fixup_minisforum_jack_detect(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action)
+{
+ if (action == HDA_FIXUP_ACT_INIT)
+ /* Clear Reset HP JD while preserving the other coefficient bits. */
+ alc_update_coef_idx(codec, 0x4a, BIT(15), 0);
+}
+
/* turn on/off mic-mute LED per capture hook via VREF change */
static int vref_micmute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
@@ -2557,6 +2572,13 @@ static void alc282_fixup_asus_tx300(struct hda_codec *codec,
}
}
+static void alc285_lenovo_dac_rename(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_BUILD)
+ rename_ctl(codec, "Line Out Playback Volume",
+ "Headphone Playback Volume");
+}
static void alc290_fixup_mono_speakers(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3262,6 +3284,36 @@ static void find_cirrus_companion_amps(struct hda_codec *cdc)
comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
}
+static void aw88399_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "i2c", "AWDZ8399", "-%s:00-aw88399-hda.%d", 2);
+}
+
+static void alc287_fixup_legion_16iax10h_aw88399(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /*
+ * Force DAC 0x02 for the bass speaker 0x17, as the default 0x06 lacks volume controls.
+ */
+ static const hda_nid_t conn[] = { 0x02 };
+ struct alc_spec *spec = codec->spec;
+
+ alc269_fixup_limit_int_mic_boost(codec, fix, action);
+ alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
+ alc_fixup_headset_jack(codec, fix, action);
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ spec->gen.suppress_auto_mic = 1;
+ snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ spec->gen.multiout.max_channels = 2;
+ spec->gen.pcm_rec[0]->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 2;
+ break;
+ }
+}
+
static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
@@ -3357,6 +3409,9 @@ static void alc287_fixup_acer_micmute_led(struct hda_codec *codec,
/* for alc285_fixup_ideapad_s740_coef() */
#include "../helpers/ideapad_s740.c"
+/* for alc298_fixup_razer_blade16_2025() */
+#include "../helpers/razer_blade16_2025.c"
+
static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
@@ -3524,6 +3579,16 @@ static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
}
}
+static void alc_fixup_yoga_pro7_audio(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /* Reuse the DAC routing selected for ThinkPad X1 Gen7 */
+ alc285_fixup_thinkpad_x1_gen7(codec, fix, action);
+
+ /* Limit the internal mic boost to 0 or 1 to avoid noise */
+ alc269_fixup_limit_int_mic_boost(codec, fix, action);
+}
+
static void alc295_fixup_dell_inspiron_top_speakers(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3929,6 +3994,7 @@ enum {
ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572,
ALC269_FIXUP_ACER_AC700,
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+ ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST,
ALC269VB_FIXUP_ASUS_ZENBOOK,
ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -3997,6 +4063,7 @@ enum {
ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC295_FIXUP_DISABLE_DAC3,
ALC285_FIXUP_SPEAKER2_TO_DAC1,
+ ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1,
ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1,
ALC285_FIXUP_ASUS_HEADSET_MIC,
ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS,
@@ -4066,7 +4133,6 @@ enum {
ALC294_FIXUP_ASUS_ALLY,
ALC294_FIXUP_ASUS_ALLY_PINS,
ALC294_FIXUP_ASUS_ALLY_VERBS,
- ALC294_FIXUP_ASUS_ALLY_SPEAKER,
ALC294_FIXUP_ASUS_HPE,
ALC294_FIXUP_ASUS_COEF_1B,
ALC294_FIXUP_ASUS_GX502_HP,
@@ -4091,6 +4157,8 @@ enum {
ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS,
ALC298_FIXUP_LG_GRAM_STYLE_14,
+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS,
+ ALC298_FIXUP_RAZER_BLADE16_2025,
ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
@@ -4108,7 +4176,6 @@ enum {
ALC269_FIXUP_LEMOTE_A190X,
ALC256_FIXUP_INTEL_NUC8_RUGGED,
ALC233_FIXUP_INTEL_NUC8_DMIC,
- ALC233_FIXUP_INTEL_NUC8_BOOST,
ALC256_FIXUP_INTEL_NUC10,
ALC255_FIXUP_XIAOMI_HEADSET_MIC,
ALC274_FIXUP_HP_MIC,
@@ -4139,6 +4206,7 @@ enum {
ALC298_FIXUP_LENOVO_C940_DUET7,
ALC287_FIXUP_LENOVO_YOGA_BOOK_9I,
ALC287_FIXUP_LENOVO_YOGA_PRO7,
+ ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK,
ALC287_FIXUP_13S_GEN2_SPEAKERS,
ALC256_FIXUP_SET_COEF_DEFAULTS,
ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
@@ -4183,7 +4251,6 @@ enum {
ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
ALC2XX_FIXUP_HEADSET_MIC,
ALC289_FIXUP_DELL_CS35L41_SPI_2,
- ALC294_FIXUP_CS35L41_I2C_2,
ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
ALC256_FIXUP_HEADPHONE_AMP_VOL,
ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
@@ -4197,6 +4264,7 @@ enum {
ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318,
ALC256_FIXUP_CHROME_BOOK,
ALC245_FIXUP_CLEVO_NOISY_MIC,
+ ALC245_FIXUP_MINISFORUM_JACK_DETECT,
ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
ALC233_FIXUP_MEDION_MTL_SPK,
ALC233_FIXUP_STARLABS_STARFIGHTER,
@@ -4206,7 +4274,6 @@ enum {
ALC274_FIXUP_HP_AIO_BIND_DACS,
ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2,
ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
- ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
ALC256_FIXUP_VAIO_RPL_MIC_NO_PRESENCE,
@@ -4226,6 +4293,10 @@ enum {
ALC236_FIXUP_DELL_HP_POP_NOISE,
ALC274_FIXUP_HP_89E9_GPIO,
ALC274_FIXUP_HP_VERBS,
+ ALC287_FIXUP_AW88399_I2C_2,
+ ALC287_FIXUP_LENOVO_LEGION_AW88399,
+ ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET,
+ ALC285_LENOVO_DAC_RENAME,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -4263,6 +4334,20 @@ static void alc287_fixup_lenovo_yoga_book_9i(struct hda_codec *codec,
}
static const struct hda_fixup alc269_fixups[] = {
+ [ALC298_FIXUP_RAZER_BLADE16_2025_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+ { 0x14, 0x90170121 }, /* tweeter as internal speaker, seq 1 */
+ { 0x17, 0x90170120 }, /* woofer as internal speaker, seq 0 */
+ { }
+ },
+ .chained = true,
+ .chain_id = ALC298_FIXUP_RAZER_BLADE16_2025,
+ },
+ [ALC298_FIXUP_RAZER_BLADE16_2025] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc298_fixup_razer_blade16_2025,
+ },
[ALC233_FIXUP_WUJIE_SPEAKERS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -4704,6 +4789,10 @@ static const struct hda_fixup alc269_fixups[] = {
},
[ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = {
.type = HDA_FIXUP_FUNC,
+ .v.func = alc269_fixup_limit_int_mic_boost
+ },
+ [ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST] = {
+ .type = HDA_FIXUP_FUNC,
.v.func = alc269_fixup_limit_int_mic_boost,
.chained = true,
.chain_id = ALC269_FIXUP_THINKPAD_ACPI,
@@ -5078,11 +5167,7 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic,
.chained = true,
- .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST,
- },
- [ALC233_FIXUP_INTEL_NUC8_BOOST] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc269_fixup_limit_int_mic_boost
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
},
[ALC255_FIXUP_DELL_SPK_NOISE] = {
.type = HDA_FIXUP_FUNC,
@@ -5143,6 +5228,10 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_speaker2_to_dac1,
+ },
+ [ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_speaker2_to_dac1,
.chained = true,
.chain_id = ALC269_FIXUP_THINKPAD_ACPI
},
@@ -5662,11 +5751,7 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
},
.chained = true,
- .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER
- },
- [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc285_fixup_speaker2_to_dac1,
+ .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
},
[ALC285_FIXUP_THINKPAD_X1_GEN7] = {
.type = HDA_FIXUP_FUNC,
@@ -6209,11 +6294,20 @@ static const struct hda_fixup alc269_fixups[] = {
},
[ALC287_FIXUP_LENOVO_YOGA_PRO7] = {
.type = HDA_FIXUP_FUNC,
- /* Reuse the DAC routing selected for ThinkPad X1 Gen7 */
- .v.func = alc285_fixup_thinkpad_x1_gen7,
+ .v.func = alc_fixup_yoga_pro7_audio,
.chained = true,
.chain_id = ALC269_FIXUP_LENOVO_XPAD_ACPI,
},
+ [ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_jack,
+ .chained = true,
+ /* Same as ALC285_FIXUP_THINKPAD_HEADSET_JACK, except that the
+ * mute LEDs are driven through ideapad_laptop rather than
+ * thinkpad_acpi.
+ */
+ .chain_id = ALC287_FIXUP_LENOVO_YOGA_PRO7,
+ },
[ALC623_FIXUP_LENOVO_THINKSTATION_P340] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_no_shutup,
@@ -6653,10 +6747,6 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC289_FIXUP_DUAL_SPK
},
- [ALC294_FIXUP_CS35L41_I2C_2] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = cs35l41_fixup_i2c_two,
- },
[ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc256_fixup_acer_sfg16_micmute_led,
@@ -6729,6 +6819,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
},
+ [ALC245_FIXUP_MINISFORUM_JACK_DETECT] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc245_fixup_minisforum_jack_detect,
+ },
[ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -6749,6 +6843,8 @@ static const struct hda_fixup alc269_fixups[] = {
[ALC233_FIXUP_STARLABS_STARFIGHTER] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc233_fixup_starlabs_starfighter,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
},
[ALC294_FIXUP_BASS_SPEAKER_15] = {
.type = HDA_FIXUP_FUNC,
@@ -6776,11 +6872,7 @@ static const struct hda_fixup alc269_fixups[] = {
{ }
},
.chained = true,
- .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1
- },
- [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = alc285_fixup_speaker2_to_dac1,
+ .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
},
[ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = {
.type = HDA_FIXUP_FUNC,
@@ -6898,6 +6990,26 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC274_FIXUP_HP_89E9_GPIO,
},
+ [ALC287_FIXUP_AW88399_I2C_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = aw88399_fixup_i2c_two,
+ },
+ [ALC287_FIXUP_LENOVO_LEGION_AW88399] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc287_fixup_legion_16iax10h_aw88399,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_AW88399_I2C_2,
+ },
+ [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_headset_jack,
+ .chained = true,
+ .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
+ },
+ [ALC285_LENOVO_DAC_RENAME] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_lenovo_dac_rename,
+ },
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -6951,8 +7063,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x159e, "Acer Nitro 5 AN515-46", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1616, "Acer Aspire A515-57", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
+ SND_PCI_QUIRK(0x1025, 0x166c, "Acer Predator PH16-71", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
@@ -6961,6 +7075,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1025, 0x1909, "Acer Nitro ANV16-42", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
@@ -7145,10 +7260,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
SND_PCI_QUIRK(0x103c, 0x85f0, "HP Laptop 15-dw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x85f3, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8603, "HP Omen 17-cb0xxx", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x860c, "HP ZBook 17 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+ SND_PCI_QUIRK(0x103c, 0x864f, "HP Laptop 15-dy0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
@@ -7259,6 +7376,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a05, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a06, "HP Dragonfly Folio G3 2-in-1", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8a0e, "HP Pavilion Laptop 15-eh2xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a1b, "HP 255 15.6 inch G9 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8a1f, "HP Laptop 14s-dr5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
@@ -7350,10 +7468,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
- SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x8c2d, "HP Victus 15-fa1xxx (MB 8C2D)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8c3f, "HP Victus 15-fa1xxx (MB 8C3F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -7442,6 +7561,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8dfd, "HP EliteBook 6 G1a 16", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e0d, "HP EliteBook 6 G1a 14 (AD3Q9ET#UUG)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8e11, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e12, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8e13, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
@@ -7501,6 +7621,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8f42, "HP ZBook 8 G2a 14W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f57, "HP Trekker G7JC", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f62, "HP ZBook 8 G2a 16W", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f7e, "HP Messi", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x8f94, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED),
SND_PCI_QUIRK(0x103c, 0x8f95, "HP ZBook 8 G2a 16", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED_INVERTED),
SND_PCI_QUIRK(0x1043, 0x1024, "ASUS Zephyrus G14 2025", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
@@ -7508,6 +7629,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
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, 0x1044, "ASUS GA403UM", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
@@ -7515,16 +7637,15 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
+ SND_PCI_QUIRK(0x1043, 0x10c4, "ASUS Vivobook S14 S5406SA", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK),
SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
- HDA_CODEC_QUIRK(0x1043, 0x1204, "ASUS Strix G16 G615JMR", ALC287_FIXUP_TXNW2781_I2C_ASUS),
- SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
- HDA_CODEC_QUIRK(0x1043, 0x1214, "ASUS ROG Strix G615LP", ALC287_FIXUP_TXNW2781_I2C_ASUS),
- SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TXNW2781_I2C_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TXNW2781_I2C_ASUS),
SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
@@ -7573,7 +7694,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
- SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
@@ -7584,7 +7705,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x19f4, "ASUS UM3405GA", ALC294_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC294_FIXUP_ASUS_SPI_HEADSET_MIC),
- SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1a8e, "ASUS G712LWS", ALC294_FIXUP_LENOVO_MIC_LOCATION),
SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
@@ -7613,6 +7734,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15),
SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1043, 0x1e3e, "ASUS VivoBook M515DA/X515DAP", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC),
@@ -7624,8 +7746,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RC72LA", ALC287_FIXUP_ASUS_ALLY_X),
SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
- HDA_CODEC_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1),
- SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
@@ -7836,7 +7957,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
@@ -7852,7 +7973,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x225c, "Lenovo ThinkPad X1 Carbon 6th Gen", ALC285_LENOVO_DAC_RENAME),
+ SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x2288, "Thinkpad X390", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
@@ -7927,7 +8049,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x386a, "Lenovo Yoga 7 16IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
+ SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_YOGA_SPEAKER2_TO_DAC1),
HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
HDA_CODEC_QUIRK(0x17aa, 0x38a7, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
@@ -7949,6 +8071,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ /* Lenovo Yoga Slim 7 14AKP10 shares PCI SSID 17aa:38b4 with Legion Slim 7
+ * 16IRH8; use codec SSID to distinguish them
+ */
+ HDA_CODEC_QUIRK(0x17aa, 0x391a, "Lenovo Yoga Slim 7 14AKP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
HDA_CODEC_QUIRK(0x17aa, 0x391c, "Lenovo Yoga 7 2-in-1 14AKP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x391d, "Lenovo Yoga 7 2-in-1 16AKP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
@@ -7958,6 +8084,12 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
+ HDA_CODEC_QUIRK(0x17aa, 0x3926, "Legion Pro 5 16ADR10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ /* Legion R9000P ADR10 shares PCI SSID 17aa:38bb with Yoga S780-14.5 Air AMD quad AAC;
+ * use codec SSID to distinguish them
+ */
+ HDA_CODEC_QUIRK(0x17aa, 0x3927, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3928, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C),
@@ -7975,7 +8107,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C),
- SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
/* Legion 7 15ASH11 shares PCI SSID 17aa:38f9 with Thinkbook 16P Gen5;
* use codec SSID to distinguish them
*/
@@ -7985,23 +8116,29 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC287_FIXUP_LENOVO_YOGA_PRO7),
SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
- SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ HDA_CODEC_QUIRK(0x17aa, 0x3906, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3907, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN_HEADSET),
SND_PCI_QUIRK(0x17aa, 0x3911, "Lenovo Yoga Pro 7 14IAH10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3912, "Lenovo Xiaoxin 14 GT", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
- SND_PCI_QUIRK(0x17aa, 0x391a, "Lenovo Yoga Slim 7 14AKP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TXNW2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3929, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x392b, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ HDA_CODEC_QUIRK(0x17aa, 0x3936, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3937, "Legion R9000P ADR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3938, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ HDA_CODEC_QUIRK(0x17aa, 0x3939, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+ SND_PCI_QUIRK(0x17aa, 0x393e, "Lenovo ThinkBook 14 G8+ IPH", ALC287_FIXUP_LENOVO_XPAD_HEADSET_JACK),
HDA_CODEC_QUIRK(0x17aa, 0x394c, "Lenovo Yoga Slim 7 14AGP11", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
- SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
@@ -8014,7 +8151,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x508b, "Thinkpad X12 Gen 1", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
- SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_THINKPAD_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -8028,9 +8165,14 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1854, 0x0489, "LG gram 16 (16Z90R-A)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
SND_PCI_QUIRK(0x1854, 0x0490, "LG Gram Style 14 (14Z90RS)", ALC298_FIXUP_LG_GRAM_STYLE_14),
+ SND_PCI_QUIRK(0x1854, 0x0554, "LG gram 16 (16Z90TR)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1a58, 0x2023, "Razer Blade 16 (2025)",
+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS),
+ SND_PCI_QUIRK(0x1a58, 0x300e, "Razer Blade 16 (2025)",
+ ALC298_FIXUP_RAZER_BLADE16_2025_PINS),
SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
@@ -8064,13 +8206,17 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
SND_PCI_QUIRK(0x1e39, 0xca14, "MEDION NM14LNL", ALC233_FIXUP_MEDION_MTL_SPK),
SND_PCI_QUIRK(0x1e50, 0x7007, "Positivo DN50E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x1e50, 0x7036, "Acer Gadget E10 ETBook", ALC233_FIXUP_WUJIE_SPEAKERS),
SND_PCI_QUIRK(0x1e50, 0x7038, "Positivo DN140", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1ee7, 0x2078, "HONOR BRB-X M1010", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1ee7, 0x2081, "HONOR MRB-XXX M1020", ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO),
+ SND_PCI_QUIRK(0x1f4c, 0xb020, "Minisforum AI X1 Pro",
+ ALC245_FIXUP_MINISFORUM_JACK_DETECT),
SND_PCI_QUIRK(0x1f4c, 0xe001, "Minisforum V3 (SE)", ALC245_FIXUP_BASS_HP_DAC),
SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2039, 0x0001, "Inspur S14-G1", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x2145, 0x0001, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER),
SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
@@ -8081,6 +8227,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX),
SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK),
+ SND_PCI_QUIRK(0x2782, 0xa128, "Positivo N15RPE-S", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x2782, 0xa212, "Lunnen Ground 14", ALC269VC_FIXUP_LUNNEN_GROUND_14),
SND_PCI_QUIRK(0x7017, 0x2014, "Star Labs StarFighter", ALC233_FIXUP_STARLABS_STARFIGHTER),
SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
@@ -8154,6 +8301,7 @@ static const struct hda_quirk alc269_fixup_vendor_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI),
SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED),
+ SND_PCI_QUIRK_VENDOR(0x2145, "Star Labs", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
{}
};
@@ -8293,6 +8441,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
{.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"},
{.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"},
+ {.id = ALC287_FIXUP_LENOVO_LEGION_AW88399, .name = "alc287-lenovo-legion-aw88399"},
{}
};
#define ALC225_STANDARD_PINS \
@@ -8898,6 +9047,7 @@ static int alc269_probe(struct hda_codec *codec, const struct hda_device_id *id)
spec->init_hook = alc256_init;
spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
if (codec->core.vendor_id == 0x10ec0236 &&
+ codec->bus->pci &&
codec->bus->pci->vendor != PCI_VENDOR_ID_AMD)
spec->en_3kpull_low = false;
break;
diff --git a/sound/hda/codecs/realtek/alc662.c b/sound/hda/codecs/realtek/alc662.c
index 2cf3664a35ff..eff7c83b9c59 100644
--- a/sound/hda/codecs/realtek/alc662.c
+++ b/sound/hda/codecs/realtek/alc662.c
@@ -325,6 +325,7 @@ enum {
ALC897_FIXUP_UNIS_H3C_X500S,
ALC897_FIXUP_HEADSET_MIC_PIN3,
ALC662_FIXUP_CSL_GPIO,
+ ALC897_FIXUP_BEELINK_SER6_AMP,
};
static const struct hda_fixup alc662_fixups[] = {
@@ -782,6 +783,10 @@ static const struct hda_fixup alc662_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc662_fixup_csl_amp,
},
+ [ALC897_FIXUP_BEELINK_SER6_AMP] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_gpio4,
+ },
};
static const struct hda_quirk alc662_fixup_tbl[] = {
@@ -852,6 +857,8 @@ static const struct hda_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x1e63, 0x6d9a, "F+ FLAPTOP r", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x1f66, 0x0202, "Beelink SER6 Max 6900", ALC897_FIXUP_BEELINK_SER6_AMP),
#if 0
/* Below is a quirk table taken from the old code.
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
index 1cfd83e251e4..f90f1dfcec68 100644
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -13,6 +13,24 @@ config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
Documentation/dev-tools/kunit/.
If in doubt, say "N".
+config SND_HDA_SCODEC_AW88399
+ tristate
+ select SND_HDA_GENERIC
+
+config SND_HDA_SCODEC_AW88399_I2C
+ tristate "Build AW88399 HD-audio side codec support for I2C Bus"
+ depends on I2C
+ depends on ACPI
+ depends on SND_SOC
+ select SND_HDA_SCODEC_AW88399
+ select SND_SOC_AW88399_LIB
+ help
+ Say Y or M here to include AW88399 I2C HD-audio side codec support
+ in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+ depends on SND_HDA=y && SND_HDA_SCODEC_AW88399_I2C=m
+
config SND_HDA_SCODEC_CS35L41
tristate
select SND_HDA_GENERIC
diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile
index 245e84f6a121..7dd010c68f78 100644
--- a/sound/hda/codecs/side-codecs/Makefile
+++ b/sound/hda/codecs/side-codecs/Makefile
@@ -3,6 +3,8 @@ subdir-ccflags-y += -I$(src)/../../common
snd-hda-cirrus-scodec-y := cirrus_scodec.o
snd-hda-cirrus-scodec-test-y := cirrus_scodec_test.o
+snd-hda-scodec-aw88399-y := aw88399_hda.o
+snd-hda-scodec-aw88399-i2c-y := aw88399_hda_i2c.o
snd-hda-scodec-cs35l41-y := cs35l41_hda.o cs35l41_hda_property.o
snd-hda-scodec-cs35l41-i2c-y := cs35l41_hda_i2c.o
snd-hda-scodec-cs35l41-spi-y := cs35l41_hda_spi.o
@@ -16,6 +18,8 @@ snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o
obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o
+obj-$(CONFIG_SND_HDA_SCODEC_AW88399) += snd-hda-scodec-aw88399.o
+obj-$(CONFIG_SND_HDA_SCODEC_AW88399_I2C) += snd-hda-scodec-aw88399-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.c b/sound/hda/codecs/side-codecs/aw88399_hda.c
new file mode 100644
index 000000000000..11cef4923024
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// AW88399 HDA side codec driver
+//
+// Based on cs35l41_hda.c and aw88399.c
+//
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <sound/hda_codec.h>
+#include "../generic.h"
+#include "hda_component.h"
+#include "aw88399_hda.h"
+
+#define AW88399_HDA_I2C_BASE_ADDR 0x34
+
+static void aw88399_hda_playback_hook(struct device *dev, int action)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ struct aw88399 *core = aw88399->core;
+ int ret = 0;
+
+ dev_dbg(aw88399->dev, "Playback action: %d\n", action);
+
+ switch (action) {
+ case HDA_GEN_PCM_ACT_OPEN:
+ pm_runtime_get_sync(dev);
+ aw88399->playing = true;
+ break;
+ case HDA_GEN_PCM_ACT_PREPARE:
+ if (core)
+ aw88399_start(core, AW88399_SYNC_START);
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ if (aw88399->aw_dev)
+ ret = aw88399_stop(aw88399->aw_dev);
+ if (ret)
+ dev_err(aw88399->dev, "Failed to stop amplifier: %d\n", ret);
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
+ if (aw88399->aw_dev)
+ aw88399_stop(aw88399->aw_dev);
+ aw88399->playing = false;
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ break;
+ default:
+ dev_warn(aw88399->dev, "Unsupported action: %d\n", action);
+ break;
+ }
+}
+
+static int aw88399_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, aw88399->index);
+ if (!comp)
+ return -EINVAL;
+
+ if (comp->dev)
+ return -EBUSY;
+
+ comp->dev = dev;
+
+ strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+ comp->playback_hook = aw88399_hda_playback_hook;
+
+ dev_info(aw88399->dev,
+ "AW88399 Bound - SSID: %s, channel: %d\n",
+ aw88399->acpi_subsystem_id, aw88399->channel);
+
+ return 0;
+}
+
+static void aw88399_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, aw88399->index);
+ if (comp && (comp->dev == dev))
+ memset(comp, 0, sizeof(*comp));
+
+ dev_dbg(aw88399->dev, "Unbound from HDA codec\n");
+}
+
+static const struct component_ops aw88399_hda_comp_ops = {
+ .bind = aw88399_hda_bind,
+ .unbind = aw88399_hda_unbind,
+};
+
+static int aw88399_hda_index_from_i2c(struct aw88399_hda *aw88399)
+{
+ return to_i2c_client(aw88399->dev)->addr - AW88399_HDA_I2C_BASE_ADDR;
+}
+
+static int aw88399_hda_init(struct aw88399_hda *aw88399)
+{
+ struct device *dev = aw88399->dev;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct aw88399 *core;
+ int ret;
+
+ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+
+ mutex_init(&core->lock);
+ core->reset_gpio = aw88399->reset_gpio;
+ core->regmap = aw88399->regmap;
+ core->bsts_unreliable = aw88399->bsts_unreliable;
+
+ aw88399_hw_reset(core);
+
+ ret = aw88399_init(core, i2c, aw88399->regmap);
+ if (ret)
+ return ret;
+
+ /* Set channel BEFORE loading firmware so ACF parser sees correct value */
+ if (core->aw_pa)
+ aw88399_dev_set_channel(core, aw88399->channel);
+
+ ret = aw88399_request_firmware_file(core);
+ if (ret)
+ return ret;
+
+ aw88399->core = core;
+ aw88399->aw_dev = core->aw_pa;
+
+ return 0;
+}
+
+static int aw88399_swap_channels(struct aw88399_hda *aw88399)
+{
+ /*
+ * Certain Lenovo Legion laptops have their
+ * I2C wiring reversed: 0x34 is physically the right speaker,
+ * 0x35 is the left. Swap channels to correct L/R assignment.
+ * This is a model-specific hardware wiring issue, not a driver bug.
+ */
+ aw88399->channel = 1 - aw88399->channel;
+ dev_dbg(aw88399->dev,
+ "Channel swap applied: index %d -> channel %d\n",
+ aw88399->index, aw88399->channel);
+ return 0;
+}
+
+static int aw88399_skip_bsts_check(struct aw88399_hda *aw88399)
+{
+ /*
+ * BSTS (boost-finished) status bit does not reliably report on
+ * some hardware. On certain Lenovo Legion laptops, both amps
+ * report BSTS=0 (boost not finished) during normal playback
+ * despite clean audio output. Skip BSTS in the startup status
+ * check to avoid false init failures.
+ */
+ aw88399->bsts_unreliable = true;
+ dev_dbg(aw88399->dev, "BSTS status check disabled\n");
+ return 0;
+}
+
+static int aw88399_apply_legion_quirks(struct aw88399_hda *aw88399)
+{
+ aw88399_swap_channels(aw88399);
+ aw88399_skip_bsts_check(aw88399);
+ return 0;
+}
+
+struct aw88399_prop_model {
+ const char *ssid;
+ int (*apply_prop)(struct aw88399_hda *aw88399);
+};
+
+static const struct aw88399_prop_model aw88399_prop_model_table[] = {
+ { "17AA3906", aw88399_apply_legion_quirks },
+ { "17AA3907", aw88399_apply_legion_quirks },
+ { "17AA3927", aw88399_apply_legion_quirks },
+ { "17AA3928", aw88399_apply_legion_quirks },
+ { "17AA3936", aw88399_apply_legion_quirks },
+ { "17AA3937", aw88399_apply_legion_quirks },
+ { "17AA3938", aw88399_apply_legion_quirks },
+ { "17AA3939", aw88399_apply_legion_quirks },
+ { }
+};
+
+static int aw88399_hda_acpi_probe(struct aw88399_hda *aw88399)
+{
+ struct acpi_device *adev;
+ const char *sub;
+ const struct aw88399_prop_model *model;
+
+ aw88399->index = aw88399_hda_index_from_i2c(aw88399);
+ aw88399->channel = aw88399->index;
+ aw88399->acpi_subsystem_id = NULL;
+
+ adev = acpi_dev_get_first_match_dev("AWDZ8399", NULL, -1);
+ if (!adev) {
+ dev_err(aw88399->dev, "Failed to find an ACPI device for AWDZ8399\n");
+ return -ENODEV;
+ }
+
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
+ acpi_dev_put(adev);
+ if (!physdev)
+ return -ENODEV;
+
+ sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+ if (IS_ERR_OR_NULL(sub))
+ return 0;
+
+ aw88399->acpi_subsystem_id = devm_kstrdup(aw88399->dev, sub, GFP_KERNEL);
+ kfree(sub);
+ if (!aw88399->acpi_subsystem_id)
+ return -ENOMEM;
+
+ for (model = aw88399_prop_model_table; model->ssid; model++) {
+ if (!strcasecmp(model->ssid, aw88399->acpi_subsystem_id)) {
+ dev_info(aw88399->dev,
+ "Applying properties for SSID %s\n",
+ aw88399->acpi_subsystem_id);
+ return model->apply_prop(aw88399);
+ }
+ }
+
+ return 0;
+}
+
+int aw88399_hda_probe(struct device *dev, struct regmap *regmap)
+{
+ struct aw88399_hda *aw88399;
+ int ret;
+
+ aw88399 = devm_kzalloc(dev, sizeof(*aw88399), GFP_KERNEL);
+ if (!aw88399)
+ return -ENOMEM;
+
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap), "Failed to obtain regmap\n");
+
+ aw88399->dev = dev;
+ aw88399->regmap = regmap;
+ dev_set_drvdata(dev, aw88399);
+
+ aw88399->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(aw88399->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(aw88399->reset_gpio),
+ "Failed to get reset GPIO\n");
+
+ ret = aw88399_hda_acpi_probe(aw88399);
+ if (ret)
+ return dev_err_probe(dev, ret, "ACPI probe failed\n");
+
+ ret = aw88399_hda_init(aw88399);
+ if (ret)
+ return dev_err_probe(dev, ret, "Chip initialization failed\n");
+
+ /* Enable runtime PM */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = component_add(dev, &aw88399_hda_comp_ops);
+ if (ret) {
+ pm_runtime_disable(dev);
+ return dev_err_probe(dev, ret, "Failed to register component\n");
+ }
+
+ dev_info(dev, "AW88399 HDA side codec registered successfully\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_probe, "SND_HDA_SCODEC_AW88399");
+
+void aw88399_hda_remove(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+ pm_runtime_disable(dev);
+
+ if (aw88399->aw_dev)
+ aw88399_stop(aw88399->aw_dev);
+
+ component_del(dev, &aw88399_hda_comp_ops);
+
+ dev_dbg(aw88399->dev, "AW88399 HDA side codec removed\n");
+}
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_remove, "SND_HDA_SCODEC_AW88399");
+
+static int aw88399_hda_runtime_suspend(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+ dev_dbg(aw88399->dev, "Runtime suspend\n");
+
+ if (aw88399->aw_dev && aw88399->playing)
+ aw88399_stop(aw88399->aw_dev);
+
+ return 0;
+}
+
+static int aw88399_hda_runtime_resume(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+ dev_dbg(aw88399->dev, "Runtime resume\n");
+
+ if (aw88399->core && aw88399->aw_dev && aw88399->playing)
+ aw88399_start(aw88399->core, AW88399_SYNC_START);
+
+ return 0;
+}
+
+static int aw88399_hda_system_suspend(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(aw88399->dev, "System suspend\n");
+
+ if (aw88399->aw_dev && aw88399->playing)
+ aw88399_stop(aw88399->aw_dev);
+
+ if (aw88399->core)
+ aw88399->core->fw_needs_reload = true;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ dev_err(aw88399->dev, "Runtime force suspend failed: %d\n", ret);
+
+ return ret;
+}
+
+static int aw88399_hda_system_resume(struct device *dev)
+{
+ struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+ int ret;
+
+ dev_dbg(aw88399->dev, "System resume\n");
+
+ if (aw88399->aw_dev)
+ aw88399_hw_reset(aw88399->core);
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ dev_err(aw88399->dev, "Runtime force resume failed: %d\n", ret);
+
+ return ret;
+}
+
+const struct dev_pm_ops aw88399_hda_pm_ops = {
+ RUNTIME_PM_OPS(aw88399_hda_runtime_suspend, aw88399_hda_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(aw88399_hda_system_suspend, aw88399_hda_system_resume)
+};
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_pm_ops, "SND_HDA_SCODEC_AW88399");
+
+MODULE_DESCRIPTION("AW88399 HDA driver");
+MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
+MODULE_AUTHOR("Marco Giunta <marco_giunta@outlook.it>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("aw88399_acf.bin");
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.h b/sound/hda/codecs/side-codecs/aw88399_hda.h
new file mode 100644
index 000000000000..ca0aa5279298
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * AW88399 HDA side codec driver
+ */
+
+#ifndef __AW88399_HDA_H__
+#define __AW88399_HDA_H__
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <sound/aw88399.h>
+
+struct aw88399;
+struct aw_device;
+
+struct aw88399_hda {
+ struct device *dev;
+ struct regmap *regmap;
+ struct gpio_desc *reset_gpio;
+ struct aw_device *aw_dev;
+ struct aw88399 *core;
+ bool bsts_unreliable;
+
+ const char *acpi_subsystem_id;
+ int index;
+ int channel;
+
+ bool playing;
+};
+
+int aw88399_hda_probe(struct device *dev, struct regmap *regmap);
+void aw88399_hda_remove(struct device *dev);
+
+extern const struct dev_pm_ops aw88399_hda_pm_ops;
+
+#endif /* __AW88399_HDA_H__ */
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c
new file mode 100644
index 000000000000..186e13adbc6c
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// AW88399 HDA I2C driver
+//
+// Based on cs35l41_hda_i2c.c
+//
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "aw88399_hda.h"
+
+static int aw88399_hda_i2c_probe(struct i2c_client *clt)
+{
+ if (!strstr(dev_name(&clt->dev), "AWDZ8399"))
+ return -ENODEV;
+
+ return aw88399_hda_probe(&clt->dev,
+ devm_regmap_init_i2c(clt, &aw88399_remap_config));
+}
+
+static void aw88399_hda_i2c_remove(struct i2c_client *clt)
+{
+ aw88399_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id aw88399_hda_i2c_id[] = {
+ { .name = "aw88399-hda" },
+ { }
+};
+
+static const struct acpi_device_id aw88399_acpi_hda_match[] = {
+ { "AWDZ8399", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, aw88399_acpi_hda_match);
+
+static struct i2c_driver aw88399_hda_i2c_driver = {
+ .driver = {
+ .name = "aw88399-hda",
+ .acpi_match_table = aw88399_acpi_hda_match,
+ .pm = &aw88399_hda_pm_ops,
+ },
+ .probe = aw88399_hda_i2c_probe,
+ .remove = aw88399_hda_i2c_remove,
+ .id_table = aw88399_hda_i2c_id,
+};
+module_i2c_driver(aw88399_hda_i2c_driver);
+
+MODULE_DESCRIPTION("HDA AW88399 I2C driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_AW88399");
+MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
index 237059ef22f5..62296be45c55 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda.c
@@ -170,6 +170,7 @@ static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
char *s, c;
int ret = 0;
+ *firmware = NULL;
if (spkid > -1 && ssid && amp_name)
*filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART,
dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
@@ -528,8 +529,8 @@ static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct
static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename)
{
- const struct firmware *tuning_param_file = NULL;
- char *tuning_param_filename = NULL;
+ const struct firmware *tuning_param_file __free(firmware) = NULL;
+ char *tuning_param_filename __free(kfree) = NULL;
int ret;
ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file,
@@ -548,19 +549,16 @@ static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_
cs35l41_set_default_tuning_params(cs35l41);
}
- release_firmware(tuning_param_file);
- kfree(tuning_param_filename);
-
return ret;
}
static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
{
- const struct firmware *coeff_firmware = NULL;
- const struct firmware *wmfw_firmware = NULL;
+ const struct firmware *coeff_firmware __free(firmware) = NULL;
+ const struct firmware *wmfw_firmware __free(firmware) = NULL;
struct cs_dsp *dsp = &cs35l41->cs_dsp;
- char *coeff_filename = NULL;
- char *wmfw_filename = NULL;
+ char *coeff_filename __free(kfree) = NULL;
+ char *wmfw_filename __free(kfree) = NULL;
int ret;
if (!cs35l41->halo_initialized) {
@@ -592,20 +590,13 @@ static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
cs35l41_hda_fw_ids[cs35l41->firmware_type]);
- if (ret)
- goto err;
-
- cs35l41_hda_apply_calibration(cs35l41);
-
-err:
- if (ret)
+ if (ret) {
cs35l41_set_default_tuning_params(cs35l41);
- release_firmware(wmfw_firmware);
- release_firmware(coeff_firmware);
- kfree(wmfw_filename);
- kfree(coeff_filename);
+ return ret;
+ }
- return ret;
+ cs35l41_hda_apply_calibration(cs35l41);
+ return 0;
}
static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
@@ -1924,7 +1915,6 @@ err:
static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
{
struct acpi_device *adev;
- struct device *physdev;
struct spi_device *spi;
const char *sub;
int ret;
@@ -1936,7 +1926,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
}
cs35l41->dacpi = adev;
- physdev = get_device(acpi_get_first_physical_node(adev));
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
if (!physdev) {
acpi_dev_put(adev);
return -ENODEV;
@@ -1954,13 +1945,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
}
ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id);
- if (ret) {
- put_device(physdev);
+ if (ret)
return ret;
- }
out:
- put_device(physdev);
-
cs35l41->bypass_fw = false;
if (cs35l41->control_bus == SPI) {
spi = to_spi_device(cs35l41->dev);
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
index 78c2cf387a00..bc207ab5b020 100644
--- a/sound/hda/codecs/side-codecs/cs35l56_hda.c
+++ b/sound/hda/codecs/side-codecs/cs35l56_hda.c
@@ -527,18 +527,6 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
base_name, NULL, NULL, "bin");
}
-static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
- char *wmfw_filename,
- const struct firmware *coeff_firmware,
- char *coeff_filename)
-{
- release_firmware(wmfw_firmware);
- kfree(wmfw_filename);
-
- release_firmware(coeff_firmware);
- kfree(coeff_filename);
-}
-
static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
{
int ret;
@@ -561,10 +549,10 @@ static int cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
{
- const struct firmware *coeff_firmware = NULL;
- const struct firmware *wmfw_firmware = NULL;
- char *coeff_filename = NULL;
- char *wmfw_filename = NULL;
+ const struct firmware *coeff_firmware __free(firmware) = NULL;
+ const struct firmware *wmfw_firmware __free(firmware) = NULL;
+ char *coeff_filename __free(kfree) = NULL;
+ char *wmfw_filename __free(kfree) = NULL;
unsigned int preloaded_fw_ver;
bool firmware_missing;
int ret;
@@ -606,14 +594,14 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
if (firmware_missing) {
if (!wmfw_firmware) {
dev_err(cs35l56->base.dev, ".%s file required but not found\n", "wmfw");
- goto err_fw_release;
+ return;
} else if (!coeff_firmware) {
dev_err(cs35l56->base.dev, ".%s file required but not found\n", "bin");
- goto err_fw_release;
+ return;
}
}
- mutex_lock(&cs35l56->base.irq_lock);
+ guard(mutex)(&cs35l56->base.irq_lock);
/*
* If the firmware hasn't been patched it must be shutdown before
@@ -624,14 +612,14 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
ret = cs35l56_firmware_shutdown(&cs35l56->base);
if (ret)
- goto err;
+ return;
}
ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
coeff_firmware, coeff_filename, "misc");
if (ret) {
dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
- goto err;
+ return;
}
if (wmfw_filename)
@@ -679,11 +667,6 @@ static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
err_powered_up:
if (!cs35l56->base.fw_patched)
cs_dsp_power_down(&cs35l56->cs_dsp);
-err:
- mutex_unlock(&cs35l56->base.irq_lock);
-err_fw_release:
- cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
- coeff_firmware, coeff_filename);
}
static void cs35l56_hda_dsp_work(struct work_struct *work)
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
index 624db967f17b..5e5f46c9fb6b 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -88,7 +88,6 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
{
struct gpio_desc *speaker_id;
struct acpi_device *adev;
- struct device *physdev;
LIST_HEAD(resources);
const char *sub;
uint32_t subid;
@@ -101,7 +100,8 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
return -ENODEV;
}
- physdev = get_device(acpi_get_first_physical_node(adev));
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
if (ret < 0) {
dev_err(p->dev, "Failed to get ACPI resource.\n");
@@ -151,14 +151,12 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
end_2563:
acpi_dev_free_resource_list(&resources);
strscpy(p->dev_name, hid, sizeof(p->dev_name));
- put_device(physdev);
acpi_dev_put(adev);
return 0;
err:
dev_err(p->dev, "read acpi error, ret: %d\n", ret);
- put_device(physdev);
acpi_dev_put(adev);
return ret;
@@ -173,13 +171,13 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
case HDA_GEN_PCM_ACT_OPEN:
pm_runtime_get_sync(dev);
scoped_guard(mutex, &tas_hda->priv->codec_lock) {
- tasdevice_tuning_switch(tas_hda->priv, 0);
+ tasdevice_tuning_switch(tas_hda->priv, 0, false);
tas_hda->priv->playback_started = true;
}
break;
case HDA_GEN_PCM_ACT_CLOSE:
scoped_guard(mutex, &tas_hda->priv->codec_lock) {
- tasdevice_tuning_switch(tas_hda->priv, 1);
+ tasdevice_tuning_switch(tas_hda->priv, 1, false);
tas_hda->priv->playback_started = false;
}
@@ -722,7 +720,7 @@ static int tas2781_runtime_suspend(struct device *dev)
* Stop the playback if it's unused.
*/
if (tas_hda->priv->playback_started) {
- tasdevice_tuning_switch(tas_hda->priv, 1);
+ tasdevice_tuning_switch(tas_hda->priv, 1, false);
tas_hda->priv->playback_started = false;
}
@@ -752,7 +750,7 @@ static int tas2781_system_suspend(struct device *dev)
/* Shutdown chip before system suspend */
if (tas_hda->priv->playback_started)
- tasdevice_tuning_switch(tas_hda->priv, 1);
+ tasdevice_tuning_switch(tas_hda->priv, 1, false);
/*
* Reset GPIO may be shared, so cannot reset here.
@@ -785,7 +783,7 @@ static int tas2781_system_resume(struct device *dev)
TASDEVICE_BIN_BLK_PRE_POWER_UP);
if (tas_hda->priv->playback_started)
- tasdevice_tuning_switch(tas_hda->priv, 0);
+ tasdevice_tuning_switch(tas_hda->priv, 0, false);
return 0;
}
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
index 271c56a79c32..da71b57a26ee 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
@@ -328,7 +328,6 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
{
struct tasdevice_priv *p = tas_hda->priv;
struct acpi_device *adev;
- struct device *physdev;
u32 values[HDA_MAX_COMPONENTS];
const char *property;
size_t nval;
@@ -341,7 +340,9 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
}
strscpy(p->dev_name, hid, sizeof(p->dev_name));
- physdev = get_device(acpi_get_first_physical_node(adev));
+
+ struct device *physdev __free(put_device) =
+ get_device(acpi_get_first_physical_node(adev));
acpi_dev_put(adev);
if (!physdev)
return -ENODEV;
@@ -381,13 +382,11 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
goto err;
}
}
- put_device(physdev);
return 0;
+
err:
dev_err(p->dev, "read acpi error, ret: %d\n", ret);
- put_device(physdev);
-
return ret;
}
@@ -400,11 +399,11 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
pm_runtime_get_sync(dev);
guard(mutex)(&tas_priv->codec_lock);
if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
- tasdevice_tuning_switch(tas_hda->priv, 0);
+ tasdevice_tuning_switch(tas_hda->priv, 0, false);
} else if (action == HDA_GEN_PCM_ACT_CLOSE) {
guard(mutex)(&tas_priv->codec_lock);
if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
- tasdevice_tuning_switch(tas_priv, 1);
+ tasdevice_tuning_switch(tas_priv, 1, false);
pm_runtime_put_autosuspend(dev);
}
}
@@ -848,7 +847,7 @@ static int tas2781_runtime_suspend(struct device *dev)
if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
&& tas_priv->playback_started)
- tasdevice_tuning_switch(tas_priv, 1);
+ tasdevice_tuning_switch(tas_priv, 1, false);
tas_priv->tasdevice[tas_priv->index].cur_book = -1;
tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
@@ -865,7 +864,7 @@ static int tas2781_runtime_resume(struct device *dev)
if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
&& tas_priv->playback_started)
- tasdevice_tuning_switch(tas_priv, 0);
+ tasdevice_tuning_switch(tas_priv, 0, false);
return 0;
}
@@ -883,7 +882,7 @@ static int tas2781_system_suspend(struct device *dev)
/* Shutdown chip before system suspend */
if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
&& tas_priv->playback_started)
- tasdevice_tuning_switch(tas_priv, 1);
+ tasdevice_tuning_switch(tas_priv, 1, false);
return 0;
}
@@ -918,7 +917,7 @@ static int tas2781_system_resume(struct device *dev)
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
if (tas_priv->playback_started)
- tasdevice_tuning_switch(tas_priv, 0);
+ tasdevice_tuning_switch(tas_priv, 0, false);
}
return ret;
diff --git a/sound/hda/common/auto_parser.c b/sound/hda/common/auto_parser.c
index 5bc95d3116ff..b3f16f616396 100644
--- a/sound/hda/common/auto_parser.c
+++ b/sound/hda/common/auto_parser.c
@@ -601,9 +601,9 @@ static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
return -1;
}
-/* get a unique suffix or an index number */
+/* get a unique suffix */
static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
- int num_pins, int *indexp)
+ int num_pins)
{
static const char * const channel_sfx[] = {
" Front", " Surround", " CLFE", " Side"
@@ -615,11 +615,8 @@ static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
return NULL;
if (num_pins == 1)
return "";
- if (num_pins > ARRAY_SIZE(channel_sfx)) {
- if (indexp)
- *indexp = i;
+ if (num_pins > ARRAY_SIZE(channel_sfx))
return "";
- }
return channel_sfx[i];
}
@@ -638,27 +635,9 @@ static const char *check_output_pfx(struct hda_codec *codec, hda_nid_t nid)
return "";
}
-static int get_hp_label_index(struct hda_codec *codec, hda_nid_t nid,
- const hda_nid_t *pins, int num_pins)
-{
- int i, j, idx = 0;
-
- const char *pfx = check_output_pfx(codec, nid);
-
- i = find_idx_in_nid_list(nid, pins, num_pins);
- if (i < 0)
- return -1;
- for (j = 0; j < i; j++)
- if (pfx == check_output_pfx(codec, pins[j]))
- idx++;
-
- return idx;
-}
-
static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
- const char *name, char *label, int maxlen,
- int *indexp)
+ const char *name, char *label, int maxlen)
{
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int attr = snd_hda_get_input_pin_attr(def_conf);
@@ -671,19 +650,11 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
if (cfg) {
/* try to give a unique suffix if needed */
- sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
- indexp);
+ sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs);
+ if (!sfx)
+ sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs);
if (!sfx)
- sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
- indexp);
- if (!sfx) {
- /* don't add channel suffix for Headphone controls */
- int idx = get_hp_label_index(codec, nid, cfg->hp_pins,
- cfg->hp_outs);
- if (idx >= 0 && indexp)
- *indexp = idx;
sfx = "";
- }
}
snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
return 1;
@@ -699,7 +670,6 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
* @cfg: the parsed pin configuration
* @label: the string buffer to store
* @maxlen: the max length of string buffer (including termination)
- * @indexp: the pointer to return the index number (for multiple ctls)
*
* Get a label for the given pin. This function works for both input and
* output pins. When @cfg is given as non-NULL, the function tries to get
@@ -708,47 +678,33 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
* This function tries to give a unique label string for the pin as much as
* possible. For example, when the multiple line-outs are present, it adds
* the channel suffix like "Front", "Surround", etc (only when @cfg is given).
- * If no unique name with a suffix is available and @indexp is non-NULL, the
- * index number is stored in the pointer.
*/
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
- char *label, int maxlen, int *indexp)
+ char *label, int maxlen)
{
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
const char *name = NULL;
int i;
bool hdmi;
- if (indexp)
- *indexp = 0;
if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
return 0;
switch (get_defcfg_device(def_conf)) {
case AC_JACK_LINE_OUT:
return fill_audio_out_name(codec, nid, cfg, "Line Out",
- label, maxlen, indexp);
+ label, maxlen);
case AC_JACK_SPEAKER:
return fill_audio_out_name(codec, nid, cfg, "Speaker",
- label, maxlen, indexp);
+ label, maxlen);
case AC_JACK_HP_OUT:
return fill_audio_out_name(codec, nid, cfg, "Headphone",
- label, maxlen, indexp);
+ label, maxlen);
case AC_JACK_SPDIF_OUT:
case AC_JACK_DIG_OTHER_OUT:
hdmi = is_hdmi_cfg(def_conf);
name = hdmi ? "HDMI" : "SPDIF";
- if (cfg && indexp)
- for (i = 0; i < cfg->dig_outs; i++) {
- hda_nid_t pin = cfg->dig_out_pins[i];
- unsigned int c;
- if (pin == nid)
- break;
- c = snd_hda_codec_get_pincfg(codec, pin);
- if (hdmi == is_hdmi_cfg(c))
- (*indexp)++;
- }
break;
default:
if (cfg) {
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index ef533770179b..7d17d773cfbf 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -39,6 +39,12 @@ static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec,
int err;
CLASS(snd_hda_power_pm, pm)(codec);
+ if (pm.err < 0 && !bus->core.chip_init) {
+ codec_warn(codec,
+ "Failed to send cmd 0x%x ret=[%d], hda control stopped\n",
+ cmd, pm.err);
+ return pm.err;
+ }
guard(mutex)(&bus->core.cmd_mutex);
if (flags & HDA_RW_NO_RESPONSE_FALLBACK)
bus->no_response_fallback = 1;
@@ -2967,8 +2973,11 @@ static void hda_codec_pm_complete(struct device *dev)
dev->power.power_state = PMSG_RESUME;
if (pm_runtime_suspended(dev) && (codec->jackpoll_interval ||
- hda_codec_need_resume(codec) || codec->forced_resume))
+ hda_codec_need_resume(codec) || codec->forced_resume ||
+ codec->acomp_requested_resume)) {
+ codec->acomp_requested_resume = 0;
pm_request_resume(dev);
+ }
}
static int hda_codec_pm_suspend(struct device *dev)
@@ -3370,7 +3379,7 @@ 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 == (__force snd_ctl_elem_iface_t)-1)
+ if (knew->iface == -1)
continue; /* skip this codec private value */
for (;;) {
kctl = snd_ctl_new1(knew, codec);
diff --git a/sound/hda/common/hda_auto_parser.h b/sound/hda/common/hda_auto_parser.h
index 87af3d8c02f7..3c5f3ad40074 100644
--- a/sound/hda/common/hda_auto_parser.h
+++ b/sound/hda/common/hda_auto_parser.h
@@ -46,7 +46,7 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec,
int input);
int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
const struct auto_pin_cfg *cfg,
- char *label, int maxlen, int *indexp);
+ char *label, int maxlen);
enum {
INPUT_PIN_ATTR_UNUSED, /* pin not connected */
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index 98b2c4acebc2..947a3152fdb5 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -723,4 +723,11 @@ void snd_hda_codec_display_power(struct hda_codec *codec, bool enable);
#define codec_dbg(codec, fmt, args...) \
dev_dbg(hda_codec_dev(codec), fmt, ##args)
+/* append a suffix string safely; equivalent with strlcat() */
+static inline void hda_append_suffix(char *str, const char *suffix, size_t size)
+{
+ size_t len = strnlen(str, size);
+ strscpy(str + len, suffix, size - len);
+}
+
#endif /* __SOUND_HDA_LOCAL_H */
diff --git a/sound/hda/common/jack.c b/sound/hda/common/jack.c
index e0a5cc38540b..1d6b0f0e6f27 100644
--- a/sound/hda/common/jack.c
+++ b/sound/hda/common/jack.c
@@ -612,10 +612,10 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
if (base_name)
strscpy(name, base_name, sizeof(name));
else
- snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL);
+ snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name));
if (phantom_jack)
/* Example final name: "Internal Mic Phantom Jack" */
- strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
+ hda_append_suffix(name, " Phantom", sizeof(name));
err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL);
if (err < 0)
return err;
diff --git a/sound/hda/common/proc.c b/sound/hda/common/proc.c
index c83796b13d3d..3dabdb418c7b 100644
--- a/sound/hda/common/proc.c
+++ b/sound/hda/common/proc.c
@@ -624,7 +624,7 @@ static void print_conn_list(struct snd_info_buffer *buffer,
/* Get Cache connections info */
cache_len = snd_hda_get_conn_list(codec, nid, &list);
if (cache_len >= 0 && (cache_len != conn_len ||
- memcmp(list, conn, conn_len) != 0)) {
+ memcmp(list, conn, conn_len * sizeof(*conn)) != 0)) {
snd_iprintf(buffer, " In-driver Connection: %d\n", cache_len);
if (cache_len > 0) {
snd_iprintf(buffer, " ");
diff --git a/sound/hda/controllers/Kconfig b/sound/hda/controllers/Kconfig
index 5d6a77e68588..26ca69b09a9c 100644
--- a/sound/hda/controllers/Kconfig
+++ b/sound/hda/controllers/Kconfig
@@ -33,6 +33,7 @@ config SND_HDA_TEGRA
config SND_HDA_CIX_IPBLOQ
tristate "CIX IPBLOQ HD Audio"
depends on ARCH_CIX || COMPILE_TEST
+ depends on ARCH_DMA_ADDR_T_64BIT
select SND_HDA
select SND_HDA_ALIGNED_MMIO
help
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
index 28c55c5a2d2e..24015c73a67f 100644
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -100,6 +100,8 @@ enum {
#define ATIHDMI_NUM_CAPTURE 0
#define ATIHDMI_NUM_PLAYBACK 8
+/* Hygon HD Audio controller */
+#define PCI_DEVICE_ID_HYGON_18H_M05H_HDA 0x14a9
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
@@ -241,6 +243,7 @@ enum {
AZX_DRIVER_ZHAOXIN,
AZX_DRIVER_ZHAOXINHDMI,
AZX_DRIVER_LOONGSON,
+ AZX_DRIVER_HYGON,
AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */
};
@@ -360,6 +363,7 @@ static const char * const driver_short_names[] = {
[AZX_DRIVER_ZHAOXIN] = "HDA Zhaoxin",
[AZX_DRIVER_ZHAOXINHDMI] = "HDA Zhaoxin HDMI",
[AZX_DRIVER_LOONGSON] = "HDA Loongson",
+ [AZX_DRIVER_HYGON] = "HDA Hygon",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
@@ -1926,6 +1930,10 @@ static int azx_first_init(struct azx *chip)
if (chip->driver_type == AZX_DRIVER_ZHAOXINHDMI)
bus->polling_mode = 1;
+ if (chip->driver_type == AZX_DRIVER_HYGON &&
+ chip->pci->device == PCI_DEVICE_ID_HYGON_18H_M05H_HDA)
+ bus->access_sdnctl_in_dword = 1;
+
bus->remap_addr = pcim_iomap_region(pci, 0, "ICH HD audio");
if (IS_ERR(bus->remap_addr))
return PTR_ERR(bus->remap_addr);
@@ -2189,6 +2197,15 @@ static int azx_probe(struct pci_dev *pci,
dev_warn(&pci->dev, "dmic_detect option is deprecated, pass snd-intel-dspcfg.dsp_driver=1 option instead\n");
}
+ /* A sanity check against wild device binding;
+ * here the range 0x200 is enough for the registers used at probe,
+ * but it doesn't mean covering all HD-audio registers
+ */
+ if (pci_resource_len(pci, 0) < 0x200) {
+ dev_err(&pci->dev, "Too small PCI BAR0\n");
+ return -EINVAL;
+ }
+
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
@@ -2381,7 +2398,7 @@ static int azx_probe_continue(struct azx *chip)
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (patch[dev] && *patch[dev]) {
- const struct firmware *fw = NULL;
+ const struct firmware *fw __free(firmware) = NULL;
dev_info(&pci->dev, "Applying patch firmware '%s'\n",
patch[dev]);
@@ -2390,7 +2407,6 @@ static int azx_probe_continue(struct azx *chip)
"Cannot load firmware, continue without patching\n");
} else {
err = snd_hda_load_patch(&chip->bus, fw->size, fw->data);
- release_firmware(fw);
if (err < 0)
goto out_free;
}
@@ -2838,6 +2854,11 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
.driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
+ /* Hygon HDAudio */
+ { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_HYGON_18H_M05H_HDA),
+ .driver_data = AZX_DRIVER_HYGON | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_NO_MSI },
+ /* Lisuan HD-audio */
+ { PCI_DEVICE(0x4c54, 0x5010), .driver_data = AZX_DRIVER_GENERIC },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/hda/core/controller.c b/sound/hda/core/controller.c
index 69e11d62bbfa..78855ac357c6 100644
--- a/sound/hda/core/controller.c
+++ b/sound/hda/core/controller.c
@@ -511,7 +511,10 @@ void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus)
{
unsigned long timeout;
- snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
+ else
+ snd_hdac_chip_updateb(bus, GCTL, AZX_GCTL_RESET, AZX_GCTL_RESET);
timeout = jiffies + msecs_to_jiffies(100);
while (!snd_hdac_chip_readb(bus, GCTL) && time_before(jiffies, timeout))
@@ -576,7 +579,10 @@ static void azx_int_disable(struct hdac_bus *bus)
/* disable interrupts in stream descriptor */
list_for_each_entry(azx_dev, &bus->stream_list, list)
- snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_INT_MASK, 0);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0);
/* disable SIE for all streams & disable controller CIE and GIE */
snd_hdac_chip_writel(bus, INTCTL, 0);
@@ -682,6 +688,11 @@ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
sd_status = snd_hdac_stream_readb(azx_dev, SD_STS);
snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK);
handled |= 1 << azx_dev->index;
+ if (sd_status & (SD_INT_FIFO_ERR | SD_INT_DESC_ERR)) {
+ dev_warn_ratelimited(bus->dev,
+ "stream %u dma error: 0x%02x\n",
+ azx_dev->index, sd_status);
+ }
if ((!azx_dev->substream && !azx_dev->cstream) ||
!azx_dev->running || !(sd_status & SD_INT_COMPLETE))
continue;
@@ -713,7 +724,7 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
BDL_SIZE, &s->bdl);
num_streams++;
if (err < 0)
- return -ENOMEM;
+ goto error_bdl;
}
if (WARN_ON(!num_streams))
@@ -722,12 +733,24 @@ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
err = snd_dma_alloc_pages(dma_type, bus->dev,
num_streams * 8, &bus->posbuf);
if (err < 0)
- return -ENOMEM;
+ goto error_bdl;
list_for_each_entry(s, &bus->stream_list, list)
s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);
/* single page (at least 4096 bytes) must suffice for both ringbuffes */
- return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
+ err = snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
+ if (err < 0)
+ goto error_posbuf;
+ return 0;
+
+error_posbuf:
+ snd_dma_free_pages(&bus->posbuf);
+error_bdl:
+ list_for_each_entry(s, &bus->stream_list, list) {
+ if (s->bdl.area)
+ snd_dma_free_pages(&s->bdl);
+ }
+ return -ENOMEM;
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages);
diff --git a/sound/hda/core/device.c b/sound/hda/core/device.c
index 160c8d0453b0..776d629ba252 100644
--- a/sound/hda/core/device.c
+++ b/sound/hda/core/device.c
@@ -663,6 +663,7 @@ static const struct hda_vendor_id hda_vendor_ids[] = {
{ 0x1af4, "QEMU" },
{ 0x1fa8, "Senarytech" },
{ 0x434d, "C-Media" },
+ { 0x4c54, "Lisuan" },
{ 0x8086, "Intel" },
{ 0x8384, "SigmaTel" },
{} /* terminator */
@@ -765,7 +766,7 @@ unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subfor
params_set_format(&params, snd_hdac_format_normalize(format));
snd_mask_set(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT),
- (__force unsigned int)subformat);
+ subformat);
bits = snd_pcm_hw_params_bits(&params);
if (maxbits)
diff --git a/sound/hda/core/ext/stream.c b/sound/hda/core/ext/stream.c
index 4c7506d49f55..517bd151fcc3 100644
--- a/sound/hda/core/ext/stream.c
+++ b/sound/hda/core/ext/stream.c
@@ -210,8 +210,8 @@ void snd_hdac_ext_stream_reset(struct hdac_ext_stream *hext_stream)
break;
udelay(3);
} while (--timeout);
- val &= ~AZX_PPLCCTL_STRST;
- writel(val, hext_stream->pplc_addr + AZX_REG_PPLCCTL);
+ snd_hdac_updatel(hext_stream->pplc_addr, AZX_REG_PPLCCTL,
+ AZX_PPLCCTL_STRST, 0);
udelay(3);
timeout = 50;
diff --git a/sound/hda/core/hda_bus_type.c b/sound/hda/core/hda_bus_type.c
index a4afd41b6f84..e1e986a8b5b5 100644
--- a/sound/hda/core/hda_bus_type.c
+++ b/sound/hda/core/hda_bus_type.c
@@ -39,10 +39,7 @@ EXPORT_SYMBOL_GPL(hdac_get_device_id);
static int hdac_codec_match(struct hdac_device *dev, const struct hdac_driver *drv)
{
- if (hdac_get_device_id(dev, drv))
- return 1;
- else
- return 0;
+ return !!hdac_get_device_id(dev, drv);
}
static int hda_bus_match(struct device *dev, const struct device_driver *drv)
@@ -59,9 +56,7 @@ static int hda_bus_match(struct device *dev, const struct device_driver *drv)
*/
if (hdrv->match)
return hdrv->match(hdev, hdrv);
- else
- return hdac_codec_match(hdev, hdrv);
- return 1;
+ return hdac_codec_match(hdev, hdrv);
}
static int hda_uevent(const struct device *dev, struct kobj_uevent_env *env)
diff --git a/sound/hda/core/stream.c b/sound/hda/core/stream.c
index b471a038b314..0091c4ef6486 100644
--- a/sound/hda/core/stream.c
+++ b/sound/hda/core/stream.c
@@ -146,8 +146,12 @@ void snd_hdac_stream_start(struct hdac_stream *azx_dev)
stripe_ctl = snd_hdac_get_stream_stripe_ctl(bus, azx_dev->substream);
else
stripe_ctl = 0;
- snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
- stripe_ctl);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
+ stripe_ctl);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK,
+ stripe_ctl);
}
/* set DMA start and interrupt mask */
if (bus->access_sdnctl_in_dword)
@@ -166,11 +170,22 @@ EXPORT_SYMBOL_GPL(snd_hdac_stream_start);
*/
static void snd_hdac_stream_clear(struct hdac_stream *azx_dev)
{
- snd_hdac_stream_updateb(azx_dev, SD_CTL,
- SD_CTL_DMA_START | SD_INT_MASK, 0);
- snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
- if (azx_dev->stripe)
- snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
+ struct hdac_bus *bus = azx_dev->bus;
+
+ if (bus->access_sdnctl_in_dword) {
+ snd_hdac_stream_updatel(azx_dev, SD_CTL,
+ SD_CTL_DMA_START | SD_INT_MASK, 0);
+ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+ if (azx_dev->stripe)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
+ } else {
+ snd_hdac_stream_updateb(azx_dev, SD_CTL,
+ SD_CTL_DMA_START | SD_INT_MASK, 0);
+ snd_hdac_stream_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
+ if (azx_dev->stripe)
+ snd_hdac_stream_updateb(azx_dev, SD_CTL_3B, SD_CTL_STRIPE_MASK, 0);
+ }
+
azx_dev->running = false;
}
@@ -225,12 +240,16 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
{
unsigned char val;
int dma_run_state;
+ struct hdac_bus *bus = azx_dev->bus;
snd_hdac_stream_clear(azx_dev);
dma_run_state = snd_hdac_stream_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START;
- snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, 0, SD_CTL_STREAM_RESET);
/* wait for hardware to report that the stream entered reset */
snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, (val & SD_CTL_STREAM_RESET), 3, 300);
@@ -238,7 +257,10 @@ void snd_hdac_stream_reset(struct hdac_stream *azx_dev)
if (azx_dev->bus->dma_stop_delay && dma_run_state)
udelay(azx_dev->bus->dma_stop_delay);
- snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
+ if (bus->access_sdnctl_in_dword)
+ snd_hdac_stream_updatel(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
+ else
+ snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_CTL_STREAM_RESET, 0);
/* wait for hardware to report that the stream is out of reset */
snd_hdac_stream_readb_poll(azx_dev, SD_CTL, val, !(val & SD_CTL_STREAM_RESET), 3, 300);
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
index 0d5f4461a7bc..eac6e22362cc 100644
--- a/sound/isa/msnd/msnd_pinnacle.c
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -367,7 +367,8 @@ static int snd_msnd_init_sma(struct snd_msnd *chip)
static int upload_dsp_code(struct snd_card *card)
{
struct snd_msnd *chip = card->private_data;
- const struct firmware *init_fw = NULL, *perm_fw = NULL;
+ const struct firmware *init_fw __free(firmware) = NULL;
+ const struct firmware *perm_fw __free(firmware) = NULL;
int err;
outb(HPBLKSEL_0, chip->io + HP_BLKS);
@@ -375,28 +376,21 @@ static int upload_dsp_code(struct snd_card *card)
err = request_firmware(&init_fw, INITCODEFILE, card->dev);
if (err < 0) {
dev_err(card->dev, LOGNAME ": Error loading " INITCODEFILE);
- goto cleanup1;
+ return err;
}
err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
if (err < 0) {
dev_err(card->dev, LOGNAME ": Error loading " PERMCODEFILE);
- goto cleanup;
+ return err;
}
memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
dev_warn(card->dev, LOGNAME ": Error uploading to DSP\n");
- err = -ENODEV;
- goto cleanup;
+ return -ENODEV;
}
dev_info(card->dev, LOGNAME ": DSP firmware uploaded\n");
- err = 0;
-
-cleanup:
- release_firmware(perm_fw);
-cleanup1:
- release_firmware(init_fw);
- return err;
+ return 0;
}
#ifdef MSND_CLASSIC
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index ce8a59650e38..9b615b588cdf 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -526,7 +526,7 @@ _release_dma:
static int sscape_upload_bootblock(struct snd_card *card)
{
struct soundscape *sscape = get_card_soundscape(card);
- const struct firmware *init_fw = NULL;
+ const struct firmware *init_fw __free(firmware) = NULL;
int data = 0;
int ret;
@@ -537,8 +537,6 @@ static int sscape_upload_bootblock(struct snd_card *card)
}
ret = upload_dma_data(sscape, init_fw->data, init_fw->size);
- release_firmware(init_fw);
-
guard(spinlock_irqsave)(&sscape->lock);
if (ret == 0)
data = host_read_ctrl_unsafe(sscape->io_base, 100);
@@ -562,7 +560,7 @@ static int sscape_upload_bootblock(struct snd_card *card)
static int sscape_upload_microcode(struct snd_card *card, int version)
{
struct soundscape *sscape = get_card_soundscape(card);
- const struct firmware *init_fw = NULL;
+ const struct firmware *init_fw __free(firmware) = NULL;
char name[14];
int err;
@@ -579,8 +577,6 @@ static int sscape_upload_microcode(struct snd_card *card, int version)
dev_info(card->dev, "sscape: MIDI firmware loaded %zu KBs\n",
init_fw->size >> 10);
- release_firmware(init_fw);
-
return err;
}
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index beca35ce04f3..6d95ea338ea9 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -232,41 +232,32 @@ snd_wavefront_fx_start (snd_wavefront_t *dev)
{
unsigned int i;
int err;
- const struct firmware *firmware = NULL;
+ const struct firmware *firmware __free(firmware) = NULL;
if (dev->fx_initialized)
return 0;
err = request_firmware(&firmware, "yamaha/yss225_registers.bin",
dev->card->dev);
- if (err < 0) {
- err = -1;
- goto out;
- }
+ if (err < 0)
+ return -1;
for (i = 0; i + 1 < firmware->size; i += 2) {
if (firmware->data[i] >= 8 && firmware->data[i] < 16) {
outb(firmware->data[i + 1],
dev->base + firmware->data[i]);
} else if (firmware->data[i] == WAIT_IDLE) {
- if (!wavefront_fx_idle(dev)) {
- err = -1;
- goto out;
- }
+ if (!wavefront_fx_idle(dev))
+ return -1;
} else {
dev_err(dev->card->dev,
"invalid address in register data\n");
- err = -1;
- goto out;
+ return -1;
}
}
dev->fx_initialized = 1;
- err = 0;
-
-out:
- release_firmware(firmware);
- return err;
+ return 0;
}
MODULE_FIRMWARE("yamaha/yss225_registers.bin");
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 2f57a6795d22..0c8f5cf26455 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -2053,7 +2053,7 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
const unsigned char *buf;
int len, err;
int section_cnt_downloaded = 0;
- const struct firmware *firmware;
+ const struct firmware *firmware __free(firmware) = NULL;
err = request_firmware(&firmware, path, dev->card->dev);
if (err < 0) {
@@ -2108,11 +2108,9 @@ wavefront_download_firmware (snd_wavefront_t *dev, char *path)
section_cnt_downloaded++;
}
- release_firmware(firmware);
return 0;
failure:
- release_firmware(firmware);
dev_err(dev->card->dev, "firmware download failed!!!\n");
return 1;
}
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 4dbc79899c09..b78e96caef9d 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -280,7 +280,7 @@ 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)
+#define INVALID_FORMAT -1
static const snd_pcm_format_t hpi_to_alsa_formats[] = {
INVALID_FORMAT, /* INVALID */
diff --git a/sound/pci/asihpi/hpi6000.c b/sound/pci/asihpi/hpi6000.c
index c8d1518ee3e7..fd7fe9dba0b8 100644
--- a/sound/pci/asihpi/hpi6000.c
+++ b/sound/pci/asihpi/hpi6000.c
@@ -537,6 +537,11 @@ static short create_adapter_obj(struct hpi_adapter_obj *pao,
hr1.size = sizeof(hr1);
error = hpi6000_message_response_sequence(pao, 0, &hm, &hr0);
+ if (error) {
+ HPI_DEBUG_LOG(ERROR, "message transport error %d\n",
+ error);
+ return error;
+ }
if (hr0.error) {
HPI_DEBUG_LOG(DEBUG, "message error %d\n", hr0.error);
return hr0.error;
diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c
index b1b5a131f626..6d2c27e47d07 100644
--- a/sound/pci/asihpi/hpidspcd.c
+++ b/sound/pci/asihpi/hpidspcd.c
@@ -23,7 +23,7 @@ struct dsp_code_private {
short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
u32 *os_error_code)
{
- const struct firmware *firmware;
+ const struct firmware *firmware __free(firmware) = NULL;
struct pci_dev *dev = os_data;
struct code_header header;
char fw_name[20];
@@ -37,11 +37,11 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
if (err || !firmware) {
dev_err(&dev->dev, "%d, request_firmware failed for %s\n",
err, fw_name);
- goto error1;
+ goto error;
}
if (firmware->size < sizeof(header)) {
dev_err(&dev->dev, "Header size too small %s\n", fw_name);
- goto error2;
+ goto error;
}
memcpy(&header, firmware->data, sizeof(header));
@@ -51,7 +51,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
dev_err(&dev->dev,
"Invalid firmware header size %d != file %zd\n",
header.size, firmware->size);
- goto error2;
+ goto error;
}
if (HPI_VER_MAJOR(header.version) != HPI_VER_MAJOR(HPI_VER)) {
@@ -59,7 +59,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
dev_err(&dev->dev,
"Incompatible firmware version DSP image %X != Driver %X\n",
header.version, HPI_VER);
- goto error2;
+ goto error;
}
if (header.version != HPI_VER) {
@@ -72,19 +72,17 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code,
dsp_code->pvt = kmalloc_obj(*dsp_code->pvt);
if (!dsp_code->pvt) {
err_ret = HPI_ERROR_MEMORY_ALLOC;
- goto error2;
+ goto error;
}
dsp_code->pvt->dev = dev;
- dsp_code->pvt->firmware = firmware;
+ dsp_code->pvt->firmware = no_free_ptr(firmware);
dsp_code->header = header;
dsp_code->block_length = header.size / sizeof(u32);
dsp_code->word_count = sizeof(header) / sizeof(u32);
return 0;
-error2:
- release_firmware(firmware);
-error1:
+error:
dsp_code->block_length = 0;
return err_ret;
}
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 9de9ae7032b8..ec2da792e1c8 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -385,8 +385,7 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
if (pci_resource_flags(pci_dev, idx) & IORESOURCE_MEM) {
memlen = pci_resource_len(pci_dev, idx);
pci.ap_mem_base[idx] =
- ioremap(pci_resource_start(pci_dev, idx),
- memlen);
+ pcim_iomap(pci_dev, idx, memlen);
if (!pci.ap_mem_base[idx]) {
HPI_DEBUG_LOG(ERROR,
"ioremap failed, aborting\n");
@@ -509,13 +508,6 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
return 0;
err:
- while (--idx >= 0) {
- if (pci.ap_mem_base[idx]) {
- iounmap(pci.ap_mem_base[idx]);
- pci.ap_mem_base[idx] = NULL;
- }
- }
-
if (adapter.p_buffer) {
adapter.buffer_size = 0;
vfree(adapter.p_buffer);
@@ -527,14 +519,11 @@ err:
void asihpi_adapter_remove(struct pci_dev *pci_dev)
{
- int idx;
struct hpi_message hm;
struct hpi_response hr;
struct hpi_adapter *pa;
- struct hpi_pci pci;
pa = pci_get_drvdata(pci_dev);
- pci = pa->adapter->pci;
/* Disable IRQ generation on DSP side */
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
@@ -550,10 +539,6 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
hm.adapter_index = pa->adapter->index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
- /* unmap PCI memory space, mapped during device init. */
- for (idx = 0; idx < HPI_MAX_ADAPTER_MEM_SPACES; ++idx)
- iounmap(pci.ap_mem_base[idx]);
-
if (pa->irq)
free_irq(pa->irq, pa);
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 1c11023184ac..19a6927c079d 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -387,7 +387,7 @@ static int load_firmware(struct snd_cs46xx *chip,
unsigned int nums, fwlen, fwsize;
const __le32 *fwdat;
struct dsp_module_desc *module = NULL;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
char fw_path[32];
sprintf(fw_path, "cs46xx/%s", fw_name);
@@ -395,10 +395,8 @@ static int load_firmware(struct snd_cs46xx *chip,
if (err < 0)
return err;
fwsize = fw->size / 4;
- if (fwsize < 2) {
- err = -EINVAL;
- goto error;
- }
+ if (fwsize < 2)
+ return -EINVAL;
err = -ENOMEM;
module = kzalloc_obj(*module);
@@ -454,14 +452,12 @@ static int load_firmware(struct snd_cs46xx *chip,
}
*module_ret = module;
- release_firmware(fw);
return 0;
error_inval:
err = -EINVAL;
error:
free_module_desc(module);
- release_firmware(fw);
return err;
}
@@ -500,22 +496,18 @@ MODULE_FIRMWARE("cs46xx/ba1");
static int load_firmware(struct snd_cs46xx *chip)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int i, size, err;
err = request_firmware(&fw, "cs46xx/ba1", &chip->pci->dev);
if (err < 0)
return err;
- if (fw->size != sizeof(*chip->ba1)) {
- err = -EINVAL;
- goto error;
- }
+ if (fw->size != sizeof(*chip->ba1))
+ return -EINVAL;
chip->ba1 = vmalloc(sizeof(*chip->ba1));
- if (!chip->ba1) {
- err = -ENOMEM;
- goto error;
- }
+ if (!chip->ba1)
+ return -ENOMEM;
memcpy_le32(chip->ba1, fw->data, sizeof(*chip->ba1));
@@ -524,11 +516,9 @@ static int load_firmware(struct snd_cs46xx *chip)
for (i = 0; i < BA1_MEMORY_COUNT; i++)
size += chip->ba1->memory[i].size;
if (size > BA1_DWORD_SIZE * 4)
- err = -EINVAL;
+ return -EINVAL;
- error:
- release_firmware(fw);
- return err;
+ return 0;
}
static __maybe_unused int snd_cs46xx_download_image(struct snd_cs46xx *chip)
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 08e0556bf161..49cabb2eb2b7 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -990,7 +990,7 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
i < icode->gpr_list_control_count) {
memset(gctl, 0, sizeof(*gctl));
id = &ctl->kcontrol->id;
- gctl->id.iface = (__force int)id->iface;
+ gctl->id.iface = id->iface;
strscpy(gctl->id.name, id->name, sizeof(gctl->id.name));
gctl->id.index = id->index;
gctl->id.device = id->device;
@@ -1156,7 +1156,7 @@ static void
snd_emu10k1_init_mono_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval, int defval_hr)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
if (high_res_gpr_volume) {
@@ -1180,7 +1180,7 @@ static void
snd_emu10k1_init_stereo_control2(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval, int defval_hr)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 2;
if (high_res_gpr_volume) {
@@ -1205,7 +1205,7 @@ static void
snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 1;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
@@ -1218,7 +1218,7 @@ static void
snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
const char *name, int gpr, int defval)
{
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, name);
ctl->vcount = ctl->count = 2;
ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
@@ -1542,7 +1542,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
* Process tone control
*/
ctl = &controls[nctl + 0];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
@@ -1551,7 +1551,7 @@ static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
ctl->value[0] = ctl->value[1] = 20;
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[nctl + 1];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
@@ -2137,7 +2137,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
* Process tone control
*/
ctl = &controls[i + 0];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Bass");
ctl->vcount = 2;
ctl->count = 10;
@@ -2147,7 +2147,7 @@ static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
ctl->tlv = snd_emu10k1_bass_treble_db_scale;
ctl->translation = EMU10K1_GPR_TRANSLATION_BASS;
ctl = &controls[i + 1];
- ctl->id.iface = (__force int)SNDRV_CTL_ELEM_IFACE_MIXER;
+ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(ctl->id.name, "Tone Control - Treble");
ctl->vcount = 2;
ctl->count = 10;
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index d16acf83668a..f4d8402f835f 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -1980,7 +1980,7 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
__maybe_unused unsigned ioport_size;
__maybe_unused unsigned iomem2_size;
struct snd_korg1212 *korg1212 = card->private_data;
- const struct firmware *dsp_code;
+ const struct firmware *dsp_code __free(firmware) = NULL;
err = pcim_enable_device(pci);
if (err < 0)
@@ -2147,10 +2147,8 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
korg1212->dma_dsp = snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV,
dsp_code->size);
- if (!korg1212->dma_dsp) {
- release_firmware(dsp_code);
+ if (!korg1212->dma_dsp)
return -ENOMEM;
- }
K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n",
korg1212->dma_dsp->area, korg1212->dma_dsp->addr, dsp_code->size,
@@ -2158,8 +2156,6 @@ static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci)
memcpy(korg1212->dma_dsp->area, dsp_code->data, dsp_code->size);
- release_firmware(dsp_code);
-
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_RebootCard, 0, 0, 0, 0);
if (rc)
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 439e3ff05fe1..aa8d5bae30d0 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -560,12 +560,11 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
};
char path[32];
-
- const struct firmware *fw_entry;
int i, err;
for (i = 0; i < 3; i++) {
sprintf(path, "mixart/%s", fw_files[i]);
+ const struct firmware *fw_entry __free(firmware) = NULL;
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
dev_err(&mgr->pci->dev,
"miXart: can't load firmware %s\n", path);
@@ -573,7 +572,6 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
}
/* fake hwdep dsp record */
err = mixart_dsp_load(mgr, i, fw_entry);
- release_firmware(fw_entry);
if (err < 0)
return err;
mgr->dsp_loaded |= 1 << i;
diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c
index 249805065f61..54f3950579aa 100644
--- a/sound/pci/pcxhr/pcxhr_hwdep.c
+++ b/sound/pci/pcxhr/pcxhr_hwdep.c
@@ -367,7 +367,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
};
char path[32];
- const struct firmware *fw_entry;
int i, err;
int fw_set = mgr->fw_file_set;
@@ -375,6 +374,7 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
if (!fw_files[fw_set][i])
continue;
sprintf(path, "pcxhr/%s", fw_files[fw_set][i]);
+ const struct firmware *fw_entry __free(firmware) = NULL;
if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
dev_err(&mgr->pci->dev,
"pcxhr: can't load firmware %s\n",
@@ -383,7 +383,6 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr)
}
/* fake hwdep dsp record */
err = pcxhr_dsp_load(mgr, i, fw_entry);
- release_firmware(fw_entry);
if (err < 0)
return err;
mgr->dsp_loaded |= 1 << i;
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index 4be085d27712..55c1b11a2900 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1260,16 +1260,16 @@ static int sis_chip_create(struct snd_card *card,
sis->irq = -1;
sis->ioport = pci_resource_start(pci, 0);
- rc = pcim_request_all_regions(pci, "SiS7019");
+ rc = pcim_request_region(pci, 0, "SiS7019");
if (rc) {
- dev_err(&pci->dev, "unable request regions\n");
+ dev_err(&pci->dev, "unable request I/O region\n");
return rc;
}
- sis->ioaddr = devm_ioremap(&pci->dev, pci_resource_start(pci, 1), 0x4000);
- if (!sis->ioaddr) {
+ sis->ioaddr = pcim_iomap_region(pci, 1, "SiS7019");
+ if (IS_ERR(sis->ioaddr)) {
dev_err(&pci->dev, "unable to remap MMIO, aborting\n");
- return -EIO;
+ return PTR_ERR(sis->ioaddr);
}
rc = sis_alloc_suspend(sis);
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 9b84d3fb9eaf..b32f84ac17cc 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -573,24 +573,18 @@ static inline unsigned int calc_linear_pos(struct via82xx_modem *chip,
viadev->bufsize2, viadev->idx_table[idx].offset,
viadev->idx_table[idx].size, count);
#endif
- if (count && size < count) {
+ if (! count)
+ /* bogus count 0 on the DMA boundary? */
+ res = viadev->idx_table[idx].offset;
+ else
+ /* count register returns full size
+ * when end of buffer is reached
+ */
+ res = viadev->idx_table[idx].offset + size;
+ if (check_invalid_pos(viadev, res)) {
dev_dbg(chip->card->dev,
- "invalid via82xx_cur_ptr, using last valid pointer\n");
+ "invalid via82xx_cur_ptr (2), using last valid pointer\n");
res = viadev->lastpos;
- } else {
- if (! count)
- /* bogus count 0 on the DMA boundary? */
- res = viadev->idx_table[idx].offset;
- else
- /* count register returns full size
- * when end of buffer is reached
- */
- res = viadev->idx_table[idx].offset + size;
- if (check_invalid_pos(viadev, res)) {
- dev_dbg(chip->card->dev,
- "invalid via82xx_cur_ptr (2), using last valid pointer\n");
- res = viadev->lastpos;
- }
}
}
viadev->lastpos = res; /* remember the last position */
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 8196e1bf0416..078fc7fc08f9 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -518,8 +518,9 @@ static const struct snd_kcontrol_new snd_aica_pcmvolume_control = {
static int load_aica_firmware(void)
{
int err;
- const struct firmware *fw_entry;
spu_reset();
+
+ const struct firmware *fw_entry __free(firmware) = NULL;
err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
if (unlikely(err))
return err;
@@ -527,7 +528,6 @@ static int load_aica_firmware(void)
spu_disable();
spu_memload(0, fw_entry->data, fw_entry->size);
spu_enable();
- release_firmware(fw_entry);
return err;
}
diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
index 88e4230d66c3..3021dc498c85 100644
--- a/sound/soc/amd/acp-config.c
+++ b/sound/soc/amd/acp-config.c
@@ -63,6 +63,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook 18 M1807GA"),
},
},
+ {
+ /* HP OmniBook X Flip 14-kc0xxx (Strix Point, ACP 7.2) */
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
+ DMI_MATCH(DMI_BOARD_NAME, "8EA1"),
+ },
+ },
{}
};
@@ -379,5 +386,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[] = {
};
EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sof_machines);
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[] = {
+ {
+ .id = "AMDI1010",
+ .drv_name = "acp7x-dsp",
+ .pdata = &acp_quirk_data,
+ .fw_filename = "sof-acp7x.ri",
+ .sof_tplg_filename = "sof-acp7x.tplg",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp7x_sof_machines);
+
MODULE_DESCRIPTION("AMD ACP Machine Configuration Module");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c
index 6ad70aa0ea83..ee75737202dc 100644
--- a/sound/soc/amd/acp-pcm-dma.c
+++ b/sound/soc/amd/acp-pcm-dma.c
@@ -691,12 +691,10 @@ 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;
+ struct audio_drv_data *irq_data = arg;
void __iomem *acp_mmio;
- struct device *dev = arg;
bool valid_irq = false;
- irq_data = dev_get_drvdata(dev);
acp_mmio = irq_data->acp_mmio;
ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT);
@@ -1291,10 +1289,10 @@ static int acp_audio_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return -ENODEV;
+ return irq;
status = devm_request_irq(&pdev->dev, irq, dma_irq_handler,
- 0, "ACP_IRQ", &pdev->dev);
+ 0, "ACP_IRQ", audio_drv_data);
if (status) {
dev_err(&pdev->dev, "ACP IRQ request failed\n");
return status;
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 283a674c7e2c..bb58a9d34993 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -686,6 +686,10 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
return 0;
}
+static const u64 acp_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.startup = acp_i2s_startup,
.hw_params = acp_i2s_hwparams,
@@ -693,6 +697,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.trigger = acp_i2s_trigger,
.set_fmt = acp_i2s_set_fmt,
.set_tdm_slot = acp_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index ef784cca13f2..01a0aaa60246 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -938,15 +938,10 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai =
snd_soc_card_get_codec_dai(card,
MAX98388_CODEC_DAI);
- int ret;
- ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF);
- if (ret < 0)
- return ret;
-
- return ret;
+ return snd_soc_dai_set_fmt(codec_dai,
+ SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF);
}
static const struct snd_soc_ops acp_max98388_ops = {
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index f83708755ed1..98771323eace 100644
--- a/sound/soc/amd/acp/acp-pci.c
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -118,17 +118,10 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
if (!chip)
return -ENOMEM;
- if (pci_enable_device(pci))
+ if (pcim_enable_device(pci))
return dev_err_probe(&pci->dev, -ENODEV,
"pci_enable_device failed\n");
- ret = pci_request_regions(pci, "AMD ACP3x audio");
- if (ret < 0) {
- dev_err(&pci->dev, "pci_request_regions failed\n");
- ret = -ENOMEM;
- goto disable_pci;
- }
-
pci_set_master(pci);
chip->acp_rev = pci->revision;
@@ -161,24 +154,21 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
break;
default:
dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
- ret = -EINVAL;
- goto release_regions;
+ return -EINVAL;
}
chip->flag = flag;
addr = pci_resource_start(pci, 0);
- chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
- if (!chip->base) {
- ret = -ENOMEM;
- goto release_regions;
- }
+ chip->base = pcim_iomap_region(pci, 0, "AMD ACP3x audio");
+ if (IS_ERR(chip->base))
+ return PTR_ERR(chip->base);
chip->addr = addr;
chip->acp_hw_ops_init(chip);
ret = acp_hw_init(chip);
if (ret)
- goto release_regions;
+ goto de_init;
ret = devm_request_irq(dev, pci->irq, irq_handler,
IRQF_SHARED, "ACP_I2S_IRQ", chip);
@@ -214,10 +204,6 @@ skip_pdev_creation:
de_init:
acp_hw_deinit(chip);
-release_regions:
- pci_release_regions(pci);
-disable_pci:
- pci_disable_device(pci);
return ret;
};
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index e8b6819cc4b4..6eac42bac855 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -432,7 +432,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
if (!soc_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs);
if (ret < 0)
return ret;
@@ -521,15 +521,15 @@ static int mc_probe(struct platform_device *pdev)
dmi_check_system(soc_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
soc_sdw_quirk, quirk_override);
soc_sdw_quirk = quirk_override;
}
- log_quirks(card->dev);
+ log_quirks(&pdev->dev);
ctx->mc_quirk = soc_sdw_quirk;
- dev_dbg(card->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk);
+ dev_dbg(&pdev->dev, "legacy quirk 0x%lx\n", ctx->mc_quirk);
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
for (i = 0; i < ctx->codec_info_list_count; i++)
codec_info_list[i].amp_num = 0;
@@ -546,12 +546,12 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) {
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s mic:acp-dmic cfg-mics:%d",
card->components,
1);
@@ -560,9 +560,9 @@ static int mc_probe(struct platform_device *pdev)
}
/* Register the card */
- ret = devm_snd_soc_register_card(card->dev, card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -580,8 +580,8 @@ static void mc_remove(struct platform_device *pdev)
}
static const struct platform_device_id mc_id_table[] = {
- { "amd_sdw", },
- {}
+ { .name = "amd_sdw" },
+ { }
};
MODULE_DEVICE_TABLE(platform, mc_id_table);
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index a423853f3a97..a9cd1f335167 100644
--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -303,7 +303,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
if (!sof_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_devs);
if (ret < 0)
return ret;
@@ -388,12 +388,12 @@ static int mc_probe(struct platform_device *pdev)
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
sof_sdw_quirk, quirk_override);
sof_sdw_quirk = quirk_override;
}
- log_quirks(card->dev);
+ log_quirks(&pdev->dev);
ctx->mc_quirk = sof_sdw_quirk;
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
@@ -412,15 +412,15 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
/* Register the card */
- ret = devm_snd_soc_register_card(card->dev, card);
+ ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -438,8 +438,8 @@ static void mc_remove(struct platform_device *pdev)
}
static const struct platform_device_id mc_id_table[] = {
- { "amd_sof_sdw", },
- {}
+ { .name = "amd_sof_sdw" },
+ { }
};
MODULE_DEVICE_TABLE(platform, mc_id_table);
diff --git a/sound/soc/amd/acp/acp-sof-mach.c b/sound/soc/amd/acp/acp-sof-mach.c
index 36ecef7013b9..8874151e159a 100644
--- a/sound/soc/amd/acp/acp-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sof-mach.c
@@ -128,31 +128,31 @@ static int acp_sof_probe(struct platform_device *pdev)
static const struct platform_device_id board_ids[] = {
{
.name = "rt5682-rt1019",
- .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data,
},
{
.name = "rt5682-max",
- .driver_data = (kernel_ulong_t)&sof_rt5682_max_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682_max_data,
},
{
.name = "rt5682s-max",
- .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_max_data,
},
{
.name = "rt5682s-rt1019",
- .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data,
},
{
.name = "nau8825-max",
- .driver_data = (kernel_ulong_t)&sof_nau8825_data
+ .driver_data = (kernel_ulong_t)&sof_nau8825_data,
},
{
.name = "rt5682s-hs-rt1019",
- .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
+ .driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data,
},
{
.name = "nau8821-max",
- .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data
+ .driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data,
},
{ }
};
diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c
index ccd01152c87d..815e088b437d 100644
--- a/sound/soc/amd/acp/amd-acp70-acpi-match.c
+++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c
@@ -659,6 +659,56 @@ static const struct snd_soc_acpi_link_adr acp70_rt721_l1u0_tas2783x2_l1u8b[] = {
{}
};
+static const struct snd_soc_acpi_adr_device rt712_vb_l1u0_adr[] = {
+ {
+ .adr = 0x000130025D071201ull,
+ /*
+ * On this platform speakers are provided by two TAS2783 amps,
+ * so the AIF2 amp path is left unused: jack + DMIC only.
+ */
+ .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
+ .endpoints = jack_dmic_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
+/*
+ * Unique ID 0xC drives the left speaker and 0x9 the right one. The order of the
+ * entries matters as much as the endpoints: asoc_sdw_parse_sdw_endpoints()
+ * appends them to the dailink in array order and sdw_compute_slave_ports()
+ * hands out payload block offsets in that same order, so the first entry is the
+ * one that receives channel 0.
+ */
+static const struct snd_soc_acpi_adr_device tas2783x2_l0u9c_adr[] = {
+ {
+ .adr = 0x00003C0102000001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "tas2783-1",
+ },
+ {
+ .adr = 0x0000390102000001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "tas2783-2",
+ },
+};
+
+/* HP OmniBook X Flip 14-kc0xxx (board 8EA1) */
+static const struct snd_soc_acpi_link_adr acp70_tas2783x2_l0u9c_rt712_vb_l1u0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(tas2783x2_l0u9c_adr),
+ .adr_d = tas2783x2_l0u9c_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt712_vb_l1u0_adr),
+ .adr_d = rt712_vb_l1u0_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_endpoint rt721_endpoints[] = {
{ /* Jack Playback/Capture Endpoint (AIF1) */
.num = 0,
@@ -706,6 +756,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = {
},
{
.link_mask = BIT(0) | BIT(1),
+ .links = acp70_tas2783x2_l0u9c_rt712_vb_l1u0,
+ .machine_check = snd_soc_acpi_amd_sdca_is_device_rt712_vb,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
.links = acp70_rt1320_l0_rt722_l1,
.drv_name = "amd_sdw",
},
diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h
index 5b6362103ca0..b602a983feb7 100644
--- a/sound/soc/amd/mach-config.h
+++ b/sound/soc/amd/mach-config.h
@@ -28,6 +28,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_sdw_machines[];
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp7x_sof_machines[];
struct config_entry {
u32 flags;
diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
index 352485dd98b1..b0147e88ba54 100644
--- a/sound/soc/amd/raven/acp3x-i2s.c
+++ b/sound/soc/amd/raven/acp3x-i2s.c
@@ -250,11 +250,17 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static const u64 acp3x_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
.hw_params = acp3x_i2s_hwparams,
.trigger = acp3x_i2s_trigger,
.set_fmt = acp3x_i2s_set_fmt,
.set_tdm_slot = acp3x_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp3x_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_component_driver acp3x_dai_component = {
diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
index bf719f628617..dbfb87e2fe92 100644
--- a/sound/soc/amd/vangogh/acp5x-i2s.c
+++ b/sound/soc/amd/vangogh/acp5x-i2s.c
@@ -337,11 +337,17 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static const u64 acp5x_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = {
.hw_params = acp5x_i2s_hwparams,
.trigger = acp5x_i2s_trigger,
.set_fmt = acp5x_i2s_set_fmt,
.set_tdm_slot = acp5x_i2s_set_tdm_slot,
+ .auto_selectable_formats = &acp5x_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_component_driver acp5x_dai_component = {
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index ae90e9f513d1..3f852393fc99 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -795,12 +795,12 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
}
},
{
- .driver_data = &acp6x_card,
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
- }
- },
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Vivobook_ASUSLaptop M6501RR_M6501RR"),
+ }
+ },
{
.driver_data = &acp6x_card,
.matches = {
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 492165c0e1ea..be702b2942a5 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -133,12 +133,17 @@ struct mca_cluster {
struct clk *clk_parent;
struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1];
- bool port_started[SNDRV_PCM_STREAM_LAST + 1];
- int port_driver; /* The cluster driving this cluster's port */
+ bool clk_provider;
+
+ bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1];
+ int port_clk_driver; /* The cluster driving this cluster's port */
bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1];
struct device_link *pd_link;
+ /* In case of clock consumer FE */
+ int syncgen_in_use;
+
unsigned int bclk_ratio;
/* Masks etc. picked up via the set_tdm_slot method */
@@ -157,7 +162,7 @@ struct mca_data {
struct reset_control *rstc;
struct device_link *pd_link;
- /* Mutex for accessing port_driver of foreign clusters */
+ /* Mutex for accessing port_clk_driver of foreign clusters */
struct mutex port_mutex;
int nclusters;
@@ -210,16 +215,22 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
SERDES_STATUS_EN | SERDES_STATUS_RST,
SERDES_STATUS_RST);
/*
- * Experiments suggest that it takes at most ~1 us
- * for the bit to clear, so wait 2 us for good measure.
+ * The SERDES cluster needs a bit of time to reset itself
+ * and settle before we start poking it. This is... slow...
*/
- udelay(2);
+ udelay(25);
WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
SERDES_STATUS_RST);
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));
+ /*
+ * ADMAC gets started right after this. This delay seems
+ * to be needed for that to be reliable, e.g. ensure the
+ * clock is stable?
+ */
+ udelay(100);
break;
default:
break;
@@ -256,11 +267,29 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
+static int mca_fe_get_portmask(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dpcm *dpcm;
+ int mask = 0;
+
+ for_each_dpcm_be(fe, substream->stream, dpcm) {
+ int no = mca_dai_to_cluster(snd_soc_rtd_to_cpu(dpcm->be, 0))->no;
+
+ mask |= 1 << no;
+ }
+
+ return mask;
+}
+
static int mca_fe_enable_clocks(struct mca_cluster *cl)
{
struct mca_data *mca = cl->host;
int ret;
+ if (!cl->clk_provider)
+ return -EINVAL;
+
ret = clk_prepare_enable(cl->clk_parent);
if (ret) {
dev_err(mca->dev,
@@ -311,7 +340,7 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
for (i = 0; i < mca->nclusters; i++) {
be_cl = &mca->clusters[i];
- if (be_cl->port_driver != cl->no)
+ if (be_cl->port_clk_driver != cl->no)
continue;
for_each_pcm_streams(stream) {
@@ -323,59 +352,79 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
return false;
}
-static int mca_be_prepare(struct snd_pcm_substream *substream,
+static int mca_be_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_data *mca = cl->host;
struct mca_cluster *fe_cl;
- int ret;
- if (cl->port_driver < 0)
+ if (cl->port_clk_driver < 0)
return -EINVAL;
- fe_cl = &mca->clusters[cl->port_driver];
-
/*
- * Typically the CODECs we are paired with will require clocks
- * to be present at time of unmute with the 'mute_stream' op
- * or at time of DAPM widget power-up. We need to enable clocks
- * here at the latest (frontend prepare would be too late).
+ * We are operating on a foreign cluster here, but since we
+ * belong to the same PCM, accesses should have been
+ * synchronized at ASoC level.
*/
- if (!mca_fe_clocks_in_use(fe_cl)) {
- ret = mca_fe_enable_clocks(fe_cl);
- if (ret < 0)
- return ret;
- }
+ fe_cl = &mca->clusters[cl->port_clk_driver];
+ if (!mca_fe_clocks_in_use(fe_cl))
+ return 0; /* Nothing to do */
- cl->clocks_in_use[substream->stream] = true;
+ cl->clocks_in_use[substream->stream] = false;
+
+ if (!mca_fe_clocks_in_use(fe_cl))
+ mca_fe_disable_clocks(fe_cl);
return 0;
}
-static int mca_be_hw_free(struct snd_pcm_substream *substream,
+static int mca_fe_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_data *mca = cl->host;
- struct mca_cluster *fe_cl;
- if (cl->port_driver < 0)
- return -EINVAL;
+ if (cl->clk_provider)
+ return 0;
- /*
- * We are operating on a foreign cluster here, but since we
- * belong to the same PCM, accesses should have been
- * synchronized at ASoC level.
- */
- fe_cl = &mca->clusters[cl->port_driver];
- if (!mca_fe_clocks_in_use(fe_cl))
- return 0; /* Nothing to do */
+ /* Turn on the cluster power domain if not already in use */
+ if (!cl->syncgen_in_use) {
+ int port = ffs(mca_fe_get_portmask(substream));
- cl->clocks_in_use[substream->stream] = false;
+ cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!cl->pd_link) {
+ dev_err(mca->dev,
+ "cluster %d: unable to prop-up power domain\n", cl->no);
+ return -EINVAL;
+ }
- if (!mca_fe_clocks_in_use(fe_cl))
- mca_fe_disable_clocks(fe_cl);
+ mca_modify(cl, REG_SYNCGEN_MCLK_SEL, SYNCGEN_MCLK_SEL, BIT(port));
+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN,
+ SYNCGEN_STATUS_EN);
+ }
+ cl->syncgen_in_use |= 1 << substream->stream;
+
+ return 0;
+}
+
+static int mca_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+
+ if (cl->clk_provider)
+ return 0;
+
+ cl->syncgen_in_use &= ~(1 << substream->stream);
+ if (cl->syncgen_in_use)
+ return 0;
+
+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);
+ if (cl->pd_link)
+ device_link_del(cl->pd_link);
return 0;
}
@@ -390,7 +439,7 @@ static unsigned int mca_crop_mask(unsigned int mask, int nchans)
static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
unsigned int mask, int slots, int nchans,
- int slot_width, bool is_tx, int port)
+ int slot_width, bool is_tx, int portmask)
{
__iomem void *serdes_base = cl->base + serdes_unit;
u32 serdes_conf, serdes_conf_mask;
@@ -449,7 +498,7 @@ static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
serdes_base + REG_RX_SERDES_SLOTMASK);
writel_relaxed(~((u32)mca_crop_mask(mask, nchans)),
serdes_base + REG_RX_SERDES_SLOTMASK + 0x4);
- writel_relaxed(1 << port,
+ writel_relaxed(portmask,
serdes_base + REG_RX_SERDES_PORT);
}
@@ -505,9 +554,18 @@ static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u32 serdes_conf = 0;
u32 bitstart;
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) !=
- SND_SOC_DAIFMT_BP_FP)
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
+ cl->clk_provider = true;
+ break;
+
+ case SND_SOC_DAIFMT_BC_FC:
+ cl->clk_provider = false;
+ break;
+
+ default:
goto err;
+ }
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -564,24 +622,6 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
return 0;
}
-static int mca_fe_get_port(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *be;
- struct snd_soc_dpcm *dpcm;
-
- be = NULL;
- for_each_dpcm_be(fe, substream->stream, dpcm) {
- be = dpcm->be;
- break;
- }
-
- if (!be)
- return -EINVAL;
-
- return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
-}
-
static int mca_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -595,7 +635,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
unsigned long bclk_ratio;
unsigned int tdm_slots, tdm_slot_width, tdm_mask;
u32 regval, pad;
- int ret, port, nchans_ceiled;
+ int ret, portmask, nchans_ceiled;
if (!cl->tdm_slot_width) {
/*
@@ -644,13 +684,13 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
tdm_mask = (1 << tdm_slots) - 1;
}
- port = mca_fe_get_port(substream);
- if (port < 0)
- return port;
+ portmask = mca_fe_get_portmask(substream);
+ if (!portmask)
+ return -EINVAL;
ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF,
tdm_mask, tdm_slots, params_channels(params),
- tdm_slot_width, is_tx, port);
+ tdm_slot_width, is_tx, portmask);
if (ret)
return ret;
@@ -699,6 +739,19 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 mca_fe_selectable_formats[] =
+{
+ /* pattern 1 */
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF,
+
+ /* pattern 2 */
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF
+};
+
static const struct snd_soc_dai_ops mca_fe_ops = {
.startup = mca_fe_startup,
.set_fmt = mca_fe_set_fmt,
@@ -706,66 +759,128 @@ static const struct snd_soc_dai_ops mca_fe_ops = {
.set_tdm_slot = mca_fe_set_tdm_slot,
.hw_params = mca_fe_hw_params,
.trigger = mca_fe_trigger,
+ .prepare = mca_fe_prepare,
+ .hw_free = mca_fe_hw_free,
+ .auto_selectable_formats = mca_fe_selectable_formats,
+ .num_auto_selectable_formats = ARRAY_SIZE(mca_fe_selectable_formats),
};
-static bool mca_be_started(struct mca_cluster *cl)
+/*
+ * Is there a FE attached which will be feeding this port's clocks?
+ */
+static bool mca_be_clk_started(struct mca_cluster *cl)
{
int stream;
for_each_pcm_streams(stream)
- if (cl->port_started[stream])
+ if (cl->port_clk_started[stream])
return true;
return false;
}
-static int mca_be_startup(struct snd_pcm_substream *substream,
+static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be,
+ int stream)
+{
+ struct snd_soc_pcm_runtime *fe = NULL;
+ struct snd_soc_dpcm *dpcm;
+
+ for_each_dpcm_fe(be, stream, dpcm) {
+ if (fe && dpcm->fe != fe) {
+ dev_err(be->dev, "many FE per one BE unsupported\n");
+ return NULL;
+ }
+
+ fe = dpcm->fe;
+ }
+
+ return fe;
+}
+
+static int mca_be_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *fe;
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
struct mca_cluster *cl = mca_dai_to_cluster(dai);
- struct mca_cluster *fe_cl;
struct mca_data *mca = cl->host;
- struct snd_soc_dpcm *dpcm;
+ struct mca_cluster *fe_cl, *fe_clk_cl;
+ int ret;
- fe = NULL;
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- for_each_dpcm_fe(be, substream->stream, dpcm) {
- if (fe && dpcm->fe != fe) {
- dev_err(mca->dev, "many FE per one BE unsupported\n");
- return -EINVAL;
- }
+ if (!fe_cl->clk_provider)
+ return 0;
- fe = dpcm->fe;
+ if (cl->port_clk_driver < 0)
+ return 0;
+
+ fe_clk_cl = &mca->clusters[cl->port_clk_driver];
+
+ /*
+ * Typically the CODECs we are paired with will require clocks
+ * to be present at time of unmute with the 'mute_stream' op
+ * or at time of DAPM widget power-up. We need to enable clocks
+ * here at the latest (frontend prepare would be too late).
+ */
+ if (!mca_fe_clocks_in_use(fe_clk_cl)) {
+ ret = mca_fe_enable_clocks(fe_clk_cl);
+ if (ret < 0)
+ return ret;
}
+ cl->clocks_in_use[substream->stream] = true;
+
+ return 0;
+}
+
+static int mca_be_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_cluster *fe_cl;
+ struct mca_data *mca = cl->host;
+
if (!fe)
return -EINVAL;
-
fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- if (mca_be_started(cl)) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
+ cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA,
+ PORT_ENABLES_TX_DATA);
+ }
+
+ if (!fe_cl->clk_provider)
+ return 0;
+
+ if (mca_be_clk_started(cl)) {
/*
* Port is already started in the other direction.
* Make sure there isn't a conflict with another cluster
- * driving the port.
+ * driving the port clocks.
*/
- if (cl->port_driver != fe_cl->no)
+ if (cl->port_clk_driver != fe_cl->no)
return -EINVAL;
- cl->port_started[substream->stream] = true;
+ cl->port_clk_started[substream->stream] = true;
return 0;
}
- writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA,
- cl->base + REG_PORT_ENABLES);
writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1),
cl->base + REG_PORT_CLOCK_SEL);
+
writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
cl->base + REG_PORT_DATA_SEL);
+
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS,
+ PORT_ENABLES_CLOCKS);
+
scoped_guard(mutex, &mca->port_mutex)
- cl->port_driver = fe_cl->no;
- cl->port_started[substream->stream] = true;
+ cl->port_clk_driver = fe_cl->no;
+ cl->port_clk_started[substream->stream] = true;
return 0;
}
@@ -773,20 +888,34 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
static void mca_be_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_cluster *fe_cl;
struct mca_data *mca = cl->host;
- cl->port_started[substream->stream] = false;
+ if (!fe)
+ return;
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- if (!mca_be_started(cl)) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0);
+ writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
+ }
+
+ if (!fe_cl->clk_provider)
+ return;
+
+ cl->port_clk_started[substream->stream] = false;
+ if (!mca_be_clk_started(cl)) {
/*
* Were we the last direction to shutdown?
- * Turn off the lights.
+ * Turn off the lights (clocks).
*/
- writel_relaxed(0, cl->base + REG_PORT_ENABLES);
- writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, 0);
+ writel_relaxed(0, cl->base + REG_PORT_CLOCK_SEL);
scoped_guard(mutex, &mca->port_mutex)
- cl->port_driver = -1;
+ cl->port_clk_driver = -1;
}
}
@@ -1092,7 +1221,7 @@ static int apple_mca_probe(struct platform_device *pdev)
cl->host = mca;
cl->no = i;
cl->base = base + CLUSTER_STRIDE * i;
- cl->port_driver = -1;
+ cl->port_clk_driver = -1;
cl->clk_parent = of_clk_get(pdev->dev.of_node, i);
if (IS_ERR(cl->clk_parent)) {
dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n",
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
index 762199faf872..d9ad262ec44d 100644
--- a/sound/soc/atmel/atmel-i2s.c
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -540,12 +540,16 @@ static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const u64 atmel_i2s_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_I2S;
+
static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
.probe = atmel_i2s_dai_probe,
.prepare = atmel_i2s_prepare,
.trigger = atmel_i2s_trigger,
.hw_params = atmel_i2s_hw_params,
.set_fmt = atmel_i2s_set_dai_fmt,
+ .auto_selectable_formats = &atmel_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver atmel_i2s_dai = {
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 89098f41679c..f4f886bf678d 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -825,6 +825,11 @@ static int atmel_ssc_resume(struct snd_soc_component *component)
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S32_LE)
+static const u64 atmel_ssc_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A;
+
static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.startup = atmel_ssc_startup,
.shutdown = atmel_ssc_shutdown,
@@ -833,6 +838,8 @@ static const struct snd_soc_dai_ops atmel_ssc_dai_ops = {
.hw_params = atmel_ssc_hw_params,
.set_fmt = atmel_ssc_set_dai_fmt,
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
+ .auto_selectable_formats = &atmel_ssc_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver atmel_ssc_dai = {
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
index 0f4021c6c588..df3e5ef8fa61 100644
--- a/sound/soc/atmel/atmel_wm8904.c
+++ b/sound/soc/atmel/atmel_wm8904.c
@@ -82,32 +82,33 @@ static struct snd_soc_card atmel_asoc_wm8904_card = {
static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct device_node *codec_np, *cpu_np;
struct snd_soc_card *card = &atmel_asoc_wm8904_card;
struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
int ret;
if (!np) {
- dev_err(&pdev->dev, "only device tree supported\n");
+ dev_err(dev, "only device tree supported\n");
return -EINVAL;
}
ret = snd_soc_of_parse_card_name(card, "atmel,model");
if (ret) {
- dev_err(&pdev->dev, "failed to parse card name\n");
+ dev_err(dev, "failed to parse card name\n");
return ret;
}
ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
if (ret) {
- dev_err(&pdev->dev, "failed to parse audio routing\n");
+ dev_err(dev, "failed to parse audio routing\n");
return ret;
}
cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
if (!cpu_np) {
- dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+ dev_err(dev, "failed to get dai and pcm info\n");
ret = -EINVAL;
return ret;
}
@@ -117,7 +118,7 @@ static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
if (!codec_np) {
- dev_err(&pdev->dev, "failed to get codec info\n");
+ dev_err(dev, "failed to get codec info\n");
ret = -EINVAL;
return ret;
}
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 17d138bb9064..a832dee73ac7 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -912,6 +912,13 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const u64 mchp_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_GATED |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
.probe = mchp_i2s_mcc_dai_probe,
.set_sysclk = mchp_i2s_mcc_set_sysclk,
@@ -922,6 +929,8 @@ static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
.hw_free = mchp_i2s_mcc_hw_free,
.set_fmt = mchp_i2s_mcc_set_dai_fmt,
.set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
+ .auto_selectable_formats = &mchp_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000
diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c
index ec7233ce1f78..a6a9b5e6cd95 100644
--- a/sound/soc/atmel/mchp-pdmc.c
+++ b/sound/soc/atmel/mchp-pdmc.c
@@ -741,6 +741,8 @@ static int mchp_pdmc_pcm_new(struct snd_soc_pcm_runtime *rtd,
return ret;
}
+static const u64 mchp_selectable_formats = SND_SOC_POSSIBLE_DAIFMT_PDM;
+
static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
.probe = mchp_pdmc_dai_probe,
.set_fmt = mchp_pdmc_set_fmt,
@@ -748,6 +750,8 @@ static const struct snd_soc_dai_ops mchp_pdmc_dai_ops = {
.hw_params = mchp_pdmc_hw_params,
.trigger = mchp_pdmc_trigger,
.pcm_new = &mchp_pdmc_pcm_new,
+ .auto_selectable_formats = &mchp_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver mchp_pdmc_dai = {
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 81abe2e18402..78346cd7959c 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -42,7 +42,7 @@ static const struct platform_device_id db1200_pids[] = {
.name = "db1550-i2s",
.driver_data = 5,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, db1200_pids);
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 57735004f416..0e9c7eef9ee8 100644
--- a/sound/soc/au1x/i2sc.c
+++ b/sound/soc/au1x/i2sc.c
@@ -202,11 +202,22 @@ static int au1xi2s_startup(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 au1xi2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops au1xi2s_dai_ops = {
.startup = au1xi2s_startup,
.trigger = au1xi2s_trigger,
.hw_params = au1xi2s_hw_params,
.set_fmt = au1xi2s_set_fmt,
+ .auto_selectable_formats = &au1xi2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver au1xi2s_dai_driver = {
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 94698e08a513..0f9d80883116 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -210,9 +210,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
{
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
unsigned long r, ro, stat;
- int chans, t, stype = substream->stream;
-
- chans = params_channels(params);
+ int t, stype = substream->stream;
r = ro = __raw_readl(AC97_CFG(pscdata));
stat = __raw_readl(AC97_STAT(pscdata));
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index bf59105fcb7a..72aa5177147f 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -262,11 +262,22 @@ static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 au1xpsc_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
.startup = au1xpsc_i2s_startup,
.trigger = au1xpsc_i2s_trigger,
.hw_params = au1xpsc_i2s_hw_params,
.set_fmt = au1xpsc_i2s_set_fmt,
+ .auto_selectable_formats = &au1xpsc_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 87d2f06c2f53..208977828254 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -748,6 +748,17 @@ static int bcm2835_i2s_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const u64 bcm2835_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.probe = bcm2835_i2s_dai_probe,
.startup = bcm2835_i2s_startup,
@@ -758,6 +769,8 @@ static const struct snd_soc_dai_ops bcm2835_i2s_dai_ops = {
.set_fmt = bcm2835_i2s_set_dai_fmt,
.set_bclk_ratio = bcm2835_i2s_set_dai_bclk_ratio,
.set_tdm_slot = bcm2835_i2s_set_dai_tdm_slot,
+ .auto_selectable_formats = &bcm2835_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver bcm2835_i2s_dai = {
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c
index 47706ae0a31f..753021789a52 100644
--- a/sound/soc/bcm/cygnus-ssp.c
+++ b/sound/soc/bcm/cygnus-ssp.c
@@ -1133,6 +1133,11 @@ static int cygnus_ssp_resume(struct snd_soc_component *component)
#define cygnus_ssp_resume NULL
#endif
+static const u64 cygnus_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.startup = cygnus_ssp_startup,
.shutdown = cygnus_ssp_shutdown,
@@ -1141,6 +1146,8 @@ static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = {
.set_fmt = cygnus_ssp_set_fmt,
.set_sysclk = cygnus_ssp_set_sysclk,
.set_tdm_slot = cygnus_set_dai_tdm_slot,
+ .auto_selectable_formats = &cygnus_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_ops cygnus_spdif_dai_ops = {
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 5dba741594fa..8195ed7c6dd6 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -401,6 +401,15 @@ static int ep93xx_i2s_resume(struct snd_soc_component *component)
#define ep93xx_i2s_resume NULL
#endif
+static const u64 ep93xx_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
.probe = ep93xx_i2s_dai_probe,
.startup = ep93xx_i2s_startup,
@@ -408,6 +417,8 @@ static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
.hw_params = ep93xx_i2s_hw_params,
.set_sysclk = ep93xx_i2s_set_sysclk,
.set_fmt = ep93xx_i2s_set_dai_fmt,
+ .auto_selectable_formats = &ep93xx_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index e4d139108d72..f9a47e262a77 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -238,6 +238,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_RT715_SDCA_SDW
imply SND_SOC_RT721_SDCA_SDW
imply SND_SOC_RT722_SDCA_SDW
+ imply SND_SOC_RT766_SDCA_SDW
imply SND_SOC_RT1308_SDW
imply SND_SOC_RT1316_SDW
imply SND_SOC_RT1318
@@ -367,6 +368,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_WSA881X
imply SND_SOC_WSA883X
imply SND_SOC_WSA884X
+ imply SND_SOC_WSA885X
imply SND_SOC_ZL38060
help
Normally ASoC codec drivers are only built if a machine driver which
@@ -615,8 +617,8 @@ config SND_SOC_AK4613
depends on I2C
config SND_SOC_AK4619
- tristate "AKM AK4619 CODEC"
- depends on I2C
+ tristate "AKM AK4619 CODEC"
+ depends on I2C
config SND_SOC_AK4642
tristate "AKM AK4642 CODEC"
@@ -726,6 +728,10 @@ config SND_SOC_AW87390
sound quality, which is a new high efficiency, low
noise, constant large volume, 6th Smart K audio amplifier.
+config SND_SOC_AW88399_LIB
+ tristate
+ select SND_SOC_AW88395_LIB
+
config SND_SOC_AW88399
tristate "Soc Audio for awinic aw88399"
depends on I2C
@@ -733,6 +739,7 @@ config SND_SOC_AW88399
select REGMAP_I2C
select GPIOLIB
select SND_SOC_AW88395_LIB
+ select SND_SOC_AW88399_LIB
help
This option enables support for aw88399 Smart PA.
The awinic AW88399 is an I2S/TDM input, high efficiency
@@ -889,6 +896,7 @@ config SND_SOC_CS35L56_SDW
tristate "Cirrus Logic CS35L56 CODEC (SDW)"
depends on SOUNDWIRE
select REGMAP_SOUNDWIRE
+ select IRQ_DOMAIN
select SND_SOC_CS35L56
select SND_SOC_CS35L56_SHARED
help
@@ -1201,16 +1209,16 @@ config SND_SOC_JZ4725B_CODEC
will be called snd-soc-jz4725b-codec.
config SND_SOC_JZ4760_CODEC
- depends on MACH_INGENIC || COMPILE_TEST
- depends on OF
- select REGMAP
- tristate "Ingenic JZ4760 internal CODEC"
- help
- Enable support for the internal CODEC found in the JZ4760 SoC
- from Ingenic.
+ depends on MACH_INGENIC || COMPILE_TEST
+ depends on OF
+ select REGMAP
+ tristate "Ingenic JZ4760 internal CODEC"
+ help
+ Enable support for the internal CODEC found in the JZ4760 SoC
+ from Ingenic.
- This driver can also be built as a module. If so, the module
- will be called snd-soc-jz4760-codec.
+ This driver can also be built as a module. If so, the module
+ will be called snd-soc-jz4760-codec.
config SND_SOC_JZ4770_CODEC
depends on MACH_INGENIC || COMPILE_TEST
@@ -1888,7 +1896,7 @@ config SND_SOC_RT5670
depends on I2C
config SND_SOC_RT5677
- tristate
+ tristate "Realtek RT5677 Codec"
depends on I2C
select REGMAP_I2C
select REGMAP_IRQ
@@ -1978,6 +1986,15 @@ config SND_SOC_RT715_SDCA_SDW
select REGMAP_SOUNDWIRE
select REGMAP_SOUNDWIRE_MBQ
+config SND_SOC_RT766_SDCA_SDW
+ tristate "Realtek RT766 SDCA Codec - SDW"
+ depends on SOUNDWIRE
+ depends on SND_SOC_SDCA
+ select SND_SOC_SDCA_HID
+ select SND_SOC_SDCA_IRQ
+ select REGMAP_SOUNDWIRE
+ select REGMAP_SOUNDWIRE_MBQ
+
config SND_SOC_RT9120
tristate "Richtek RT9120 Stereo Class-D Amplifier"
depends on I2C
@@ -2297,8 +2314,8 @@ config SND_SOC_TLV320ADC3XXX
depends on I2C
depends on GPIOLIB
help
- Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
- ADCs.
+ Enable support for Texas Instruments TLV320ADC3001 and TLV320ADC3101
+ ADCs.
config SND_SOC_TLV320AIC23
tristate
@@ -2771,6 +2788,16 @@ config SND_SOC_WSA884X
This enables support for Qualcomm WSA8840/WSA8845/WSA8845H Class-D
Smart Speaker Amplifier.
+config SND_SOC_WSA885X
+ tristate "WSA885X Codec"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This enables support for Qualcomm WSA885X Stereo Smart Speaker
+ Amplifier. The codec driver programs the amplifier register
+ map and exposes the DAI and mixer controls used by Qualcomm
+ audio machine drivers.
+
config SND_SOC_ZL38060
tristate "Microsemi ZL38060 Connected Home Audio Processor"
depends on SPI_MASTER
@@ -2894,28 +2921,32 @@ config SND_SOC_TPA6130A2
depends on I2C
config SND_SOC_LPASS_MACRO_COMMON
- tristate
+ tristate
config SND_SOC_LPASS_WSA_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm WSA Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_VA_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm VA Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_RX_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm RX Macro in LPASS(Low Power Audio SubSystem)"
config SND_SOC_LPASS_TX_MACRO
depends on COMMON_CLK
+ depends on PM_CLK
select REGMAP_MMIO
select SND_SOC_LPASS_MACRO_COMMON
tristate "Qualcomm TX Macro in LPASS(Low Power Audio SubSystem)"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index aa0396e5b575..3d122ace75ad 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -55,6 +55,7 @@ snd-soc-aw88395-y := aw88395/aw88395.o
snd-soc-aw88166-y := aw88166.o
snd-soc-aw88261-y := aw88261.o
snd-soc-aw88399-y := aw88399.o
+snd-soc-aw88399-lib-y := aw88399-lib.o
snd-soc-bd28623-y := bd28623.o
snd-soc-bt-sco-y := bt-sco.o
snd-soc-chv3-codec-y := chv3-codec.o
@@ -284,6 +285,7 @@ snd-soc-rt715-y := rt715.o rt715-sdw.o
snd-soc-rt715-sdca-y := rt715-sdca.o rt715-sdca-sdw.o
snd-soc-rt721-sdca-y := rt721-sdca.o rt721-sdca-sdw.o
snd-soc-rt722-sdca-y := rt722-sdca.o rt722-sdca-sdw.o
+snd-soc-rt766-sdca-y := rt766-sdca.o rt766-sdca-sdw.o
snd-soc-rt9120-y := rt9120.o
snd-soc-rt9123-y := rt9123.o
snd-soc-rt9123p-y := rt9123p.o
@@ -426,6 +428,7 @@ snd-soc-wm-hubs-y := wm_hubs.o
snd-soc-wsa881x-y := wsa881x.o
snd-soc-wsa883x-y := wsa883x.o
snd-soc-wsa884x-y := wsa884x.o
+snd-soc-wsa885x-y := wsa885x.o
snd-soc-zl38060-y := zl38060.o
# Amp
snd-soc-max9877-y := max9877.o
@@ -496,6 +499,7 @@ obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o
obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o
obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o
obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o
+obj-$(CONFIG_SND_SOC_AW88399_LIB) += snd-soc-aw88399-lib.o
obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o
obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o
obj-$(CONFIG_SND_SOC_CHV3_CODEC) += snd-soc-chv3-codec.o
@@ -724,6 +728,7 @@ obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o
obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o
obj-$(CONFIG_SND_SOC_RT721_SDCA_SDW) += snd-soc-rt721-sdca.o
obj-$(CONFIG_SND_SOC_RT722_SDCA_SDW) += snd-soc-rt722-sdca.o
+obj-$(CONFIG_SND_SOC_RT766_SDCA_SDW) += snd-soc-rt766-sdca.o
obj-$(CONFIG_SND_SOC_RT9120) += snd-soc-rt9120.o
obj-$(CONFIG_SND_SOC_RT9123) += snd-soc-rt9123.o
obj-$(CONFIG_SND_SOC_RT9123P) += snd-soc-rt9123p.o
@@ -876,6 +881,7 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o
obj-$(CONFIG_SND_SOC_WSA883X) += snd-soc-wsa883x.o
obj-$(CONFIG_SND_SOC_WSA884X) += snd-soc-wsa884x.o
+obj-$(CONFIG_SND_SOC_WSA885X) += snd-soc-wsa885x.o
obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o
# Amp
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index 6e8ef9cd1b31..2cf96cbdd294 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -14,6 +14,7 @@
* for ST-Ericsson.
*/
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -989,9 +990,8 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(component->dev);
- mutex_lock(&drvdata->ctrl_lock);
+ guard(mutex)(&drvdata->ctrl_lock);
ucontrol->value.enumerated.item[0] = drvdata->sid_status;
- mutex_unlock(&drvdata->ctrl_lock);
return 0;
}
@@ -1014,7 +1014,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
return -EIO;
}
- mutex_lock(&drvdata->ctrl_lock);
+ guard(mutex)(&drvdata->ctrl_lock);
sidconf = snd_soc_component_read(component, AB8500_SIDFIRCONF);
if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
@@ -1025,7 +1025,8 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
} else {
status = -EBUSY;
}
- goto out;
+ dev_dbg(component->dev, "%s: Exit\n", __func__);
+ return status;
}
snd_soc_component_write(component, AB8500_SIDFIRADR, 0);
@@ -1043,9 +1044,6 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
drvdata->sid_status = SID_FIR_CONFIGURED;
-out:
- mutex_unlock(&drvdata->ctrl_lock);
-
dev_dbg(component->dev, "%s: Exit\n", __func__);
return status;
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 8afeadcaf8b0..dbea83bd49b6 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -193,9 +193,15 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 ad1836_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops ad1836_dai_ops = {
.hw_params = ad1836_hw_params,
.set_fmt = ad1836_set_dai_fmt,
+ .auto_selectable_formats = &ad1836_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define AD183X_DAI(_name, num_dacs, num_adcs) \
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index b93531c3a9a4..9841c779b175 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -394,6 +394,14 @@ static int ad193x_startup(struct snd_pcm_substream *substream,
&constr);
}
+static const u64 ad193x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
static const struct snd_soc_dai_ops ad193x_dai_ops = {
.startup = ad193x_startup,
.hw_params = ad193x_hw_params,
@@ -401,6 +409,8 @@ static const struct snd_soc_dai_ops ad193x_dai_ops = {
.set_tdm_slot = ad193x_set_tdm_slot,
.set_sysclk = ad193x_set_dai_sysclk,
.set_fmt = ad193x_set_dai_fmt,
+ .auto_selectable_formats = &ad193x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index a70c46dd5d76..27ce03b0fb91 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -68,23 +68,33 @@
#define ADAU1761_FIRMWARE "adau1761.bin"
static const struct reg_default adau1761_reg_defaults[] = {
- { ADAU1761_DEJITTER, 0x03 },
+ { ADAU17X1_CLOCK_CONTROL, 0x00 },
+ { ADAU17X1_PLL_CONTROL, 0x00 },
{ ADAU1761_DIGMIC_JACKDETECT, 0x00 },
+ { ADAU17X1_REC_POWER_MGMT, 0x00 },
{ ADAU1761_REC_MIXER_LEFT0, 0x00 },
{ ADAU1761_REC_MIXER_LEFT1, 0x00 },
{ ADAU1761_REC_MIXER_RIGHT0, 0x00 },
{ ADAU1761_REC_MIXER_RIGHT1, 0x00 },
{ ADAU1761_LEFT_DIFF_INPUT_VOL, 0x00 },
+ { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
+ { ADAU17X1_MICBIAS, 0x00 },
{ ADAU1761_ALC_CTRL0, 0x00 },
{ ADAU1761_ALC_CTRL1, 0x00 },
{ ADAU1761_ALC_CTRL2, 0x00 },
{ ADAU1761_ALC_CTRL3, 0x00 },
- { ADAU1761_RIGHT_DIFF_INPUT_VOL, 0x00 },
- { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
+ { ADAU17X1_SERIAL_PORT0, 0x00 },
+ { ADAU17X1_SERIAL_PORT1, 0x00 },
+ { ADAU17X1_CONVERTER0, 0x00 },
+ { ADAU17X1_CONVERTER1, 0x00 },
+ { ADAU17X1_ADC_CONTROL, 0x00 },
+ { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
+ { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
{ ADAU1761_PLAY_MIXER_LEFT0, 0x00 },
{ ADAU1761_PLAY_MIXER_LEFT1, 0x00 },
{ ADAU1761_PLAY_MIXER_RIGHT0, 0x00 },
{ ADAU1761_PLAY_MIXER_RIGHT1, 0x00 },
+ { ADAU1761_PLAY_LR_MIXER_LEFT, 0x00 },
{ ADAU1761_PLAY_LR_MIXER_RIGHT, 0x00 },
{ ADAU1761_PLAY_MIXER_MONO, 0x00 },
{ ADAU1761_PLAY_HP_LEFT_VOL, 0x00 },
@@ -93,20 +103,6 @@ static const struct reg_default adau1761_reg_defaults[] = {
{ ADAU1761_PLAY_LINE_RIGHT_VOL, 0x00 },
{ ADAU1761_PLAY_MONO_OUTPUT_VOL, 0x00 },
{ ADAU1761_POP_CLICK_SUPPRESS, 0x00 },
- { ADAU1761_JACK_DETECT_PIN, 0x00 },
- { ADAU1761_CLK_ENABLE0, 0x00 },
- { ADAU1761_CLK_ENABLE1, 0x00 },
- { ADAU17X1_CLOCK_CONTROL, 0x00 },
- { ADAU17X1_PLL_CONTROL, 0x00 },
- { ADAU17X1_REC_POWER_MGMT, 0x00 },
- { ADAU17X1_MICBIAS, 0x00 },
- { ADAU17X1_SERIAL_PORT0, 0x00 },
- { ADAU17X1_SERIAL_PORT1, 0x00 },
- { ADAU17X1_CONVERTER0, 0x00 },
- { ADAU17X1_CONVERTER1, 0x00 },
- { ADAU17X1_LEFT_INPUT_DIGITAL_VOL, 0x00 },
- { ADAU17X1_RIGHT_INPUT_DIGITAL_VOL, 0x00 },
- { ADAU17X1_ADC_CONTROL, 0x00 },
{ ADAU17X1_PLAY_POWER_MGMT, 0x00 },
{ ADAU17X1_DAC_CONTROL0, 0x00 },
{ ADAU17X1_DAC_CONTROL1, 0x00 },
@@ -114,12 +110,16 @@ static const struct reg_default adau1761_reg_defaults[] = {
{ ADAU17X1_SERIAL_PORT_PAD, 0xaa },
{ ADAU17X1_CONTROL_PORT_PAD0, 0xaa },
{ ADAU17X1_CONTROL_PORT_PAD1, 0x00 },
+ { ADAU1761_JACK_DETECT_PIN, 0x00 },
+ { ADAU1761_DEJITTER, 0x03 },
{ ADAU17X1_DSP_SAMPLING_RATE, 0x01 },
{ ADAU17X1_SERIAL_INPUT_ROUTE, 0x00 },
{ ADAU17X1_SERIAL_OUTPUT_ROUTE, 0x00 },
{ ADAU17X1_DSP_ENABLE, 0x00 },
{ ADAU17X1_DSP_RUN, 0x00 },
{ ADAU17X1_SERIAL_SAMPLING_RATE, 0x00 },
+ { ADAU1761_CLK_ENABLE0, 0x00 },
+ { ADAU1761_CLK_ENABLE1, 0x00 },
};
static const DECLARE_TLV_DB_SCALE(adau1761_sing_in_tlv, -1500, 300, 1);
diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c
index 92b226b8b4bb..4342eb7dd9e5 100644
--- a/sound/soc/codecs/adau7118-hw.c
+++ b/sound/soc/codecs/adau7118-hw.c
@@ -22,7 +22,7 @@ static const struct of_device_id adau7118_of_match[] = {
MODULE_DEVICE_TABLE(of, adau7118_of_match);
static const struct platform_device_id adau7118_id[] = {
- { .name = "adau7118" },
+ { .name = "adau7118" },
{ }
};
MODULE_DEVICE_TABLE(platform, adau7118_id);
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index 8a89187f9c78..e97c72ac9b2b 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -743,11 +743,19 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream,
adav80x->rate = 0;
}
+static const u64 adav80x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops adav80x_dai_ops = {
.set_fmt = adav80x_set_dai_fmt,
.hw_params = adav80x_hw_params,
.startup = adav80x_dai_startup,
.shutdown = adav80x_dai_shutdown,
+ .auto_selectable_formats = &adav80x_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index 3e0696b5abf5..be5306d07d40 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -95,6 +95,7 @@
* see
* AK4613_ENABLE_TDM_TEST
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -384,7 +385,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
struct device *dev = component->dev;
- mutex_lock(&priv->lock);
+ guard(mutex)(&priv->lock);
priv->cnt--;
if (priv->cnt < 0) {
dev_err(dev, "unexpected counter error\n");
@@ -392,7 +393,6 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
}
if (!priv->cnt)
priv->ctrl1 = 0;
- mutex_unlock(&priv->lock);
}
static void ak4613_hw_constraints(struct ak4613_priv *priv,
@@ -507,10 +507,9 @@ static int ak4613_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct ak4613_priv *priv = snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->lock);
+ guard(mutex)(&priv->lock);
ak4613_hw_constraints(priv, substream);
priv->cnt++;
- mutex_unlock(&priv->lock);
return 0;
}
@@ -599,45 +598,47 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
*/
ret = -EINVAL;
- mutex_lock(&priv->lock);
- if (priv->cnt > 1) {
- /*
- * If it was already working, use current priv->ctrl1
- */
- ret = 0;
- } else {
- /*
- * It is not yet working,
- */
- unsigned int channel = params_channels(params);
- u8 tdm;
-
- /* STEREO or TDM */
- if (channel == 2)
- tdm = AK4613_CONFIG_MODE_STEREO;
- else
- tdm = AK4613_CONFIG_GET(priv, MODE);
-
- for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
- const struct ak4613_interface *iface = ak4613_iface + i;
-
- if ((iface->fmt == fmt) && (iface->width == width)) {
- /*
- * Ctrl1
- * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
- * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE|
- * < tdm > < iface->dif >
- */
- priv->ctrl1 = (tdm << 6) | (iface->dif << 3);
- ret = 0;
- break;
+ scoped_guard(mutex, &priv->lock) {
+ if (priv->cnt > 1) {
+ /*
+ * If it was already working, use current priv->ctrl1
+ */
+ ret = 0;
+ } else {
+ /*
+ * It is not yet working,
+ */
+ unsigned int channel = params_channels(params);
+ u8 tdm;
+
+ /* STEREO or TDM */
+ if (channel == 2)
+ tdm = AK4613_CONFIG_MODE_STEREO;
+ else
+ tdm = AK4613_CONFIG_GET(priv, MODE);
+
+ for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) {
+ const struct ak4613_interface *iface = ak4613_iface + i;
+
+ if (iface->fmt == fmt && iface->width == width) {
+ /*
+ * Ctrl1
+ * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
+ * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE|
+ * < tdm > < iface->dif >
+ */
+ priv->ctrl1 = (tdm << 6) | (iface->dif << 3);
+ ret = 0;
+ break;
+ }
}
}
}
- mutex_unlock(&priv->lock);
- if (ret < 0)
- goto hw_params_end;
+ if (ret < 0) {
+ dev_warn(dev, "unsupported data width/format combination\n");
+ return ret;
+ }
snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1);
snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2);
@@ -645,10 +646,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic);
snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc);
-hw_params_end:
- if (ret < 0)
- dev_warn(dev, "unsupported data width/format combination\n");
-
return ret;
}
diff --git a/sound/soc/codecs/arizona-jack.c b/sound/soc/codecs/arizona-jack.c
index a9063bac2752..819d080b1188 100644
--- a/sound/soc/codecs/arizona-jack.c
+++ b/sound/soc/codecs/arizona-jack.c
@@ -5,6 +5,7 @@
* Copyright (C) 2012-2014 Wolfson Microelectronics plc
*/
+#include <linux/cleanup.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -707,15 +708,13 @@ static void arizona_micd_timeout_work(struct work_struct *work)
struct arizona_priv,
micd_timeout_work.work);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
dev_dbg(info->arizona->dev, "MICD timed out, reporting HP\n");
info->detecting = false;
arizona_identify_headphone(info);
-
- mutex_unlock(&info->lock);
}
static int arizona_micd_adc_read(struct arizona_priv *info)
@@ -921,12 +920,11 @@ static void arizona_micd_detect(struct work_struct *work)
cancel_delayed_work_sync(&info->micd_timeout_work);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
/* If the cable was removed while measuring ignore the result */
if (!(info->jack->status & SND_JACK_MECHANICAL)) {
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
- mutex_unlock(&info->lock);
return;
}
@@ -936,7 +934,6 @@ static void arizona_micd_detect(struct work_struct *work)
arizona_button_reading(info);
pm_runtime_mark_last_busy(arizona->dev);
- mutex_unlock(&info->lock);
}
static irqreturn_t arizona_micdet(int irq, void *data)
@@ -948,10 +945,10 @@ static irqreturn_t arizona_micdet(int irq, void *data)
cancel_delayed_work_sync(&info->micd_detect_work);
cancel_delayed_work_sync(&info->micd_timeout_work);
- mutex_lock(&info->lock);
- if (!info->detecting)
- debounce = 0;
- mutex_unlock(&info->lock);
+ scoped_guard(mutex, &info->lock) {
+ if (!info->detecting)
+ debounce = 0;
+ }
if (debounce)
queue_delayed_work(system_power_efficient_wq,
@@ -969,9 +966,8 @@ static void arizona_hpdet_work(struct work_struct *work)
struct arizona_priv,
hpdet_work.work);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
arizona_start_hpdet_acc_id(info);
- mutex_unlock(&info->lock);
}
static int arizona_hpdet_wait(struct arizona_priv *info)
@@ -1018,9 +1014,9 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
cancelled_hp = cancel_delayed_work_sync(&info->hpdet_work);
cancelled_mic = cancel_delayed_work_sync(&info->micd_timeout_work);
- pm_runtime_get_sync(arizona->dev);
+ guard(pm_runtime_active_auto)(arizona->dev);
- mutex_lock(&info->lock);
+ guard(mutex)(&info->lock);
if (info->micd_clamp) {
mask = ARIZONA_MICD_CLAMP_STS;
@@ -1036,8 +1032,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val);
if (ret) {
dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret);
- mutex_unlock(&info->lock);
- pm_runtime_put_autosuspend(arizona->dev);
return IRQ_NONE;
}
@@ -1056,62 +1050,61 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
&info->micd_timeout_work,
msecs_to_jiffies(micd_timeout));
}
+ } else {
+ info->last_jackdet = val;
- goto out;
- }
- info->last_jackdet = val;
+ if (info->last_jackdet == present) {
+ dev_dbg(arizona->dev, "Detected jack\n");
+ snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
- if (info->last_jackdet == present) {
- dev_dbg(arizona->dev, "Detected jack\n");
- snd_soc_jack_report(info->jack, SND_JACK_MECHANICAL, SND_JACK_MECHANICAL);
+ info->detecting = true;
+ info->mic = false;
+ info->jack_flips = 0;
- info->detecting = true;
- info->mic = false;
- info->jack_flips = 0;
+ if (!arizona->pdata.hpdet_acc_id) {
+ arizona_start_mic(info);
+ } else {
+ queue_delayed_work(system_power_efficient_wq,
+ &info->hpdet_work,
+ msecs_to_jiffies(HPDET_DEBOUNCE));
+ }
- if (!arizona->pdata.hpdet_acc_id) {
- arizona_start_mic(info);
+ if (info->micd_clamp || !arizona->pdata.jd_invert)
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB |
+ ARIZONA_JD1_DB, 0);
} else {
- queue_delayed_work(system_power_efficient_wq,
- &info->hpdet_work,
- msecs_to_jiffies(HPDET_DEBOUNCE));
- }
+ dev_dbg(arizona->dev, "Detected jack removal\n");
- if (info->micd_clamp || !arizona->pdata.jd_invert)
- regmap_update_bits(arizona->regmap,
- ARIZONA_JACK_DETECT_DEBOUNCE,
- ARIZONA_MICD_CLAMP_DB |
- ARIZONA_JD1_DB, 0);
- } else {
- dev_dbg(arizona->dev, "Detected jack removal\n");
-
- arizona_stop_mic(info);
+ arizona_stop_mic(info);
- info->num_hpdet_res = 0;
- for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
- info->hpdet_res[i] = 0;
- info->mic = false;
- info->hpdet_done = false;
- info->hpdet_retried = false;
+ info->num_hpdet_res = 0;
+ for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++)
+ info->hpdet_res[i] = 0;
+ info->mic = false;
+ info->hpdet_done = false;
+ info->hpdet_retried = false;
- snd_soc_jack_report(info->jack, 0, ARIZONA_JACK_MASK | info->micd_button_mask);
+ snd_soc_jack_report(info->jack, 0,
+ ARIZONA_JACK_MASK | info->micd_button_mask);
- /*
- * If the jack was removed during a headphone detection we
- * need to wait for the headphone detection to finish, as
- * it can not be aborted. We don't want to be able to start
- * a new headphone detection from a fresh insert until this
- * one is finished.
- */
- arizona_hpdet_wait(info);
+ /*
+ * If the jack was removed during a headphone detection we
+ * need to wait for the headphone detection to finish, as
+ * it can not be aborted. We don't want to be able to start
+ * a new headphone detection from a fresh insert until this
+ * one is finished.
+ */
+ arizona_hpdet_wait(info);
- regmap_update_bits(arizona->regmap,
- ARIZONA_JACK_DETECT_DEBOUNCE,
- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
- ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
+ regmap_update_bits(arizona->regmap,
+ ARIZONA_JACK_DETECT_DEBOUNCE,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB,
+ ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB);
+ }
}
-out:
/* Clear trig_sts to make sure DCVDD is not forced up */
regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG,
ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
@@ -1119,10 +1112,6 @@ out:
ARIZONA_JD1_FALL_TRIG_STS |
ARIZONA_JD1_RISE_TRIG_STS);
- mutex_unlock(&info->lock);
-
- pm_runtime_put_autosuspend(arizona->dev);
-
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 8c683b0bb74c..4411165c3734 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
@@ -1158,17 +1159,16 @@ int arizona_dvfs_up(struct snd_soc_component *component, unsigned int flags)
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&priv->dvfs_lock);
+ guard(mutex)(&priv->dvfs_lock);
if (!priv->dvfs_cached && !priv->dvfs_reqs) {
ret = arizona_dvfs_enable(component);
if (ret)
- goto err;
+ return ret;
}
priv->dvfs_reqs |= flags;
-err:
- mutex_unlock(&priv->dvfs_lock);
+
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_up);
@@ -1179,7 +1179,7 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
unsigned int old_reqs;
int ret = 0;
- mutex_lock(&priv->dvfs_lock);
+ guard(mutex)(&priv->dvfs_lock);
old_reqs = priv->dvfs_reqs;
priv->dvfs_reqs &= ~flags;
@@ -1187,7 +1187,6 @@ int arizona_dvfs_down(struct snd_soc_component *component, unsigned int flags)
if (!priv->dvfs_cached && old_reqs && !priv->dvfs_reqs)
ret = arizona_dvfs_disable(component);
- mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_down);
@@ -1199,7 +1198,7 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
struct arizona_priv *priv = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&priv->dvfs_lock);
+ guard(mutex)(&priv->dvfs_lock);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -1222,7 +1221,6 @@ int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w,
break;
}
- mutex_unlock(&priv->dvfs_lock);
return ret;
}
EXPORT_SYMBOL_GPL(arizona_dvfs_sysclk_ev);
@@ -1657,13 +1655,11 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_component *component,
{ 0x80, 0x0 },
};
- mutex_lock(&arizona->dac_comp_lock);
-
- dac_comp[1].def = arizona->dac_comp_coeff;
- if (rate >= 176400)
- dac_comp[2].def = arizona->dac_comp_enabled;
-
- mutex_unlock(&arizona->dac_comp_lock);
+ scoped_guard(mutex, &arizona->dac_comp_lock) {
+ dac_comp[1].def = arizona->dac_comp_coeff;
+ if (rate >= 176400)
+ dac_comp[2].def = arizona->dac_comp_enabled;
+ }
regmap_multi_reg_write(arizona->regmap,
dac_comp,
diff --git a/sound/soc/codecs/aw87390.c b/sound/soc/codecs/aw87390.c
index 020213e0ca4b..5555c45dffcc 100644
--- a/sound/soc/codecs/aw87390.c
+++ b/sound/soc/codecs/aw87390.c
@@ -7,6 +7,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
#include <linux/regmap.h>
@@ -225,11 +226,10 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol,
struct aw87390 *aw87390 = snd_soc_component_get_drvdata(codec);
int ret;
- mutex_lock(&aw87390->lock);
+ guard(mutex)(&aw87390->lock);
ret = aw87390_dev_set_profile_index(aw87390->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change\n");
- mutex_unlock(&aw87390->lock);
return 0;
}
@@ -238,8 +238,6 @@ static int aw87390_profile_set(struct snd_kcontrol *kcontrol,
aw87390_power_on(aw87390->aw_pa);
}
- mutex_unlock(&aw87390->lock);
-
return 1;
}
@@ -250,7 +248,7 @@ static const struct snd_kcontrol_new aw87390_controls[] = {
static int aw87390_request_firmware_file(struct aw87390 *aw87390)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
int ret;
aw87390->aw_pa->fw_status = AW87390_DEV_FW_FAILED;
@@ -265,14 +263,11 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390)
aw87390->aw_cfg = devm_kzalloc(aw87390->aw_pa->dev,
struct_size(aw87390->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw87390->aw_cfg) {
- release_firmware(cont);
+ if (!aw87390->aw_cfg)
return -ENOMEM;
- }
aw87390->aw_cfg->len = cont->size;
memcpy(aw87390->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
ret = aw88395_dev_load_acf_check(aw87390->aw_pa, aw87390->aw_cfg);
if (ret) {
@@ -280,14 +275,12 @@ static int aw87390_request_firmware_file(struct aw87390 *aw87390)
return ret;
}
- mutex_lock(&aw87390->lock);
+ guard(mutex)(&aw87390->lock);
ret = aw88395_dev_cfg_load(aw87390->aw_pa, aw87390->aw_cfg);
if (ret)
dev_err(aw87390->aw_pa->dev, "aw_dev acf parse failed\n");
- mutex_unlock(&aw87390->lock);
-
return ret;
}
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
index d5e886a8f106..3247ba5c71b8 100644
--- a/sound/soc/codecs/aw88081.c
+++ b/sound/soc/codecs/aw88081.c
@@ -7,6 +7,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -763,9 +764,8 @@ static void aw88081_startup_work(struct work_struct *work)
struct aw88081 *aw88081 =
container_of(work, struct aw88081, start_work.work);
- mutex_lock(&aw88081->lock);
+ guard(mutex)(&aw88081->lock);
aw88081_start_pa(aw88081);
- mutex_unlock(&aw88081->lock);
}
static void aw88081_start(struct aw88081 *aw88081, bool sync_start)
@@ -942,11 +942,10 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
int ret;
/* pa stop or stopping just set profile */
- mutex_lock(&aw88081->lock);
+ guard(mutex)(&aw88081->lock);
ret = aw88081_dev_set_profile_index(aw88081->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88081->lock);
return 0;
}
@@ -955,8 +954,6 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
aw88081_start(aw88081, AW88081_SYNC_START);
}
- mutex_unlock(&aw88081->lock);
-
return 1;
}
@@ -1136,7 +1133,7 @@ static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg
static int aw88081_request_firmware_file(struct aw88081 *aw88081)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
struct aw_container *aw_cfg;
int ret;
@@ -1150,26 +1147,21 @@ static int aw88081_request_firmware_file(struct aw88081 *aw88081)
AW88081_ACF_FILE, cont ? cont->size : 0);
aw_cfg = devm_kzalloc(aw88081->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw_cfg) {
- release_firmware(cont);
+ if (!aw_cfg)
return -ENOMEM;
- }
+
aw_cfg->len = (int)cont->size;
memcpy(aw_cfg->data, cont->data, cont->size);
aw88081->aw_cfg = aw_cfg;
- release_firmware(cont);
-
ret = aw88395_dev_load_acf_check(aw88081->aw_pa, aw88081->aw_cfg);
if (ret)
return ret;
- mutex_lock(&aw88081->lock);
- ret = aw88081_dev_init(aw88081, aw88081->aw_cfg);
- mutex_unlock(&aw88081->lock);
+ guard(mutex)(&aw88081->lock);
- return ret;
+ return aw88081_dev_init(aw88081, aw88081->aw_cfg);
}
static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
@@ -1178,7 +1170,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88081 *aw88081 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88081->lock);
+ guard(mutex)(&aw88081->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88081_start(aw88081, AW88081_ASYNC_START);
@@ -1189,7 +1181,6 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88081->lock);
return 0;
}
diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c
index 3f15f4ac51f7..d2a138211c59 100644
--- a/sound/soc/codecs/aw88166.c
+++ b/sound/soc/codecs/aw88166.c
@@ -7,6 +7,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -1173,9 +1174,8 @@ static void aw88166_startup_work(struct work_struct *work)
struct aw88166 *aw88166 =
container_of(work, struct aw88166, start_work.work);
- mutex_lock(&aw88166->lock);
+ guard(mutex)(&aw88166->lock);
aw88166_start_pa(aw88166);
- mutex_unlock(&aw88166->lock);
}
static void aw88166_start(struct aw88166 *aw88166, bool sync_start)
@@ -1413,11 +1413,10 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol,
struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
int ret;
- mutex_lock(&aw88166->lock);
+ guard(mutex)(&aw88166->lock);
ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88166->lock);
return 0;
}
@@ -1426,8 +1425,6 @@ static int aw88166_profile_set(struct snd_kcontrol *kcontrol,
aw88166_start(aw88166, AW88166_SYNC_START);
}
- mutex_unlock(&aw88166->lock);
-
return 1;
}
@@ -1573,7 +1570,7 @@ static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg
static int aw88166_request_firmware_file(struct aw88166 *aw88166)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
const char *fw_name;
int ret;
@@ -1593,13 +1590,11 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166)
aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev,
struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw88166->aw_cfg) {
- release_firmware(cont);
+ if (!aw88166->aw_cfg)
return -ENOMEM;
- }
+
aw88166->aw_cfg->len = (int)cont->size;
memcpy(aw88166->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg);
if (ret) {
@@ -1607,12 +1602,12 @@ static int aw88166_request_firmware_file(struct aw88166 *aw88166)
return ret;
}
- mutex_lock(&aw88166->lock);
- /* aw device init */
- ret = aw88166_dev_init(aw88166, aw88166->aw_cfg);
- if (ret)
- dev_err(aw88166->aw_pa->dev, "dev init failed\n");
- mutex_unlock(&aw88166->lock);
+ scoped_guard(mutex, &aw88166->lock) {
+ /* aw device init */
+ ret = aw88166_dev_init(aw88166, aw88166->aw_cfg);
+ if (ret)
+ dev_err(aw88166->aw_pa->dev, "dev init failed\n");
+ }
return ret;
}
@@ -1639,7 +1634,7 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88166->lock);
+ guard(mutex)(&aw88166->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88166_start(aw88166, AW88166_ASYNC_START);
@@ -1650,7 +1645,6 @@ static int aw88166_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88166->lock);
return 0;
}
diff --git a/sound/soc/codecs/aw88261.c b/sound/soc/codecs/aw88261.c
index 549783d3e75e..b8d06534bc8f 100644
--- a/sound/soc/codecs/aw88261.c
+++ b/sound/soc/codecs/aw88261.c
@@ -8,6 +8,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
#include <linux/bitops.h>
@@ -206,10 +207,10 @@ static int aw88261_dev_check_sysst(struct aw_device *aw_dev)
return ret;
check_val = reg_val & (~AW88261_BIT_SYSST_CHECK_MASK)
- & AW88261_BIT_SYSST_CHECK;
- if (check_val != AW88261_BIT_SYSST_CHECK) {
+ & AW88261_BIT_PLL_CHECK;
+ if (check_val != AW88261_BIT_PLL_CHECK) {
dev_dbg(aw_dev->dev, "check sysst fail, reg_val=0x%04x, check:0x%x",
- reg_val, AW88261_BIT_SYSST_CHECK);
+ reg_val, AW88261_BIT_PLL_CHECK);
usleep_range(AW88261_2000_US, AW88261_2000_US + 10);
} else {
return 0;
@@ -960,11 +961,10 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
int ret;
/* pa stop or stopping just set profile */
- mutex_lock(&aw88261->lock);
+ guard(mutex)(&aw88261->lock);
ret = aw88261_dev_set_profile_index(aw88261->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88261->lock);
return 0;
}
@@ -973,8 +973,6 @@ static int aw88261_profile_set(struct snd_kcontrol *kcontrol,
aw88261_start(aw88261);
}
- mutex_unlock(&aw88261->lock);
-
return 1;
}
@@ -1038,7 +1036,7 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88261 *aw88261 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88261->lock);
+ guard(mutex)(&aw88261->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88261_start(aw88261);
@@ -1049,7 +1047,6 @@ static int aw88261_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88261->lock);
return 0;
}
@@ -1152,7 +1149,7 @@ static int aw88261_dev_init(struct aw88261 *aw88261, struct aw_container *aw_cfg
static int aw88261_request_firmware_file(struct aw88261 *aw88261)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
struct aw_container *aw_cfg;
const char *fw_name;
int ret;
@@ -1172,13 +1169,11 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261)
fw_name, cont ? cont->size : 0);
aw_cfg = devm_kzalloc(aw88261->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw_cfg) {
- release_firmware(cont);
+ if (!aw_cfg)
return -ENOMEM;
- }
+
aw_cfg->len = (int)cont->size;
memcpy(aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
aw88261->aw_cfg = aw_cfg;
@@ -1188,12 +1183,12 @@ static int aw88261_request_firmware_file(struct aw88261 *aw88261)
return ret;
}
- mutex_lock(&aw88261->lock);
- /* aw device init */
- ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
- if (ret)
- dev_err(aw88261->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88261->lock);
+ scoped_guard(mutex, &aw88261->lock) {
+ /* aw device init */
+ ret = aw88261_dev_init(aw88261, aw88261->aw_cfg);
+ if (ret)
+ dev_err(aw88261->aw_pa->dev, "dev init failed");
+ }
return ret;
}
diff --git a/sound/soc/codecs/aw88261.h b/sound/soc/codecs/aw88261.h
index 270ccf375f36..f16f9f8c40a2 100644
--- a/sound/soc/codecs/aw88261.h
+++ b/sound/soc/codecs/aw88261.h
@@ -194,12 +194,6 @@
AW88261_OTHS_OT_VALUE | \
AW88261_PLLS_LOCKED_VALUE))
-#define AW88261_BIT_SYSST_CHECK \
- (AW88261_BSTS_FINISHED_VALUE | \
- AW88261_SWS_SWITCHING_VALUE | \
- AW88261_CLKS_STABLE_VALUE | \
- AW88261_PLLS_LOCKED_VALUE)
-
#define AW88261_ULS_HMUTE_START_BIT (14)
#define AW88261_ULS_HMUTE_BITS_LEN (1)
#define AW88261_ULS_HMUTE_MASK \
diff --git a/sound/soc/codecs/aw88395/aw88395.c b/sound/soc/codecs/aw88395/aw88395.c
index ee0e8bd8c54c..2f4108624d13 100644
--- a/sound/soc/codecs/aw88395/aw88395.c
+++ b/sound/soc/codecs/aw88395/aw88395.c
@@ -8,6 +8,7 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/firmware.h>
@@ -51,9 +52,8 @@ static void aw88395_startup_work(struct work_struct *work)
struct aw88395 *aw88395 =
container_of(work, struct aw88395, start_work.work);
- mutex_lock(&aw88395->lock);
+ guard(mutex)(&aw88395->lock);
aw88395_start_pa(aw88395);
- mutex_unlock(&aw88395->lock);
}
static void aw88395_start(struct aw88395 *aw88395, bool sync_start)
@@ -224,11 +224,10 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol,
int ret;
/* pa stop or stopping just set profile */
- mutex_lock(&aw88395->lock);
+ guard(mutex)(&aw88395->lock);
ret = aw88395_dev_set_profile_index(aw88395->aw_pa, ucontrol->value.integer.value[0]);
if (ret < 0) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88395->lock);
return 0;
}
@@ -237,8 +236,6 @@ static int aw88395_profile_set(struct snd_kcontrol *kcontrol,
aw88395_start(aw88395, AW88395_SYNC_START);
}
- mutex_unlock(&aw88395->lock);
-
return 1;
}
@@ -366,7 +363,7 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88395 *aw88395 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88395->lock);
+ guard(mutex)(&aw88395->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88395_start(aw88395, AW88395_ASYNC_START);
@@ -377,7 +374,6 @@ static int aw88395_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88395->lock);
return 0;
}
@@ -461,7 +457,7 @@ static void aw88395_hw_reset(struct aw88395 *aw88395)
static int aw88395_request_firmware_file(struct aw88395 *aw88395)
{
- const struct firmware *cont = NULL;
+ const struct firmware *cont __free(firmware) = NULL;
struct aw_container *aw_cfg;
int ret;
@@ -477,13 +473,11 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395)
AW88395_ACF_FILE, cont ? cont->size : 0);
aw_cfg = devm_kzalloc(aw88395->aw_pa->dev, struct_size(aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw_cfg) {
- release_firmware(cont);
+ if (!aw_cfg)
return -ENOMEM;
- }
+
aw_cfg->len = (int)cont->size;
memcpy(aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
aw88395->aw_cfg = aw_cfg;
@@ -495,12 +489,12 @@ static int aw88395_request_firmware_file(struct aw88395 *aw88395)
dev_dbg(aw88395->aw_pa->dev, "%s : bin load success\n", __func__);
- mutex_lock(&aw88395->lock);
- /* aw device init */
- ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg);
- if (ret < 0)
- dev_err(aw88395->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88395->lock);
+ scoped_guard(mutex, &aw88395->lock) {
+ /* aw device init */
+ ret = aw88395_dev_init(aw88395->aw_pa, aw88395->aw_cfg);
+ if (ret < 0)
+ dev_err(aw88395->aw_pa->dev, "dev init failed");
+ }
return ret;
}
diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c
index 79c3135a4110..12d42d27560d 100644
--- a/sound/soc/codecs/aw88395/aw88395_device.c
+++ b/sound/soc/codecs/aw88395/aw88395_device.c
@@ -8,6 +8,7 @@
// Author: Ben Yi <yijiangtao@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/i2c.h>
#include <linux/minmax.h>
@@ -70,7 +71,7 @@ int aw_dev_dsp_write(struct aw_device *aw_dev,
u32 reg_value;
int ret;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
switch (data_type) {
case AW_DSP_16_DATA:
ret = aw_dev_dsp_write_16bit(aw_dev, dsp_addr, dsp_data);
@@ -93,7 +94,6 @@ int aw_dev_dsp_write(struct aw_device *aw_dev,
/* clear dsp chip select state*/
if (regmap_read(aw_dev->regmap, AW88395_ID_REG, &reg_value))
dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret);
- mutex_unlock(&aw_dev->dsp_lock);
return ret;
}
@@ -156,7 +156,7 @@ int aw_dev_dsp_read(struct aw_device *aw_dev,
u32 reg_value;
int ret;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
switch (data_type) {
case AW_DSP_16_DATA:
ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data);
@@ -179,7 +179,6 @@ int aw_dev_dsp_read(struct aw_device *aw_dev,
/* clear dsp chip select state*/
if (regmap_read(aw_dev->regmap, AW88395_ID_REG, &reg_value))
dev_err(aw_dev->dev, "%s fail to clear chip state. Err=%d\n", __func__, ret);
- mutex_unlock(&aw_dev->dsp_lock);
return ret;
}
@@ -1110,42 +1109,36 @@ static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
#ifdef AW88395_DSP_I2C_WRITES
u32 tmp_len;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base);
if (ret)
- goto error_operation;
+ return ret;
for (i = 0; i < len; i += AW88395_MAX_RAM_WRITE_BYTE_SIZE) {
tmp_len = min(len - i, AW88395_MAX_RAM_WRITE_BYTE_SIZE);
ret = regmap_raw_write(aw_dev->regmap, AW88395_DSPMDAT_REG,
&data[i], tmp_len);
if (ret)
- goto error_operation;
+ return ret;
}
- mutex_unlock(&aw_dev->dsp_lock);
#else
__be16 reg_val;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
/* i2c write */
ret = regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, base);
if (ret)
- goto error_operation;
+ return ret;
for (i = 0; i < len; i += 2) {
reg_val = cpu_to_be16p((u16 *)(data + i));
ret = regmap_write(aw_dev->regmap, AW88395_DSPMDAT_REG,
(u16)reg_val);
if (ret)
- goto error_operation;
+ return ret;
}
- mutex_unlock(&aw_dev->dsp_lock);
#endif
return 0;
-
-error_operation:
- mutex_unlock(&aw_dev->dsp_lock);
- return ret;
}
static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
@@ -1231,14 +1224,14 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
{
unsigned int reg_val;
- mutex_lock(&aw_dev->dsp_lock);
+ guard(mutex)(&aw_dev->dsp_lock);
/* check the odd bits of reg 0x40 */
regmap_write(aw_dev->regmap, AW88395_DSPMADD_REG, AW88395_DSP_ODD_NUM_BIT_TEST);
regmap_read(aw_dev->regmap, AW88395_DSPMADD_REG, &reg_val);
if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check reg 0x40 odd bit failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_ODD_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
/* check the even bits of reg 0x40 */
@@ -1247,7 +1240,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check reg 0x40 even bit failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
/* check dsp_fw_base_addr */
@@ -1256,7 +1249,7 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
if (reg_val != AW88395_DSP_EVEN_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check dsp fw addr failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_EVEN_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
/* check dsp_cfg_base_addr */
@@ -1265,15 +1258,10 @@ static int aw_dev_check_sram(struct aw_device *aw_dev)
if (reg_val != AW88395_DSP_ODD_NUM_BIT_TEST) {
dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
reg_val, AW88395_DSP_ODD_NUM_BIT_TEST);
- goto error;
+ return -EPERM;
}
- mutex_unlock(&aw_dev->dsp_lock);
return 0;
-
-error:
- mutex_unlock(&aw_dev->dsp_lock);
- return -EPERM;
}
int aw88395_dev_fw_update(struct aw_device *aw_dev, bool up_dsp_fw_en, bool force_up_en)
diff --git a/sound/soc/codecs/aw88399-lib.c b/sound/soc/codecs/aw88399-lib.c
new file mode 100644
index 000000000000..809c2faa0c0c
--- /dev/null
+++ b/sound/soc/codecs/aw88399-lib.c
@@ -0,0 +1,1409 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88399-lib.c -- AW88399 Common functions for ASoC and HDA audio drivers
+//
+// Copyright (c) 2023 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/minmax.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/aw88399.h>
+#include "aw88395/aw88395_device.h"
+
+const struct regmap_config aw88399_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88399_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+EXPORT_SYMBOL_GPL(aw88399_remap_config);
+
+static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ int ret;
+
+ if (pwd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
+ if (ret)
+ dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
+ else
+ *int_status = reg_val;
+
+ dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
+}
+
+static void aw_dev_clear_int_status(struct aw_device *aw_dev)
+{
+ u16 int_status;
+
+ /* read int status and clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ /* make sure int status is clear */
+ aw_dev_get_int_status(aw_dev, &int_status);
+ if (int_status)
+ dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
+}
+
+static int aw_dev_get_iis_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
+ dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode1 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88399_CCO_MUX_MASK);
+ if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) {
+ dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
+ return -EPERM;
+ }
+
+ /* change mode2 */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
+ ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = aw_dev_get_iis_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+int aw_dev_check_syspll(struct aw_device *aw_dev)
+{
+ int ret;
+
+ ret = aw_dev_check_mode1_pll(aw_dev);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
+ ret = aw_dev_check_mode2_pll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "mode2 check iis failed");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw_dev_check_syspll);
+
+static int aw_dev_check_sysst(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int check_val;
+ unsigned int reg_val;
+ int ret, i;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
+ check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
+ else
+ check_val = AW88399_BIT_SYSST_SWS_CHECK;
+
+ /*
+ * On some hardware the BSTS (boost-finished) status bit does not
+ * reliably assert even when audio output is working normally.
+ * Allow per-instance bypass when flagged by the side-codec driver.
+ */
+ if (aw88399->bsts_unreliable)
+ check_val &= ~AW88399_BSTS_FINISHED_VALUE;
+
+ for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
+ dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
+ i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ } else {
+ return 0;
+ }
+ }
+
+ return -EPERM;
+}
+
+static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ int ret;
+
+ if (amppd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
+{
+ int ret;
+
+ if (is_enable)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed\n", __func__);
+}
+EXPORT_SYMBOL_GPL(aw_dev_dsp_enable);
+
+static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
+{
+ uint16_t icalkh_val, icalkl_val, icalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
+ if (ret)
+ return ret;
+ icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ icalk_val = icalkh_val & icalkl_val;
+ else
+ icalk_val = icalkh_val | icalkl_val;
+
+ if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
+ icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
+ *icalk = (int16_t)icalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = vcalkh_val & vcalkl_val;
+ else
+ vcalk_val = vcalkh_val | vcalkl_val;
+
+ if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
+ vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
+{
+ uint16_t vcalkh_val, vcalkl_val, vcalk_val;
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+ vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
+
+ if (aw88399->check_val == AW_EF_AND_CHECK)
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+ else
+ vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
+ (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
+
+ if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
+ vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
+
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw_dev_set_vcalb(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ unsigned int vsense_select, vsense_value;
+ int32_t ical_k, vcal_k, vcalb;
+ int16_t icalk, vcalk;
+ uint16_t reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
+ if (ret)
+ return ret;
+
+ vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
+
+ ret = aw88399_dev_get_icalk(aw88399, &icalk);
+ if (ret) {
+ dev_err(aw_dev->dev, "get icalk failed\n");
+ return ret;
+ }
+
+ ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+
+ switch (vsense_select) {
+ case AW88399_DEV_VDSEL_VSENSE:
+ ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
+ ical_k / vcal_k * aw88399->vcalb_init_val;
+ break;
+ case AW88399_DEV_VDSEL_DAC:
+ ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
+ vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
+ vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
+ AW88399_ISCAL_DAC_FACTOR * ical_k /
+ vcal_k * aw88399->vcalb_init_val;
+ break;
+ default:
+ dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
+ ret = -EINVAL;
+ break;
+ }
+ if (ret)
+ return ret;
+
+ vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
+ reg_val = (uint32_t)vcalb;
+
+ regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
+
+ return 0;
+}
+
+int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ uint16_t re_lbits, re_hbits;
+ u32 cali_re;
+ int ret;
+
+ if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
+ (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
+ return -EINVAL;
+
+ cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
+ aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
+
+ re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
+ re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
+ if (ret) {
+ dev_err(aw_dev->dev, "set cali re error");
+ return ret;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
+ if (ret)
+ dev_err(aw_dev->dev, "set cali re error");
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw_dev_update_cali_re);
+
+static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, fw_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate fw_end_addr */
+ fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
+
+ /* write fw_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
+ if (ret)
+ return ret;
+ /* enable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
+
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ /* read crc check result */
+ regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
+ __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
+{
+ uint16_t check_val, cfg_len_val;
+ unsigned int reg_val;
+ int ret;
+
+ /* calculate cfg end addr */
+ cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
+
+ /* write cfg_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
+ if (ret)
+ return ret;
+
+ /* enable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
+ if (ret)
+ return ret;
+
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ /* read crc check result */
+ ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
+
+ /* disable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
+ ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
+ check_val, AW88399_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
+ if (ret)
+ return ret;
+
+ ret = aw_dev_fw_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = aw_dev_cfg_crc_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "cfg_crc_check failed\n");
+ goto crc_check_failed;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+
+ return ret;
+
+crc_check_failed:
+ regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
+ return ret;
+}
+
+static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
+{
+ int ret;
+
+ if (flag)
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
+ ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+}
+
+int aw_dev_get_dsp_status(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
+ if (ret)
+ return ret;
+ if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
+ return -EPERM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw_dev_get_dsp_status);
+
+static int aw_dev_dsp_check(struct aw_device *aw_dev)
+{
+ int ret, i;
+
+ switch (aw_dev->dsp_cfg) {
+ case AW88399_DEV_DSP_BYPASS:
+ dev_dbg(aw_dev->dev, "dsp bypass");
+ ret = 0;
+ break;
+ case AW88399_DEV_DSP_WORK:
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_dsp_enable(aw_dev, true);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
+ ret = aw_dev_get_dsp_status(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+ }
+ }
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
+{
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ unsigned int reg_value;
+ u16 real_value;
+ int ret;
+
+ real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
+
+ real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
+
+ ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw_dev_set_volume);
+
+static void aw_dev_fade_in(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ u16 fade_in_vol = desc->ctl_volume;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_in_time == 0) {
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+ return;
+ }
+
+ for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
+ }
+
+ if (i != fade_in_vol)
+ aw_dev_set_volume(aw_dev, fade_in_vol);
+}
+
+static void aw_dev_fade_out(struct aw_device *aw_dev)
+{
+ struct aw_volume_desc *desc = &aw_dev->volume_desc;
+ int fade_step = aw_dev->fade_step;
+ int i;
+
+ if (fade_step == 0 || aw_dev->fade_out_time == 0) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
+ aw_dev_set_volume(aw_dev, i);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+
+ if (i != AW88399_MUTE_VOL) {
+ aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
+{
+ if (is_mute) {
+ aw_dev_fade_out(aw_dev);
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
+ ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
+ aw_dev_fade_in(aw_dev);
+ }
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_mute);
+
+static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+
+ if (dither)
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
+}
+
+static int aw88399_dev_start(struct aw88399 *aw88399)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88399_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ aw88399_dev_set_dither(aw88399, false);
+
+ /* power on */
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
+
+ ret = aw_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw_dev_amppd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw_dev_check_sysst(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed");
+ goto sysst_check_fail;
+ }
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
+ ret = aw_dev_hw_crc_check(aw88399);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp crc check failed");
+ goto crc_check_fail;
+ }
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_set_vcalb(aw88399);
+ aw_dev_update_cali_re(&aw_dev->cali_desc);
+
+ ret = aw_dev_dsp_check(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp status check failed");
+ goto dsp_check_fail;
+ }
+ } else {
+ dev_dbg(aw_dev->dev, "start pa with dsp bypass");
+ }
+
+ /* enable tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, true);
+
+ if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
+ aw88399_dev_set_dither(aw88399, true);
+
+ /* close mute */
+ aw88399_dev_mute(aw_dev, false);
+ /* clear inturrupt */
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88399_DEV_PW_ON;
+
+ return 0;
+
+dsp_check_fail:
+crc_check_fail:
+ aw_dev_dsp_enable(aw_dev, false);
+sysst_check_fail:
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev_amppd(aw_dev, true);
+pll_check_fail:
+ aw_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len, unsigned short base)
+{
+ u32 tmp_len;
+ int i, ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
+ tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
+ ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
+ &data[i], tmp_len);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
+{
+ struct aw_device *aw_dev =
+ container_of(cali_desc, struct aw_device, cali_desc);
+ u32 dsp_ra;
+ int ret;
+
+ ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
+ &dsp_ra, AW_DSP_32_DATA);
+ if (ret) {
+ dev_err(aw_dev->dev, "read ra error");
+ return ret;
+ }
+
+ cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
+ AW88399_DSP_RE_SHIFT);
+
+ return 0;
+}
+
+static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp config len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp config data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
+ if (ret)
+ return ret;
+
+ aw_dev->dsp_cfg_len = len;
+
+ ret = aw_dev_get_ra(&aw_dev->cali_desc);
+
+ return ret;
+}
+
+static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
+
+ if (!len || !data) {
+ dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
+ return -EINVAL;
+ }
+
+ aw_dev->dsp_fw_len = len;
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
+
+ return ret;
+}
+
+static int aw_dev_check_sram(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+
+ /* read dsp_rom_check_reg */
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
+ dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
+ reg_val, AW88399_DSP_ROM_CHECK_DATA);
+ return -EPERM;
+ }
+
+ /* check dsp_cfg_base_addr */
+ aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
+ AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
+ aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
+ if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
+ dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
+ reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
+{
+ int ret;
+
+ switch (flag) {
+ case AW88399_DEV_MEMCLK_PLL:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select pll failed");
+ break;
+ case AW88399_DEV_MEMCLK_OSC:
+ ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
+ ~AW88399_MEM_CLKSEL_MASK,
+ AW88399_MEM_CLKSEL_OSCCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select OSC failed");
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
+ break;
+ }
+}
+
+static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
+{
+ struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
+ if (ret) {
+ dev_dbg(aw_dev->dev, "%s failed", __func__);
+ return;
+ }
+ if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
+ profctrl_desc->cur_mode = AW88399_RCV_MODE;
+ else
+ profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
+}
+
+static int aw_dev_update_reg_container(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
+ u16 read_vol, reg_val;
+ int data_len, i, ret;
+ int16_t *reg_data;
+ u8 reg_addr;
+
+ reg_data = (int16_t *)data;
+ data_len = len >> 1;
+
+ if (data_len & 0x1) {
+ dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < data_len; i += 2) {
+ reg_addr = reg_data[i];
+ reg_val = reg_data[i + 1];
+
+ if (reg_addr == AW88399_DSPVCALB_REG) {
+ aw88399->vcalb_init_val = reg_val;
+ continue;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL_REG) {
+ if (reg_val & (~AW88399_DSPBY_MASK))
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
+ else
+ aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
+
+ reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
+ AW88399_DSPBY_MASK);
+ reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
+ AW88399_DSPBY_BYPASS_VALUE);
+ }
+
+ if (reg_addr == AW88399_I2SCTRL3_REG) {
+ reg_val &= AW88399_I2STXEN_MASK;
+ reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88399_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
+ AW88399_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ if (reg_addr == AW88399_DBGCTRL_REG) {
+ if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
+ aw88399->check_val = AW_EF_OR_CHECK;
+ else
+ aw88399->check_val = AW_EF_AND_CHECK;
+
+ aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
+ }
+
+ if (reg_addr == AW88399_CRCCTRL_REG)
+ aw88399->crc_init_val = reg_val;
+
+ ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
+ if (ret)
+ return ret;
+ }
+
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+
+ aw_dev_get_cur_mode_st(aw_dev);
+
+ if (aw_dev->prof_cur != aw_dev->prof_index)
+ vol_desc->ctl_volume = 0;
+ else
+ aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
+
+ return 0;
+}
+
+static int aw_dev_reg_update(struct aw88399 *aw88399,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ if (!len || !data) {
+ dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_update_reg_container(aw88399, data, len);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "reg update failed");
+
+ return ret;
+}
+
+int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
+{
+ struct aw_prof_info *prof_info = &aw_dev->prof_info;
+ struct aw_prof_desc *prof_desc;
+
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
+ index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ *prof_name = prof_info->prof_name_list[prof_desc->id];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_get_prof_name);
+
+static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index,
+ struct aw_prof_desc **prof_desc)
+{
+ if ((index >= aw_dev->prof_info.count) || (index < 0)) {
+ dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
+ __func__, index, aw_dev->prof_info.count);
+ return -EINVAL;
+ }
+
+ *prof_desc = &aw_dev->prof_info.prof_desc[index];
+
+ return 0;
+}
+
+static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ struct aw_prof_desc *prof_index_desc;
+ struct aw_sec_data_desc *sec_desc;
+ char *prof_name;
+ int ret;
+
+ if ((aw_dev->prof_cur == aw_dev->prof_index) &&
+ (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
+ dev_dbg(aw_dev->dev, "scene no change, not update");
+ return 0;
+ }
+
+ if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
+ dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
+ return -EPERM;
+ }
+
+ ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
+ if (ret)
+ return ret;
+
+ dev_dbg(aw_dev->dev, "start update %s", prof_name);
+
+ ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
+ if (ret)
+ return ret;
+
+ /* update reg */
+ sec_desc = prof_index_desc->sec_desc;
+ ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed");
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+
+ ret = aw_dev_check_sram(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "check sram failed");
+ goto error;
+ }
+
+ if (up_dsp_fw_en) {
+ dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
+ ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp fw failed");
+ goto error;
+ }
+ }
+
+ /* update dsp config */
+ ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
+ sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update dsp cfg failed");
+ goto error;
+ }
+
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+
+error:
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ return ret;
+}
+
+static void aw88399_start_pa(struct aw88399 *aw88399)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88399_START_RETRIES; i++) {
+ ret = aw88399_dev_start(aw88399);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
+ ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed");
+ continue;
+ }
+ } else {
+ dev_dbg(aw88399->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+void aw88399_startup_work(struct work_struct *work)
+{
+ struct aw88399 *aw88399 =
+ container_of(work, struct aw88399, start_work.work);
+
+ mutex_lock(&aw88399->lock);
+ aw88399_start_pa(aw88399);
+ mutex_unlock(&aw88399->lock);
+}
+EXPORT_SYMBOL_GPL(aw88399_startup_work);
+
+void aw88399_start(struct aw88399 *aw88399, bool sync_start)
+{
+ int ret;
+
+ if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
+ return;
+
+ if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
+ return;
+
+ ret = aw88399_dev_fw_update(aw88399, aw88399->fw_needs_reload ?
+ AW88399_DSP_FW_UPDATE_ON : AW88399_DSP_FW_UPDATE_OFF, true);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "fw update failed.");
+ return;
+ }
+
+ aw88399->fw_needs_reload = false;
+
+ if (sync_start == AW88399_SYNC_START)
+ aw88399_start_pa(aw88399);
+ else
+ queue_delayed_work(system_dfl_wq,
+ &aw88399->start_work,
+ AW88399_START_WORK_DELAY_MS);
+}
+EXPORT_SYMBOL_GPL(aw88399_start);
+
+static int aw_dev_check_sysint(struct aw_device *aw_dev)
+{
+ u16 reg_val;
+
+ aw_dev_get_int_status(aw_dev, &reg_val);
+ if (reg_val & AW88399_BIT_SYSINT_CHECK) {
+ dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int aw88399_stop(struct aw_device *aw_dev)
+{
+ struct aw_sec_data_desc *dsp_cfg =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
+ struct aw_sec_data_desc *dsp_fw =
+ &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
+ int int_st;
+
+ if (aw_dev->status == AW88399_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88399_DEV_PW_OFF;
+
+ aw88399_dev_mute(aw_dev, true);
+ usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
+
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ int_st = aw_dev_check_sysint(aw_dev);
+
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_amppd(aw_dev, true);
+
+ if (int_st) {
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
+ aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
+ aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
+ aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
+ }
+
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_stop);
+
+static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88399->aw_pa;
+ int ret;
+
+ ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
+ if (ret) {
+ dev_err(aw_dev->dev, "aw_dev acf parse failed");
+ return -EINVAL;
+ }
+ aw_dev->fade_in_time = AW88399_1000_US / 10;
+ aw_dev->fade_out_time = AW88399_1000_US >> 1;
+ aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
+ aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
+
+ ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88399_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
+
+ /* enable amppd */
+ aw_dev_amppd(aw_dev, true);
+
+ /* close dsp */
+ aw_dev_dsp_enable(aw_dev, false);
+ /* set power down */
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+int aw88399_request_firmware_file(struct aw88399 *aw88399)
+{
+ const struct firmware *cont __free(firmware) = NULL;
+ int ret;
+
+ aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88399_ACF_FILE, cont ? cont->size : 0);
+
+ aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
+ struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
+ if (!aw88399->aw_cfg)
+ return -ENOMEM;
+
+ aw88399->aw_cfg->len = (int)cont->size;
+ memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
+
+ ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
+ if (ret) {
+ dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
+ return ret;
+ }
+
+ mutex_lock(&aw88399->lock);
+ /* aw device init */
+ ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
+ if (ret)
+ dev_err(aw88399->aw_pa->dev, "dev init failed");
+ mutex_unlock(&aw88399->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aw88399_request_firmware_file);
+
+void aw88399_hw_reset(struct aw88399 *aw88399)
+{
+ if (aw88399->reset_gpio) {
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
+ usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
+ }
+}
+EXPORT_SYMBOL_GPL(aw88399_hw_reset);
+
+static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
+{
+ struct device_node *np = aw_dev->dev->of_node;
+ u32 channel_value;
+ int ret;
+
+ ret = of_property_read_u32(np, "awinic,audio-channel", &channel_value);
+ if (ret) {
+ /*
+ * On ACPI systems, DT properties don't exist. Derive channel
+ * from I2C address: 0x34 -> channel 0 (left), 0x35 -> channel 1 (right)
+ */
+ aw_dev->channel = aw_dev->i2c->addr - 0x34;
+ dev_dbg(aw_dev->dev,
+ "DT channel property not found, using I2C address-based channel %d (addr 0x%02x)\n",
+ aw_dev->channel, aw_dev->i2c->addr);
+ return;
+ }
+ aw_dev->channel = channel_value;
+}
+
+int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
+ return ret;
+ }
+ if (chip_id != AW88399_CHIP_ID) {
+ dev_err(&i2c->dev, "unsupported device");
+ return -ENXIO;
+ }
+ dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+ aw88399->aw_pa = aw_dev;
+
+ aw_dev->i2c = i2c;
+ aw_dev->dev = &i2c->dev;
+ aw_dev->regmap = regmap;
+ mutex_init(&aw_dev->dsp_lock);
+
+ aw_dev->chip_id = chip_id;
+ aw_dev->acf = NULL;
+ aw_dev->prof_info.prof_desc = NULL;
+ aw_dev->prof_info.count = 0;
+ aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
+ aw_dev->channel = AW88399_DEV_DEFAULT_CH;
+ aw_dev->fw_status = AW88399_DEV_FW_FAILED;
+
+ aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
+
+ aw88399_parse_channel_dt(aw_dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aw88399_init);
+
+void aw88399_dev_set_channel(struct aw88399 *aw88399, int channel)
+{
+ aw88399->aw_pa->channel = channel;
+}
+EXPORT_SYMBOL_GPL(aw88399_dev_set_channel);
+
+MODULE_DESCRIPTION("AW88399 common device library");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/aw88399.c b/sound/soc/codecs/aw88399.c
index b2ec3503f7e2..e9dab5e7bae3 100644
--- a/sound/soc/codecs/aw88399.c
+++ b/sound/soc/codecs/aw88399.c
@@ -7,1220 +7,16 @@
// Author: Weidong Wang <wangweidong.a@awinic.com>
//
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/minmax.h>
#include <linux/regmap.h>
#include <linux/sort.h>
#include <sound/soc.h>
#include "aw88399.h"
#include "aw88395/aw88395_device.h"
-static const struct regmap_config aw88399_remap_config = {
- .val_bits = 16,
- .reg_bits = 8,
- .max_register = AW88399_REG_MAX,
- .reg_format_endian = REGMAP_ENDIAN_LITTLE,
- .val_format_endian = REGMAP_ENDIAN_BIG,
-};
-
-static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
-{
- int ret;
-
- if (pwd)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_PWDN_MASK, AW88399_PWDN_POWER_DOWN_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_PWDN_MASK, AW88399_PWDN_WORKING_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSINT_REG, &reg_val);
- if (ret)
- dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret);
- else
- *int_status = reg_val;
-
- dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status);
-}
-
-static void aw_dev_clear_int_status(struct aw_device *aw_dev)
-{
- u16 int_status;
-
- /* read int status and clear */
- aw_dev_get_int_status(aw_dev, &int_status);
- /* make sure int status is clear */
- aw_dev_get_int_status(aw_dev, &int_status);
- if (int_status)
- dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status);
-}
-
-static int aw_dev_get_iis_status(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
- if (ret)
- return ret;
- if ((reg_val & AW88399_BIT_PLL_CHECK) != AW88399_BIT_PLL_CHECK) {
- dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int aw_dev_check_mode1_pll(struct aw_device *aw_dev)
-{
- int ret, i;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode1 iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- return 0;
- }
- }
-
- return -EPERM;
-}
-
-static int aw_dev_check_mode2_pll(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret, i;
-
- ret = regmap_read(aw_dev->regmap, AW88399_PLLCTRL2_REG, &reg_val);
- if (ret)
- return ret;
-
- reg_val &= (~AW88399_CCO_MUX_MASK);
- if (reg_val == AW88399_CCO_MUX_DIVIDED_VALUE) {
- dev_dbg(aw_dev->dev, "CCO_MUX is already divider");
- return -EPERM;
- }
-
- /* change mode2 */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_DIVIDED_VALUE);
- if (ret)
- return ret;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- break;
- }
- }
-
- /* change mode1 */
- regmap_update_bits(aw_dev->regmap, AW88399_PLLCTRL2_REG,
- ~AW88399_CCO_MUX_MASK, AW88399_CCO_MUX_BYPASS_VALUE);
- if (ret == 0) {
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = aw_dev_get_iis_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error");
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- break;
- }
- }
- }
-
- return ret;
-}
-
-static int aw_dev_check_syspll(struct aw_device *aw_dev)
-{
- int ret;
-
- ret = aw_dev_check_mode1_pll(aw_dev);
- if (ret) {
- dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check");
- ret = aw_dev_check_mode2_pll(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "mode2 check iis failed");
- return ret;
- }
- }
-
- return 0;
-}
-
-static int aw_dev_check_sysst(struct aw_device *aw_dev)
-{
- unsigned int check_val;
- unsigned int reg_val;
- int ret, i;
-
- ret = regmap_read(aw_dev->regmap, AW88399_PWMCTRL3_REG, &reg_val);
- if (ret)
- return ret;
-
- if (reg_val & (~AW88399_NOISE_GATE_EN_MASK))
- check_val = AW88399_BIT_SYSST_NOSWS_CHECK;
- else
- check_val = AW88399_BIT_SYSST_SWS_CHECK;
-
- for (i = 0; i < AW88399_DEV_SYSST_CHECK_MAX; i++) {
- ret = regmap_read(aw_dev->regmap, AW88399_SYSST_REG, &reg_val);
- if (ret)
- return ret;
-
- if ((reg_val & (~AW88399_BIT_SYSST_CHECK_MASK) & check_val) != check_val) {
- dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x",
- i, reg_val, AW88399_BIT_SYSST_NOSWS_CHECK);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- } else {
- return 0;
- }
- }
-
- return -EPERM;
-}
-
-static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd)
-{
- int ret;
-
- if (amppd)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_AMPPD_MASK, AW88399_AMPPD_POWER_DOWN_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_AMPPD_MASK, AW88399_AMPPD_WORKING_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable)
-{
- int ret;
-
- if (is_enable)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_DSPBY_MASK, AW88399_DSPBY_WORKING_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_DSPBY_MASK, AW88399_DSPBY_BYPASS_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed\n", __func__);
-}
-
-static int aw88399_dev_get_icalk(struct aw88399 *aw88399, int16_t *icalk)
-{
- uint16_t icalkh_val, icalkl_val, icalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH4_REG, &reg_val);
- if (ret)
- return ret;
- icalkh_val = reg_val & (~AW88399_EF_ISN_GESLP_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL4_REG, &reg_val);
- if (ret)
- return ret;
- icalkl_val = reg_val & (~AW88399_EF_ISN_GESLP_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- icalk_val = icalkh_val & icalkl_val;
- else
- icalk_val = icalkh_val | icalkl_val;
-
- if (icalk_val & (~AW88399_EF_ISN_GESLP_SIGN_MASK))
- icalk_val = icalk_val | AW88399_EF_ISN_GESLP_SIGN_NEG;
- *icalk = (int16_t)icalk_val;
-
- return 0;
-}
-
-static int aw88399_dev_get_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
-{
- uint16_t vcalkh_val, vcalkl_val, vcalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH3_REG, &reg_val);
- if (ret)
- return ret;
-
- vcalkh_val = reg_val & (~AW88399_EF_VSN_GESLP_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL3_REG, &reg_val);
- if (ret)
- return ret;
-
- vcalkl_val = reg_val & (~AW88399_EF_VSN_GESLP_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- vcalk_val = vcalkh_val & vcalkl_val;
- else
- vcalk_val = vcalkh_val | vcalkl_val;
-
- if (vcalk_val & AW88399_EF_VSN_GESLP_SIGN_MASK)
- vcalk_val = vcalk_val | AW88399_EF_VSN_GESLP_SIGN_NEG;
- *vcalk = (int16_t)vcalk_val;
-
- return 0;
-}
-
-static int aw88399_dev_get_internal_vcalk(struct aw88399 *aw88399, int16_t *vcalk)
-{
- uint16_t vcalkh_val, vcalkl_val, vcalk_val;
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRH2_REG, &reg_val);
- if (ret)
- return ret;
- vcalkh_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_H_MASK);
-
- ret = regmap_read(aw_dev->regmap, AW88399_EFRL2_REG, &reg_val);
- if (ret)
- return ret;
- vcalkl_val = reg_val & (~AW88399_INTERNAL_VSN_TRIM_L_MASK);
-
- if (aw88399->check_val == AW_EF_AND_CHECK)
- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) &
- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
- else
- vcalk_val = (vcalkh_val >> AW88399_INTERNAL_VSN_TRIM_H_START_BIT) |
- (vcalkl_val >> AW88399_INTERNAL_VSN_TRIM_L_START_BIT);
-
- if (vcalk_val & (~AW88399_TEM4_SIGN_MASK))
- vcalk_val = vcalk_val | AW88399_TEM4_SIGN_NEG;
-
- *vcalk = (int16_t)vcalk_val;
-
- return 0;
-}
-
-static int aw_dev_set_vcalb(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- unsigned int vsense_select, vsense_value;
- int32_t ical_k, vcal_k, vcalb;
- int16_t icalk, vcalk;
- uint16_t reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_VSNCTRL1_REG, &vsense_value);
- if (ret)
- return ret;
-
- vsense_select = vsense_value & (~AW88399_VDSEL_MASK);
-
- ret = aw88399_dev_get_icalk(aw88399, &icalk);
- if (ret) {
- dev_err(aw_dev->dev, "get icalk failed\n");
- return ret;
- }
-
- ical_k = icalk * AW88399_ICABLK_FACTOR + AW88399_CABL_BASE_VALUE;
-
- switch (vsense_select) {
- case AW88399_DEV_VDSEL_VSENSE:
- ret = aw88399_dev_get_vcalk(aw88399, &vcalk);
- vcal_k = vcalk * AW88399_VCABLK_FACTOR + AW88399_CABL_BASE_VALUE;
- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_FACTOR / AW88399_ISCAL_FACTOR *
- ical_k / vcal_k * aw88399->vcalb_init_val;
- break;
- case AW88399_DEV_VDSEL_DAC:
- ret = aw88399_dev_get_internal_vcalk(aw88399, &vcalk);
- vcal_k = vcalk * AW88399_VCABLK_DAC_FACTOR + AW88399_CABL_BASE_VALUE;
- vcalb = AW88399_VCALB_ACCURACY * AW88399_VSCAL_DAC_FACTOR /
- AW88399_ISCAL_DAC_FACTOR * ical_k /
- vcal_k * aw88399->vcalb_init_val;
- break;
- default:
- dev_err(aw_dev->dev, "%s: unsupported vsense\n", __func__);
- ret = -EINVAL;
- break;
- }
- if (ret)
- return ret;
-
- vcalb = vcalb >> AW88399_VCALB_ADJ_FACTOR;
- reg_val = (uint32_t)vcalb;
-
- regmap_write(aw_dev->regmap, AW88399_DSPVCALB_REG, reg_val);
-
- return 0;
-}
-
-static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc)
-{
- struct aw_device *aw_dev =
- container_of(cali_desc, struct aw_device, cali_desc);
- uint16_t re_lbits, re_hbits;
- u32 cali_re;
- int ret;
-
- if ((aw_dev->cali_desc.cali_re >= AW88399_CALI_RE_MAX) ||
- (aw_dev->cali_desc.cali_re <= AW88399_CALI_RE_MIN))
- return -EINVAL;
-
- cali_re = AW88399_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
- aw_dev->cali_desc.ra), AW88399_DSP_RE_SHIFT);
-
- re_hbits = (cali_re & (~AW88399_CALI_RE_HBITS_MASK)) >> AW88399_CALI_RE_HBITS_SHIFT;
- re_lbits = (cali_re & (~AW88399_CALI_RE_LBITS_MASK)) >> AW88399_CALI_RE_LBITS_SHIFT;
-
- ret = regmap_write(aw_dev->regmap, AW88399_ACR1_REG, re_hbits);
- if (ret) {
- dev_err(aw_dev->dev, "set cali re error");
- return ret;
- }
-
- ret = regmap_write(aw_dev->regmap, AW88399_ACR2_REG, re_lbits);
- if (ret)
- dev_err(aw_dev->dev, "set cali re error");
-
- return ret;
-}
-
-static int aw_dev_fw_crc_check(struct aw_device *aw_dev)
-{
- uint16_t check_val, fw_len_val;
- unsigned int reg_val;
- int ret;
-
- /* calculate fw_end_addr */
- fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_FW_BASE_ADDR;
-
- /* write fw_end_addr to crc_end_addr */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_END_ADDR_MASK, fw_len_val);
- if (ret)
- return ret;
- /* enable fw crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_ENABLE_VALUE);
-
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
-
- /* read crc check result */
- regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
- if (ret)
- return ret;
-
- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
-
- /* disable fw crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CODE_EN_MASK, AW88399_CRC_CODE_EN_DISABLE_VALUE);
- if (ret)
- return ret;
-
- if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
- dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x",
- __func__, check_val, AW88399_CRC_CHECK_PASS_VAL);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int aw_dev_cfg_crc_check(struct aw_device *aw_dev)
-{
- uint16_t check_val, cfg_len_val;
- unsigned int reg_val;
- int ret;
-
- /* calculate cfg end addr */
- cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88399_CRC_CFG_BASE_ADDR;
-
- /* write cfg_end_addr to crc_end_addr */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_END_ADDR_MASK, cfg_len_val);
- if (ret)
- return ret;
-
- /* enable cfg crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_ENABLE_VALUE);
- if (ret)
- return ret;
-
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
-
- /* read crc check result */
- ret = regmap_read(aw_dev->regmap, AW88399_HAGCST_REG, &reg_val);
- if (ret)
- return ret;
-
- check_val = (reg_val & (~AW88399_CRC_CHECK_BITS_MASK)) >> AW88399_CRC_CHECK_START_BIT;
-
- /* disable cfg crc check */
- ret = regmap_update_bits(aw_dev->regmap, AW88399_CRCCTRL_REG,
- ~AW88399_CRC_CFG_EN_MASK, AW88399_CRC_CFG_EN_DISABLE_VALUE);
- if (ret)
- return ret;
-
- if (check_val != AW88399_CRC_CHECK_PASS_VAL) {
- dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x",
- check_val, AW88399_CRC_CHECK_PASS_VAL);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int aw_dev_hw_crc_check(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_BYPASS_VALUE);
- if (ret)
- return ret;
-
- ret = aw_dev_fw_crc_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "fw_crc_check failed\n");
- goto crc_check_failed;
- }
-
- ret = aw_dev_cfg_crc_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "cfg_crc_check failed\n");
- goto crc_check_failed;
- }
-
- ret = regmap_write(aw_dev->regmap, AW88399_CRCCTRL_REG, aw88399->crc_init_val);
- if (ret)
- return ret;
-
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
-
- return ret;
-
-crc_check_failed:
- regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_RAM_CG_BYP_MASK, AW88399_RAM_CG_BYP_WORK_VALUE);
- return ret;
-}
-
-static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag)
-{
- int ret;
-
- if (flag)
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCTRL3_REG,
- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_ENABLE_VALUE);
- else
- ret = regmap_update_bits(aw_dev->regmap, AW88399_I2SCFG1_REG,
- ~AW88399_I2STXEN_MASK, AW88399_I2STXEN_DISABLE_VALUE);
-
- if (ret)
- dev_dbg(aw_dev->dev, "%s failed", __func__);
-}
-
-static int aw_dev_get_dsp_status(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_WDT_REG, &reg_val);
- if (ret)
- return ret;
- if (!(reg_val & (~AW88399_WDT_CNT_MASK)))
- return -EPERM;
-
- return 0;
-}
-
-static int aw_dev_dsp_check(struct aw_device *aw_dev)
-{
- int ret, i;
-
- switch (aw_dev->dsp_cfg) {
- case AW88399_DEV_DSP_BYPASS:
- dev_dbg(aw_dev->dev, "dsp bypass");
- ret = 0;
- break;
- case AW88399_DEV_DSP_WORK:
- aw_dev_dsp_enable(aw_dev, false);
- aw_dev_dsp_enable(aw_dev, true);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- for (i = 0; i < AW88399_DEV_DSP_CHECK_MAX; i++) {
- ret = aw_dev_get_dsp_status(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "dsp wdt status error=%d", ret);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
- }
- }
- break;
- default:
- dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value)
-{
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- unsigned int reg_value;
- u16 real_value;
- int ret;
-
- real_value = min((value + vol_desc->init_volume), (unsigned int)AW88399_MUTE_VOL);
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL2_REG, &reg_value);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value);
-
- real_value = (real_value << AW88399_VOL_START_BIT) | (reg_value & AW88399_VOL_MASK);
-
- ret = regmap_write(aw_dev->regmap, AW88399_SYSCTRL2_REG, real_value);
-
- return ret;
-}
-
-static void aw_dev_fade_in(struct aw_device *aw_dev)
-{
- struct aw_volume_desc *desc = &aw_dev->volume_desc;
- u16 fade_in_vol = desc->ctl_volume;
- int fade_step = aw_dev->fade_step;
- int i;
-
- if (fade_step == 0 || aw_dev->fade_in_time == 0) {
- aw_dev_set_volume(aw_dev, fade_in_vol);
- return;
- }
-
- for (i = AW88399_MUTE_VOL; i >= fade_in_vol; i -= fade_step) {
- aw_dev_set_volume(aw_dev, i);
- usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10);
- }
-
- if (i != fade_in_vol)
- aw_dev_set_volume(aw_dev, fade_in_vol);
-}
-
-static void aw_dev_fade_out(struct aw_device *aw_dev)
-{
- struct aw_volume_desc *desc = &aw_dev->volume_desc;
- int fade_step = aw_dev->fade_step;
- int i;
-
- if (fade_step == 0 || aw_dev->fade_out_time == 0) {
- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
- return;
- }
-
- for (i = desc->ctl_volume; i <= AW88399_MUTE_VOL; i += fade_step) {
- aw_dev_set_volume(aw_dev, i);
- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
- }
-
- if (i != AW88399_MUTE_VOL) {
- aw_dev_set_volume(aw_dev, AW88399_MUTE_VOL);
- usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
- }
-}
-
-static void aw88399_dev_mute(struct aw_device *aw_dev, bool is_mute)
-{
- if (is_mute) {
- aw_dev_fade_out(aw_dev);
- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_HMUTE_MASK, AW88399_HMUTE_ENABLE_VALUE);
- } else {
- regmap_update_bits(aw_dev->regmap, AW88399_SYSCTRL_REG,
- ~AW88399_HMUTE_MASK, AW88399_HMUTE_DISABLE_VALUE);
- aw_dev_fade_in(aw_dev);
- }
-}
-
-static void aw88399_dev_set_dither(struct aw88399 *aw88399, bool dither)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
-
- if (dither)
- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_ENABLE_VALUE);
- else
- regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_DITHER_EN_MASK, AW88399_DITHER_EN_DISABLE_VALUE);
-}
-
-static int aw88399_dev_start(struct aw88399 *aw88399)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- if (aw_dev->status == AW88399_DEV_PW_ON) {
- dev_dbg(aw_dev->dev, "already power on");
- return 0;
- }
-
- aw88399_dev_set_dither(aw88399, false);
-
- /* power on */
- aw_dev_pwd(aw_dev, false);
- usleep_range(AW88399_2000_US, AW88399_2000_US + 10);
-
- ret = aw_dev_check_syspll(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "pll check failed cannot start");
- goto pll_check_fail;
- }
-
- /* amppd on */
- aw_dev_amppd(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 50);
-
- /* check i2s status */
- ret = aw_dev_check_sysst(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "sysst check failed");
- goto sysst_check_fail;
- }
-
- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK) {
- ret = aw_dev_hw_crc_check(aw88399);
- if (ret) {
- dev_err(aw_dev->dev, "dsp crc check failed");
- goto crc_check_fail;
- }
- aw_dev_dsp_enable(aw_dev, false);
- aw_dev_set_vcalb(aw88399);
- aw_dev_update_cali_re(&aw_dev->cali_desc);
-
- ret = aw_dev_dsp_check(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "dsp status check failed");
- goto dsp_check_fail;
- }
- } else {
- dev_dbg(aw_dev->dev, "start pa with dsp bypass");
- }
-
- /* enable tx feedback */
- aw_dev_i2s_tx_enable(aw_dev, true);
-
- if (aw88399->dither_st == AW88399_DITHER_EN_ENABLE_VALUE)
- aw88399_dev_set_dither(aw88399, true);
-
- /* close mute */
- aw88399_dev_mute(aw_dev, false);
- /* clear inturrupt */
- aw_dev_clear_int_status(aw_dev);
- aw_dev->status = AW88399_DEV_PW_ON;
-
- return 0;
-
-dsp_check_fail:
-crc_check_fail:
- aw_dev_dsp_enable(aw_dev, false);
-sysst_check_fail:
- aw_dev_clear_int_status(aw_dev);
- aw_dev_amppd(aw_dev, true);
-pll_check_fail:
- aw_dev_pwd(aw_dev, true);
- aw_dev->status = AW88399_DEV_PW_OFF;
-
- return ret;
-}
-
-static int aw_dev_dsp_update_container(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len, unsigned short base)
-{
- u32 tmp_len;
- int i, ret;
-
- ret = regmap_write(aw_dev->regmap, AW88399_DSPMADD_REG, base);
- if (ret)
- return ret;
-
- for (i = 0; i < len; i += AW88399_MAX_RAM_WRITE_BYTE_SIZE) {
- tmp_len = min(len - i, AW88399_MAX_RAM_WRITE_BYTE_SIZE);
- ret = regmap_raw_write(aw_dev->regmap, AW88399_DSPMDAT_REG,
- &data[i], tmp_len);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int aw_dev_get_ra(struct aw_cali_desc *cali_desc)
-{
- struct aw_device *aw_dev =
- container_of(cali_desc, struct aw_device, cali_desc);
- u32 dsp_ra;
- int ret;
-
- ret = aw_dev_dsp_read(aw_dev, AW88399_DSP_REG_CFG_ADPZ_RA,
- &dsp_ra, AW_DSP_32_DATA);
- if (ret) {
- dev_err(aw_dev->dev, "read ra error");
- return ret;
- }
-
- cali_desc->ra = AW88399_DSP_RE_TO_SHOW_RE(dsp_ra,
- AW88399_DSP_RE_SHIFT);
-
- return 0;
-}
-
-static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- dev_dbg(aw_dev->dev, "dsp config len:%d", len);
-
- if (!len || !data) {
- dev_err(aw_dev->dev, "dsp config data is null or len is 0");
- return -EINVAL;
- }
-
- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_CFG_ADDR);
- if (ret)
- return ret;
-
- aw_dev->dsp_cfg_len = len;
-
- ret = aw_dev_get_ra(&aw_dev->cali_desc);
-
- return ret;
-}
-
-static int aw_dev_dsp_update_fw(struct aw_device *aw_dev,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- dev_dbg(aw_dev->dev, "dsp firmware len:%d", len);
-
- if (!len || !data) {
- dev_err(aw_dev->dev, "dsp firmware data is null or len is 0");
- return -EINVAL;
- }
-
- aw_dev->dsp_fw_len = len;
- ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88399_DSP_FW_ADDR);
-
- return ret;
-}
-
-static int aw_dev_check_sram(struct aw_device *aw_dev)
-{
- unsigned int reg_val;
-
- /* read dsp_rom_check_reg */
- aw_dev_dsp_read(aw_dev, AW88399_DSP_ROM_CHECK_ADDR, &reg_val, AW_DSP_16_DATA);
- if (reg_val != AW88399_DSP_ROM_CHECK_DATA) {
- dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]",
- reg_val, AW88399_DSP_ROM_CHECK_DATA);
- return -EPERM;
- }
-
- /* check dsp_cfg_base_addr */
- aw_dev_dsp_write(aw_dev, AW88399_DSP_CFG_ADDR,
- AW88399_DSP_ODD_NUM_BIT_TEST, AW_DSP_16_DATA);
- aw_dev_dsp_read(aw_dev, AW88399_DSP_CFG_ADDR, &reg_val, AW_DSP_16_DATA);
- if (reg_val != AW88399_DSP_ODD_NUM_BIT_TEST) {
- dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]",
- reg_val, AW88399_DSP_ODD_NUM_BIT_TEST);
- return -EPERM;
- }
-
- return 0;
-}
-
-static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
-{
- int ret;
-
- switch (flag) {
- case AW88399_DEV_MEMCLK_PLL:
- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_MEM_CLKSEL_MASK,
- AW88399_MEM_CLKSEL_DAPHCLK_VALUE);
- if (ret)
- dev_err(aw_dev->dev, "memclk select pll failed");
- break;
- case AW88399_DEV_MEMCLK_OSC:
- ret = regmap_update_bits(aw_dev->regmap, AW88399_DBGCTRL_REG,
- ~AW88399_MEM_CLKSEL_MASK,
- AW88399_MEM_CLKSEL_OSCCLK_VALUE);
- if (ret)
- dev_err(aw_dev->dev, "memclk select OSC failed");
- break;
- default:
- dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x", flag);
- break;
- }
-}
-
-static void aw_dev_get_cur_mode_st(struct aw_device *aw_dev)
-{
- struct aw_profctrl_desc *profctrl_desc = &aw_dev->profctrl_desc;
- unsigned int reg_val;
- int ret;
-
- ret = regmap_read(aw_dev->regmap, AW88399_SYSCTRL_REG, &reg_val);
- if (ret) {
- dev_dbg(aw_dev->dev, "%s failed", __func__);
- return;
- }
- if ((reg_val & (~AW88399_RCV_MODE_MASK)) == AW88399_RCV_MODE_RECEIVER_VALUE)
- profctrl_desc->cur_mode = AW88399_RCV_MODE;
- else
- profctrl_desc->cur_mode = AW88399_NOT_RCV_MODE;
-}
-
-static int aw_dev_update_reg_container(struct aw88399 *aw88399,
- unsigned char *data, unsigned int len)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- u16 read_vol, reg_val;
- int data_len, i, ret;
- int16_t *reg_data;
- u8 reg_addr;
-
- reg_data = (int16_t *)data;
- data_len = len >> 1;
-
- if (data_len & 0x1) {
- dev_err(aw_dev->dev, "data len:%d unsupported", data_len);
- return -EINVAL;
- }
-
- for (i = 0; i < data_len; i += 2) {
- reg_addr = reg_data[i];
- reg_val = reg_data[i + 1];
-
- if (reg_addr == AW88399_DSPVCALB_REG) {
- aw88399->vcalb_init_val = reg_val;
- continue;
- }
-
- if (reg_addr == AW88399_SYSCTRL_REG) {
- if (reg_val & (~AW88399_DSPBY_MASK))
- aw_dev->dsp_cfg = AW88399_DEV_DSP_BYPASS;
- else
- aw_dev->dsp_cfg = AW88399_DEV_DSP_WORK;
-
- reg_val &= (AW88399_HMUTE_MASK | AW88399_PWDN_MASK |
- AW88399_DSPBY_MASK);
- reg_val |= (AW88399_HMUTE_ENABLE_VALUE | AW88399_PWDN_POWER_DOWN_VALUE |
- AW88399_DSPBY_BYPASS_VALUE);
- }
-
- if (reg_addr == AW88399_I2SCTRL3_REG) {
- reg_val &= AW88399_I2STXEN_MASK;
- reg_val |= AW88399_I2STXEN_DISABLE_VALUE;
- }
-
- if (reg_addr == AW88399_SYSCTRL2_REG) {
- read_vol = (reg_val & (~AW88399_VOL_MASK)) >>
- AW88399_VOL_START_BIT;
- aw_dev->volume_desc.init_volume = read_vol;
- }
-
- if (reg_addr == AW88399_DBGCTRL_REG) {
- if ((reg_val & (~AW88399_EF_DBMD_MASK)) == AW88399_EF_DBMD_OR_VALUE)
- aw88399->check_val = AW_EF_OR_CHECK;
- else
- aw88399->check_val = AW_EF_AND_CHECK;
-
- aw88399->dither_st = reg_val & (~AW88399_DITHER_EN_MASK);
- }
-
- if (reg_addr == AW88399_CRCCTRL_REG)
- aw88399->crc_init_val = reg_val;
-
- ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
- if (ret)
- return ret;
- }
-
- aw_dev_pwd(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
-
- aw_dev_get_cur_mode_st(aw_dev);
-
- if (aw_dev->prof_cur != aw_dev->prof_index)
- vol_desc->ctl_volume = 0;
- else
- aw_dev_set_volume(aw_dev, vol_desc->ctl_volume);
-
- return 0;
-}
-
-static int aw_dev_reg_update(struct aw88399 *aw88399,
- unsigned char *data, unsigned int len)
-{
- int ret;
-
- if (!len || !data) {
- dev_err(aw88399->aw_pa->dev, "reg data is null or len is 0");
- return -EINVAL;
- }
-
- ret = aw_dev_update_reg_container(aw88399, data, len);
- if (ret)
- dev_err(aw88399->aw_pa->dev, "reg update failed");
-
- return ret;
-}
-
-static int aw88399_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name)
-{
- struct aw_prof_info *prof_info = &aw_dev->prof_info;
- struct aw_prof_desc *prof_desc;
-
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
- dev_err(aw_dev->dev, "index[%d] overflow count[%d]",
- index, aw_dev->prof_info.count);
- return -EINVAL;
- }
-
- prof_desc = &aw_dev->prof_info.prof_desc[index];
-
- *prof_name = prof_info->prof_name_list[prof_desc->id];
-
- return 0;
-}
-
-static int aw88399_dev_get_prof_data(struct aw_device *aw_dev, int index,
- struct aw_prof_desc **prof_desc)
-{
- if ((index >= aw_dev->prof_info.count) || (index < 0)) {
- dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n",
- __func__, index, aw_dev->prof_info.count);
- return -EINVAL;
- }
-
- *prof_desc = &aw_dev->prof_info.prof_desc[index];
-
- return 0;
-}
-
-static int aw88399_dev_fw_update(struct aw88399 *aw88399, bool up_dsp_fw_en, bool force_up_en)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- struct aw_prof_desc *prof_index_desc;
- struct aw_sec_data_desc *sec_desc;
- char *prof_name;
- int ret;
-
- if ((aw_dev->prof_cur == aw_dev->prof_index) &&
- (force_up_en == AW88399_FORCE_UPDATE_OFF)) {
- dev_dbg(aw_dev->dev, "scene no change, not update");
- return 0;
- }
-
- if (aw_dev->fw_status == AW88399_DEV_FW_FAILED) {
- dev_err(aw_dev->dev, "fw status[%d] error", aw_dev->fw_status);
- return -EPERM;
- }
-
- ret = aw88399_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name);
- if (ret)
- return ret;
-
- dev_dbg(aw_dev->dev, "start update %s", prof_name);
-
- ret = aw88399_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc);
- if (ret)
- return ret;
-
- /* update reg */
- sec_desc = prof_index_desc->sec_desc;
- ret = aw_dev_reg_update(aw88399, sec_desc[AW88395_DATA_TYPE_REG].data,
- sec_desc[AW88395_DATA_TYPE_REG].len);
- if (ret) {
- dev_err(aw_dev->dev, "update reg failed");
- return ret;
- }
-
- aw88399_dev_mute(aw_dev, true);
-
- if (aw_dev->dsp_cfg == AW88399_DEV_DSP_WORK)
- aw_dev_dsp_enable(aw_dev, false);
-
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
-
- ret = aw_dev_check_sram(aw_dev);
- if (ret) {
- dev_err(aw_dev->dev, "check sram failed");
- goto error;
- }
-
- if (up_dsp_fw_en) {
- dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver);
- ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data,
- sec_desc[AW88395_DATA_TYPE_DSP_FW].len);
- if (ret) {
- dev_err(aw_dev->dev, "update dsp fw failed");
- goto error;
- }
- }
-
- /* update dsp config */
- ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data,
- sec_desc[AW88395_DATA_TYPE_DSP_CFG].len);
- if (ret) {
- dev_err(aw_dev->dev, "update dsp cfg failed");
- goto error;
- }
-
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
-
- aw_dev->prof_cur = aw_dev->prof_index;
-
- return 0;
-
-error:
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
- return ret;
-}
-
-static void aw88399_start_pa(struct aw88399 *aw88399)
-{
- int ret, i;
-
- for (i = 0; i < AW88399_START_RETRIES; i++) {
- ret = aw88399_dev_start(aw88399);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "aw88399 device start failed. retry = %d", i);
- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_ON, true);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "fw update failed");
- continue;
- }
- } else {
- dev_dbg(aw88399->aw_pa->dev, "start success\n");
- break;
- }
- }
-}
-
-static void aw88399_startup_work(struct work_struct *work)
-{
- struct aw88399 *aw88399 =
- container_of(work, struct aw88399, start_work.work);
-
- mutex_lock(&aw88399->lock);
- aw88399_start_pa(aw88399);
- mutex_unlock(&aw88399->lock);
-}
-
-static void aw88399_start(struct aw88399 *aw88399, bool sync_start)
-{
- int ret;
-
- if (aw88399->aw_pa->fw_status != AW88399_DEV_FW_OK)
- return;
-
- if (aw88399->aw_pa->status == AW88399_DEV_PW_ON)
- return;
-
- ret = aw88399_dev_fw_update(aw88399, AW88399_DSP_FW_UPDATE_OFF, true);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "fw update failed.");
- return;
- }
-
- if (sync_start == AW88399_SYNC_START)
- aw88399_start_pa(aw88399);
- else
- queue_delayed_work(system_dfl_wq,
- &aw88399->start_work,
- AW88399_START_WORK_DELAY_MS);
-}
-
-static int aw_dev_check_sysint(struct aw_device *aw_dev)
-{
- u16 reg_val;
-
- aw_dev_get_int_status(aw_dev, &reg_val);
- if (reg_val & AW88399_BIT_SYSINT_CHECK) {
- dev_err(aw_dev->dev, "pa stop check fail:0x%04x", reg_val);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int aw88399_stop(struct aw_device *aw_dev)
-{
- struct aw_sec_data_desc *dsp_cfg =
- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG];
- struct aw_sec_data_desc *dsp_fw =
- &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW];
- int int_st;
-
- if (aw_dev->status == AW88399_DEV_PW_OFF) {
- dev_dbg(aw_dev->dev, "already power off");
- return 0;
- }
-
- aw_dev->status = AW88399_DEV_PW_OFF;
-
- aw88399_dev_mute(aw_dev, true);
- usleep_range(AW88399_4000_US, AW88399_4000_US + 100);
-
- aw_dev_i2s_tx_enable(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
-
- int_st = aw_dev_check_sysint(aw_dev);
-
- aw_dev_dsp_enable(aw_dev, false);
-
- aw_dev_amppd(aw_dev, true);
-
- if (int_st) {
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_OSC);
- aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len);
- aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len);
- aw_dev_select_memclk(aw_dev, AW88399_DEV_MEMCLK_PLL);
- }
-
- aw_dev_pwd(aw_dev, true);
-
- return 0;
-}
-
static struct snd_soc_dai_driver aw88399_dai[] = {
{
.name = "aw88399-aif",
@@ -1702,11 +498,10 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol,
struct aw88399 *aw88399 = snd_soc_component_get_drvdata(codec);
int ret;
- mutex_lock(&aw88399->lock);
+ guard(mutex)(&aw88399->lock);
ret = aw88399_dev_set_profile_index(aw88399->aw_pa, ucontrol->value.integer.value[0]);
if (ret) {
dev_dbg(codec->dev, "profile index does not change");
- mutex_unlock(&aw88399->lock);
return 0;
}
@@ -1715,8 +510,6 @@ static int aw88399_profile_set(struct snd_kcontrol *kcontrol,
aw88399_start(aw88399, AW88399_SYNC_START);
}
- mutex_unlock(&aw88399->lock);
-
return 1;
}
@@ -1869,86 +662,6 @@ static int aw88399_calib_set(struct snd_kcontrol *kcontrol,
return 0;
}
-static int aw88399_dev_init(struct aw88399 *aw88399, struct aw_container *aw_cfg)
-{
- struct aw_device *aw_dev = aw88399->aw_pa;
- int ret;
-
- ret = aw88395_dev_cfg_load(aw_dev, aw_cfg);
- if (ret) {
- dev_err(aw_dev->dev, "aw_dev acf parse failed");
- return -EINVAL;
- }
- aw_dev->fade_in_time = AW88399_1000_US / 10;
- aw_dev->fade_out_time = AW88399_1000_US >> 1;
- aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id;
- aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id;
-
- ret = aw88399_dev_fw_update(aw88399, AW88399_FORCE_UPDATE_ON, AW88399_DSP_FW_UPDATE_ON);
- if (ret) {
- dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
- return ret;
- }
-
- aw88399_dev_mute(aw_dev, true);
-
- /* close tx feedback */
- aw_dev_i2s_tx_enable(aw_dev, false);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 100);
-
- /* enable amppd */
- aw_dev_amppd(aw_dev, true);
-
- /* close dsp */
- aw_dev_dsp_enable(aw_dev, false);
- /* set power down */
- aw_dev_pwd(aw_dev, true);
-
- return 0;
-}
-
-static int aw88399_request_firmware_file(struct aw88399 *aw88399)
-{
- const struct firmware *cont = NULL;
- int ret;
-
- aw88399->aw_pa->fw_status = AW88399_DEV_FW_FAILED;
-
- ret = request_firmware(&cont, AW88399_ACF_FILE, aw88399->aw_pa->dev);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "request [%s] failed!", AW88399_ACF_FILE);
- return ret;
- }
-
- dev_dbg(aw88399->aw_pa->dev, "loaded %s - size: %zu\n",
- AW88399_ACF_FILE, cont ? cont->size : 0);
-
- aw88399->aw_cfg = devm_kzalloc(aw88399->aw_pa->dev,
- struct_size(aw88399->aw_cfg, data, cont->size), GFP_KERNEL);
- if (!aw88399->aw_cfg) {
- release_firmware(cont);
- return -ENOMEM;
- }
- aw88399->aw_cfg->len = (int)cont->size;
- memcpy(aw88399->aw_cfg->data, cont->data, cont->size);
- release_firmware(cont);
-
- ret = aw88395_dev_load_acf_check(aw88399->aw_pa, aw88399->aw_cfg);
- if (ret) {
- dev_err(aw88399->aw_pa->dev, "load [%s] failed!", AW88399_ACF_FILE);
- return ret;
- }
-
- mutex_lock(&aw88399->lock);
- /* aw device init */
- ret = aw88399_dev_init(aw88399, aw88399->aw_cfg);
- if (ret)
- dev_err(aw88399->aw_pa->dev, "dev init failed");
- mutex_unlock(&aw88399->lock);
-
- return ret;
-}
-
static const struct snd_kcontrol_new aw88399_controls[] = {
SOC_SINGLE_EXT("PCM Playback Volume", AW88399_SYSCTRL2_REG,
6, AW88399_MUTE_VOL, 0, aw88399_volume_get,
@@ -1975,7 +688,7 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct aw88399 *aw88399 = snd_soc_component_get_drvdata(component);
- mutex_lock(&aw88399->lock);
+ guard(mutex)(&aw88399->lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
aw88399_start(aw88399, AW88399_ASYNC_START);
@@ -1986,7 +699,6 @@ static int aw88399_playback_event(struct snd_soc_dapm_widget *w,
default:
break;
}
- mutex_unlock(&aw88399->lock);
return 0;
}
@@ -2040,70 +752,6 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88399 = {
.num_controls = ARRAY_SIZE(aw88399_controls),
};
-static void aw88399_hw_reset(struct aw88399 *aw88399)
-{
- if (aw88399->reset_gpio) {
- gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- gpiod_set_value_cansleep(aw88399->reset_gpio, 0);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- gpiod_set_value_cansleep(aw88399->reset_gpio, 1);
- usleep_range(AW88399_1000_US, AW88399_1000_US + 10);
- }
-}
-
-static void aw88399_parse_channel_dt(struct aw_device *aw_dev)
-{
- struct device_node *np = aw_dev->dev->of_node;
- u32 channel_value;
-
- of_property_read_u32(np, "awinic,audio-channel", &channel_value);
- aw_dev->channel = channel_value;
-}
-
-static int aw88399_init(struct aw88399 *aw88399, struct i2c_client *i2c, struct regmap *regmap)
-{
- struct aw_device *aw_dev;
- unsigned int chip_id;
- int ret;
-
- ret = regmap_read(regmap, AW88399_ID_REG, &chip_id);
- if (ret) {
- dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
- return ret;
- }
- if (chip_id != AW88399_CHIP_ID) {
- dev_err(&i2c->dev, "unsupported device");
- return -ENXIO;
- }
- dev_dbg(&i2c->dev, "chip id = %x\n", chip_id);
-
- aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
- if (!aw_dev)
- return -ENOMEM;
- aw88399->aw_pa = aw_dev;
-
- aw_dev->i2c = i2c;
- aw_dev->dev = &i2c->dev;
- aw_dev->regmap = regmap;
- mutex_init(&aw_dev->dsp_lock);
-
- aw_dev->chip_id = chip_id;
- aw_dev->acf = NULL;
- aw_dev->prof_info.prof_desc = NULL;
- aw_dev->prof_info.count = 0;
- aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
- aw_dev->channel = AW88399_DEV_DEFAULT_CH;
- aw_dev->fw_status = AW88399_DEV_FW_FAILED;
-
- aw_dev->fade_step = AW88399_VOLUME_STEP_DB;
- aw_dev->volume_desc.ctl_volume = AW88399_VOL_DEFAULT_VALUE;
-
- aw88399_parse_channel_dt(aw_dev);
-
- return 0;
-}
-
static int aw88399_i2c_probe(struct i2c_client *i2c)
{
struct aw88399 *aw88399;
diff --git a/sound/soc/codecs/aw88399.h b/sound/soc/codecs/aw88399.h
index b386f4836748..04123bf0ad84 100644
--- a/sound/soc/codecs/aw88399.h
+++ b/sound/soc/codecs/aw88399.h
@@ -10,512 +10,10 @@
#ifndef __AW88399_H__
#define __AW88399_H__
-/* registers list */
-#define AW88399_ID_REG (0x00)
-#define AW88399_SYSST_REG (0x01)
-#define AW88399_SYSINT_REG (0x02)
-#define AW88399_SYSINTM_REG (0x03)
-#define AW88399_SYSCTRL_REG (0x04)
-#define AW88399_SYSCTRL2_REG (0x05)
-#define AW88399_I2SCTRL1_REG (0x06)
-#define AW88399_I2SCTRL2_REG (0x07)
-#define AW88399_I2SCTRL3_REG (0x08)
-#define AW88399_DACCFG1_REG (0x09)
-#define AW88399_DACCFG2_REG (0x0A)
-#define AW88399_DACCFG3_REG (0x0B)
-#define AW88399_DACCFG4_REG (0x0C)
-#define AW88399_DACCFG5_REG (0x0D)
-#define AW88399_DACCFG6_REG (0x0E)
-#define AW88399_DACCFG7_REG (0x0F)
-#define AW88399_MPDCFG1_REG (0x10)
-#define AW88399_MPDCFG2_REG (0x11)
-#define AW88399_MPDCFG3_REG (0x12)
-#define AW88399_MPDCFG4_REG (0x13)
-#define AW88399_PWMCTRL1_REG (0x14)
-#define AW88399_PWMCTRL2_REG (0x15)
-#define AW88399_PWMCTRL3_REG (0x16)
-#define AW88399_I2SCFG1_REG (0x17)
-#define AW88399_DBGCTRL_REG (0x18)
-#define AW88399_HAGCST_REG (0x20)
-#define AW88399_VBAT_REG (0x21)
-#define AW88399_TEMP_REG (0x22)
-#define AW88399_PVDD_REG (0x23)
-#define AW88399_ISNDAT_REG (0x24)
-#define AW88399_VSNDAT_REG (0x25)
-#define AW88399_I2SINT_REG (0x26)
-#define AW88399_I2SCAPCNT_REG (0x27)
-#define AW88399_ANASTA1_REG (0x28)
-#define AW88399_ANASTA2_REG (0x29)
-#define AW88399_ANASTA3_REG (0x2A)
-#define AW88399_TESTDET_REG (0x2B)
-#define AW88399_DSMCFG1_REG (0x30)
-#define AW88399_DSMCFG2_REG (0x31)
-#define AW88399_DSMCFG3_REG (0x32)
-#define AW88399_DSMCFG4_REG (0x33)
-#define AW88399_DSMCFG5_REG (0x34)
-#define AW88399_DSMCFG6_REG (0x35)
-#define AW88399_DSMCFG7_REG (0x36)
-#define AW88399_DSMCFG8_REG (0x37)
-#define AW88399_TESTIN_REG (0x38)
-#define AW88399_TESTOUT_REG (0x39)
-#define AW88399_MEMTEST_REG (0x3A)
-#define AW88399_VSNCTRL1_REG (0x3B)
-#define AW88399_ISNCTRL1_REG (0x3C)
-#define AW88399_ISNCTRL2_REG (0x3D)
-#define AW88399_DSPMADD_REG (0x40)
-#define AW88399_DSPMDAT_REG (0x41)
-#define AW88399_WDT_REG (0x42)
-#define AW88399_ACR1_REG (0x43)
-#define AW88399_ACR2_REG (0x44)
-#define AW88399_ASR1_REG (0x45)
-#define AW88399_ASR2_REG (0x46)
-#define AW88399_DSPCFG_REG (0x47)
-#define AW88399_ASR3_REG (0x48)
-#define AW88399_ASR4_REG (0x49)
-#define AW88399_DSPVCALB_REG (0x4A)
-#define AW88399_CRCCTRL_REG (0x4B)
-#define AW88399_DSPDBG1_REG (0x4C)
-#define AW88399_DSPDBG2_REG (0x4D)
-#define AW88399_DSPDBG3_REG (0x4E)
-#define AW88399_PLLCTRL1_REG (0x50)
-#define AW88399_PLLCTRL2_REG (0x51)
-#define AW88399_PLLCTRL3_REG (0x52)
-#define AW88399_CDACTRL1_REG (0x53)
-#define AW88399_CDACTRL2_REG (0x54)
-#define AW88399_CDACTRL3_REG (0x55)
-#define AW88399_SADCCTRL1_REG (0x56)
-#define AW88399_SADCCTRL2_REG (0x57)
-#define AW88399_BOPCTRL1_REG (0x58)
-#define AW88399_BOPCTRL2_REG (0x5A)
-#define AW88399_BOPCTRL3_REG (0x5B)
-#define AW88399_BOPCTRL4_REG (0x5C)
-#define AW88399_BOPCTRL5_REG (0x5D)
-#define AW88399_BOPCTRL6_REG (0x5E)
-#define AW88399_BOPCTRL7_REG (0x5F)
-#define AW88399_BSTCTRL1_REG (0x60)
-#define AW88399_BSTCTRL2_REG (0x61)
-#define AW88399_BSTCTRL3_REG (0x62)
-#define AW88399_BSTCTRL4_REG (0x63)
-#define AW88399_BSTCTRL5_REG (0x64)
-#define AW88399_BSTCTRL6_REG (0x65)
-#define AW88399_BSTCTRL7_REG (0x66)
-#define AW88399_BSTCTRL8_REG (0x67)
-#define AW88399_BSTCTRL9_REG (0x68)
-#define AW88399_BSTCTRL10_REG (0x69)
-#define AW88399_CPCTRL_REG (0x6A)
-#define AW88399_EFWH_REG (0x6C)
-#define AW88399_EFWM2_REG (0x6D)
-#define AW88399_EFWM1_REG (0x6E)
-#define AW88399_EFWL_REG (0x6F)
-#define AW88399_TESTCTRL1_REG (0x70)
-#define AW88399_TESTCTRL2_REG (0x71)
-#define AW88399_EFCTRL1_REG (0x72)
-#define AW88399_EFCTRL2_REG (0x73)
-#define AW88399_EFRH4_REG (0x74)
-#define AW88399_EFRH3_REG (0x75)
-#define AW88399_EFRH2_REG (0x76)
-#define AW88399_EFRH1_REG (0x77)
-#define AW88399_EFRL4_REG (0x78)
-#define AW88399_EFRL3_REG (0x79)
-#define AW88399_EFRL2_REG (0x7A)
-#define AW88399_EFRL1_REG (0x7B)
-#define AW88399_TM_REG (0x7C)
-#define AW88399_TM2_REG (0x7D)
-
-#define AW88399_REG_MAX (0x7E)
-#define AW88399_MUTE_VOL (1023)
-
-#define AW88399_DSP_CFG_ADDR (0x9B00)
-#define AW88399_DSP_REG_CFG_ADPZ_RA (0x9B68)
-#define AW88399_DSP_FW_ADDR (0x8980)
-#define AW88399_DSP_ROM_CHECK_ADDR (0x1F40)
-#define AW88399_DSP_ROM_CHECK_DATA (0x4638)
-
-#define AW88399_CALI_RE_HBITS_MASK (~(0xFFFF0000))
-#define AW88399_CALI_RE_HBITS_SHIFT (16)
-
-#define AW88399_CALI_RE_LBITS_MASK (~(0xFFFF))
-#define AW88399_CALI_RE_LBITS_SHIFT (0)
-
-#define AW88399_I2STXEN_START_BIT (9)
-#define AW88399_I2STXEN_BITS_LEN (1)
-#define AW88399_I2STXEN_MASK \
- (~(((1<<AW88399_I2STXEN_BITS_LEN)-1) << AW88399_I2STXEN_START_BIT))
-
-#define AW88399_I2STXEN_DISABLE (0)
-#define AW88399_I2STXEN_DISABLE_VALUE \
- (AW88399_I2STXEN_DISABLE << AW88399_I2STXEN_START_BIT)
-
-#define AW88399_I2STXEN_ENABLE (1)
-#define AW88399_I2STXEN_ENABLE_VALUE \
- (AW88399_I2STXEN_ENABLE << AW88399_I2STXEN_START_BIT)
-
-#define AW88399_VOL_START_BIT (0)
-#define AW88399_VOL_BITS_LEN (10)
-#define AW88399_VOL_MASK \
- (~(((1<<AW88399_VOL_BITS_LEN)-1) << AW88399_VOL_START_BIT))
-
-#define AW88399_PWDN_START_BIT (0)
-#define AW88399_PWDN_BITS_LEN (1)
-#define AW88399_PWDN_MASK \
- (~(((1<<AW88399_PWDN_BITS_LEN)-1) << AW88399_PWDN_START_BIT))
-
-#define AW88399_PWDN_POWER_DOWN (1)
-#define AW88399_PWDN_POWER_DOWN_VALUE \
- (AW88399_PWDN_POWER_DOWN << AW88399_PWDN_START_BIT)
-
-#define AW88399_PWDN_WORKING (0)
-#define AW88399_PWDN_WORKING_VALUE \
- (AW88399_PWDN_WORKING << AW88399_PWDN_START_BIT)
-
-#define AW88399_DSPBY_START_BIT (2)
-#define AW88399_DSPBY_BITS_LEN (1)
-#define AW88399_DSPBY_MASK \
- (~(((1<<AW88399_DSPBY_BITS_LEN)-1) << AW88399_DSPBY_START_BIT))
-
-#define AW88399_DSPBY_WORKING (0)
-#define AW88399_DSPBY_WORKING_VALUE \
- (AW88399_DSPBY_WORKING << AW88399_DSPBY_START_BIT)
-
-#define AW88399_DSPBY_BYPASS (1)
-#define AW88399_DSPBY_BYPASS_VALUE \
- (AW88399_DSPBY_BYPASS << AW88399_DSPBY_START_BIT)
-
-#define AW88399_MEM_CLKSEL_START_BIT (3)
-#define AW88399_MEM_CLKSEL_BITS_LEN (1)
-#define AW88399_MEM_CLKSEL_MASK \
- (~(((1<<AW88399_MEM_CLKSEL_BITS_LEN)-1) << AW88399_MEM_CLKSEL_START_BIT))
-
-#define AW88399_MEM_CLKSEL_OSCCLK (0)
-#define AW88399_MEM_CLKSEL_OSCCLK_VALUE \
- (AW88399_MEM_CLKSEL_OSCCLK << AW88399_MEM_CLKSEL_START_BIT)
-
-#define AW88399_MEM_CLKSEL_DAPHCLK (1)
-#define AW88399_MEM_CLKSEL_DAPHCLK_VALUE \
- (AW88399_MEM_CLKSEL_DAPHCLK << AW88399_MEM_CLKSEL_START_BIT)
-
-#define AW88399_DITHER_EN_START_BIT (15)
-#define AW88399_DITHER_EN_BITS_LEN (1)
-#define AW88399_DITHER_EN_MASK \
- (~(((1<<AW88399_DITHER_EN_BITS_LEN)-1) << AW88399_DITHER_EN_START_BIT))
-
-#define AW88399_DITHER_EN_DISABLE (0)
-#define AW88399_DITHER_EN_DISABLE_VALUE \
- (AW88399_DITHER_EN_DISABLE << AW88399_DITHER_EN_START_BIT)
-
-#define AW88399_DITHER_EN_ENABLE (1)
-#define AW88399_DITHER_EN_ENABLE_VALUE \
- (AW88399_DITHER_EN_ENABLE << AW88399_DITHER_EN_START_BIT)
-
-#define AW88399_HMUTE_START_BIT (8)
-#define AW88399_HMUTE_BITS_LEN (1)
-#define AW88399_HMUTE_MASK \
- (~(((1<<AW88399_HMUTE_BITS_LEN)-1) << AW88399_HMUTE_START_BIT))
-
-#define AW88399_HMUTE_DISABLE (0)
-#define AW88399_HMUTE_DISABLE_VALUE \
- (AW88399_HMUTE_DISABLE << AW88399_HMUTE_START_BIT)
-
-#define AW88399_HMUTE_ENABLE (1)
-#define AW88399_HMUTE_ENABLE_VALUE \
- (AW88399_HMUTE_ENABLE << AW88399_HMUTE_START_BIT)
-
-#define AW88399_EF_DBMD_START_BIT (2)
-#define AW88399_EF_DBMD_BITS_LEN (1)
-#define AW88399_EF_DBMD_MASK \
- (~(((1<<AW88399_EF_DBMD_BITS_LEN)-1) << AW88399_EF_DBMD_START_BIT))
-
-#define AW88399_EF_DBMD_OR (1)
-#define AW88399_EF_DBMD_OR_VALUE \
- (AW88399_EF_DBMD_OR << AW88399_EF_DBMD_START_BIT)
-
-#define AW88399_VDSEL_START_BIT (5)
-#define AW88399_VDSEL_BITS_LEN (1)
-#define AW88399_VDSEL_MASK \
- (~(((1<<AW88399_VDSEL_BITS_LEN)-1) << AW88399_VDSEL_START_BIT))
-
-#define AW88399_EF_ISN_GESLP_H_START_BIT (0)
-#define AW88399_EF_ISN_GESLP_H_BITS_LEN (10)
-#define AW88399_EF_ISN_GESLP_H_MASK \
- (~(((1<<AW88399_EF_ISN_GESLP_H_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_H_START_BIT))
-
-/* EF_VSN_GESLP_H bit 9:0 (EFRH3 0x75) */
-#define AW88399_EF_VSN_GESLP_H_START_BIT (0)
-#define AW88399_EF_VSN_GESLP_H_BITS_LEN (10)
-#define AW88399_EF_VSN_GESLP_H_MASK \
- (~(((1<<AW88399_EF_VSN_GESLP_H_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_H_START_BIT))
-
-#define AW88399_EF_ISN_GESLP_L_START_BIT (0)
-#define AW88399_EF_ISN_GESLP_L_BITS_LEN (10)
-#define AW88399_EF_ISN_GESLP_L_MASK \
- (~(((1<<AW88399_EF_ISN_GESLP_L_BITS_LEN)-1) << AW88399_EF_ISN_GESLP_L_START_BIT))
-
-/* EF_VSN_GESLP_L bit 9:0 (EFRL3 0x79) */
-#define AW88399_EF_VSN_GESLP_L_START_BIT (0)
-#define AW88399_EF_VSN_GESLP_L_BITS_LEN (10)
-#define AW88399_EF_VSN_GESLP_L_MASK \
- (~(((1<<AW88399_EF_VSN_GESLP_L_BITS_LEN)-1) << AW88399_EF_VSN_GESLP_L_START_BIT))
-
-#define AW88399_INTERNAL_VSN_TRIM_H_START_BIT (9)
-#define AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN (6)
-#define AW88399_INTERNAL_VSN_TRIM_H_MASK \
- (~(((1<<AW88399_INTERNAL_VSN_TRIM_H_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_H_START_BIT))
-
-#define AW88399_INTERNAL_VSN_TRIM_L_START_BIT (9)
-#define AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN (6)
-#define AW88399_INTERNAL_VSN_TRIM_L_MASK \
- (~(((1<<AW88399_INTERNAL_VSN_TRIM_L_BITS_LEN)-1) << AW88399_INTERNAL_VSN_TRIM_L_START_BIT))
-
-#define AW88399_RCV_MODE_START_BIT (7)
-#define AW88399_RCV_MODE_BITS_LEN (1)
-#define AW88399_RCV_MODE_MASK \
- (~(((1<<AW88399_RCV_MODE_BITS_LEN)-1) << AW88399_RCV_MODE_START_BIT))
-
-#define AW88399_CLKI_START_BIT (4)
-#define AW88399_NOCLKI_START_BIT (5)
-#define AW88399_PLLI_START_BIT (0)
-#define AW88399_PLLI_INT_VALUE (1)
-#define AW88399_PLLI_INT_INTERRUPT \
- (AW88399_PLLI_INT_VALUE << AW88399_PLLI_START_BIT)
-
-#define AW88399_CLKI_INT_VALUE (1)
-#define AW88399_CLKI_INT_INTERRUPT \
- (AW88399_CLKI_INT_VALUE << AW88399_CLKI_START_BIT)
-
-#define AW88399_NOCLKI_INT_VALUE (1)
-#define AW88399_NOCLKI_INT_INTERRUPT \
- (AW88399_NOCLKI_INT_VALUE << AW88399_NOCLKI_START_BIT)
-
-#define AW88399_BIT_SYSINT_CHECK \
- (AW88399_PLLI_INT_INTERRUPT | \
- AW88399_CLKI_INT_INTERRUPT | \
- AW88399_NOCLKI_INT_INTERRUPT)
-
-#define AW88399_CRC_CHECK_START_BIT (12)
-#define AW88399_CRC_CHECK_BITS_LEN (3)
-#define AW88399_CRC_CHECK_BITS_MASK \
- (~(((1<<AW88399_CRC_CHECK_BITS_LEN)-1) << AW88399_CRC_CHECK_START_BIT))
-
-#define AW88399_RCV_MODE_RECEIVER (1)
-#define AW88399_RCV_MODE_RECEIVER_VALUE \
- (AW88399_RCV_MODE_RECEIVER << AW88399_RCV_MODE_START_BIT)
-
-#define AW88399_AMPPD_START_BIT (1)
-#define AW88399_AMPPD_BITS_LEN (1)
-#define AW88399_AMPPD_MASK \
- (~(((1<<AW88399_AMPPD_BITS_LEN)-1) << AW88399_AMPPD_START_BIT))
-
-#define AW88399_AMPPD_WORKING (0)
-#define AW88399_AMPPD_WORKING_VALUE \
- (AW88399_AMPPD_WORKING << AW88399_AMPPD_START_BIT)
-
-#define AW88399_AMPPD_POWER_DOWN (1)
-#define AW88399_AMPPD_POWER_DOWN_VALUE \
- (AW88399_AMPPD_POWER_DOWN << AW88399_AMPPD_START_BIT)
-
-#define AW88399_RAM_CG_BYP_START_BIT (0)
-#define AW88399_RAM_CG_BYP_BITS_LEN (1)
-#define AW88399_RAM_CG_BYP_MASK \
- (~(((1<<AW88399_RAM_CG_BYP_BITS_LEN)-1) << AW88399_RAM_CG_BYP_START_BIT))
-
-#define AW88399_RAM_CG_BYP_WORK (0)
-#define AW88399_RAM_CG_BYP_WORK_VALUE \
- (AW88399_RAM_CG_BYP_WORK << AW88399_RAM_CG_BYP_START_BIT)
-
-#define AW88399_RAM_CG_BYP_BYPASS (1)
-#define AW88399_RAM_CG_BYP_BYPASS_VALUE \
- (AW88399_RAM_CG_BYP_BYPASS << AW88399_RAM_CG_BYP_START_BIT)
-
-#define AW88399_CRC_END_ADDR_START_BIT (0)
-#define AW88399_CRC_END_ADDR_BITS_LEN (12)
-#define AW88399_CRC_END_ADDR_MASK \
- (~(((1<<AW88399_CRC_END_ADDR_BITS_LEN)-1) << AW88399_CRC_END_ADDR_START_BIT))
-
-#define AW88399_CRC_CODE_EN_START_BIT (13)
-#define AW88399_CRC_CODE_EN_BITS_LEN (1)
-#define AW88399_CRC_CODE_EN_MASK \
- (~(((1<<AW88399_CRC_CODE_EN_BITS_LEN)-1) << AW88399_CRC_CODE_EN_START_BIT))
-
-#define AW88399_CRC_CODE_EN_DISABLE (0)
-#define AW88399_CRC_CODE_EN_DISABLE_VALUE \
- (AW88399_CRC_CODE_EN_DISABLE << AW88399_CRC_CODE_EN_START_BIT)
-
-#define AW88399_CRC_CODE_EN_ENABLE (1)
-#define AW88399_CRC_CODE_EN_ENABLE_VALUE \
- (AW88399_CRC_CODE_EN_ENABLE << AW88399_CRC_CODE_EN_START_BIT)
-
-#define AW88399_CRC_CFG_EN_START_BIT (12)
-#define AW88399_CRC_CFG_EN_BITS_LEN (1)
-#define AW88399_CRC_CFG_EN_MASK \
- (~(((1<<AW88399_CRC_CFG_EN_BITS_LEN)-1) << AW88399_CRC_CFG_EN_START_BIT))
-
-#define AW88399_CRC_CFG_EN_DISABLE (0)
-#define AW88399_CRC_CFG_EN_DISABLE_VALUE \
- (AW88399_CRC_CFG_EN_DISABLE << AW88399_CRC_CFG_EN_START_BIT)
-
-#define AW88399_CRC_CFG_EN_ENABLE (1)
-#define AW88399_CRC_CFG_EN_ENABLE_VALUE \
- (AW88399_CRC_CFG_EN_ENABLE << AW88399_CRC_CFG_EN_START_BIT)
-
-#define AW88399_OCDS_START_BIT (3)
-#define AW88399_OCDS_OC (1)
-#define AW88399_OCDS_OC_VALUE \
- (AW88399_OCDS_OC << AW88399_OCDS_START_BIT)
-
-#define AW88399_NOCLKS_START_BIT (5)
-#define AW88399_NOCLKS_NO_CLOCK (1)
-#define AW88399_NOCLKS_NO_CLOCK_VALUE \
- (AW88399_NOCLKS_NO_CLOCK << AW88399_NOCLKS_START_BIT)
-
-#define AW88399_SWS_START_BIT (8)
-#define AW88399_SWS_SWITCHING (1)
-#define AW88399_SWS_SWITCHING_VALUE \
- (AW88399_SWS_SWITCHING << AW88399_SWS_START_BIT)
-
-#define AW88399_BSTS_START_BIT (9)
-#define AW88399_BSTS_FINISHED (1)
-#define AW88399_BSTS_FINISHED_VALUE \
- (AW88399_BSTS_FINISHED << AW88399_BSTS_START_BIT)
-
-#define AW88399_UVLS_START_BIT (14)
-#define AW88399_UVLS_NORMAL (0)
-#define AW88399_UVLS_NORMAL_VALUE \
- (AW88399_UVLS_NORMAL << AW88399_UVLS_START_BIT)
-
-#define AW88399_BSTOCS_START_BIT (11)
-#define AW88399_BSTOCS_OVER_CURRENT (1)
-#define AW88399_BSTOCS_OVER_CURRENT_VALUE \
- (AW88399_BSTOCS_OVER_CURRENT << AW88399_BSTOCS_START_BIT)
-
-#define AW88399_OTHS_START_BIT (1)
-#define AW88399_OTHS_OT (1)
-#define AW88399_OTHS_OT_VALUE \
- (AW88399_OTHS_OT << AW88399_OTHS_START_BIT)
-
-#define AW88399_PLLS_START_BIT (0)
-#define AW88399_PLLS_LOCKED (1)
-#define AW88399_PLLS_LOCKED_VALUE \
- (AW88399_PLLS_LOCKED << AW88399_PLLS_START_BIT)
-
-#define AW88399_CLKS_START_BIT (4)
-#define AW88399_CLKS_STABLE (1)
-#define AW88399_CLKS_STABLE_VALUE \
- (AW88399_CLKS_STABLE << AW88399_CLKS_START_BIT)
-
-#define AW88399_BIT_PLL_CHECK \
- (AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE)
-
-#define AW88399_BIT_SYSST_CHECK_MASK \
- (~(AW88399_UVLS_NORMAL_VALUE | \
- AW88399_BSTOCS_OVER_CURRENT_VALUE | \
- AW88399_BSTS_FINISHED_VALUE | \
- AW88399_SWS_SWITCHING_VALUE | \
- AW88399_NOCLKS_NO_CLOCK_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_OCDS_OC_VALUE | \
- AW88399_OTHS_OT_VALUE | \
- AW88399_PLLS_LOCKED_VALUE))
-
-#define AW88399_BIT_SYSST_NOSWS_CHECK \
- (AW88399_BSTS_FINISHED_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE)
-
-#define AW88399_BIT_SYSST_SWS_CHECK \
- (AW88399_BSTS_FINISHED_VALUE | \
- AW88399_CLKS_STABLE_VALUE | \
- AW88399_PLLS_LOCKED_VALUE | \
- AW88399_SWS_SWITCHING_VALUE)
-
-#define AW88399_CCO_MUX_START_BIT (14)
-#define AW88399_CCO_MUX_BITS_LEN (1)
-#define AW88399_CCO_MUX_MASK \
- (~(((1<<AW88399_CCO_MUX_BITS_LEN)-1) << AW88399_CCO_MUX_START_BIT))
-
-#define AW88399_CCO_MUX_DIVIDED (0)
-#define AW88399_CCO_MUX_DIVIDED_VALUE \
- (AW88399_CCO_MUX_DIVIDED << AW88399_CCO_MUX_START_BIT)
-
-#define AW88399_CCO_MUX_BYPASS (1)
-#define AW88399_CCO_MUX_BYPASS_VALUE \
- (AW88399_CCO_MUX_BYPASS << AW88399_CCO_MUX_START_BIT)
-
-#define AW88399_NOISE_GATE_EN_START_BIT (13)
-#define AW88399_NOISE_GATE_EN_BITS_LEN (1)
-#define AW88399_NOISE_GATE_EN_MASK \
- (~(((1<<AW88399_NOISE_GATE_EN_BITS_LEN)-1) << AW88399_NOISE_GATE_EN_START_BIT))
-
-#define AW88399_WDT_CNT_START_BIT (0)
-#define AW88399_WDT_CNT_BITS_LEN (8)
-#define AW88399_WDT_CNT_MASK \
- (~(((1<<AW88399_WDT_CNT_BITS_LEN)-1) << AW88399_WDT_CNT_START_BIT))
-
-#define AW88399_REABS_START_BIT (3)
-#define AW88399_REABS_BITS_LEN (1)
-#define AW88399_REABS_MASK \
- (~(((1<<AW88399_REABS_BITS_LEN)-1) << AW88399_REABS_START_BIT))
-
-#define AW88399_DSP_VOL_START_BIT (8)
-#define AW88399_DSP_VOL_BITS_LEN (8)
-#define AW88399_DSP_VOL_MASK \
- (~(((1<<AW88399_DSP_VOL_BITS_LEN)-1) << AW88399_DSP_VOL_START_BIT))
-
-#define AW883XX_DSP_NG_EN_START (13)
-#define AW883XX_DSP_NG_EN_LEN (1)
-#define AW883XX_DSP_NG_EN_MASK \
- (~(((1 << AW883XX_DSP_NG_EN_LEN) - 1) << AW883XX_DSP_NG_EN_START))
-#define AW883XX_DSP_NG_EN_DISABLE (0)
-#define AW883XX_DSP_NG_EN_DISABLE_VALUE \
- (AW883XX_DSP_NG_EN_DISABLE << AW883XX_DSP_NG_EN_START)
-
-#define AW88399_VOLUME_STEP_DB (64)
-#define AW88399_VOL_DEFAULT_VALUE (0)
-#define AW88399_DSP_ODD_NUM_BIT_TEST (0x5555)
-#define AW88399_EF_ISN_GESLP_SIGN_MASK (~(1 << 9))
-#define AW88399_EF_ISN_GESLP_SIGN_NEG (0xfe00)
-
-#define AW88399_EF_VSN_GESLP_SIGN_MASK (~(1 << 9))
-#define AW88399_EF_VSN_GESLP_SIGN_NEG (0xfe00)
-
-#define AW88399_TEM4_SIGN_MASK (~(1 << 5))
-#define AW88399_TEM4_SIGN_NEG (0xffc0)
-
-#define AW88399_ICABLK_FACTOR (1)
-#define AW88399_VCABLK_FACTOR (1)
-#define AW88399_VCABLK_DAC_FACTOR (2)
-
-#define AW88399_VCALB_ADJ_FACTOR (12)
-#define AW88399_VCALB_ACCURACY (1 << 12)
-
-#define AW88399_ISCAL_FACTOR (3125)
-#define AW88399_VSCAL_FACTOR (18875)
-#define AW88399_ISCAL_DAC_FACTOR (3125)
-#define AW88399_VSCAL_DAC_FACTOR (12600)
-#define AW88399_CABL_BASE_VALUE (1000)
-
-#define AW88399_DEV_DEFAULT_CH (0)
-#define AW88399_DEV_DSP_CHECK_MAX (5)
-#define AW88399_MAX_RAM_WRITE_BYTE_SIZE (128)
-#define AW88399_DSP_RE_SHIFT (12)
-#define AW88399_CALI_RE_MAX (15000)
-#define AW88399_CALI_RE_MIN (4000)
-#define AW_FW_ADDR_LEN (4)
-#define AW88399_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
-#define AW88399_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
-#define AW88399_CRC_CHECK_PASS_VAL (0x4)
-
-#define AW88399_CRC_CFG_BASE_ADDR (0xD80)
-#define AW88399_CRC_FW_BASE_ADDR (0x4C0)
-#define AW88399_ACF_FILE "aw88399_acf.bin"
-#define AW88399_DEV_SYSST_CHECK_MAX (10)
-#define AW88399_CHIP_ID 0x2183
+#include <sound/aw88399.h>
#define AW88399_I2C_NAME "aw88399"
-#define AW88399_START_RETRIES (5)
-#define AW88399_START_WORK_DELAY_MS (0)
-
#define AW88399_RATES (SNDRV_PCM_RATE_8000_48000 | \
SNDRV_PCM_RATE_96000)
#define AW88399_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -550,80 +48,4 @@
.put = profile_set, \
}
-enum {
- AW_EF_AND_CHECK = 0,
- AW_EF_OR_CHECK,
-};
-
-enum {
- AW88399_DEV_VDSEL_DAC = 0,
- AW88399_DEV_VDSEL_VSENSE = 32,
-};
-
-enum {
- AW88399_DSP_CRC_NA = 0,
- AW88399_DSP_CRC_OK = 1,
-};
-
-enum {
- AW88399_DSP_FW_UPDATE_OFF = 0,
- AW88399_DSP_FW_UPDATE_ON = 1,
-};
-
-enum {
- AW88399_FORCE_UPDATE_OFF = 0,
- AW88399_FORCE_UPDATE_ON = 1,
-};
-
-enum {
- AW88399_1000_US = 1000,
- AW88399_2000_US = 2000,
- AW88399_3000_US = 3000,
- AW88399_4000_US = 4000,
-};
-
-enum AW88399_DEV_STATUS {
- AW88399_DEV_PW_OFF = 0,
- AW88399_DEV_PW_ON,
-};
-
-enum AW88399_DEV_FW_STATUS {
- AW88399_DEV_FW_FAILED = 0,
- AW88399_DEV_FW_OK,
-};
-
-enum AW88399_DEV_MEMCLK {
- AW88399_DEV_MEMCLK_OSC = 0,
- AW88399_DEV_MEMCLK_PLL = 1,
-};
-
-enum AW88399_DEV_DSP_CFG {
- AW88399_DEV_DSP_WORK = 0,
- AW88399_DEV_DSP_BYPASS = 1,
-};
-
-enum {
- AW88399_NOT_RCV_MODE = 0,
- AW88399_RCV_MODE = 1,
-};
-
-enum {
- AW88399_SYNC_START = 0,
- AW88399_ASYNC_START,
-};
-
-struct aw88399 {
- struct aw_device *aw_pa;
- struct mutex lock;
- struct gpio_desc *reset_gpio;
- struct delayed_work start_work;
- struct regmap *regmap;
- struct aw_container *aw_cfg;
-
- unsigned int check_val;
- unsigned int crc_init_val;
- unsigned int vcalb_init_val;
- unsigned int dither_st;
-};
-
-#endif
+#endif /* __AW88399_H__ */
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
index c0bf45b76cb8..b085885e3f18 100644
--- a/sound/soc/codecs/bt-sco.c
+++ b/sound/soc/codecs/bt-sco.c
@@ -85,13 +85,9 @@ static int bt_sco_probe(struct platform_device *pdev)
}
static const struct platform_device_id bt_sco_driver_ids[] = {
- {
- .name = "dfbmcs320",
- },
- {
- .name = "bt-sco",
- },
- {},
+ { .name = "dfbmcs320" },
+ { .name = "bt-sco" },
+ { }
};
MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 6b80c455b074..fc41e1547bda 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -26,14 +26,6 @@
/* Register 9 - CPCAP_REG_INTS2 --- Interrupt Sense 2 */
#define CPCAP_BIT_PTT_S 11 /* Push To Talk */
-/* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
-#define CPCAP_BIT_AUDIO_LOW_PWR 6
-#define CPCAP_BIT_AUD_LOWPWR_SPEED 5
-#define CPCAP_BIT_VAUDIOPRISTBY 4
-#define CPCAP_BIT_VAUDIO_MODE1 2
-#define CPCAP_BIT_VAUDIO_MODE0 1
-#define CPCAP_BIT_V_AUDIO_EN 0
-
/* Register 513 CPCAP_REG_CC --- CODEC */
#define CPCAP_BIT_CDC_CLK2 15
#define CPCAP_BIT_CDC_CLK1 14
@@ -239,7 +231,6 @@ struct cpcap_reg_info {
};
static const struct cpcap_reg_info cpcap_default_regs[] = {
- { CPCAP_REG_VAUDIOC, 0x003F, 0x0000 },
{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
{ CPCAP_REG_CC, 0xFFFF, 0x0000 },
{ CPCAP_REG_CDI, 0xBFFF, 0x0000 },
@@ -1265,6 +1256,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_component *component = dai->component;
struct device *dev = component->dev;
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
@@ -1298,7 +1290,7 @@ static int cpcap_voice_hw_params(struct snd_pcm_substream *substream,
return err;
}
- return 0;
+ return snd_soc_runtime_set_dai_fmt(rtd, rtd->dai_link->dai_fmt);
}
static int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id,
@@ -1391,121 +1383,8 @@ static int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
-
-/*
- * Configure codec for voice call if requested.
- *
- * We can configure most with snd_soc_dai_set_sysclk(), snd_soc_dai_set_fmt()
- * and snd_soc_dai_set_tdm_slot(). This function configures the rest of the
- * cpcap related hardware as CPU is not involved in the voice call.
- */
-static int cpcap_voice_call(struct cpcap_audio *cpcap, struct snd_soc_dai *dai,
- bool voice_call)
-{
- int mask, err;
-
- /* Modem to codec VAUDIO_MODE1 */
- mask = BIT(CPCAP_BIT_VAUDIO_MODE1);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_VAUDIOC,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Clear MIC1_MUX for call */
- mask = BIT(CPCAP_BIT_MIC1_MUX);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
- mask, voice_call ? 0 : mask);
- if (err)
- return err;
-
- /* Set MIC2_MUX for call */
- mask = BIT(CPCAP_BIT_MB_ON1L) | BIT(CPCAP_BIT_MB_ON1R) |
- BIT(CPCAP_BIT_MIC2_MUX) | BIT(CPCAP_BIT_MIC2_PGA_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Enable LDSP for call */
- mask = BIT(CPCAP_BIT_A2_LDSP_L_EN) | BIT(CPCAP_BIT_A2_LDSP_R_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Enable CPCAP_BIT_PGA_CDC_EN for call */
- mask = BIT(CPCAP_BIT_PGA_CDC_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Unmute voice for call */
- if (dai) {
- err = snd_soc_dai_digital_mute(dai, !voice_call,
- SNDRV_PCM_STREAM_PLAYBACK);
- if (err)
- return err;
- }
-
- /* Set modem to codec mic CDC and HPF for call */
- mask = BIT(CPCAP_BIT_MIC2_CDC_EN) | BIT(CPCAP_BIT_CDC_EN_RX) |
- BIT(CPCAP_BIT_AUDOHPF_1) | BIT(CPCAP_BIT_AUDOHPF_0) |
- BIT(CPCAP_BIT_AUDIHPF_1) | BIT(CPCAP_BIT_AUDIHPF_0);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CC,
- mask, voice_call ? mask : 0);
- if (err)
- return err;
-
- /* Enable modem to codec CDC for call*/
- mask = BIT(CPCAP_BIT_CDC_CLK_EN);
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
- mask, voice_call ? mask : 0);
-
- return err;
-}
-
-static int cpcap_voice_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;
- struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
- int err, ts_mask, mask;
- bool voice_call;
-
- /*
- * Primitive test for voice call, probably needs more checks
- * later on for 16-bit calls detected, Bluetooth headset etc.
- */
- if (tx_mask == 0 && rx_mask == 1 && slot_width == 8)
- voice_call = true;
- else
- voice_call = false;
-
- ts_mask = 0x7 << CPCAP_BIT_MIC2_TIMESLOT0;
- ts_mask |= 0x7 << CPCAP_BIT_MIC1_RX_TIMESLOT0;
-
- mask = (tx_mask & 0x7) << CPCAP_BIT_MIC2_TIMESLOT0;
- mask |= (rx_mask & 0x7) << CPCAP_BIT_MIC1_RX_TIMESLOT0;
-
- err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI,
- ts_mask, mask);
- if (err)
- return err;
-
- err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, slot_width * 1000);
- if (err)
- return err;
-
- err = cpcap_voice_call(cpcap, dai, voice_call);
- if (err)
- return err;
-
- return 0;
-}
-
-static int cpcap_voice_set_mute(struct snd_soc_dai *dai, int mute, int direction)
+static int cpcap_voice_set_mute(struct snd_soc_dai *dai,
+ int mute, int direction)
{
struct snd_soc_component *component = dai->component;
struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
@@ -1526,7 +1405,6 @@ static const struct snd_soc_dai_ops cpcap_dai_voice_ops = {
.hw_params = cpcap_voice_hw_params,
.set_sysclk = cpcap_voice_set_dai_sysclk,
.set_fmt = cpcap_voice_set_dai_fmt,
- .set_tdm_slot = cpcap_voice_set_tdm_slot,
.mute_stream = cpcap_voice_set_mute,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 7dc5a7c3ca96..1148e37e29ce 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -12,6 +12,7 @@
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/cleanup.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
@@ -319,10 +320,18 @@ static int i2s_rx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
(uint8_t *)&p, sizeof(p), NULL, 0);
}
+static const u64 i2s_rx_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops i2s_rx_dai_ops = {
.hw_params = i2s_rx_hw_params,
.set_fmt = i2s_rx_set_fmt,
.set_bclk_ratio = i2s_rx_set_bclk_ratio,
+ .auto_selectable_formats = &i2s_rx_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static int i2s_rx_event(struct snd_soc_dapm_widget *w,
@@ -608,10 +617,10 @@ static void wov_copy_work(struct work_struct *w)
container_of(w, struct cros_ec_codec_priv, wov_copy_work.work);
int ret;
- mutex_lock(&priv->wov_dma_lock);
+ guard(mutex)(&priv->wov_dma_lock);
if (!priv->wov_substream) {
dev_warn(priv->dev, "no pcm substream\n");
- goto leave;
+ return;
}
if (ec_codec_capable(priv, EC_CODEC_CAP_WOV_AUDIO_SHM))
@@ -624,8 +633,6 @@ static void wov_copy_work(struct work_struct *w)
msecs_to_jiffies(10));
else if (ret)
dev_err(priv->dev, "failed to read audio data\n");
-leave:
- mutex_unlock(&priv->wov_dma_lock);
}
static int wov_enable_get(struct snd_kcontrol *kcontrol,
@@ -895,12 +902,11 @@ static int wov_pcm_hw_params(struct snd_soc_component *component,
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->wov_dma_lock);
+ guard(mutex)(&priv->wov_dma_lock);
priv->wov_substream = substream;
priv->wov_rp = priv->wov_wp = 0;
priv->wov_dma_offset = 0;
priv->wov_burst_read = true;
- mutex_unlock(&priv->wov_dma_lock);
return 0;
}
@@ -911,10 +917,10 @@ static int wov_pcm_hw_free(struct snd_soc_component *component,
struct cros_ec_codec_priv *priv =
snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->wov_dma_lock);
- wov_queue_dequeue(priv, wov_queue_size(priv));
- priv->wov_substream = NULL;
- mutex_unlock(&priv->wov_dma_lock);
+ scoped_guard(mutex, &priv->wov_dma_lock) {
+ wov_queue_dequeue(priv, wov_queue_size(priv));
+ priv->wov_substream = NULL;
+ }
cancel_delayed_work_sync(&priv->wov_copy_work);
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 371e99205b58..41a9a5b005c6 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -7,6 +7,7 @@
#include <asm/byteorder.h>
#include <kunit/static_stub.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/dev_printk.h>
#include <linux/efi.h>
@@ -83,10 +84,12 @@ static int cs_amp_write_cal_coeff(struct cs_dsp *dsp,
KUNIT_STATIC_STUB_REDIRECT(cs_amp_write_cal_coeff, dsp, controls, ctl_name, val);
if (IS_REACHABLE(CONFIG_FW_CS_DSP)) {
- mutex_lock(&dsp->pwr_lock);
- cs_ctl = cs_dsp_get_ctl(dsp, ctl_name, controls->mem_region, controls->alg_id);
- ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval));
- mutex_unlock(&dsp->pwr_lock);
+ scoped_guard(mutex, &dsp->pwr_lock) {
+ cs_ctl = cs_dsp_get_ctl(dsp, ctl_name,
+ controls->mem_region,
+ controls->alg_id);
+ ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, &beval, sizeof(beval));
+ }
if (ret < 0) {
dev_err(dsp->dev, "Failed to write to '%s': %d\n", ctl_name, ret);
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index c835088de578..8288fb6d50be 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -538,7 +538,15 @@ static int cs35l32_runtime_resume(struct device *dev)
gpiod_set_value_cansleep(cs35l32->reset_gpio, 1);
regcache_cache_only(cs35l32->regmap, false);
- regcache_sync(cs35l32->regmap);
+ ret = regcache_sync(cs35l32->regmap);
+ if (ret) {
+ regcache_cache_only(cs35l32->regmap, true);
+ regcache_mark_dirty(cs35l32->regmap);
+ gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
+ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies),
+ cs35l32->supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index f49edb9ea1f2..e217da124549 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -40,6 +40,7 @@ struct cs35l33_private {
struct regmap *regmap;
struct gpio_desc *reset_gpio;
bool amp_cal;
+ bool irq_requested;
int mclk_int;
struct regulator_bulk_data core_supplies[2];
int num_core_supplies;
@@ -881,6 +882,9 @@ static int cs35l33_runtime_resume(struct device *dev)
goto err;
}
+ if (cs35l33->irq_requested)
+ enable_irq(to_i2c_client(dev)->irq);
+
return 0;
err:
@@ -900,6 +904,10 @@ static int cs35l33_runtime_suspend(struct device *dev)
/* redo the calibration in next power up */
cs35l33->amp_cal = false;
+ /* Drain and block the threaded IRQ before cache_only/power-off. */
+ if (cs35l33->irq_requested)
+ disable_irq(to_i2c_client(dev)->irq);
+
regcache_cache_only(cs35l33->regmap, true);
regcache_mark_dirty(cs35l33->regmap);
regulator_bulk_disable(cs35l33->num_core_supplies,
@@ -1154,10 +1162,12 @@ static int cs35l33_i2c_probe(struct i2c_client *i2c_client)
}
ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
- cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
- "cs35l33", cs35l33);
+ cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs35l33", cs35l33);
if (ret != 0)
dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+ else
+ cs35l33->irq_requested = true;
/* We could issue !RST or skip it based on AMP topology */
cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index e80984b22159..3f265bd760f7 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -45,6 +45,7 @@ struct cs35l34_private {
int num_core_supplies;
int mclk_int;
bool tdm_mode;
+ bool irq_requested;
struct gpio_desc *reset_gpio; /* Active-low reset GPIO */
};
@@ -1032,10 +1033,12 @@ static int cs35l34_i2c_probe(struct i2c_client *i2c_client)
}
ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL,
- cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
- "cs35l34", cs35l34);
+ cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "cs35l34", cs35l34);
if (ret != 0)
dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
+ else
+ cs35l34->irq_requested = true;
cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"reset", GPIOD_OUT_LOW);
@@ -1140,6 +1143,9 @@ static int cs35l34_runtime_resume(struct device *dev)
dev_err(dev, "Failed to restore register cache\n");
goto err;
}
+
+ if (cs35l34->irq_requested)
+ enable_irq(to_i2c_client(dev)->irq);
return 0;
err:
regcache_cache_only(cs35l34->regmap, true);
@@ -1153,6 +1159,10 @@ static int cs35l34_runtime_suspend(struct device *dev)
{
struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
+ /* Drain and block the threaded IRQ before cache_only/power-off. */
+ if (cs35l34->irq_requested)
+ disable_irq(to_i2c_client(dev)->irq);
+
regcache_cache_only(cs35l34->regmap, true);
regcache_mark_dirty(cs35l34->regmap);
diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
index 4f6ddf1c5a3f..5e69ddbe342a 100644
--- a/sound/soc/codecs/cs35l56-i2c.c
+++ b/sound/soc/codecs/cs35l56-i2c.c
@@ -51,15 +51,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n");
}
- ret = cs35l56_common_probe(cs35l56);
- if (ret != 0)
- return ret;
-
- ret = cs35l56_irq_request(&cs35l56->base, client->irq);
- if (ret < 0)
- cs35l56_remove(cs35l56);
-
- return ret;
+ return cs35l56_common_probe(cs35l56, client->irq);
}
static void cs35l56_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c
index 0a55b93b96f9..4fba59e80c37 100644
--- a/sound/soc/codecs/cs35l56-sdw.c
+++ b/sound/soc/codecs/cs35l56-sdw.c
@@ -231,7 +231,7 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
* a soft reset.
*/
if (cs35l56->base.init_done)
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
+ cs35l56_unmask_soundwire_interrupts(cs35l56);
out:
pm_runtime_put_autosuspend(cs35l56->base.dev);
@@ -240,47 +240,17 @@ out:
static int cs35l56_sdw_interrupt(struct sdw_slave *peripheral,
struct sdw_slave_intr_status *status)
{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
-
- /* SoundWire core holds our pm_runtime when calling this function. */
-
- dev_dbg(cs35l56->base.dev, "int control_port=%#x\n", status->control_port);
-
- if ((status->control_port & SDW_SCP_INT1_IMPL_DEF) == 0)
- return 0;
-
/*
- * Prevent bus manager suspending and possibly issuing a
- * bus-reset before the queued work has run.
+ * The IRQ itself was handled through the regmap_irq handler, this is
+ * just clearing up the additional Cirrus SoundWire registers that are
+ * not covered by the SoundWire framework or the IRQ handler itself.
*/
- pm_runtime_get_noresume(cs35l56->base.dev);
-
- /*
- * Mask and clear until it has been handled.
- * None of the interrupts are time-critical so use the
- * power-efficient queue.
- */
- cs35l56_mask_soundwire_interrupts(peripheral);
- queue_work(system_power_efficient_wq, &cs35l56->sdw_irq_work);
+ sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1);
+ sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
return 0;
}
-static void cs35l56_sdw_irq_work(struct work_struct *work)
-{
- struct cs35l56_private *cs35l56 = container_of(work,
- struct cs35l56_private,
- sdw_irq_work);
-
- cs35l56_irq(-1, &cs35l56->base);
-
- /* unmask interrupts */
- if (!cs35l56->sdw_irq_no_unmask)
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
-
- pm_runtime_put_autosuspend(cs35l56->base.dev);
-}
-
static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
@@ -302,6 +272,7 @@ static int cs35l56_sdw_read_prop(struct sdw_slave *peripheral)
prop->source_ports = BIT(CS35L56_SDW1_CAPTURE_PORT);
prop->sink_ports = BIT(CS35L56_SDW1_PLAYBACK_PORT);
prop->paging_support = true;
+ prop->use_domain_irq = true;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | SDW_SCP_INT1_IMPL_DEF;
@@ -406,7 +377,7 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
if (ret)
return ret;
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
+ cs35l56_unmask_soundwire_interrupts(cs35l56);
return 0;
}
@@ -418,21 +389,12 @@ static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
if (!cs35l56->base.init_done)
return 0;
- cs35l56_disable_sdw_interrupts(cs35l56);
+ /* runtime_resume unmasks the interrupt */
+ cs35l56_mask_soundwire_interrupts(cs35l56);
return cs35l56_system_suspend(dev);
}
-static int __maybe_unused cs35l56_sdw_system_resume(struct device *dev)
-{
- struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
-
- cs35l56->sdw_irq_no_unmask = false;
- /* runtime_resume re-enables the interrupt */
-
- return cs35l56_system_resume(dev);
-}
-
static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id)
{
struct device *dev = &peripheral->dev;
@@ -447,7 +409,6 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
cs35l56->base.dev = dev;
cs35l56->sdw_peripheral = peripheral;
cs35l56->sdw_link_num = peripheral->bus->link_id;
- INIT_WORK(&cs35l56->sdw_irq_work, cs35l56_sdw_irq_work);
dev_set_drvdata(dev, cs35l56);
@@ -457,6 +418,7 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
regmap_config = &cs35l56_regmap_sdw;
break;
case 0x3563:
+ case 0x3562:
regmap_config = &cs35l63_regmap_sdw;
break;
default:
@@ -483,25 +445,21 @@ static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_devi
/* Start in cache-only until device is enumerated */
regcache_cache_only(cs35l56->base.regmap, true);
- ret = cs35l56_common_probe(cs35l56);
- if (ret != 0)
- return ret;
-
- return 0;
+ return cs35l56_common_probe(cs35l56, peripheral->irq);
}
static void cs35l56_sdw_remove(struct sdw_slave *peripheral)
{
struct cs35l56_private *cs35l56 = dev_get_drvdata(&peripheral->dev);
- cs35l56_disable_sdw_interrupts(cs35l56);
+ cs35l56_mask_soundwire_interrupts(cs35l56);
cs35l56_remove(cs35l56);
}
static const struct dev_pm_ops cs35l56_sdw_pm = {
SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL)
- SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_sdw_system_resume)
+ SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume)
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
/* NOIRQ stage not needed, SoundWire doesn't use a hard IRQ */
};
@@ -509,6 +467,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = {
static const struct sdw_device_id cs35l56_sdw_id[] = {
SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0x3556),
SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0x3557),
+ SDW_SLAVE_ENTRY(0x01FA, 0x3562, 0x3562),
SDW_SLAVE_ENTRY(0x01FA, 0x3563, 0x3563),
{},
};
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index f14e2eaaa4ee..7b3e37d462d6 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -96,6 +96,7 @@ int cs35l56_set_patch(struct cs35l56_base *cs35l56_base)
ARRAY_SIZE(cs35l56_patch_fw));
break;
case 0x63:
+ case 0x62:
ret = regmap_register_patch(cs35l56_base->regmap, cs35l63_patch_fw,
ARRAY_SIZE(cs35l63_patch_fw));
break;
@@ -389,6 +390,7 @@ static void cs35l56_set_fw_reg_table(struct cs35l56_base *cs35l56_base)
}
break;
case 0x63:
+ case 0x62:
cs35l56_base->fw_reg = &cs35l63_fw_reg;
break;
}
@@ -595,6 +597,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
}
break;
case 0x63:
+ case 0x62:
regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
cs35l63_system_reset_seq,
ARRAY_SIZE(cs35l63_system_reset_seq));
@@ -613,26 +616,7 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_system_reset, "SND_SOC_CS35L56_SHARED");
-int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
-{
- int ret;
-
- if (irq < 1)
- return 0;
-
- ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
- IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
- "cs35l56", cs35l56_base);
- if (!ret)
- cs35l56_base->irq = irq;
- else
- dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED");
-
-irqreturn_t cs35l56_irq(int irq, void *data)
+static irqreturn_t cs35l56_irq(int irq, void *data)
{
struct cs35l56_base *cs35l56_base = data;
unsigned int status1 = 0, status8 = 0, status20 = 0;
@@ -640,23 +624,22 @@ irqreturn_t cs35l56_irq(int irq, void *data)
unsigned int val;
int rv;
- irqreturn_t ret = IRQ_NONE;
-
if (!cs35l56_base->init_done)
return IRQ_NONE;
- mutex_lock(&cs35l56_base->irq_lock);
+ guard(mutex)(&cs35l56_base->irq_lock);
- rv = pm_runtime_resume_and_get(cs35l56_base->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED(cs35l56_base->dev, pm);
+ rv = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (rv < 0) {
dev_err(cs35l56_base->dev, "irq: failed to get pm_runtime: %d\n", rv);
- goto err_unlock;
+ return IRQ_NONE;
}
regmap_read(cs35l56_base->regmap, CS35L56_IRQ1_STATUS, &val);
if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
dev_dbg(cs35l56_base->dev, "Spurious IRQ: no pending interrupt\n");
- goto err;
+ return IRQ_NONE;
}
/* Ack interrupts */
@@ -680,7 +663,7 @@ irqreturn_t cs35l56_irq(int irq, void *data)
/* Check to see if unmasked bits are active */
if (!status1 && !status8 && !status20)
- goto err;
+ return IRQ_NONE;
if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
dev_crit(cs35l56_base->dev, "Amp short error\n");
@@ -688,16 +671,27 @@ irqreturn_t cs35l56_irq(int irq, void *data)
if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
dev_crit(cs35l56_base->dev, "Overtemp error\n");
- ret = IRQ_HANDLED;
+ return IRQ_HANDLED;
+}
-err:
- pm_runtime_put(cs35l56_base->dev);
-err_unlock:
- mutex_unlock(&cs35l56_base->irq_lock);
+int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq)
+{
+ int ret;
+
+ if (irq < 1)
+ return 0;
+
+ ret = devm_request_threaded_irq(cs35l56_base->dev, irq, NULL, cs35l56_irq,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
+ "cs35l56", cs35l56_base);
+ if (!ret)
+ cs35l56_base->irq = irq;
+ else
+ dev_err(cs35l56_base->dev, "Failed to get IRQ: %d\n", ret);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_irq, "SND_SOC_CS35L56_SHARED");
+EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, "SND_SOC_CS35L56_SHARED");
int cs35l56_is_fw_reload_needed(struct cs35l56_base *cs35l56_base)
{
@@ -816,14 +810,10 @@ int cs35l56_runtime_resume_common(struct cs35l56_base *cs35l56_base, bool is_sou
if (!cs35l56_base->init_done)
return 0;
- if (!cs35l56_base->can_hibernate)
- goto out_sync;
-
- /* Must be done before releasing cache-only */
- if (!is_soundwire)
+ /* Hibernate wake must be done before releasing cache-only */
+ if (cs35l56_base->can_hibernate && !is_soundwire)
cs35l56_issue_wake_event(cs35l56_base);
-out_sync:
ret = cs35l56_wait_for_firmware_boot(cs35l56_base);
if (ret) {
dev_err(cs35l56_base->dev, "Hibernate wake failed: %d\n", ret);
@@ -1470,6 +1460,7 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base)
cs35l56_base->calibration_controls = &cs35l56_calibration_controls;
break;
case 0x35A630:
+ case 0x35A620:
cs35l56_base->calibration_controls = &cs35l63_calibration_controls;
devid = devid >> 4;
break;
diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
index b1eb924a5b6c..21b18da9e73d 100644
--- a/sound/soc/codecs/cs35l56-spi.c
+++ b/sound/soc/codecs/cs35l56-spi.c
@@ -40,15 +40,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = cs35l56_common_probe(cs35l56);
- if (ret != 0)
- return ret;
-
- ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
- if (ret < 0)
- cs35l56_remove(cs35l56);
-
- return ret;
+ return cs35l56_common_probe(cs35l56, spi->irq);
}
static void cs35l56_spi_remove(struct spi_device *spi)
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 063ef7a70de0..b9118ad8fab5 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -37,48 +37,49 @@
#include "wm_adsp.h"
#include "cs35l56.h"
-void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral)
+void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56)
{
/*
+ * Mask unconditionally.
+ *
* The read of GEN_INT_STAT_1 is required as per the SoundWire spec
* for interrupt status bits to clear.
* GEN_INT_MASK_1 masks the _inputs_ to GEN_INT_STAT1.
*/
- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
- sdw_read_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1);
- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1, 0);
+ sdw_read_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1);
+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_STAT_1, 0xFF);
}
EXPORT_SYMBOL_NS_GPL(cs35l56_mask_soundwire_interrupts, "SND_SOC_CS35L56_CORE");
-void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral)
+void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56)
{
- sdw_write_no_pm(peripheral, CS35L56_SDW_GEN_INT_MASK_1, CS35L56_SDW_INT_MASK_CODEC_IRQ);
+ if (!cs35l56->base.irq)
+ return;
+
+ sdw_write_no_pm(cs35l56->sdw_peripheral, CS35L56_SDW_GEN_INT_MASK_1,
+ CS35L56_SDW_INT_MASK_CODEC_IRQ);
}
EXPORT_SYMBOL_NS_GPL(cs35l56_unmask_soundwire_interrupts, "SND_SOC_CS35L56_CORE");
-void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56)
+static void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56)
{
if (!cs35l56->sdw_peripheral)
return;
- cs35l56->sdw_irq_no_unmask = true;
- flush_work(&cs35l56->sdw_irq_work);
-
- /* Mask interrupts and flush in case sdw_irq_work was queued again */
- cs35l56_mask_soundwire_interrupts(cs35l56->sdw_peripheral);
- flush_work(&cs35l56->sdw_irq_work);
+ cs35l56_mask_soundwire_interrupts(cs35l56);
+ if (cs35l56->base.irq)
+ disable_irq(cs35l56->base.irq);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_disable_sdw_interrupts, "SND_SOC_CS35L56_CORE");
-void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56)
+static void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56)
{
- if (!cs35l56->sdw_peripheral)
+ if (!cs35l56->sdw_peripheral || !cs35l56->base.irq)
return;
- cs35l56->sdw_irq_no_unmask = false;
- cs35l56_unmask_soundwire_interrupts(cs35l56->sdw_peripheral);
+ enable_irq(cs35l56->base.irq);
+ cs35l56_unmask_soundwire_interrupts(cs35l56);
}
-EXPORT_SYMBOL_NS_GPL(cs35l56_enable_sdw_interrupts, "SND_SOC_CS35L56_CORE");
static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -828,11 +829,7 @@ static void cs35l56_patch(struct cs35l56_private *cs35l56, bool firmware_missing
{
int ret;
- /*
- * Disable SoundWire interrupts to prevent race with IRQ work.
- * Setting sdw_irq_no_unmask prevents the handler re-enabling
- * the SoundWire interrupt.
- */
+ /* Disable SoundWire interrupts to prevent race with IRQ handler thread */
cs35l56_disable_sdw_interrupts(cs35l56);
ret = cs35l56_firmware_shutdown(&cs35l56->base);
@@ -1402,6 +1399,7 @@ static int _cs35l56_component_probe(struct snd_soc_component *component)
ARRAY_SIZE(cs35l56_controls));
break;
case 0x63:
+ case 0x62:
ret = snd_soc_add_component_controls(component, cs35l63_controls,
ARRAY_SIZE(cs35l63_controls));
break;
@@ -1941,7 +1939,7 @@ static int cs35l56_try_get_broken_sdca_spkid_gpio(struct cs35l56_private *cs35l5
return ret;
}
-int cs35l56_common_probe(struct cs35l56_private *cs35l56)
+int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq)
{
int ret;
@@ -2018,16 +2016,24 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
goto err_remove_wm_adsp;
}
+ ret = cs35l56_irq_request(&cs35l56->base, irq);
+ if (ret)
+ goto err_remove_wm_adsp;
+
ret = snd_soc_register_component(cs35l56->base.dev,
&soc_component_dev_cs35l56,
cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
if (ret < 0) {
dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
- goto err_remove_wm_adsp;
+ goto err_free_irq;
}
return 0;
+err_free_irq:
+ if (cs35l56->base.irq)
+ devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base);
+
err_remove_wm_adsp:
wm_adsp2_remove(&cs35l56->dsp);
diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h
index 9acd2e7e17c9..35c02ae17de3 100644
--- a/sound/soc/codecs/cs35l56.h
+++ b/sound/soc/codecs/cs35l56.h
@@ -39,8 +39,6 @@ struct cs35l56_private {
struct sdw_slave *sdw_peripheral;
struct regmap *sdw_bus_regmap;
const char *fallback_fw_suffix;
- struct work_struct sdw_irq_work;
- bool sdw_irq_no_unmask;
bool soft_resetting;
bool sdw_attached;
struct completion init_completion;
@@ -65,10 +63,8 @@ static inline struct cs35l56_private *cs35l56_private_from_base(struct cs35l56_b
extern const struct dev_pm_ops cs35l56_pm_ops_i2c_spi;
-void cs35l56_mask_soundwire_interrupts(struct sdw_slave *peripheral);
-void cs35l56_unmask_soundwire_interrupts(struct sdw_slave *peripheral);
-void cs35l56_disable_sdw_interrupts(struct cs35l56_private *cs35l56);
-void cs35l56_enable_sdw_interrupts(struct cs35l56_private *cs35l56);
+void cs35l56_mask_soundwire_interrupts(struct cs35l56_private *cs35l56);
+void cs35l56_unmask_soundwire_interrupts(struct cs35l56_private *cs35l56);
int cs35l56_system_suspend(struct device *dev);
int cs35l56_system_suspend_late(struct device *dev);
@@ -76,9 +72,8 @@ int cs35l56_system_suspend_no_irq(struct device *dev);
int cs35l56_system_resume_no_irq(struct device *dev);
int cs35l56_system_resume_early(struct device *dev);
int cs35l56_system_resume(struct device *dev);
-irqreturn_t cs35l56_irq(int irq, void *data);
int cs35l56_irq_request(struct cs35l56_base *cs35l56_base, int irq);
-int cs35l56_common_probe(struct cs35l56_private *cs35l56);
+int cs35l56_common_probe(struct cs35l56_private *cs35l56, int irq);
int cs35l56_init(struct cs35l56_private *cs35l56);
void cs35l56_remove(struct cs35l56_private *cs35l56);
diff --git a/sound/soc/codecs/cs40l50-codec.c b/sound/soc/codecs/cs40l50-codec.c
index aa629ef53db4..676367163067 100644
--- a/sound/soc/codecs/cs40l50-codec.c
+++ b/sound/soc/codecs/cs40l50-codec.c
@@ -288,8 +288,8 @@ static int cs40l50_codec_driver_probe(struct platform_device *pdev)
}
static const struct platform_device_id cs40l50_id[] = {
- { "cs40l50-codec", },
- {}
+ { .name = "cs40l50-codec" },
+ { }
};
MODULE_DEVICE_TABLE(platform, cs40l50_id);
diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c
index ad1256910a18..b61ca74dcf0b 100644
--- a/sound/soc/codecs/cs42l42-sdw.c
+++ b/sound/soc/codecs/cs42l42-sdw.c
@@ -481,10 +481,20 @@ static int cs42l42_sdw_runtime_resume(struct device *dev)
regcache_cache_only(cs42l42->regmap, false);
/* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
- regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
- regcache_sync(cs42l42->regmap);
+ ret = regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
+ if (ret)
+ goto err_sync;
+
+ ret = regcache_sync(cs42l42->regmap);
+ if (ret)
+ goto err_sync;
return 0;
+
+err_sync:
+ regcache_cache_only(cs42l42->regmap, true);
+ regcache_mark_dirty(cs42l42->regmap);
+ return ret;
}
static int cs42l42_sdw_resume(struct device *dev)
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 2652a639a79a..fadf68860601 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -9,6 +9,7 @@
* Author: Michael White <michael.white@cirrus.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -565,7 +566,7 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
/* Prevent race with interrupt handler */
- mutex_lock(&cs42l42->irq_lock);
+ guard(mutex)(&cs42l42->irq_lock);
cs42l42->jack = jk;
if (jk) {
@@ -581,7 +582,6 @@ static int cs42l42_set_jack(struct snd_soc_component *component, struct snd_soc_
break;
}
}
- mutex_unlock(&cs42l42->irq_lock);
return 0;
}
@@ -1668,13 +1668,10 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
unsigned int current_button_status;
unsigned int i;
- pm_runtime_get_sync(cs42l42->dev);
- mutex_lock(&cs42l42->irq_lock);
- if (cs42l42->suspended || !cs42l42->init_done) {
- mutex_unlock(&cs42l42->irq_lock);
- pm_runtime_put_autosuspend(cs42l42->dev);
+ guard(pm_runtime_active_auto)(cs42l42->dev);
+ guard(mutex)(&cs42l42->irq_lock);
+ if (cs42l42->suspended || !cs42l42->init_done)
return IRQ_NONE;
- }
/* Read sticky registers to clear interurpt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
@@ -1774,9 +1771,6 @@ irqreturn_t cs42l42_irq_thread(int irq, void *data)
}
}
- mutex_unlock(&cs42l42->irq_lock);
- pm_runtime_put_autosuspend(cs42l42->dev);
-
return IRQ_HANDLED;
}
EXPORT_SYMBOL_NS_GPL(cs42l42_irq_thread, "SND_SOC_CS42L42_CORE");
@@ -2163,22 +2157,22 @@ int cs42l42_suspend(struct device *dev)
* future interrupts. This ensures a safe disable if the interrupt
* is shared.
*/
- mutex_lock(&cs42l42->irq_lock);
- cs42l42->suspended = true;
+ scoped_guard(mutex, &cs42l42->irq_lock) {
+ cs42l42->suspended = true;
- /* Save register values that will be overwritten by shutdown sequence */
- for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) {
- regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, &reg);
- save_regs[i] = (u8)reg;
- }
+ /* Save register values that will be overwritten by shutdown sequence */
+ for (i = 0; i < ARRAY_SIZE(cs42l42_shutdown_seq); ++i) {
+ regmap_read(cs42l42->regmap, cs42l42_shutdown_seq[i].reg, &reg);
+ save_regs[i] = (u8)reg;
+ }
- /* Shutdown codec */
- regmap_multi_reg_write(cs42l42->regmap,
- cs42l42_shutdown_seq,
- ARRAY_SIZE(cs42l42_shutdown_seq));
+ /* Shutdown codec */
+ regmap_multi_reg_write(cs42l42->regmap,
+ cs42l42_shutdown_seq,
+ ARRAY_SIZE(cs42l42_shutdown_seq));
- /* All interrupt sources are now disabled */
- mutex_unlock(&cs42l42->irq_lock);
+ /* All interrupt sources are now disabled */
+ }
/* Wait for power-down complete */
msleep(CS42L42_PDN_DONE_TIME_MS);
@@ -2250,13 +2244,13 @@ void cs42l42_resume_restore(struct device *dev)
regcache_cache_only(cs42l42->regmap, false);
regcache_mark_dirty(cs42l42->regmap);
- mutex_lock(&cs42l42->irq_lock);
- /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
- regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
- regcache_sync(cs42l42->regmap);
+ scoped_guard(mutex, &cs42l42->irq_lock) {
+ /* Sync LATCH_TO_VP first so the VP domain registers sync correctly */
+ regcache_sync_region(cs42l42->regmap, CS42L42_MIC_DET_CTL1, CS42L42_MIC_DET_CTL1);
+ regcache_sync(cs42l42->regmap);
- cs42l42->suspended = false;
- mutex_unlock(&cs42l42->irq_lock);
+ cs42l42->suspended = false;
+ }
dev_dbg(dev, "System resumed\n");
}
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
index dbf45cabfffe..a2555dd9229e 100644
--- a/sound/soc/codecs/cs42l43-jack.c
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
#include <linux/build_bug.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -67,6 +68,21 @@ static int cs42l43_find_index(struct cs42l43_codec *priv, const char * const pro
return -EINVAL;
}
+static void cs42l43_apply_accdet_config(struct cs42l43_codec *priv,
+ unsigned int autocontrol,
+ unsigned int pdncntl)
+{
+ struct cs42l43 *cs42l43 = priv->core;
+
+ regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
+ CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |
+ CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);
+ regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,
+ CS42L43_RING_SENSE_EN_MASK, pdncntl);
+
+ dev_dbg(priv->dev, "Successfully configured accessory detect\n");
+}
+
int cs42l43_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *d)
{
@@ -80,31 +96,34 @@ int cs42l43_set_jack(struct snd_soc_component *component,
dev_dbg(priv->dev, "Configure accessory detect\n");
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for jack config: %d\n", ret);
return ret;
}
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
priv->jack_hp = jack;
- if (!jack)
- goto done;
+ if (!jack) {
+ cs42l43_apply_accdet_config(priv, autocontrol, pdncntl);
+ return 0;
+ }
ret = device_property_count_u32(cs42l43->dev, "cirrus,buttons-ohms");
if (ret != -EINVAL) {
if (ret < 0) {
dev_err(priv->dev, "Property cirrus,buttons-ohms malformed: %d\n",
ret);
- goto error;
+ return ret;
}
if (ret > CS42L43_N_BUTTONS) {
ret = -EINVAL;
dev_err(priv->dev, "Property cirrus,buttons-ohms too many entries\n");
- goto error;
+ return ret;
}
ret = device_property_read_u32_array(cs42l43->dev, "cirrus,buttons-ohms",
@@ -112,7 +131,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
if (ret < 0) {
dev_err(priv->dev, "Property cirrus,button-ohms malformed: %d\n",
ret);
- goto error;
+ return ret;
}
} else {
priv->buttons[0] = 70;
@@ -124,7 +143,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
ret = cs42l43_find_index(priv, "cirrus,detect-us", 50000, &priv->detect_us,
cs42l43_accdet_us, ARRAY_SIZE(cs42l43_accdet_us));
if (ret < 0)
- goto error;
+ return ret;
hs2 |= ret << CS42L43_AUTO_HSDET_TIME_SHIFT;
@@ -134,7 +153,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->bias_ramp_ms, cs42l43_accdet_ramp_ms,
ARRAY_SIZE(cs42l43_accdet_ramp_ms));
if (ret < 0)
- goto error;
+ return ret;
hs2 |= ret << CS42L43_HSBIAS_RAMP_SHIFT;
@@ -142,7 +161,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->bias_sense_ua, cs42l43_accdet_bias_sense,
ARRAY_SIZE(cs42l43_accdet_bias_sense));
if (ret < 0)
- goto error;
+ return ret;
if (priv->bias_sense_ua)
autocontrol |= ret << CS42L43_HSBIAS_SENSE_TRIP_SHIFT;
@@ -154,7 +173,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->tip_debounce_ms);
if (ret < 0 && ret != -EINVAL) {
dev_err(priv->dev, "Property cirrus,tip-debounce-ms malformed: %d\n", ret);
- goto error;
+ return ret;
}
/* This tip sense invert is set normally, as TIPSENSE_INV already inverted */
@@ -170,7 +189,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->tip_fall_db_ms, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT;
@@ -178,7 +197,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
&priv->tip_rise_db_ms, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
tip_deb |= ret << CS42L43_TIPSENSE_RISING_DB_TIME_SHIFT;
@@ -199,7 +218,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
NULL, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
ring_deb |= ret << CS42L43_RINGSENSE_FALLING_DB_TIME_SHIFT;
@@ -207,7 +226,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
NULL, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
- goto error;
+ return ret;
ring_deb |= ret << CS42L43_RINGSENSE_RISING_DB_TIME_SHIFT;
pdncntl |= CS42L43_RING_SENSE_EN_MASK;
@@ -228,23 +247,9 @@ int cs42l43_set_jack(struct snd_soc_component *component,
CS42L43_HSBIAS_RAMP_MASK | CS42L43_HSDET_MODE_MASK |
CS42L43_AUTO_HSDET_TIME_MASK, hs2);
-done:
- ret = 0;
-
- regmap_update_bits(cs42l43->regmap, CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
- CS42L43_JACKDET_MODE_MASK | CS42L43_S0_AUTO_ADCMUTE_DISABLE_MASK |
- CS42L43_HSBIAS_SENSE_TRIP_MASK, autocontrol);
- regmap_update_bits(cs42l43->regmap, CS42L43_PDNCNTL,
- CS42L43_RING_SENSE_EN_MASK, pdncntl);
-
- dev_dbg(priv->dev, "Successfully configured accessory detect\n");
-
-error:
- mutex_unlock(&priv->jack_lock);
-
- pm_runtime_put_autosuspend(priv->dev);
+ cs42l43_apply_accdet_config(priv, autocontrol, pdncntl);
- return ret;
+ return 0;
}
static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect)
@@ -370,22 +375,22 @@ irqreturn_t cs42l43_button_press(int irq, void *data)
{
struct cs42l43_codec *priv = data;
struct cs42l43 *cs42l43 = priv->core;
- irqreturn_t iret = IRQ_NONE;
unsigned int buttons = 0;
unsigned int val = 0;
int i, ret;
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for button press: %d\n", ret);
- return iret;
+ return IRQ_NONE;
}
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
if (!priv->button_detect_running) {
dev_dbg(priv->dev, "Spurious button press IRQ\n");
- goto error;
+ return IRQ_NONE;
}
// Wait for 2 full cycles of comb filter to ensure good reading
@@ -396,12 +401,12 @@ irqreturn_t cs42l43_button_press(int irq, void *data)
/* Bail if jack removed, the button is irrelevant and likely invalid */
if (!cs42l43_jack_present(priv)) {
dev_dbg(priv->dev, "Button ignored due to removal\n");
- goto error;
+ return IRQ_NONE;
}
if (val & CS42L43_HSBIAS_CLAMP_STS_MASK) {
dev_dbg(priv->dev, "Button ignored due to bias sense\n");
- goto error;
+ return IRQ_NONE;
}
val = (val & CS42L43_HSDET_DC_STS_MASK) >> CS42L43_HSDET_DC_STS_SHIFT;
@@ -424,45 +429,32 @@ irqreturn_t cs42l43_button_press(int irq, void *data)
snd_soc_jack_report(priv->jack_hp, buttons, CS42L43_JACK_BUTTONS);
- iret = IRQ_HANDLED;
-
-error:
- mutex_unlock(&priv->jack_lock);
-
- pm_runtime_put_autosuspend(priv->dev);
-
- return iret;
+ return IRQ_HANDLED;
}
irqreturn_t cs42l43_button_release(int irq, void *data)
{
struct cs42l43_codec *priv = data;
- irqreturn_t iret = IRQ_NONE;
int ret;
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for button release: %d\n", ret);
- return iret;
+ return IRQ_NONE;
}
- mutex_lock(&priv->jack_lock);
-
- if (priv->button_detect_running) {
- dev_dbg(priv->dev, "Button release IRQ\n");
-
- snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);
+ guard(mutex)(&priv->jack_lock);
- iret = IRQ_HANDLED;
- } else {
+ if (!priv->button_detect_running) {
dev_dbg(priv->dev, "Spurious button release IRQ\n");
+ return IRQ_NONE;
}
- mutex_unlock(&priv->jack_lock);
+ dev_dbg(priv->dev, "Button release IRQ\n");
+ snd_soc_jack_report(priv->jack_hp, 0, CS42L43_JACK_BUTTONS);
- pm_runtime_put_autosuspend(priv->dev);
-
- return iret;
+ return IRQ_HANDLED;
}
void cs42l43_bias_sense_timeout(struct work_struct *work)
@@ -472,13 +464,14 @@ void cs42l43_bias_sense_timeout(struct work_struct *work)
struct cs42l43 *cs42l43 = priv->core;
int ret;
- ret = pm_runtime_resume_and_get(priv->dev);
+ PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(priv->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
if (ret) {
dev_err(priv->dev, "Failed to resume for bias sense: %d\n", ret);
return;
}
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
if (cs42l43_jack_present(priv) && priv->button_detect_running) {
dev_dbg(priv->dev, "Bias sense timeout out, restore bias\n");
@@ -491,10 +484,6 @@ void cs42l43_bias_sense_timeout(struct work_struct *work)
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
}
-
- mutex_unlock(&priv->jack_lock);
-
- pm_runtime_put_autosuspend(priv->dev);
}
static const struct reg_sequence cs42l43_3pole_patch[] = {
@@ -896,9 +885,8 @@ int cs42l43_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
ucontrol->value.integer.value[0] = priv->jack_override;
- mutex_unlock(&priv->jack_lock);
return 0;
}
@@ -914,17 +902,13 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
if (override >= e->items)
return -EINVAL;
- mutex_lock(&priv->jack_lock);
+ guard(mutex)(&priv->jack_lock);
- if (!cs42l43_jack_present(priv)) {
- mutex_unlock(&priv->jack_lock);
+ if (!cs42l43_jack_present(priv))
return -EBUSY;
- }
- if (override == priv->jack_override) {
- mutex_unlock(&priv->jack_lock);
+ if (override == priv->jack_override)
return 0;
- }
priv->jack_override = override;
@@ -984,7 +968,5 @@ int cs42l43_jack_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
cs42l43_jack_override_modes[override].report);
}
- mutex_unlock(&priv->jack_lock);
-
return 1;
}
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 1d133577702e..1b817e1a6ea5 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -8,6 +8,7 @@
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/build_bug.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -1207,14 +1208,12 @@ static void cs42l43_spk_vu_sync(struct cs42l43_codec *priv)
{
struct cs42l43 *cs42l43 = priv->core;
- mutex_lock(&priv->spk_vu_lock);
+ guard(mutex)(&priv->spk_vu_lock);
regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
CS42L43_AMP1_2_VU_MASK, CS42L43_AMP1_2_VU_MASK);
regmap_update_bits(cs42l43->regmap, CS42L43_INTP_VOLUME_CTRL1,
CS42L43_AMP1_2_VU_MASK, 0);
-
- mutex_unlock(&priv->spk_vu_lock);
}
static int cs42l43_shutter_get(struct cs42l43_codec *priv, unsigned int shift)
@@ -1601,7 +1600,7 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w,
struct cs42l43 *cs42l43 = priv->core;
int ret;
- mutex_lock(&cs42l43->pll_lock);
+ guard(mutex)(&cs42l43->pll_lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1626,8 +1625,6 @@ static int cs42l43_pll_ev(struct snd_soc_dapm_widget *w,
break;
}
- mutex_unlock(&cs42l43->pll_lock);
-
return ret;
}
@@ -2565,13 +2562,10 @@ static int cs42l43_set_sysclk(struct snd_soc_component *component, int clk_id,
{
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
struct cs42l43 *cs42l43 = priv->core;
- int ret;
- mutex_lock(&cs42l43->pll_lock);
- ret = cs42l43_set_pll(priv, src, freq);
- mutex_unlock(&cs42l43->pll_lock);
+ guard(mutex)(&cs42l43->pll_lock);
- return ret;
+ return cs42l43_set_pll(priv, src, freq);
}
static int cs42l43_component_probe(struct snd_soc_component *component)
@@ -2941,8 +2935,8 @@ static const struct dev_pm_ops cs42l43_codec_pm_ops = {
};
static const struct platform_device_id cs42l43_codec_id_table[] = {
- { "cs42l43-codec", },
- {}
+ { .name = "cs42l43-codec" },
+ { }
};
MODULE_DEVICE_TABLE(platform, cs42l43_codec_id_table);
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
index f2448b4c11fc..a545730b7ed9 100644
--- a/sound/soc/codecs/cs42l84.c
+++ b/sound/soc/codecs/cs42l84.c
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -280,10 +281,9 @@ static int cs42l84_set_jack(struct snd_soc_component *component, struct snd_soc_
struct cs42l84_private *cs42l84 = snd_soc_component_get_drvdata(component);
/* Prevent race with interrupt handler */
- mutex_lock(&cs42l84->irq_lock);
+ guard(mutex)(&cs42l84->irq_lock);
cs42l84->jack = jk;
snd_soc_jack_report(jk, cs42l84->hs_type, SND_JACK_HEADSET);
- mutex_unlock(&cs42l84->irq_lock);
return 0;
}
@@ -830,7 +830,7 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
u8 current_ring_state;
int i;
- mutex_lock(&cs42l84->irq_lock);
+ guard(mutex)(&cs42l84->irq_lock);
/* Read sticky registers to clear interrupt */
for (i = 0; i < ARRAY_SIZE(stickies); i++) {
regmap_read(cs42l84->regmap, irq_params_table[i].status_addr,
@@ -901,8 +901,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
break;
}
- mutex_unlock(&cs42l84->irq_lock);
-
return IRQ_HANDLED;
}
@@ -918,8 +916,6 @@ static irqreturn_t cs42l84_irq_thread(int irq, void *data)
}
}
- mutex_unlock(&cs42l84->irq_lock);
-
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index e7b06f962790..48d88dad4ceb 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -6,6 +6,7 @@
*
* Authors: Li Xu <li.xu@cirrus.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -818,26 +819,26 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
unsigned int required_clk;
u8 dsd_speed;
- mutex_lock(&cs43130->clk_mutex);
- if (!cs43130->clk_req) {
- /* no DAI is currently using clk */
- if (!(CS43130_MCLK_22M % params_rate(params)))
- required_clk = CS43130_MCLK_22M;
- else
- required_clk = CS43130_MCLK_24M;
+ scoped_guard(mutex, &cs43130->clk_mutex) {
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ if (!(CS43130_MCLK_22M % params_rate(params)))
+ required_clk = CS43130_MCLK_22M;
+ else
+ required_clk = CS43130_MCLK_24M;
+
+ cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ }
- cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
- if (cs43130->pll_bypass)
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
- else
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ cs43130->clk_req++;
+ if (cs43130->clk_req == 2)
+ cs43130_pcm_dsd_mix(true, cs43130->regmap);
}
- cs43130->clk_req++;
- if (cs43130->clk_req == 2)
- cs43130_pcm_dsd_mix(true, cs43130->regmap);
- mutex_unlock(&cs43130->clk_mutex);
-
switch (params_rate(params)) {
case 176400:
dsd_speed = 0;
@@ -881,26 +882,26 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
unsigned int required_clk;
u8 dsd_speed;
- mutex_lock(&cs43130->clk_mutex);
- if (!cs43130->clk_req) {
- /* no DAI is currently using clk */
- if (!(CS43130_MCLK_22M % params_rate(params)))
- required_clk = CS43130_MCLK_22M;
- else
- required_clk = CS43130_MCLK_24M;
+ scoped_guard(mutex, &cs43130->clk_mutex) {
+ if (!cs43130->clk_req) {
+ /* no DAI is currently using clk */
+ if (!(CS43130_MCLK_22M % params_rate(params)))
+ required_clk = CS43130_MCLK_22M;
+ else
+ required_clk = CS43130_MCLK_24M;
+
+ cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
+ if (cs43130->pll_bypass)
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
+ else
+ cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ }
- cs43130_set_pll(component, 0, 0, cs43130->mclk, required_clk);
- if (cs43130->pll_bypass)
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_EXT);
- else
- cs43130_change_clksrc(component, CS43130_MCLK_SRC_PLL);
+ cs43130->clk_req++;
+ if (cs43130->clk_req == 2)
+ cs43130_pcm_dsd_mix(true, cs43130->regmap);
}
- cs43130->clk_req++;
- if (cs43130->clk_req == 2)
- cs43130_pcm_dsd_mix(true, cs43130->regmap);
- mutex_unlock(&cs43130->clk_mutex);
-
switch (dai->id) {
case CS43130_ASP_DOP_DAI:
case CS43130_XSP_DOP_DAI:
@@ -988,14 +989,13 @@ static int cs43130_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_component *component = dai->component;
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
- mutex_lock(&cs43130->clk_mutex);
+ guard(mutex)(&cs43130->clk_mutex);
cs43130->clk_req--;
if (!cs43130->clk_req) {
/* no DAI is currently using clk */
cs43130_change_clksrc(component, CS43130_MCLK_SRC_RCO);
cs43130_pcm_dsd_mix(false, cs43130->regmap);
}
- mutex_unlock(&cs43130->clk_mutex);
return 0;
}
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index 6ac6d306b054..9a7f70175717 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -340,7 +340,13 @@ static int cs4349_runtime_resume(struct device *dev)
gpiod_set_value_cansleep(cs4349->reset_gpio, 1);
regcache_cache_only(cs4349->regmap, false);
- regcache_sync(cs4349->regmap);
+ ret = regcache_sync(cs4349->regmap);
+ if (ret) {
+ regcache_cache_only(cs4349->regmap, true);
+ regcache_mark_dirty(cs4349->regmap);
+ gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c
index da64e0a1db28..2f30dd834709 100644
--- a/sound/soc/codecs/cs47l15.c
+++ b/sound/soc/codecs/cs47l15.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -1285,9 +1286,8 @@ static int cs47l15_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -1317,9 +1317,8 @@ static void cs47l15_component_remove(struct snd_soc_component *component)
struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l15->core.madera;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
wm_adsp2_component_remove(&cs47l15->core.adsp[0], component);
}
diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c
index a8fe5a99a8bb..e77ac7bc8466 100644
--- a/sound/soc/codecs/cs47l35.c
+++ b/sound/soc/codecs/cs47l35.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
@@ -1566,9 +1567,8 @@ static int cs47l35_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -1600,9 +1600,8 @@ static void cs47l35_component_remove(struct snd_soc_component *component)
struct madera *madera = cs47l35->core.madera;
int i;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
for (i = 0; i < CS47L35_NUM_ADSP; i++)
wm_adsp2_component_remove(&cs47l35->core.adsp[i], component);
diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c
index 42fafb0b392c..9ee60616c04c 100644
--- a/sound/soc/codecs/cs47l85.c
+++ b/sound/soc/codecs/cs47l85.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -2504,9 +2505,8 @@ static int cs47l85_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -2537,9 +2537,8 @@ static void cs47l85_component_remove(struct snd_soc_component *component)
struct madera *madera = cs47l85->core.madera;
int i;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
for (i = 0; i < CS47L85_NUM_ADSP; i++)
wm_adsp2_component_remove(&cs47l85->core.adsp[i], component);
diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c
index 77e8aabb241a..6ce603bfd500 100644
--- a/sound/soc/codecs/cs47l90.c
+++ b/sound/soc/codecs/cs47l90.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -2423,9 +2424,8 @@ static int cs47l90_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -2456,9 +2456,8 @@ static void cs47l90_component_remove(struct snd_soc_component *component)
struct madera *madera = cs47l90->core.madera;
int i;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
for (i = 0; i < CS47L90_NUM_ADSP; i++)
wm_adsp2_component_remove(&cs47l90->core.adsp[i], component);
diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c
index 868237bd6d91..07bc303d9797 100644
--- a/sound/soc/codecs/cs47l92.c
+++ b/sound/soc/codecs/cs47l92.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
@@ -1892,9 +1893,8 @@ static int cs47l92_component_probe(struct snd_soc_component *component)
snd_soc_component_init_regmap(component, madera->regmap);
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = snd_soc_component_to_dapm(component);
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = snd_soc_component_to_dapm(component);
ret = madera_init_inputs(component);
if (ret)
@@ -1922,9 +1922,8 @@ static void cs47l92_component_remove(struct snd_soc_component *component)
struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component);
struct madera *madera = cs47l92->core.madera;
- mutex_lock(&madera->dapm_ptr_lock);
- madera->dapm = NULL;
- mutex_unlock(&madera->dapm_ptr_lock);
+ scoped_guard(mutex, &madera->dapm_ptr_lock)
+ madera->dapm = NULL;
wm_adsp2_component_remove(&cs47l92->core.adsp[0], component);
}
diff --git a/sound/soc/codecs/cs48l32.c b/sound/soc/codecs/cs48l32.c
index 086ed0f57a85..a9967771124e 100644
--- a/sound/soc/codecs/cs48l32.c
+++ b/sound/soc/codecs/cs48l32.c
@@ -8,6 +8,7 @@
#include <dt-bindings/sound/cs48l32.h>
#include <linux/array_size.h>
#include <linux/build_bug.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/container_of.h>
#include <linux/delay.h>
@@ -236,15 +237,13 @@ static int cs48l32_rate_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_v
int ret;
/* Prevent any mixer mux changes while we do this */
- mutex_lock(&cs48l32_codec->rate_lock);
+ guard(mutex)(&cs48l32_codec->rate_lock);
/* The write must be guarded by a number of SYSCLK cycles */
cs48l32_spin_sysclk(cs48l32_codec);
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
cs48l32_spin_sysclk(cs48l32_codec);
- mutex_unlock(&cs48l32_codec->rate_lock);
-
return ret;
}
@@ -2242,7 +2241,6 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai,
struct cs48l32_dai_priv *dai_priv = &cs48l32_codec->dai[dai->id - 1];
unsigned int base = dai->driver->base;
unsigned int current_asp_rate, target_asp_rate;
- bool change_rate_domain = false;
int ret;
if (clk_id == dai_priv->clk)
@@ -2284,19 +2282,15 @@ static int cs48l32_dai_set_sysclk(struct snd_soc_dai *dai,
if ((current_asp_rate & CS48L32_ASP_RATE_MASK) !=
(target_asp_rate & CS48L32_ASP_RATE_MASK)) {
- change_rate_domain = true;
-
- mutex_lock(&cs48l32_codec->rate_lock);
/* Guard the rate change with SYSCLK cycles */
- cs48l32_spin_sysclk(cs48l32_codec);
- }
-
- snd_soc_component_update_bits(component, base + CS48L32_ASP_CONTROL1,
- CS48L32_ASP_RATE_MASK, target_asp_rate);
-
- if (change_rate_domain) {
- cs48l32_spin_sysclk(cs48l32_codec);
- mutex_unlock(&cs48l32_codec->rate_lock);
+ scoped_guard(mutex, &cs48l32_codec->rate_lock) {
+ cs48l32_spin_sysclk(cs48l32_codec);
+ snd_soc_component_update_bits(component,
+ base + CS48L32_ASP_CONTROL1,
+ CS48L32_ASP_RATE_MASK,
+ target_asp_rate);
+ cs48l32_spin_sysclk(cs48l32_codec);
+ }
}
}
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 0dd35fa86cc5..d02ab74e549b 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -9,6 +9,7 @@
//
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -96,51 +97,60 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_GPIO_WAKE, 0x00000000 },
{ CX2072X_GPIO_UM_ENABLE, 0x00000000 },
{ CX2072X_GPIO_STICKY_MASK, 0x00000000 },
- { CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 },
- { CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a },
- { CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a },
{ CX2072X_DAC1_POWER_STATE, 0x00000433 },
{ CX2072X_DAC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
{ CX2072X_DAC1_EAPD_ENABLE, 0x00000000 },
- { CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 },
- { CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a },
- { CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a },
+ { CX2072X_DAC1_AMP_GAIN_RIGHT, 0x0000004a },
+ { CX2072X_DAC1_AMP_GAIN_LEFT, 0x0000004a },
+ { CX2072X_DAC1_CONVERTER_FORMAT, 0x00000031 },
{ CX2072X_DAC2_POWER_STATE, 0x00000433 },
{ CX2072X_DAC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
- { CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_DAC2_AMP_GAIN_RIGHT, 0x0000004a },
+ { CX2072X_DAC2_AMP_GAIN_LEFT, 0x0000004a },
+ { CX2072X_DAC2_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 },
+ { CX2072X_ADC1_POWER_STATE, 0x00000433 },
+ { CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_0, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_1, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_2, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_3, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_4, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_5, 0x0000004a },
- { CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_RIGHT_6, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_0, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_1, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_2, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_3, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_4, 0x0000004a },
+ { CX2072X_ADC1_AMP_GAIN_LEFT_5, 0x0000004a },
{ CX2072X_ADC1_AMP_GAIN_LEFT_6, 0x0000004a },
- { CX2072X_ADC1_CONNECTION_SELECT_CONTROL, 0x00000000 },
- { CX2072X_ADC1_POWER_STATE, 0x00000433 },
- { CX2072X_ADC1_CONVERTER_STREAM_CHANNEL, 0x00000000 },
- { CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_ADC1_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 },
+ { CX2072X_ADC2_POWER_STATE, 0x00000433 },
+ { CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
{ CX2072X_ADC2_AMP_GAIN_RIGHT_0, 0x0000004a },
- { CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a },
{ CX2072X_ADC2_AMP_GAIN_RIGHT_1, 0x0000004a },
- { CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_ADC2_AMP_GAIN_RIGHT_2, 0x0000004a },
+ { CX2072X_ADC2_AMP_GAIN_LEFT_0, 0x0000004a },
+ { CX2072X_ADC2_AMP_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_ADC2_AMP_GAIN_LEFT_2, 0x0000004a },
- { CX2072X_ADC2_CONNECTION_SELECT_CONTROL, 0x00000000 },
- { CX2072X_ADC2_POWER_STATE, 0x00000433 },
- { CX2072X_ADC2_CONVERTER_STREAM_CHANNEL, 0x00000000 },
+ { CX2072X_ADC2_CONVERTER_FORMAT, 0x00000031 },
+ { CX2072X_MIXER_POWER_STATE, 0x00000433 },
+ { CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a },
+ { CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a },
+ { CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a },
+ { CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a },
{ CX2072X_PORTA_CONNECTION_SELECT_CTRL, 0x00000000 },
{ CX2072X_PORTA_POWER_STATE, 0x00000433 },
{ CX2072X_PORTA_PIN_CTRL, 0x000000c0 },
{ CX2072X_PORTA_UNSOLICITED_RESPONSE, 0x00000000 },
{ CX2072X_PORTA_PIN_SENSE, 0x00000000 },
{ CX2072X_PORTA_EAPD_BTL, 0x00000002 },
+ { CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 },
+ { CX2072X_PORTG_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTG_PIN_CTRL, 0x00000040 },
+ { CX2072X_PORTG_EAPD_BTL, 0x00000002 },
{ CX2072X_PORTB_POWER_STATE, 0x00000433 },
{ CX2072X_PORTB_PIN_CTRL, 0x00000000 },
{ CX2072X_PORTB_UNSOLICITED_RESPONSE, 0x00000000 },
@@ -148,43 +158,16 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_PORTB_EAPD_BTL, 0x00000002 },
{ CX2072X_PORTB_GAIN_RIGHT, 0x00000000 },
{ CX2072X_PORTB_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTC_POWER_STATE, 0x00000433 },
- { CX2072X_PORTC_PIN_CTRL, 0x00000000 },
- { CX2072X_PORTC_GAIN_RIGHT, 0x00000000 },
- { CX2072X_PORTC_GAIN_LEFT, 0x00000000 },
{ CX2072X_PORTD_POWER_STATE, 0x00000433 },
{ CX2072X_PORTD_PIN_CTRL, 0x00000020 },
{ CX2072X_PORTD_UNSOLICITED_RESPONSE, 0x00000000 },
{ CX2072X_PORTD_PIN_SENSE, 0x00000000 },
{ CX2072X_PORTD_GAIN_RIGHT, 0x00000000 },
{ CX2072X_PORTD_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 },
- { CX2072X_PORTE_POWER_STATE, 0x00000433 },
- { CX2072X_PORTE_PIN_CTRL, 0x00000040 },
- { CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 },
- { CX2072X_PORTE_PIN_SENSE, 0x00000000 },
- { CX2072X_PORTE_EAPD_BTL, 0x00000002 },
- { CX2072X_PORTE_GAIN_RIGHT, 0x00000000 },
- { CX2072X_PORTE_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTF_POWER_STATE, 0x00000433 },
- { CX2072X_PORTF_PIN_CTRL, 0x00000000 },
- { CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 },
- { CX2072X_PORTF_PIN_SENSE, 0x00000000 },
- { CX2072X_PORTF_GAIN_RIGHT, 0x00000000 },
- { CX2072X_PORTF_GAIN_LEFT, 0x00000000 },
- { CX2072X_PORTG_POWER_STATE, 0x00000433 },
- { CX2072X_PORTG_PIN_CTRL, 0x00000040 },
- { CX2072X_PORTG_CONNECTION_SELECT_CTRL, 0x00000000 },
- { CX2072X_PORTG_EAPD_BTL, 0x00000002 },
- { CX2072X_PORTM_POWER_STATE, 0x00000433 },
- { CX2072X_PORTM_PIN_CTRL, 0x00000000 },
- { CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 },
- { CX2072X_PORTM_EAPD_BTL, 0x00000002 },
- { CX2072X_MIXER_POWER_STATE, 0x00000433 },
- { CX2072X_MIXER_GAIN_RIGHT_0, 0x0000004a },
- { CX2072X_MIXER_GAIN_LEFT_0, 0x0000004a },
- { CX2072X_MIXER_GAIN_RIGHT_1, 0x0000004a },
- { CX2072X_MIXER_GAIN_LEFT_1, 0x0000004a },
+ { CX2072X_PORTC_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTC_PIN_CTRL, 0x00000000 },
+ { CX2072X_PORTC_GAIN_RIGHT, 0x00000000 },
+ { CX2072X_PORTC_GAIN_LEFT, 0x00000000 },
{ CX2072X_SPKR_DRC_ENABLE_STEP, 0x040065a4 },
{ CX2072X_SPKR_DRC_CONTROL, 0x007b0024 },
{ CX2072X_SPKR_DRC_TEST, 0x00000000 },
@@ -195,12 +178,15 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_I2SPCM_CONTROL3, 0x00000000 },
{ CX2072X_I2SPCM_CONTROL4, 0x00000000 },
{ CX2072X_I2SPCM_CONTROL5, 0x00000000 },
- { CX2072X_I2SPCM_CONTROL6, 0x00000000 },
{ CX2072X_UM_INTERRUPT_CRTL_E, 0x00000000 },
+ { CX2072X_I2SPCM_CONTROL6, 0x00000000 },
+ { CX2072X_DIGITAL_TEST16, 0x00000021 },
+ { CX2072X_DIGITAL_TEST17, 0x00000018 },
+ { CX2072X_DIGITAL_TEST18, 0x00000024 },
+ { CX2072X_DIGITAL_TEST19, 0x00000001 },
+ { CX2072X_DIGITAL_TEST20, 0x00000002 },
{ CX2072X_CODEC_TEST2, 0x00000000 },
{ CX2072X_CODEC_TEST9, 0x00000004 },
- { CX2072X_CODEC_TEST20, 0x00000600 },
- { CX2072X_CODEC_TEST26, 0x00000208 },
{ CX2072X_ANALOG_TEST4, 0x00000000 },
{ CX2072X_ANALOG_TEST5, 0x00000000 },
{ CX2072X_ANALOG_TEST6, 0x0000059a },
@@ -215,11 +201,26 @@ static const struct reg_default cx2072x_reg_defaults[] = {
{ CX2072X_DIGITAL_TEST11, 0x00000000 },
{ CX2072X_DIGITAL_TEST12, 0x00000084 },
{ CX2072X_DIGITAL_TEST15, 0x00000077 },
- { CX2072X_DIGITAL_TEST16, 0x00000021 },
- { CX2072X_DIGITAL_TEST17, 0x00000018 },
- { CX2072X_DIGITAL_TEST18, 0x00000024 },
- { CX2072X_DIGITAL_TEST19, 0x00000001 },
- { CX2072X_DIGITAL_TEST20, 0x00000002 },
+ { CX2072X_CODEC_TEST20, 0x00000600 },
+ { CX2072X_CODEC_TEST26, 0x00000208 },
+ { CX2072X_PORTE_CONNECTION_SELECT_CTRL, 0x00000000 },
+ { CX2072X_PORTE_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTE_PIN_CTRL, 0x00000040 },
+ { CX2072X_PORTE_UNSOLICITED_RESPONSE, 0x00000000 },
+ { CX2072X_PORTE_PIN_SENSE, 0x00000000 },
+ { CX2072X_PORTE_EAPD_BTL, 0x00000002 },
+ { CX2072X_PORTE_GAIN_RIGHT, 0x00000000 },
+ { CX2072X_PORTE_GAIN_LEFT, 0x00000000 },
+ { CX2072X_PORTF_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTF_PIN_CTRL, 0x00000000 },
+ { CX2072X_PORTF_UNSOLICITED_RESPONSE, 0x00000000 },
+ { CX2072X_PORTF_PIN_SENSE, 0x00000000 },
+ { CX2072X_PORTF_GAIN_RIGHT, 0x00000000 },
+ { CX2072X_PORTF_GAIN_LEFT, 0x00000000 },
+ { CX2072X_PORTM_CONNECTION_SELECT_CTRL, 0x00000000 },
+ { CX2072X_PORTM_POWER_STATE, 0x00000433 },
+ { CX2072X_PORTM_PIN_CTRL, 0x00000000 },
+ { CX2072X_PORTM_EAPD_BTL, 0x00000002 },
};
/*
@@ -1408,7 +1409,7 @@ static int cx2072x_jack_status_check(void *data)
unsigned int type = 0;
int state = 0;
- mutex_lock(&cx2072x->lock);
+ guard(mutex)(&cx2072x->lock);
regmap_read(cx2072x->regmap, CX2072X_PORTA_PIN_SENSE, &jack);
jack = jack >> 24;
@@ -1434,8 +1435,6 @@ static int cx2072x_jack_status_check(void *data)
/* clear interrupt */
regmap_write(cx2072x->regmap, CX2072X_UM_INTERRUPT_CRTL_E, 0x12 << 24);
- mutex_unlock(&cx2072x->lock);
-
dev_dbg(codec->dev, "CX2072X_HSDETECT type=0x%X,Jack state = %x\n",
type, state);
return state;
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index 4bf91ab2553a..923b997efbc4 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -11,6 +11,7 @@
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/property.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -216,13 +217,10 @@ static int da7213_volsw_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_get_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_get_volsw(kcontrol, ucontrol);
}
static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol,
@@ -230,13 +228,10 @@ static int da7213_volsw_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_put_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_put_volsw(kcontrol, ucontrol);
}
static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol,
@@ -244,13 +239,10 @@ static int da7213_enum_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_get_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_get_enum_double(kcontrol, ucontrol);
}
static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol,
@@ -258,13 +250,10 @@ static int da7213_enum_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = snd_soc_put_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
- return ret;
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
}
/* ALC */
@@ -465,9 +454,8 @@ static int da7213_tonegen_freq_get(struct snd_kcontrol *kcontrol,
__le16 val;
int ret;
- mutex_lock(&da7213->ctrl_lock);
- ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val));
- mutex_unlock(&da7213->ctrl_lock);
+ scoped_guard(mutex, &da7213->ctrl_lock)
+ ret = regmap_raw_read(da7213->regmap, reg, &val, sizeof(val));
if (ret)
return ret;
@@ -499,12 +487,11 @@ static int da7213_tonegen_freq_put(struct snd_kcontrol *kcontrol,
*/
val_new = cpu_to_le16(ucontrol->value.integer.value[0]);
- mutex_lock(&da7213->ctrl_lock);
+ guard(mutex)(&da7213->ctrl_lock);
ret = regmap_raw_read(da7213->regmap, reg, &val_old, sizeof(val_old));
if (ret == 0 && (val_old != val_new))
ret = regmap_raw_write(da7213->regmap, reg,
&val_new, sizeof(val_new));
- mutex_unlock(&da7213->ctrl_lock);
if (ret < 0)
return ret;
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index f0874d891e12..f6d371e93549 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -8,6 +8,7 @@
*/
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
@@ -256,13 +257,10 @@ static int da7219_volsw_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_get_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_get_volsw(kcontrol, ucontrol);
}
static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
@@ -270,13 +268,10 @@ static int da7219_volsw_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_put_volsw(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_put_volsw(kcontrol, ucontrol);
}
static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
@@ -284,13 +279,10 @@ static int da7219_enum_locked_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_get_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_get_enum_double(kcontrol, ucontrol);
}
static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
@@ -298,13 +290,10 @@ static int da7219_enum_locked_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = snd_soc_put_enum_double(kcontrol, ucontrol);
- mutex_unlock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
- return ret;
+ return snd_soc_put_enum_double(kcontrol, ucontrol);
}
/* ALC */
@@ -422,9 +411,8 @@ static int da7219_tonegen_freq_get(struct snd_kcontrol *kcontrol,
__le16 val;
int ret;
- mutex_lock(&da7219->ctrl_lock);
- ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
- mutex_unlock(&da7219->ctrl_lock);
+ scoped_guard(mutex, &da7219->ctrl_lock)
+ ret = regmap_raw_read(da7219->regmap, reg, &val, sizeof(val));
if (ret)
return ret;
@@ -456,12 +444,11 @@ static int da7219_tonegen_freq_put(struct snd_kcontrol *kcontrol,
*/
val_new = cpu_to_le16(ucontrol->value.integer.value[0]);
- mutex_lock(&da7219->ctrl_lock);
+ guard(mutex)(&da7219->ctrl_lock);
ret = regmap_raw_read(da7219->regmap, reg, &val_old, sizeof(val_old));
if (ret == 0 && (val_old != val_new))
ret = regmap_raw_write(da7219->regmap, reg,
- &val_new, sizeof(val_new));
- mutex_unlock(&da7219->ctrl_lock);
+ &val_new, sizeof(val_new));
if (ret < 0)
return ret;
@@ -1167,15 +1154,12 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&da7219->pll_lock);
+ guard(mutex)(&da7219->pll_lock);
- if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) {
- mutex_unlock(&da7219->pll_lock);
+ if (da7219->clk_src == clk_id && da7219->mclk_rate == freq)
return 0;
- }
- if ((freq < 2000000) || (freq > 54000000)) {
- mutex_unlock(&da7219->pll_lock);
+ if (freq < 2000000 || freq > 54000000) {
dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
freq);
return -EINVAL;
@@ -1193,7 +1177,6 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
break;
default:
dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
- mutex_unlock(&da7219->pll_lock);
return -EINVAL;
}
@@ -1203,17 +1186,13 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai,
freq = clk_round_rate(da7219->mclk, freq);
ret = clk_set_rate(da7219->mclk, freq);
if (ret) {
- dev_err(codec_dai->dev, "Failed to set clock rate %d\n",
- freq);
- mutex_unlock(&da7219->pll_lock);
+ dev_err(codec_dai->dev, "Failed to set clock rate %d\n", freq);
return ret;
}
}
da7219->mclk_rate = freq;
- mutex_unlock(&da7219->pll_lock);
-
return 0;
}
@@ -1296,13 +1275,10 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
{
struct snd_soc_component *component = codec_dai->component;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&da7219->pll_lock);
- ret = da7219_set_pll(component, source, fout);
- mutex_unlock(&da7219->pll_lock);
+ guard(mutex)(&da7219->pll_lock);
- return ret;
+ return da7219_set_pll(component, source, fout);
}
static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index 3abe77423f29..24ec8b211cdb 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -9,11 +9,13 @@
#include <linux/module.h>
#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -30,6 +32,13 @@ static const unsigned int supported_mclk_lrck_ratios[] = {
256, 384, 400, 500, 512, 768, 1024
};
+static const char * const es8316_supply_names[] = {
+ "avdd",
+ "cpvdd",
+ "dvdd",
+ "pvdd",
+};
+
struct es8316_priv {
struct mutex lock;
struct clk *mclk;
@@ -620,15 +629,15 @@ static irqreturn_t es8316_irq(int irq, void *data)
struct snd_soc_component *comp = es8316->component;
unsigned int flags;
- mutex_lock(&es8316->lock);
+ guard(mutex)(&es8316->lock);
regmap_read(es8316->regmap, ES8316_GPIO_FLAG, &flags);
if (flags == 0x00)
- goto out; /* Powered-down / reset */
+ return IRQ_HANDLED; /* Powered-down / reset */
/* Catch spurious IRQ before set_jack is called */
if (!es8316->jack)
- goto out;
+ return IRQ_HANDLED;
if (es8316->jd_inverted)
flags ^= ES8316_GPIO_FLAG_HP_NOT_INSERTED;
@@ -681,8 +690,6 @@ static irqreturn_t es8316_irq(int irq, void *data)
}
}
-out:
- mutex_unlock(&es8316->lock);
return IRQ_HANDLED;
}
@@ -699,18 +706,16 @@ static void es8316_enable_jack_detect(struct snd_soc_component *component,
es8316->jd_inverted = device_property_read_bool(component->dev,
"everest,jack-detect-inverted");
- mutex_lock(&es8316->lock);
-
- es8316->jack = jack;
+ scoped_guard(mutex, &es8316->lock) {
+ es8316->jack = jack;
- if (es8316->jack->status & SND_JACK_MICROPHONE)
- es8316_enable_micbias_for_mic_gnd_short_detect(component);
-
- snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
- ES8316_GPIO_ENABLE_INTERRUPT,
- ES8316_GPIO_ENABLE_INTERRUPT);
+ if (es8316->jack->status & SND_JACK_MICROPHONE)
+ es8316_enable_micbias_for_mic_gnd_short_detect(component);
- mutex_unlock(&es8316->lock);
+ snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
+ ES8316_GPIO_ENABLE_INTERRUPT,
+ ES8316_GPIO_ENABLE_INTERRUPT);
+ }
/* Enable irq and sync initial jack state */
enable_irq(es8316->irq);
@@ -726,7 +731,7 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
disable_irq(es8316->irq);
- mutex_lock(&es8316->lock);
+ guard(mutex)(&es8316->lock);
snd_soc_component_update_bits(component, ES8316_GPIO_DEBOUNCE,
ES8316_GPIO_ENABLE_INTERRUPT, 0);
@@ -737,8 +742,6 @@ static void es8316_disable_jack_detect(struct snd_soc_component *component)
}
es8316->jack = NULL;
-
- mutex_unlock(&es8316->lock);
}
static int es8316_set_jack(struct snd_soc_component *component,
@@ -871,6 +874,11 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client)
i2c_set_clientdata(i2c_client, es8316);
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(es8316_supply_names),
+ es8316_supply_names);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to enable supplies\n");
+
es8316->regmap = devm_regmap_init_i2c(i2c_client, &es8316_regmap);
if (IS_ERR(es8316->regmap))
return PTR_ERR(es8316->regmap);
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index a79b2da35099..c5460589a88b 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -6,6 +6,7 @@
// Authors: David Yang <yangxiaohua@everest-semi.com>
//
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
@@ -790,7 +791,7 @@ static void es8326_jack_button_handler(struct work_struct *work)
if (!(es8326->jack->status & SND_JACK_HEADSET)) /* Jack unplugged */
return;
- mutex_lock(&es8326->lock);
+ guard(mutex)(&es8326->lock);
iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
switch (iface) {
case 0x93:
@@ -845,7 +846,6 @@ static void es8326_jack_button_handler(struct work_struct *work)
}
es8326_disable_micbias(es8326->component);
}
- mutex_unlock(&es8326->lock);
}
static void es8326_jack_detect_handler(struct work_struct *work)
@@ -855,7 +855,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
struct snd_soc_component *comp = es8326->component;
unsigned int iface;
- mutex_lock(&es8326->lock);
+ guard(mutex)(&es8326->lock);
iface = snd_soc_component_read(comp, ES8326_HPDET_STA);
dev_dbg(comp->dev, "gpio flag %#04x", iface);
@@ -873,7 +873,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
regmap_update_bits(es8326->regmap, ES8326_HPDET_TYPE,
ES8326_HP_DET_JACK_POL, (es8326->jd_inverted ?
~es8326->jack_pol : es8326->jack_pol));
- goto exit;
+ return;
}
if ((iface & ES8326_HPINSERT_FLAG) == 0) {
@@ -930,7 +930,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
queue_delayed_work(system_dfl_wq, &es8326->jack_detect_work,
msecs_to_jiffies(400));
es8326->hp = 1;
- goto exit;
+ return;
}
if (es8326->jack->status & SND_JACK_HEADSET) {
/* detect button */
@@ -939,7 +939,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
(ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
es8326_enable_micbias(es8326->component);
queue_delayed_work(system_dfl_wq, &es8326->button_press_work, 10);
- goto exit;
+ return;
}
if ((iface & ES8326_HPBUTTON_FLAG) == 0x01) {
dev_dbg(comp->dev, "Headphone detected\n");
@@ -958,8 +958,6 @@ static void es8326_jack_detect_handler(struct work_struct *work)
usleep_range(10000, 15000);
}
}
-exit:
- mutex_unlock(&es8326->lock);
}
static irqreturn_t es8326_irq(int irq, void *dev_id)
@@ -1200,13 +1198,12 @@ static void es8326_enable_jack_detect(struct snd_soc_component *component,
{
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
- mutex_lock(&es8326->lock);
- if (es8326->jd_inverted)
- snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
- ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
- es8326->jack = jack;
-
- mutex_unlock(&es8326->lock);
+ scoped_guard(mutex, &es8326->lock) {
+ if (es8326->jd_inverted)
+ snd_soc_component_update_bits(component, ES8326_HPDET_TYPE,
+ ES8326_HP_DET_JACK_POL, ~es8326->jack_pol);
+ es8326->jack = jack;
+ }
es8326_irq(es8326->irq, es8326);
}
@@ -1219,13 +1216,12 @@ static void es8326_disable_jack_detect(struct snd_soc_component *component)
return; /* Already disabled (or never enabled) */
cancel_delayed_work_sync(&es8326->jack_detect_work);
- mutex_lock(&es8326->lock);
+ guard(mutex)(&es8326->lock);
if (es8326->jack->status & SND_JACK_MICROPHONE) {
es8326_disable_micbias(component);
snd_soc_jack_report(es8326->jack, 0, SND_JACK_HEADSET);
}
es8326->jack = NULL;
- mutex_unlock(&es8326->lock);
}
static int es8326_set_jack(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 9838fe42cb6f..aaa6646ad4c5 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -405,6 +405,11 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
{ "Mic Bias", NULL, "Mic Bias Gen" },
+ { "LINPUT1", NULL, "Mic Bias" },
+ { "RINPUT1", NULL, "Mic Bias" },
+ { "LINPUT2", NULL, "Mic Bias" },
+ { "RINPUT2", NULL, "Mic Bias" },
+
{ "Left Mixer", NULL, "Left DAC" },
{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
{ "Left Mixer", "Right Playback Switch", "Right DAC" },
diff --git a/sound/soc/codecs/es8389.c b/sound/soc/codecs/es8389.c
index 3484c87853cb..80efce3e0a22 100644
--- a/sound/soc/codecs/es8389.c
+++ b/sound/soc/codecs/es8389.c
@@ -36,6 +36,10 @@ struct es8389_private {
unsigned int sysclk;
int mastermode;
+ u8 hpfl;
+ u8 hpfr;
+ u32 hpf_freq;
+ u32 capture_rate;
u8 mclk_src;
u8 vddd;
int version;
@@ -50,10 +54,29 @@ static const char * const es8389_core_supplies[] = {
static bool es8389_volatile_register(struct device *dev,
unsigned int reg)
{
- if ((reg <= 0xff))
- return true;
- else
+ switch (reg) {
+ case ES8389_ADCL_VOL:
+ case ES8389_ADCR_VOL:
+ case ES8389_MIC1_GAIN:
+ case ES8389_MIC2_GAIN:
+ case ES8389_DACL_VOL:
+ case ES8389_DACR_VOL:
+ case ES8389_ALC_ON:
+ case ES8389_ALC_CTL:
+ case ES8389_ALC_TARGET:
+ case ES8389_ALC_GAIN:
+ case ES8389_ADC_MUTE:
+ case ES8389_OSR_VOL:
+ case ES8389_DAC_INV:
+ case ES8389_MIX_VOL:
+ case ES8389_DAC_MIX:
+ case ES8389_ADC_RESET:
+ case ES8389_ADC_MODE:
+ case ES8389_DMIC_EN:
return false;
+ default:
+ return true;
+ }
}
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 0);
@@ -63,6 +86,92 @@ static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -9500, 100, 0);
static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -3200, 200, 0);
static const DECLARE_TLV_DB_SCALE(alc_max_level, -3200, 200, 0);
+static const u32 hpf_table[10][10] = {
+ {1020, 754, 624, 559, 527, 511, 502, 498, 497, 496},
+ {754, 495, 368, 306, 274, 259, 251, 247, 246, 244},
+ {624, 368, 243, 182, 151, 136, 128, 124, 123, 121},
+ {559, 306, 182, 120, 90, 75, 68, 63, 62, 60},
+ {527, 274, 151, 90, 60, 45, 38, 33, 32, 31},
+ {511, 259, 136, 75, 45, 30, 23, 19, 18, 17},
+ {502, 251, 128, 68, 38, 23, 16, 13, 11, 11},
+ {498, 247, 124, 63, 33, 19, 13, 10, 8, 8},
+ {497, 246, 123, 62, 32, 18, 11, 8, 8, 0},
+ {496, 244, 121, 60, 31, 17, 11, 8, 0, 0}
+};
+
+static bool find_best_hpf_freq(u32 target_hz, u8 *hpf1, u8 *hpf2, u32 *out)
+{
+ int best_row = -1, best_col = -1;
+ u32 min_diff = U32_MAX;
+ u32 f, diff;
+ int i, j;
+
+ if (target_hz > 1020)
+ return false;
+
+ for (i = 0; i < 10; i++) {
+ for (j = i; j < 10; j++) {
+ f = hpf_table[i][j];
+
+ diff = (target_hz > f) ? (target_hz - f) : (f - target_hz);
+ if (diff < min_diff) {
+ min_diff = diff;
+ best_row = i;
+ best_col = j;
+ *out = f;
+ }
+ }
+ }
+
+ *hpf1 = best_col + ES8389_HPF_OFFSET;
+ *hpf2 = best_row + ES8389_HPF_OFFSET;
+
+ return true;
+}
+
+static int es8389_hpf_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = es8389->hpf_freq;
+ return 0;
+}
+
+static int es8389_hpf_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+ u32 freq;
+ bool hpf;
+
+ if (es8389->hpf_freq == ucontrol->value.integer.value[0])
+ return 0;
+
+ if (es8389->capture_rate) {
+ freq = (ucontrol->value.integer.value[0] * 48000) / es8389->capture_rate;
+
+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq);
+ if (!hpf)
+ return -EBUSY;
+
+ if (es8389->hpf_freq != ucontrol->value.integer.value[0])
+ dev_dbg(component->dev, "At the %u Hz sampling rate, %ld Hz could not be obtained."
+ "the frequency has been set to the closest value, %u Hz\n",
+ es8389->capture_rate, ucontrol->value.integer.value[0], es8389->hpf_freq);
+
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr);
+ } else {
+ es8389->hpf_freq = ucontrol->value.integer.value[0];
+ dev_dbg(component->dev, "PCM_STREAM_CAPTURE is not active.retain the input frequency\n");
+ }
+
+ return 1;
+}
+
static int es8389_dmic_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -143,6 +252,16 @@ static const struct soc_enum alc_ramprate =
static const struct soc_enum alc_winsize =
SOC_ENUM_SINGLE(ES8389_ALC_CTL, 0, 16, winsize);
+static const char *const es8389_adcl_mux_txt[] = {
+ "Normal",
+ "ADC2 channel to ADC1 channel",
+};
+
+static const char *const es8389_adcr_mux_txt[] = {
+ "Normal",
+ "ADC1 channel to ADC2 channel",
+};
+
static const char *const es8389_outl_mux_txt[] = {
"Normal",
"DAC2 channel to DAC1 channel",
@@ -170,6 +289,20 @@ static const unsigned int es8389_pga_values[] = {
1, 5, 6
};
+static const struct soc_enum es8389_adcl_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 5,
+ ARRAY_SIZE(es8389_adcl_mux_txt), es8389_adcl_mux_txt);
+
+static const struct snd_kcontrol_new es8389_adcl_mux_controls =
+ SOC_DAPM_ENUM("INPUTL MUX", es8389_adcl_mux_enum);
+
+static const struct soc_enum es8389_adcr_mux_enum =
+ SOC_ENUM_SINGLE(ES8389_ADC_MODE, 4,
+ ARRAY_SIZE(es8389_adcr_mux_txt), es8389_adcr_mux_txt);
+
+static const struct snd_kcontrol_new es8389_adcr_mux_controls =
+ SOC_DAPM_ENUM("INPUTR MUX", es8389_adcr_mux_enum);
+
static const struct soc_enum es8389_outl_mux_enum =
SOC_ENUM_SINGLE(ES8389_DAC_MIX, 5,
ARRAY_SIZE(es8389_outl_mux_txt), es8389_outl_mux_txt);
@@ -240,6 +373,8 @@ static const struct snd_kcontrol_new es8389_snd_controls[] = {
SOC_DOUBLE("ADC OSR Volume ON Switch", ES8389_ADC_MUTE, 6, 7, 1, 0),
SOC_SINGLE_TLV("ADC OSR Volume", ES8389_OSR_VOL, 0, 0xFF, 0, adc_vol_tlv),
SOC_DOUBLE("ADC OUTPUT Invert Switch", ES8389_ADC_HPF2, 5, 6, 1, 0),
+ SOC_SINGLE_EXT("ADC HPF Freq Select", SND_SOC_NOPM, 0, 1020, 0,
+ es8389_hpf_get, es8389_hpf_set),
SOC_SINGLE_TLV("DACL Playback Volume", ES8389_DACL_VOL, 0, 0xFF, 0, dac_vol_tlv),
SOC_SINGLE_TLV("DACR Playback Volume", ES8389_DACR_VOL, 0, 0xFF, 0, dac_vol_tlv),
@@ -298,6 +433,8 @@ static const struct snd_soc_dapm_widget es8389_dapm_widgets[] = {
&es8389_adc_mixer_controls[0],
ARRAY_SIZE(es8389_adc_mixer_controls)),
SND_SOC_DAPM_MUX("ADC MUX", SND_SOC_NOPM, 0, 0, &es8389_dmic_mux_controls),
+ SND_SOC_DAPM_MUX("INPUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_adcl_mux_controls),
+ SND_SOC_DAPM_MUX("INPUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_adcr_mux_controls),
SND_SOC_DAPM_MUX("OUTL MUX", SND_SOC_NOPM, 0, 0, &es8389_outl_mux_controls),
SND_SOC_DAPM_MUX("OUTR MUX", SND_SOC_NOPM, 0, 0, &es8389_outr_mux_controls),
@@ -311,10 +448,15 @@ static const struct snd_soc_dapm_route es8389_dapm_routes[] = {
{"ADCL", NULL, "PGAL"},
{"ADCR", NULL, "PGAR"},
+ {"INPUTL MUX", "Normal", "ADCL"},
+ {"INPUTL MUX", "ADC2 channel to ADC1 channel", "ADCR"},
+ {"INPUTR MUX", "Normal", "ADCR"},
+ {"INPUTR MUX", "ADC1 channel to ADC2 channel", "ADCL"},
+
{"ADC Mixer", "DACL ADCL Mixer", "DACL"},
{"ADC Mixer", "DACR ADCR Mixer", "DACR"},
- {"ADC Mixer", NULL, "ADCL"},
- {"ADC Mixer", NULL, "ADCR"},
+ {"ADC Mixer", NULL, "INPUTL MUX"},
+ {"ADC Mixer", NULL, "INPUTR MUX"},
{"ADC MUX", "AMIC", "ADC Mixer"},
{"ADC MUX", "DMIC", "DMIC"},
@@ -415,52 +557,54 @@ static const struct _coeff_div coeff_div[] = {
{36, 576000, 16000, 0x00, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{48, 768000, 16000, 0x02, 0x57, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{50, 800000, 16000, 0x00, 0x7E, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {64, 1024000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {72, 1152000, 16000, 0x00, 0x45, 0x24, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{96, 1536000, 16000, 0x02, 0x55, 0x84, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{128, 2048000, 16000, 0x00, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{144, 2304000, 16000, 0x00, 0x51, 0x00, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x23, 0x8F, 0xBF, 0xC0, 0x1F, 0x8F, 0x01, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {150, 2400000, 16000, 0x02, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{192, 3072000, 16000, 0x02, 0x65, 0x25, 0xE0, 0x00, 0xE1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {256, 4096000, 16000, 0x00, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{300, 4800000, 16000, 0x02, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{384, 6144000, 16000, 0x02, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {512, 8192000, 16000, 0x01, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{750, 12000000, 16000, 0x0E, 0x7E, 0x01, 0xC9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {768, 12288000, 16000, 0x02, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {1024, 16384000, 16000, 0x03, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1152, 18432000, 16000, 0x08, 0x51, 0x04, 0xD0, 0x01, 0xC1, 0x90, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1200, 19200000, 16000, 0x0B, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1500, 24000000, 16000, 0x0E, 0x26, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
- {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xD1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
+ {1536, 24576000, 16000, 0x05, 0x41, 0x04, 0xC0, 0x01, 0xC1, 0x90, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0xFF, 0x7F, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{1625, 26000000, 16000, 0x40, 0x6E, 0x05, 0xC8, 0x01, 0xC2, 0x90, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x12, 0x31, 0x0E, 2, 2},
{800, 19200000, 24000, 0x07, 0x66, 0x01, 0xD9, 0x00, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0xC7, 0x95, 0x00, 0x12, 0x00, 0x1A, 0x49, 0x14, 2, 2},
{375, 12000000, 32000, 0x0E, 0x2E, 0x05, 0xC8, 0x00, 0xC2, 0x80, 0x40, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 0},
- {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2},
- {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {600, 19200000, 32000, 0x05, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x23, 0x61, 0x1B, 2, 2},
+ {32, 1411200, 44100, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{64, 2822400, 44100, 0x00, 0x51, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {128, 5644800, 44100, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {256, 11289600, 44100, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {512, 22579200, 44100, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {32, 1536000, 48000, 0x00, 0x45, 0xA4, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{48, 2304000, 48000, 0x02, 0x55, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{50, 2400000, 48000, 0x00, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{64, 3072000, 48000, 0x00, 0x51, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {100, 4800000, 48000, 0x00, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{125, 6000000, 48000, 0x04, 0x6E, 0x05, 0xC8, 0x10, 0xC2, 0x80, 0x00, 0x01, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {128, 6144000, 48000, 0x00, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {200, 9600000, 48000, 0x01, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x00, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{250, 12000000, 48000, 0x04, 0x76, 0x01, 0xC8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xD2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
- {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xD1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {256, 12288000, 48000, 0x01, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {384, 18432000, 48000, 0x02, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {400, 19200000, 48000, 0x03, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0x40, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {500, 24000000, 48000, 0x04, 0x46, 0x01, 0xD8, 0x10, 0xC2, 0x80, 0xC0, 0x00, 0x18, 0x95, 0xD0, 0xC0, 0x63, 0x95, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
+ {512, 24576000, 48000, 0x03, 0x41, 0x04, 0xD0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{800, 38400000, 48000, 0x18, 0x45, 0x04, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x1F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x12, 0x00, 0x35, 0x91, 0x28, 2, 2},
{128, 11289600, 88200, 0x00, 0x50, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0x40, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x32, 0x89, 0x25, 2, 2},
- {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xD1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
+ {64, 6144000, 96000, 0x00, 0x41, 0x00, 0xD0, 0x10, 0xC1, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{96, 9216000, 96000, 0x02, 0x43, 0x00, 0xC0, 0x10, 0xC0, 0x80, 0x00, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{256, 24576000, 96000, 0x00, 0x40, 0x00, 0xC0, 0x10, 0xC1, 0x80, 0xC0, 0x00, 0x9F, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x35, 0x91, 0x28, 2, 2},
{128, 24576000, 192000, 0x00, 0x50, 0x00, 0xC0, 0x18, 0xC1, 0x81, 0xC0, 0x00, 0x8F, 0x7F, 0xBF, 0xC0, 0x3F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 2, 2},
+ {64, 12288000, 192000, 0x00, 0x41, 0x00, 0xC0, 0x18, 0xC1, 0x80, 0x00, 0x00, 0x8F, 0x7F, 0xEF, 0xC0, 0x7F, 0x7F, 0x80, 0x12, 0xC0, 0x3F, 0xF9, 0x3F, 1, 0},
};
static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
@@ -564,6 +708,8 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
int coeff, ret;
u8 dmic_enable, state = 0;
unsigned int regv;
+ u32 freq;
+ bool hpf;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -590,7 +736,7 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
if (es8389->mclk_src == ES8389_SCLK_PIN) {
regmap_update_bits(es8389->regmap, ES8389_MASTER_CLK,
- ES8389_MCLK_SOURCE, es8389->mclk_src);
+ ES8389_MCLK_MASK, ES8389_MCLK_FROM_SCLK);
es8389->sysclk = params_channels(params) * params_width(params) * params_rate(params);
}
@@ -641,6 +787,28 @@ static int es8389_pcm_hw_params(struct snd_pcm_substream *substream,
dev_warn(component->dev, "Clock coefficients do not match");
}
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ es8389->capture_rate = params_rate(params);
+ freq = (es8389->hpf_freq * 48000) / params_rate(params);
+ hpf = find_best_hpf_freq(freq, &es8389->hpfl, &es8389->hpfr, &es8389->hpf_freq);
+ if (!hpf) {
+ dev_err(component->dev, "The HPF frequency is invalid\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int es8389_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct es8389_private *es8389 = snd_soc_component_get_drvdata(component);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ es8389->capture_rate = 0;
+
return 0;
}
@@ -721,8 +889,8 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
regmap_update_bits(es8389->regmap, ES8389_DAC_FORMAT_MUTE,
0x03, 0x00);
} else {
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, 0x0a);
- regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, 0x0a);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF1, 0x0f, es8389->hpfl);
+ regmap_update_bits(es8389->regmap, ES8389_ADC_HPF2, 0x0f, es8389->hpfr);
regmap_update_bits(es8389->regmap, ES8389_ADC_FORMAT_MUTE,
0x03, 0x00);
}
@@ -738,6 +906,7 @@ static int es8389_mute(struct snd_soc_dai *dai, int mute, int direction)
static const struct snd_soc_dai_ops es8389_ops = {
.hw_params = es8389_pcm_hw_params,
+ .hw_free = es8389_pcm_hw_free,
.set_fmt = es8389_set_dai_fmt,
.set_sysclk = es8389_set_dai_sysclk,
.set_tdm_slot = es8389_set_tdm_slot,
@@ -771,7 +940,7 @@ static void es8389_init(struct snd_soc_component *component)
regmap_read(es8389->regmap, ES8389_MAX_REGISTER, &reg);
es8389->version = reg;
- regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x00);
+ regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x56);
regmap_write(es8389->regmap, ES8389_RESET, 0x7E);
regmap_write(es8389->regmap, ES8389_ISO_CTL, 0x38);
regmap_write(es8389->regmap, ES8389_ADC_HPF1, 0x64);
@@ -823,7 +992,7 @@ static void es8389_init(struct snd_soc_component *component)
regmap_write(es8389->regmap, ES8389_SCLK_DIV, 0x04);
regmap_write(es8389->regmap, ES8389_LRCK_DIV1, 0x01);
regmap_write(es8389->regmap, ES8389_LRCK_DIV2, 0x00);
- regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x00);
+ regmap_write(es8389->regmap, ES8389_OSC_CLK, 0x10);
regmap_write(es8389->regmap, ES8389_ADC_OSR, 0x1F);
regmap_write(es8389->regmap, ES8389_ADC_DSP, 0x7F);
regmap_write(es8389->regmap, ES8389_ADC_MUTE, 0xC0);
@@ -861,13 +1030,13 @@ static int es8389_resume(struct snd_soc_component *component)
regcache_cache_only(es8389->regmap, false);
regcache_cache_bypass(es8389->regmap, true);
regmap_read(es8389->regmap, ES8389_RESET, &regv);
- regcache_cache_bypass(es8389->regmap, false);
if (regv == 0xff)
es8389_init(component);
else
es8389_set_bias_level(component, SND_SOC_BIAS_ON);
+ regcache_cache_bypass(es8389->regmap, false);
regcache_sync(es8389->regmap);
return 0;
@@ -913,6 +1082,7 @@ static int es8389_probe(struct snd_soc_component *component)
return ret;
}
+ es8389->hpf_freq = ES8389_HPF_DEFAULT;
es8389_init(component);
es8389_set_bias_level(component, SND_SOC_BIAS_STANDBY);
diff --git a/sound/soc/codecs/es8389.h b/sound/soc/codecs/es8389.h
index d21e72f876a6..de39e9bf96e9 100644
--- a/sound/soc/codecs/es8389.h
+++ b/sound/soc/codecs/es8389.h
@@ -106,6 +106,9 @@
#define ES8389_MIC_SEL_MASK (7 << 4)
#define ES8389_MIC_DEFAULT (1 << 4)
+#define ES8389_HPF_DEFAULT 16
+#define ES8389_HPF_OFFSET 4
+
#define ES8389_MASTER_MODE_EN (1 << 0)
#define ES8389_TDM_OFF (0 << 0)
@@ -116,9 +119,11 @@
#define ES8389_TDM_SLOT (0x70 << 0)
#define ES8389_TDM_SHIFT 4
-#define ES8389_MCLK_SOURCE (1 << 6)
-#define ES8389_MCLK_PIN (1 << 6)
-#define ES8389_SCLK_PIN (0 << 6)
+#define ES8389_MCLK_MASK (3 << 6)
+#define ES8389_MCLK_FROM_SCLK (1 << 6)
+#define ES8389_MCLK_SOURCE ES8389_MCLK_PIN
+#define ES8389_MCLK_PIN 0
+#define ES8389_SCLK_PIN 1
/* ES8389_FMT */
#define ES8389_S24_LE (0 << 5)
diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c
index 1122455aab77..80db0f2f4aef 100644
--- a/sound/soc/codecs/es9356.c
+++ b/sound/soc/codecs/es9356.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/soundwire/sdw.h>
@@ -19,8 +20,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
-#include <sound/sdca_function.h>
-#include <sound/sdca_regmap.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <sound/jack.h>
@@ -500,16 +499,19 @@ static int es9356_power_state(struct snd_soc_dai *dai, unsigned char ps, unsigne
}
/* power state changes are not independent across functions */
- mutex_lock(&es9356->pde_lock);
- ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps0:ps3);
- if (ret) {
- regmap_write(es9356->regmap,
- SDW_SDCA_CTL(func, pde_entity, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps?ps3:ps0);
- es9356_pde_transition_delay(es9356, func, pde_entity, ps?ps3:ps0);
- } else
- dev_dbg(component->dev, "%s PDE is already %d\n", __func__, ps?ps0:ps3);
-
- mutex_unlock(&es9356->pde_lock);
+ scoped_guard(mutex, &es9356->pde_lock) {
+ ret = es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps0 : ps3);
+ if (ret) {
+ regmap_write(es9356->regmap,
+ SDW_SDCA_CTL(func, pde_entity,
+ ES9356_SDCA_CTL_REQ_POWER_STATE, 0),
+ ps ? ps3 : ps0);
+ es9356_pde_transition_delay(es9356, func, pde_entity, ps ? ps3 : ps0);
+ } else {
+ dev_dbg(component->dev, "%s PDE is already %d\n", __func__,
+ ps ? ps0 : ps3);
+ }
+ }
if (rate)
regmap_write(es9356->regmap,
@@ -671,7 +673,7 @@ static int es9356_sdca_mbq_size(struct device *dev, unsigned int reg)
}
}
-static struct regmap_sdw_mbq_cfg es9356_mbq_config = {
+static const struct regmap_sdw_mbq_cfg es9356_mbq_config = {
.mbq_size = es9356_sdca_mbq_size,
};
@@ -1091,9 +1093,8 @@ static int es9356_sdca_dev_system_suspend(struct device *dev)
{
struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev);
- mutex_lock(&es9356->disable_irq_lock);
- es9356->disable_irq = true;
- mutex_unlock(&es9356->disable_irq_lock);
+ scoped_guard(mutex, &es9356->disable_irq_lock)
+ es9356->disable_irq = true;
return es9356_sdca_dev_suspend(dev);
}
diff --git a/sound/soc/codecs/fs-amp-lib.c b/sound/soc/codecs/fs-amp-lib.c
index c8f56617e370..a562c72fc524 100644
--- a/sound/soc/codecs/fs-amp-lib.c
+++ b/sound/soc/codecs/fs-amp-lib.c
@@ -221,7 +221,7 @@ static void fs_print_firmware_info(struct fs_amp_lib *amp_lib)
int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name)
{
- const struct firmware *cont;
+ const struct firmware *cont __free(firmware) = NULL;
struct fs_fwm_header *hdr;
int ret;
@@ -237,7 +237,6 @@ int fs_amp_load_firmware(struct fs_amp_lib *amp_lib, const char *name)
dev_info(amp_lib->dev, "Loading %s - size: %zu\n", name, cont->size);
hdr = devm_kmemdup(amp_lib->dev, cont->data, cont->size, GFP_KERNEL);
- release_firmware(cont);
if (!hdr)
return -ENOMEM;
diff --git a/sound/soc/codecs/fs210x.c b/sound/soc/codecs/fs210x.c
index d794ff918b6f..510cbeea5b62 100644
--- a/sound/soc/codecs/fs210x.c
+++ b/sound/soc/codecs/fs210x.c
@@ -4,6 +4,7 @@
//
// Copyright (C) 2016-2025 Shanghai FourSemi Semiconductor Co.,Ltd.
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -771,9 +772,8 @@ static int fs210x_dai_hw_params(struct snd_pcm_substream *substream,
if (fs210x->devid == FS2105S_DEVICE_ID && fs210x->srate == 16000)
return -EOPNOTSUPP;
- mutex_lock(&fs210x->lock);
- ret = fs210x_set_hw_params(fs210x);
- mutex_unlock(&fs210x->lock);
+ scoped_guard(mutex, &fs210x->lock)
+ ret = fs210x_set_hw_params(fs210x);
if (ret)
dev_err(fs210x->dev, "Failed to set hw params: %d\n", ret);
@@ -790,15 +790,11 @@ static int fs210x_dai_mute(struct snd_soc_dai *dai, int mute, int stream)
fs210x = snd_soc_component_get_drvdata(dai->component);
- mutex_lock(&fs210x->lock);
-
- if (!fs210x->is_inited || fs210x->is_suspended) {
- mutex_unlock(&fs210x->lock);
- return 0;
+ scoped_guard(mutex, &fs210x->lock) {
+ if (!fs210x->is_inited || fs210x->is_suspended)
+ return 0;
}
- mutex_unlock(&fs210x->lock);
-
if (mute) {
cancel_delayed_work_sync(&fs210x->fault_check_work);
cancel_delayed_work_sync(&fs210x->start_work);
@@ -817,15 +813,11 @@ static int fs210x_dai_trigger(struct snd_pcm_substream *substream,
fs210x = snd_soc_component_get_drvdata(dai->component);
- mutex_lock(&fs210x->lock);
-
- if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing) {
- mutex_unlock(&fs210x->lock);
- return 0;
+ scoped_guard(mutex, &fs210x->lock) {
+ if (!fs210x->is_inited || fs210x->is_suspended || fs210x->is_playing)
+ return 0;
}
- mutex_unlock(&fs210x->lock);
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -853,13 +845,11 @@ static void fs210x_start_work(struct work_struct *work)
fs210x = container_of(work, struct fs210x_priv, start_work.work);
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
ret = fs210x_dev_play(fs210x);
if (ret)
dev_err(fs210x->dev, "Failed to start playing: %d\n", ret);
-
- mutex_unlock(&fs210x->lock);
}
static void fs210x_fault_check_work(struct work_struct *work)
@@ -870,15 +860,13 @@ static void fs210x_fault_check_work(struct work_struct *work)
fs210x = container_of(work, struct fs210x_priv, fault_check_work.work);
- mutex_lock(&fs210x->lock);
+ scoped_guard(mutex, &fs210x->lock) {
+ if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing)
+ return;
- if (!fs210x->is_inited || fs210x->is_suspended || !fs210x->is_playing) {
- mutex_unlock(&fs210x->lock);
- return;
+ ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status);
}
- ret = fs210x_reg_read(fs210x, FS210X_05H_ANASTAT, &status);
- mutex_unlock(&fs210x->lock);
if (ret)
return;
@@ -991,7 +979,7 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol,
if (fs210x->scene_id < 1)
return -EINVAL;
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
/*
* FS210x has scene(s) as below:
* init scene: id = 0
@@ -1000,7 +988,6 @@ static int fs210x_effect_scene_get(struct snd_kcontrol *kcontrol,
*/
index = fs210x->scene_id - 1;
ucontrol->value.integer.value[0] = index;
- mutex_unlock(&fs210x->lock);
return 0;
}
@@ -1019,7 +1006,7 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
/*
* FS210x has scene(s) as below:
@@ -1029,17 +1016,14 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
*/
scene_id = ucontrol->value.integer.value[0] + 1;
scene_count = fs210x->amp_lib.scene_count - 1; /* Skip init scene */
- if (scene_id < 1 || scene_id > scene_count) {
- mutex_unlock(&fs210x->lock);
+ if (scene_id < 1 || scene_id > scene_count)
return -ERANGE;
- }
if (scene_id != fs210x->scene_id)
is_changed = true;
if (fs210x->is_suspended) {
fs210x->scene_id = scene_id;
- mutex_unlock(&fs210x->lock);
return is_changed;
}
@@ -1047,8 +1031,6 @@ static int fs210x_effect_scene_put(struct snd_kcontrol *kcontrol,
if (ret)
dev_err(fs210x->dev, "Failed to set scene: %d\n", ret);
- mutex_unlock(&fs210x->lock);
-
if (!ret && is_changed)
return 1;
@@ -1062,12 +1044,10 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w,
struct fs210x_priv *fs210x = snd_soc_component_get_drvdata(cmpnt);
int ret = 0;
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
- if (fs210x->is_suspended) {
- mutex_unlock(&fs210x->lock);
+ if (fs210x->is_suspended)
return 0;
- }
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -1088,8 +1068,6 @@ static int fs210x_playback_event(struct snd_soc_dapm_widget *w,
break;
}
- mutex_unlock(&fs210x->lock);
-
return ret;
}
@@ -1220,11 +1198,9 @@ static int fs210x_probe(struct snd_soc_component *cmpnt)
if (ret)
return ret;
- mutex_lock(&fs210x->lock);
- ret = fs210x_init_chip(fs210x);
- mutex_unlock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
- return ret;
+ return fs210x_init_chip(fs210x);
}
static void fs210x_remove(struct snd_soc_component *cmpnt)
@@ -1251,15 +1227,15 @@ static int fs210x_suspend(struct snd_soc_component *cmpnt)
regcache_cache_only(fs210x->regmap, true);
- mutex_lock(&fs210x->lock);
- fs210x->cur_scene = NULL;
- fs210x->is_inited = false;
- fs210x->is_playing = false;
- fs210x->is_suspended = true;
+ scoped_guard(mutex, &fs210x->lock) {
+ fs210x->cur_scene = NULL;
+ fs210x->is_inited = false;
+ fs210x->is_playing = false;
+ fs210x->is_suspended = true;
- gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */
- fsleep(30000); /* >= 30ms */
- mutex_unlock(&fs210x->lock);
+ gpiod_set_value_cansleep(fs210x->gpio_sdz, 1); /* Active */
+ fsleep(30000); /* >= 30ms */
+ }
cancel_delayed_work_sync(&fs210x->start_work);
cancel_delayed_work_sync(&fs210x->fault_check_work);
@@ -1288,14 +1264,11 @@ static int fs210x_resume(struct snd_soc_component *cmpnt)
return ret;
}
- mutex_lock(&fs210x->lock);
+ guard(mutex)(&fs210x->lock);
fs210x->is_suspended = false;
- ret = fs210x_init_chip(fs210x);
- mutex_unlock(&fs210x->lock);
-
- return ret;
+ return fs210x_init_chip(fs210x);
}
#else
#define fs210x_suspend NULL
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 680e341aa7f1..1c06fdbf0e71 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -437,7 +437,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
#ifdef CONFIG_SND_HDA_PATCH_LOADER
if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) {
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
dev_info(&hdev->dev, "Applying patch firmware '%s'\n",
loadable_patch[hda_pvt->dev_index]);
@@ -451,7 +451,6 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret);
goto error_no_pm;
}
- release_firmware(fw);
}
}
#endif
@@ -642,10 +641,8 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
- if (ret < 0) {
+ if (ret < 0)
dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret);
- return ret;
- }
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 3220f9226e0b..d9e6fa6d3e99 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -10,6 +10,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/module.h>
@@ -537,10 +538,11 @@ static struct hdac_hdmi_port *hdac_hdmi_get_port_from_cvt(
continue;
list_for_each_entry(port, &pcm->port_list, head) {
- mutex_lock(&pcm->lock);
- ret = hdac_hdmi_query_port_connlist(hdev,
- port->pin, port);
- mutex_unlock(&pcm->lock);
+ scoped_guard(mutex, &pcm->lock) {
+ ret = hdac_hdmi_query_port_connlist(hdev,
+ port->pin,
+ port);
+ }
if (ret < 0)
continue;
@@ -640,11 +642,11 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt);
if (pcm) {
- mutex_lock(&pcm->lock);
- pcm->chmap_set = false;
- memset(pcm->chmap, 0, sizeof(pcm->chmap));
- pcm->channels = 0;
- mutex_unlock(&pcm->lock);
+ scoped_guard(mutex, &pcm->lock) {
+ pcm->chmap_set = false;
+ memset(pcm->chmap, 0, sizeof(pcm->chmap));
+ pcm->channels = 0;
+ }
}
if (dai_map->port)
@@ -922,7 +924,7 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
if (port == NULL)
return -EINVAL;
- mutex_lock(&hdmi->pin_mutex);
+ guard(mutex)(&hdmi->pin_mutex);
list_for_each_entry(pcm, &hdmi->pcm_list, head) {
if (list_empty(&pcm->port_list))
continue;
@@ -945,12 +947,10 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,
list_add_tail(&port->head, &pcm->port_list);
if (port->eld.monitor_present && port->eld.eld_valid) {
hdac_hdmi_jack_report_sync(pcm, port, true);
- mutex_unlock(&hdmi->pin_mutex);
return ret;
}
}
}
- mutex_unlock(&hdmi->pin_mutex);
return ret;
}
@@ -1274,67 +1274,65 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin,
* In case of non MST pin, get_eld info API expectes port
* to be -1.
*/
- mutex_lock(&hdmi->pin_mutex);
- port->eld.monitor_present = false;
+ scoped_guard(mutex, &hdmi->pin_mutex) {
+ port->eld.monitor_present = false;
- if (pin->mst_capable)
- port_id = port->id;
+ if (pin->mst_capable)
+ port_id = port->id;
- size = snd_hdac_acomp_get_eld(hdev, pin->nid, port_id,
- &port->eld.monitor_present,
- port->eld.eld_buffer,
- ELD_MAX_SIZE);
+ 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(hdev, port) < 0)
- size = -EINVAL;
- }
+ if (size > 0) {
+ size = min(size, ELD_MAX_SIZE);
+ if (hdac_hdmi_parse_eld(hdev, port) < 0)
+ size = -EINVAL;
+ }
- eld_valid = port->eld.eld_valid;
+ eld_valid = port->eld.eld_valid;
- if (size > 0) {
- port->eld.eld_valid = true;
- port->eld.eld_size = size;
- } else {
- port->eld.eld_valid = false;
- port->eld.eld_size = 0;
- }
+ if (size > 0) {
+ port->eld.eld_valid = true;
+ port->eld.eld_size = size;
+ } else {
+ port->eld.eld_valid = false;
+ port->eld.eld_size = 0;
+ }
- eld_changed = (eld_valid != port->eld.eld_valid);
+ eld_changed = (eld_valid != port->eld.eld_valid);
- pcm = hdac_hdmi_get_pcm(hdev, port);
+ pcm = hdac_hdmi_get_pcm(hdev, port);
- if (!port->eld.monitor_present || !port->eld.eld_valid) {
+ if (!port->eld.monitor_present || !port->eld.eld_valid) {
- dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
- __func__, pin->nid, port->id);
-
- /*
- * PCMs are not registered during device probe, so don't
- * report jack here. It will be done in usermode mux
- * control select.
- */
- if (pcm) {
- hdac_hdmi_jack_report(pcm, port, false);
- schedule_work(&port->dapm_work);
- }
+ dev_dbg(&hdev->dev, "%s: disconnect for pin:port %d:%d\n",
+ __func__, pin->nid, port->id);
- mutex_unlock(&hdmi->pin_mutex);
- return;
- }
+ /*
+ * PCMs are not registered during device probe, so don't
+ * report jack here. It will be done in usermode mux
+ * control select.
+ */
+ if (pcm) {
+ hdac_hdmi_jack_report(pcm, port, false);
+ schedule_work(&port->dapm_work);
+ }
- if (port->eld.monitor_present && port->eld.eld_valid) {
- if (pcm) {
- hdac_hdmi_jack_report(pcm, port, true);
- schedule_work(&port->dapm_work);
+ return;
}
- print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
- port->eld.eld_buffer, port->eld.eld_size, false);
+ if (port->eld.monitor_present && port->eld.eld_valid) {
+ if (pcm) {
+ hdac_hdmi_jack_report(pcm, port, true);
+ schedule_work(&port->dapm_work);
+ }
+ print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1,
+ port->eld.eld_buffer, port->eld.eld_size, false);
+ }
}
- mutex_unlock(&hdmi->pin_mutex);
if (eld_changed && pcm)
snd_ctl_notify(hdmi->card,
@@ -1795,13 +1793,12 @@ static void hdac_hdmi_set_chmap(struct hdac_device *hdev, int pcm_idx,
if (list_empty(&pcm->port_list))
return;
- mutex_lock(&pcm->lock);
+ guard(mutex)(&pcm->lock);
pcm->chmap_set = true;
memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap));
list_for_each_entry(port, &pcm->port_list, head)
if (prepared)
hdac_hdmi_setup_audio_infoframe(hdev, pcm, port);
- mutex_unlock(&pcm->lock);
}
static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdev, int pcm_idx)
@@ -1866,8 +1863,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
hdmi_priv = devm_kzalloc(&hdev->dev, sizeof(*hdmi_priv), GFP_KERNEL);
- if (hdmi_priv == NULL)
+ if (hdmi_priv == NULL) {
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return -ENOMEM;
+ }
snd_hdac_register_chmap_ops(hdev, &hdmi_priv->chmap);
hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
@@ -1876,8 +1875,10 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
hdmi_priv->hdev = hdev;
- if (!hdac_id)
+ if (!hdac_id) {
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return -ENODEV;
+ }
if (hdac_id->driver_data)
hdmi_priv->drv_data =
@@ -1902,6 +1903,8 @@ static int hdac_hdmi_dev_probe(struct hdac_device *hdev)
if (ret < 0) {
dev_err(&hdev->dev,
"Failed in parse and map nid with err: %d\n", ret);
+ snd_hdac_ext_bus_link_put(hdev->bus, hlink);
+ snd_hdac_display_power(hdev->bus, hdev->addr, false);
return ret;
}
snd_hdac_refresh_widgets(hdev);
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 13ae9e83bc21..bc2c22436ba6 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -4,6 +4,7 @@
* Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Author: Jyri Sarha <jsarha@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/string.h>
#include <sound/core.h>
@@ -452,31 +453,30 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (!((has_playback && tx) || (has_capture && !tx)))
return 0;
- mutex_lock(&hcp->lock);
+ guard(mutex)(&hcp->lock);
if (hcp->busy) {
dev_err(dai->dev, "Only one simultaneous stream supported!\n");
- mutex_unlock(&hcp->lock);
return -EINVAL;
}
if (hcp->hcd.ops->audio_startup) {
ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data);
if (ret)
- goto err;
+ return ret;
}
if (tx && hcp->hcd.ops->get_eld) {
ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data,
hcp->eld, sizeof(hcp->eld));
if (ret)
- goto err;
+ return ret;
snd_parse_eld(dai->dev, &hcp->eld_parsed,
hcp->eld, sizeof(hcp->eld));
ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld);
if (ret)
- goto err;
+ return ret;
/* Select chmap supported */
hdmi_codec_eld_chmap(hcp);
@@ -484,8 +484,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
hcp->busy = true;
-err:
- mutex_unlock(&hcp->lock);
return ret;
}
@@ -503,9 +501,8 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream,
hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
- mutex_lock(&hcp->lock);
+ guard(mutex)(&hcp->lock);
hcp->busy = false;
- mutex_unlock(&hcp->lock);
}
static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai,
diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c
index 084090ccef77..387f17b5f7b3 100644
--- a/sound/soc/codecs/idt821034.c
+++ b/sound/soc/codecs/idt821034.c
@@ -7,6 +7,7 @@
// Author: Herve Codina <herve.codina@bootlin.com>
#include <linux/bitrev.h>
+#include <linux/cleanup.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -413,12 +414,12 @@ static int idt821034_kctrl_gain_get(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(mc->reg);
- mutex_lock(&idt821034->mutex);
- if (IDT821034_ID_IS_OUT(mc->reg))
- val = idt821034->amps.ch[ch].amp_out.gain;
- else
- val = idt821034->amps.ch[ch].amp_in.gain;
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex) {
+ if (IDT821034_ID_IS_OUT(mc->reg))
+ val = idt821034->amps.ch[ch].amp_out.gain;
+ else
+ val = idt821034->amps.ch[ch].amp_in.gain;
+ }
ucontrol->value.integer.value[0] = val & mask;
if (invert)
@@ -456,7 +457,7 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(mc->reg);
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
if (IDT821034_ID_IS_OUT(mc->reg)) {
amp = &idt821034->amps.ch[ch].amp_out;
@@ -466,22 +467,18 @@ static int idt821034_kctrl_gain_put(struct snd_kcontrol *kcontrol,
gain_type = IDT821034_GAIN_TX;
}
- if (amp->gain == val) {
- ret = 0;
- goto end;
- }
+ if (amp->gain == val)
+ return 0;
if (!amp->is_muted) {
ret = idt821034_set_gain_channel(idt821034, ch, gain_type, val);
if (ret)
- goto end;
+ return ret;
}
amp->gain = val;
- ret = 1; /* The value changed */
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return 1;
}
static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol,
@@ -495,11 +492,11 @@ static int idt821034_kctrl_mute_get(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(id);
- mutex_lock(&idt821034->mutex);
- is_muted = IDT821034_ID_IS_OUT(id) ?
- idt821034->amps.ch[ch].amp_out.is_muted :
- idt821034->amps.ch[ch].amp_in.is_muted;
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex) {
+ is_muted = IDT821034_ID_IS_OUT(id) ?
+ idt821034->amps.ch[ch].amp_out.is_muted :
+ idt821034->amps.ch[ch].amp_in.is_muted;
+ }
ucontrol->value.integer.value[0] = !is_muted;
@@ -521,7 +518,7 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol,
ch = IDT821034_ID_GET_CHAN(id);
is_mute = !ucontrol->value.integer.value[0];
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
if (IDT821034_ID_IS_OUT(id)) {
amp = &idt821034->amps.ch[ch].amp_out;
@@ -531,21 +528,17 @@ static int idt821034_kctrl_mute_put(struct snd_kcontrol *kcontrol,
gain_type = IDT821034_GAIN_TX;
}
- if (amp->is_muted == is_mute) {
- ret = 0;
- goto end;
- }
+ if (amp->is_muted == is_mute)
+ return 0;
ret = idt821034_set_gain_channel(idt821034, ch, gain_type,
is_mute ? 0 : amp->gain);
if (ret)
- goto end;
+ return ret;
amp->is_muted = is_mute;
- ret = 1; /* The value changed */
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return 1;
}
static const DECLARE_TLV_DB_LINEAR(idt821034_gain_in, -300, 1300);
@@ -623,24 +616,20 @@ static int idt821034_power_event(struct snd_soc_dapm_widget *w,
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(component);
unsigned int id = w->shift;
u8 power, mask;
- int ret;
u8 ch;
ch = IDT821034_ID_GET_CHAN(id);
mask = IDT821034_ID_IS_OUT(id) ? IDT821034_CONF_PWRUP_RX : IDT821034_CONF_PWRUP_TX;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
power = idt821034_get_channel_power(idt821034, ch);
if (SND_SOC_DAPM_EVENT_ON(event))
power |= mask;
else
power &= ~mask;
- ret = idt821034_set_channel_power(idt821034, ch, power);
-
- mutex_unlock(&idt821034->mutex);
- return ret;
+ return idt821034_set_channel_power(idt821034, ch, power);
}
static const struct snd_soc_dapm_widget idt821034_dapm_widgets[] = {
@@ -717,9 +706,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai,
ch = 0;
while (mask && ch < IDT821034_NB_CHANNEL) {
if (mask & 0x1) {
- mutex_lock(&idt821034->mutex);
- ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_RX, slot);
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex)
+ ret = idt821034_set_channel_ts(idt821034, ch,
+ IDT821034_CH_RX, slot);
if (ret) {
dev_err(dai->dev, "ch%u set tx tdm slot failed (%d)\n",
ch, ret);
@@ -742,9 +731,9 @@ static int idt821034_dai_set_tdm_slot(struct snd_soc_dai *dai,
ch = 0;
while (mask && ch < IDT821034_NB_CHANNEL) {
if (mask & 0x1) {
- mutex_lock(&idt821034->mutex);
- ret = idt821034_set_channel_ts(idt821034, ch, IDT821034_CH_TX, slot);
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex)
+ ret = idt821034_set_channel_ts(idt821034, ch,
+ IDT821034_CH_TX, slot);
if (ret) {
dev_err(dai->dev, "ch%u set rx tdm slot failed (%d)\n",
ch, ret);
@@ -769,9 +758,8 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component);
u8 conf;
- int ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
conf = idt821034_get_codec_conf(idt821034);
@@ -785,13 +773,10 @@ static int idt821034_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
default:
dev_err(dai->dev, "Unsupported DAI format 0x%x\n",
fmt & SND_SOC_DAIFMT_FORMAT_MASK);
- ret = -EINVAL;
- goto end;
+ return -EINVAL;
}
- ret = idt821034_set_codec_conf(idt821034, conf);
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return idt821034_set_codec_conf(idt821034, conf);
}
static int idt821034_dai_hw_params(struct snd_pcm_substream *substream,
@@ -800,9 +785,8 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream,
{
struct idt821034 *idt821034 = snd_soc_component_get_drvdata(dai->component);
u8 conf;
- int ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
conf = idt821034_get_codec_conf(idt821034);
@@ -816,13 +800,10 @@ static int idt821034_dai_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(dai->dev, "Unsupported PCM format 0x%x\n",
params_format(params));
- ret = -EINVAL;
- goto end;
+ return -EINVAL;
}
- ret = idt821034_set_codec_conf(idt821034, conf);
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return idt821034_set_codec_conf(idt821034, conf);
}
static const unsigned int idt821034_sample_bits[] = {8};
@@ -897,11 +878,11 @@ static int idt821034_reset_audio(struct idt821034 *idt821034)
int ret;
u8 i;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
ret = idt821034_set_codec_conf(idt821034, 0);
if (ret)
- goto end;
+ return ret;
for (i = 0; i < IDT821034_NB_CHANNEL; i++) {
idt821034->amps.ch[i].amp_out.gain = IDT821034_GAIN_OUT_INIT_RAW;
@@ -909,24 +890,21 @@ static int idt821034_reset_audio(struct idt821034 *idt821034)
ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_RX,
idt821034->amps.ch[i].amp_out.gain);
if (ret)
- goto end;
+ return ret;
idt821034->amps.ch[i].amp_in.gain = IDT821034_GAIN_IN_INIT_RAW;
idt821034->amps.ch[i].amp_in.is_muted = false;
ret = idt821034_set_gain_channel(idt821034, i, IDT821034_GAIN_TX,
idt821034->amps.ch[i].amp_in.gain);
if (ret)
- goto end;
+ return ret;
ret = idt821034_set_channel_power(idt821034, i, 0);
if (ret)
- goto end;
+ return ret;
}
- ret = 0;
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+ return 0;
}
static int idt821034_component_probe(struct snd_soc_component *component)
@@ -965,7 +943,7 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
u8 slic_raw;
int ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_raw = idt821034_get_written_slic_raw(idt821034, ch);
if (val)
@@ -974,8 +952,6 @@ static int idt821034_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
slic_raw &= ~mask;
ret = idt821034_write_slic_raw(idt821034, ch, slic_raw);
- mutex_unlock(&idt821034->mutex);
-
if (ret)
dev_err(&idt821034->spi->dev, "set gpio %d (%u, 0x%x) failed (%d)\n",
offset, ch, mask, ret);
@@ -991,9 +967,8 @@ static int idt821034_chip_gpio_get(struct gpio_chip *c, unsigned int offset)
u8 slic_raw;
int ret;
- mutex_lock(&idt821034->mutex);
- ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw);
- mutex_unlock(&idt821034->mutex);
+ scoped_guard(mutex, &idt821034->mutex)
+ ret = idt821034_read_slic_raw(idt821034, ch, &slic_raw);
if (ret) {
dev_err(&idt821034->spi->dev, "get gpio %d (%u, 0x%x) failed (%d)\n",
offset, ch, mask, ret);
@@ -1015,9 +990,8 @@ static int idt821034_chip_get_direction(struct gpio_chip *c, unsigned int offset
struct idt821034 *idt821034 = gpiochip_get_data(c);
u8 slic_dir;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_dir = idt821034_get_slic_conf(idt821034, ch);
- mutex_unlock(&idt821034->mutex);
return slic_dir & mask ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
}
@@ -1034,7 +1008,7 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs
if (mask & ~(IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN))
return -EPERM;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_conf = idt821034_get_slic_conf(idt821034, ch) | mask;
@@ -1044,7 +1018,6 @@ static int idt821034_chip_direction_input(struct gpio_chip *c, unsigned int offs
offset, ch, mask, ret);
}
- mutex_unlock(&idt821034->mutex);
return ret;
}
@@ -1060,7 +1033,7 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off
if (ret)
return ret;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
slic_conf = idt821034_get_slic_conf(idt821034, ch) & ~mask;
@@ -1070,7 +1043,6 @@ static int idt821034_chip_direction_output(struct gpio_chip *c, unsigned int off
offset, ch, mask, ret);
}
- mutex_unlock(&idt821034->mutex);
return ret;
}
@@ -1079,24 +1051,22 @@ static int idt821034_reset_gpio(struct idt821034 *idt821034)
int ret;
u8 i;
- mutex_lock(&idt821034->mutex);
+ guard(mutex)(&idt821034->mutex);
/* IO0 and IO1 as input for all channels and output IO set to 0 */
for (i = 0; i < IDT821034_NB_CHANNEL; i++) {
ret = idt821034_set_slic_conf(idt821034, i,
IDT821034_SLIC_IO1_IN | IDT821034_SLIC_IO0_IN);
if (ret)
- goto end;
+ return ret;
ret = idt821034_write_slic_raw(idt821034, i, 0);
if (ret)
- goto end;
+ return ret;
}
- ret = 0;
-end:
- mutex_unlock(&idt821034->mutex);
- return ret;
+
+ return 0;
}
static int idt821034_gpio_init(struct idt821034 *idt821034)
diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c
index a3d6318c9050..dadb4a6c287f 100644
--- a/sound/soc/codecs/lochnagar-sc.c
+++ b/sound/soc/codecs/lochnagar-sc.c
@@ -137,15 +137,23 @@ static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBP_CFP);
}
+static const u64 lochnagar_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops lochnagar_sc_line_ops = {
.startup = lochnagar_sc_line_startup,
.shutdown = lochnagar_sc_line_shutdown,
.set_fmt = lochnagar_sc_set_line_fmt,
+ .auto_selectable_formats = &lochnagar_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_ops lochnagar_sc_usb_ops = {
.startup = lochnagar_sc_startup,
.set_fmt = lochnagar_sc_set_usb_fmt,
+ .auto_selectable_formats = &lochnagar_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver lochnagar_sc_dai[] = {
diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c
index 6e3b8d0897dd..7e59616ed7bc 100644
--- a/sound/soc/codecs/lpass-macro-common.c
+++ b/sound/soc/codecs/lpass-macro-common.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -71,21 +72,16 @@ EXPORT_SYMBOL_GPL(lpass_macro_pds_exit);
void lpass_macro_set_codec_version(enum lpass_codec_version version)
{
- mutex_lock(&lpass_codec_mutex);
+ guard(mutex)(&lpass_codec_mutex);
lpass_codec_version = version;
- mutex_unlock(&lpass_codec_mutex);
}
EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version);
enum lpass_codec_version lpass_macro_get_codec_version(void)
{
- enum lpass_codec_version ver;
+ guard(mutex)(&lpass_codec_mutex);
- mutex_lock(&lpass_codec_mutex);
- ver = lpass_codec_version;
- mutex_unlock(&lpass_codec_mutex);
-
- return ver;
+ return lpass_codec_version;
}
EXPORT_SYMBOL_GPL(lpass_macro_get_codec_version);
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index 6233aa9f5bc6..282a6aaa9986 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <sound/soc.h>
@@ -2030,9 +2031,10 @@ static struct snd_soc_dai_driver rx_macro_dai[] = {
},
};
-static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
+static int rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
{
struct regmap *regmap = rx->regmap;
+ int ret;
if (mclk_enable) {
if (rx->rx_mclk_users == 0) {
@@ -2047,14 +2049,16 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_FS_MCLK_CNT_EN_MASK,
CDC_RX_FS_MCLK_CNT_ENABLE);
regcache_mark_dirty(regmap);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
}
rx->rx_mclk_users++;
} else {
if (rx->rx_mclk_users <= 0) {
dev_err(rx->dev, "%s: clock already disabled\n", __func__);
rx->rx_mclk_users = 0;
- return;
+ return 0;
}
rx->rx_mclk_users--;
if (rx->rx_mclk_users == 0) {
@@ -2068,6 +2072,8 @@ static void rx_macro_mclk_enable(struct rx_macro *rx, bool mclk_enable)
CDC_RX_CLK_MCLK2_EN_MASK, 0x0);
}
}
+
+ return 0;
}
static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
@@ -2079,11 +2085,9 @@ static int rx_macro_mclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- rx_macro_mclk_enable(rx, true);
- break;
+ return rx_macro_mclk_enable(rx, true);
case SND_SOC_DAPM_POST_PMD:
- rx_macro_mclk_enable(rx, false);
- break;
+ return rx_macro_mclk_enable(rx, false);
default:
dev_err(component->dev, "%s: invalid DAPM event %d\n", __func__, event);
ret = -EINVAL;
@@ -3671,14 +3675,16 @@ static int swclk_gate_enable(struct clk_hw *hw)
struct rx_macro *rx = to_rx_macro(hw);
int ret;
- ret = clk_prepare_enable(rx->mclk);
+ ret = pm_runtime_resume_and_get(rx->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = rx_macro_mclk_enable(rx, true);
if (ret) {
- dev_err(rx->dev, "unable to prepare mclk\n");
+ clk_disable_unprepare(rx->mclk);
return ret;
}
- rx_macro_mclk_enable(rx, true);
-
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
CDC_RX_SWR_CLK_EN_MASK, 1);
@@ -3693,7 +3699,7 @@ static void swclk_gate_disable(struct clk_hw *hw)
CDC_RX_SWR_CLK_EN_MASK, 0);
rx_macro_mclk_enable(rx, false);
- clk_disable_unprepare(rx->mclk);
+ pm_runtime_put_autosuspend(rx->dev);
}
static int swclk_gate_is_enabled(struct clk_hw *hw)
@@ -3864,28 +3870,31 @@ static int rx_macro_probe(struct platform_device *pdev)
rx->dev = dev;
/* set MCLK and NPL rates */
- clk_set_rate(rx->mclk, MCLK_FREQ);
- clk_set_rate(rx->npl, MCLK_FREQ);
-
- ret = clk_prepare_enable(rx->macro);
+ ret = clk_set_rate(rx->mclk, MCLK_FREQ);
if (ret)
return ret;
- ret = clk_prepare_enable(rx->dcodec);
+ ret = clk_set_rate(rx->npl, MCLK_FREQ);
if (ret)
- goto err_dcodec;
+ return ret;
- ret = clk_prepare_enable(rx->mclk);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err_mclk;
+ return ret;
- ret = clk_prepare_enable(rx->npl);
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_npl;
+ return ret;
- ret = clk_prepare_enable(rx->fsgen);
+ ret = pm_runtime_resume_and_get(dev);
if (ret)
- goto err_fsgen;
+ return ret;
/* reset swr block */
regmap_update_bits(rx->regmap, CDC_RX_CLK_RST_CTRL_SWR_CONTROL,
@@ -3902,46 +3911,25 @@ static int rx_macro_probe(struct platform_device *pdev)
rx_macro_dai,
ARRAY_SIZE(rx_macro_dai));
if (ret)
- goto err_clkout;
-
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = rx_macro_register_mclk_output(rx);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
+
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);
return 0;
-err_clkout:
- clk_disable_unprepare(rx->fsgen);
-err_fsgen:
- clk_disable_unprepare(rx->npl);
-err_npl:
- clk_disable_unprepare(rx->mclk);
-err_mclk:
- clk_disable_unprepare(rx->dcodec);
-err_dcodec:
- clk_disable_unprepare(rx->macro);
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");
return ret;
}
-static void rx_macro_remove(struct platform_device *pdev)
-{
- struct rx_macro *rx = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(rx->mclk);
- clk_disable_unprepare(rx->npl);
- clk_disable_unprepare(rx->fsgen);
- clk_disable_unprepare(rx->macro);
- clk_disable_unprepare(rx->dcodec);
-}
-
static const struct of_device_id rx_macro_dt_match[] = {
{
.compatible = "qcom,sc7280-lpass-rx-macro",
@@ -3969,13 +3957,17 @@ MODULE_DEVICE_TABLE(of, rx_macro_dt_match);
static int rx_macro_runtime_suspend(struct device *dev)
{
struct rx_macro *rx = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(rx->regmap, true);
- regcache_mark_dirty(rx->regmap);
- clk_disable_unprepare(rx->fsgen);
- clk_disable_unprepare(rx->npl);
- clk_disable_unprepare(rx->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(rx->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(rx->regmap);
return 0;
}
@@ -3985,33 +3977,23 @@ static int rx_macro_runtime_resume(struct device *dev)
struct rx_macro *rx = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(rx->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
return ret;
}
- ret = clk_prepare_enable(rx->npl);
- if (ret) {
- dev_err(dev, "unable to prepare mclkx2\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(rx->fsgen);
+ regcache_cache_only(rx->regmap, false);
+ ret = regcache_sync(rx->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(rx->regmap, true);
+ regcache_mark_dirty(rx->regmap);
+ pm_clk_suspend(dev);
+ return ret;
}
- regcache_cache_only(rx->regmap, false);
- regcache_sync(rx->regmap);
return 0;
-err_fsgen:
- clk_disable_unprepare(rx->npl);
-err_npl:
- clk_disable_unprepare(rx->mclk);
-
- return ret;
}
static const struct dev_pm_ops rx_macro_pm_ops = {
@@ -4026,7 +4008,6 @@ static struct platform_driver rx_macro_driver = {
.pm = pm_ptr(&rx_macro_pm_ops),
},
.probe = rx_macro_probe,
- .remove = rx_macro_remove,
};
module_platform_driver(rx_macro_driver);
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index 0cbf50647ff5..a8e83eb60ba2 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -6,6 +6,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <sound/soc.h>
@@ -614,6 +615,7 @@ static int tx_macro_mclk_enable(struct tx_macro *tx,
bool mclk_enable)
{
struct regmap *regmap = tx->regmap;
+ int ret;
if (mclk_enable) {
if (tx->tx_mclk_users == 0) {
@@ -626,7 +628,9 @@ static int tx_macro_mclk_enable(struct tx_macro *tx,
CDC_TX_FS_CNT_EN_MASK,
CDC_TX_FS_CNT_ENABLE);
regcache_mark_dirty(regmap);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret)
+ return ret;
}
tx->tx_mclk_users++;
} else {
@@ -739,11 +743,9 @@ static int tx_macro_mclk_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- tx_macro_mclk_enable(tx, true);
- break;
+ return tx_macro_mclk_enable(tx, true);
case SND_SOC_DAPM_POST_PMD:
- tx_macro_mclk_enable(tx, false);
- break;
+ return tx_macro_mclk_enable(tx, false);
default:
break;
}
@@ -2149,17 +2151,20 @@ static int swclk_gate_enable(struct clk_hw *hw)
struct regmap *regmap = tx->regmap;
int ret;
- ret = clk_prepare_enable(tx->mclk);
+ ret = pm_runtime_resume_and_get(tx->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = tx_macro_mclk_enable(tx, true);
if (ret) {
- dev_err(tx->dev, "failed to enable mclk\n");
+ pm_runtime_put_autosuspend(tx->dev);
return ret;
}
- tx_macro_mclk_enable(tx, true);
-
regmap_update_bits(regmap, CDC_TX_CLK_RST_CTRL_SWR_CONTROL,
CDC_TX_SWR_CLK_EN_MASK,
CDC_TX_SWR_CLK_ENABLE);
+
return 0;
}
@@ -2172,7 +2177,7 @@ static void swclk_gate_disable(struct clk_hw *hw)
CDC_TX_SWR_CLK_EN_MASK, 0x0);
tx_macro_mclk_enable(tx, false);
- clk_disable_unprepare(tx->mclk);
+ pm_runtime_put_autosuspend(tx->dev);
}
static int swclk_gate_is_enabled(struct clk_hw *hw)
@@ -2315,28 +2320,31 @@ static int tx_macro_probe(struct platform_device *pdev)
tx->active_decimator[TX_MACRO_AIF3_CAP] = -1;
/* set MCLK and NPL rates */
- clk_set_rate(tx->mclk, MCLK_FREQ);
- clk_set_rate(tx->npl, MCLK_FREQ);
-
- ret = clk_prepare_enable(tx->macro);
+ ret = clk_set_rate(tx->mclk, MCLK_FREQ);
if (ret)
goto err;
- ret = clk_prepare_enable(tx->dcodec);
+ ret = clk_set_rate(tx->npl, MCLK_FREQ);
if (ret)
- goto err_dcodec;
+ goto err;
- ret = clk_prepare_enable(tx->mclk);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err_mclk;
+ goto err;
- ret = clk_prepare_enable(tx->npl);
- if (ret)
- goto err_npl;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ goto err;
- ret = clk_prepare_enable(tx->fsgen);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_fsgen;
+ goto err;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err;
/* reset soundwire block */
@@ -2356,30 +2364,21 @@ static int tx_macro_probe(struct platform_device *pdev)
tx_macro_dai,
ARRAY_SIZE(tx_macro_dai));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = tx_macro_register_mclk_output(tx);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
+
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);
return 0;
-err_clkout:
- clk_disable_unprepare(tx->fsgen);
-err_fsgen:
- clk_disable_unprepare(tx->npl);
-err_npl:
- clk_disable_unprepare(tx->mclk);
-err_mclk:
- clk_disable_unprepare(tx->dcodec);
-err_dcodec:
- clk_disable_unprepare(tx->macro);
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");
err:
lpass_macro_pds_exit(tx->pds);
@@ -2390,25 +2389,23 @@ static void tx_macro_remove(struct platform_device *pdev)
{
struct tx_macro *tx = dev_get_drvdata(&pdev->dev);
- clk_disable_unprepare(tx->macro);
- clk_disable_unprepare(tx->dcodec);
- clk_disable_unprepare(tx->mclk);
- clk_disable_unprepare(tx->npl);
- clk_disable_unprepare(tx->fsgen);
-
lpass_macro_pds_exit(tx->pds);
}
static int tx_macro_runtime_suspend(struct device *dev)
{
struct tx_macro *tx = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(tx->regmap, true);
- regcache_mark_dirty(tx->regmap);
- clk_disable_unprepare(tx->fsgen);
- clk_disable_unprepare(tx->npl);
- clk_disable_unprepare(tx->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(tx->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(tx->regmap);
return 0;
}
@@ -2418,34 +2415,23 @@ static int tx_macro_runtime_resume(struct device *dev)
struct tx_macro *tx = dev_get_drvdata(dev);
int ret;
- ret = clk_prepare_enable(tx->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(tx->regmap, true);
+ regcache_mark_dirty(tx->regmap);
return ret;
}
- ret = clk_prepare_enable(tx->npl);
- if (ret) {
- dev_err(dev, "unable to prepare npl\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(tx->fsgen);
+ regcache_cache_only(tx->regmap, false);
+ ret = regcache_sync(tx->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(tx->regmap, true);
+ regcache_mark_dirty(tx->regmap);
+ pm_clk_suspend(dev);
+ return ret;
}
- regcache_cache_only(tx->regmap, false);
- regcache_sync(tx->regmap);
-
return 0;
-err_fsgen:
- clk_disable_unprepare(tx->npl);
-err_npl:
- clk_disable_unprepare(tx->mclk);
-
- return ret;
}
static const struct dev_pm_ops tx_macro_pm_ops = {
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index 58a5798823d7..dbc5795b9273 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -10,6 +10,7 @@
#include <linux/of_clk.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
@@ -1351,34 +1352,43 @@ static int fsgen_gate_enable(struct clk_hw *hw)
{
struct va_macro *va = to_va_macro(hw);
struct regmap *regmap = va->regmap;
- int ret;
+ int ret, rpm_ret;
- if (va->has_swr_master) {
- ret = clk_prepare_enable(va->mclk);
- if (ret)
- return ret;
- }
+ ret = pm_runtime_resume_and_get(va->dev);
+ if (ret < 0)
+ return ret;
ret = va_macro_mclk_enable(va, true);
+ if (ret) {
+ rpm_ret = pm_runtime_put_autosuspend(va->dev);
+ if (rpm_ret < 0)
+ dev_warn(va->dev,
+ "runtime PM put failed in fsgen enable unwind: %d\n",
+ rpm_ret);
+ return ret;
+ }
if (va->has_swr_master)
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
CDC_VA_SWR_CLK_EN_MASK, CDC_VA_SWR_CLK_ENABLE);
- return ret;
+ return 0;
}
static void fsgen_gate_disable(struct clk_hw *hw)
{
struct va_macro *va = to_va_macro(hw);
struct regmap *regmap = va->regmap;
+ int ret;
if (va->has_swr_master)
regmap_update_bits(regmap, CDC_VA_CLK_RST_CTRL_SWR_CONTROL,
CDC_VA_SWR_CLK_EN_MASK, 0x0);
va_macro_mclk_enable(va, false);
- if (va->has_swr_master)
- clk_disable_unprepare(va->mclk);
+
+ ret = pm_runtime_put_autosuspend(va->dev);
+ if (ret < 0)
+ dev_warn(va->dev, "runtime PM put failed in fsgen disable: %d\n", ret);
}
static int fsgen_gate_is_enabled(struct clk_hw *hw)
@@ -1539,6 +1549,7 @@ static int va_macro_probe(struct platform_device *pdev)
void __iomem *base;
u32 sample_rate = 0;
int ret;
+ int rpm_ret;
va = devm_kzalloc(dev, sizeof(*va), GFP_KERNEL);
if (!va)
@@ -1594,7 +1605,9 @@ static int va_macro_probe(struct platform_device *pdev)
va->has_npl_clk = data->has_npl_clk;
/* mclk rate */
- clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ);
+ ret = clk_set_rate(va->mclk, 2 * VA_MACRO_MCLK_FREQ);
+ if (ret)
+ goto err;
if (va->has_npl_clk) {
va->npl = devm_clk_get(dev, "npl");
@@ -1603,25 +1616,29 @@ static int va_macro_probe(struct platform_device *pdev)
goto err;
}
- clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ);
+ ret = clk_set_rate(va->npl, 2 * VA_MACRO_MCLK_FREQ);
+ if (ret)
+ goto err;
}
- ret = clk_prepare_enable(va->macro);
+ ret = devm_pm_clk_create(dev);
if (ret)
goto err;
- ret = clk_prepare_enable(va->dcodec);
- if (ret)
- goto err_dcodec;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ goto err;
- ret = clk_prepare_enable(va->mclk);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_mclk;
+ goto err;
- if (va->has_npl_clk) {
- ret = clk_prepare_enable(va->npl);
- if (ret)
- goto err_npl;
+ rpm_ret = pm_runtime_resume_and_get(dev);
+ if (rpm_ret < 0) {
+ ret = rpm_ret;
+ goto err;
}
/**
@@ -1634,7 +1651,7 @@ static int va_macro_probe(struct platform_device *pdev)
/* read version from register */
ret = va_macro_set_lpass_codec_version(va);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
}
if (va->has_swr_master) {
@@ -1664,35 +1681,28 @@ static int va_macro_probe(struct platform_device *pdev)
va_macro_dais,
ARRAY_SIZE(va_macro_dais));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = va_macro_register_fsgen_output(va);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
va->fsgen = devm_clk_hw_get_clk(dev, &va->hw, "fsgen");
if (IS_ERR(va->fsgen)) {
ret = PTR_ERR(va->fsgen);
- goto err_clkout;
+ goto err_rpm_put;
}
+ rpm_ret = pm_runtime_put_autosuspend(dev);
+ if (rpm_ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", rpm_ret);
+
return 0;
-err_clkout:
- if (va->has_npl_clk)
- clk_disable_unprepare(va->npl);
-err_npl:
- clk_disable_unprepare(va->mclk);
-err_mclk:
- clk_disable_unprepare(va->dcodec);
-err_dcodec:
- clk_disable_unprepare(va->macro);
+err_rpm_put:
+ rpm_ret = pm_runtime_put_sync_suspend(dev);
+ if (rpm_ret < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind: %d\n", rpm_ret);
err:
lpass_macro_pds_exit(va->pds);
@@ -1703,27 +1713,23 @@ static void va_macro_remove(struct platform_device *pdev)
{
struct va_macro *va = dev_get_drvdata(&pdev->dev);
- if (va->has_npl_clk)
- clk_disable_unprepare(va->npl);
-
- clk_disable_unprepare(va->mclk);
- clk_disable_unprepare(va->dcodec);
- clk_disable_unprepare(va->macro);
-
lpass_macro_pds_exit(va->pds);
}
static int va_macro_runtime_suspend(struct device *dev)
{
struct va_macro *va = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(va->regmap, true);
- regcache_mark_dirty(va->regmap);
- if (va->has_npl_clk)
- clk_disable_unprepare(va->npl);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(va->regmap, false);
+ return ret;
+ }
- clk_disable_unprepare(va->mclk);
+ regcache_mark_dirty(va->regmap);
return 0;
}
@@ -1731,25 +1737,28 @@ static int va_macro_runtime_suspend(struct device *dev)
static int va_macro_runtime_resume(struct device *dev)
{
struct va_macro *va = dev_get_drvdata(dev);
- int ret;
+ int ret, sret;
- ret = clk_prepare_enable(va->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(va->dev, "unable to prepare mclk\n");
+ regcache_cache_only(va->regmap, true);
+ regcache_mark_dirty(va->regmap);
return ret;
}
- if (va->has_npl_clk) {
- ret = clk_prepare_enable(va->npl);
- if (ret) {
- clk_disable_unprepare(va->mclk);
- dev_err(va->dev, "unable to prepare npl\n");
- return ret;
- }
- }
-
regcache_cache_only(va->regmap, false);
- regcache_sync(va->regmap);
+
+ ret = regcache_sync(va->regmap);
+ if (ret) {
+ regcache_cache_only(va->regmap, true);
+ regcache_mark_dirty(va->regmap);
+ sret = pm_clk_suspend(dev);
+ if (sret)
+ dev_err(va->dev,
+ "failed to suspend clocks after regcache sync failure: %d\n",
+ sret);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index af521e0988db..cfd2ac0a6cda 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -12,6 +12,7 @@
#include <linux/clk-provider.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
#include <sound/tlv.h>
@@ -2529,15 +2530,13 @@ static const struct snd_soc_dapm_route wsa_audio_map[] = {
static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
{
struct regmap *regmap = wsa->regmap;
+ int ret;
if (enable) {
- int ret;
-
- ret = clk_prepare_enable(wsa->mclk);
- if (ret) {
- dev_err(wsa->dev, "failed to enable mclk\n");
+ ret = pm_runtime_resume_and_get(wsa->dev);
+ if (ret < 0)
return ret;
- }
+
wsa_macro_mclk_enable(wsa, true);
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
@@ -2548,7 +2547,10 @@ static int wsa_swrm_clock(struct wsa_macro *wsa, bool enable)
regmap_update_bits(regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
CDC_WSA_SWR_CLK_EN_MASK, 0);
wsa_macro_mclk_enable(wsa, false);
- clk_disable_unprepare(wsa->mclk);
+
+ ret = pm_runtime_put_autosuspend(wsa->dev);
+ if (ret < 0)
+ dev_warn(wsa->dev, "runtime PM put failed: %d\n", ret);
}
return 0;
@@ -2656,7 +2658,7 @@ static int wsa_macro_register_mclk_output(struct wsa_macro *wsa)
init.num_parents = 1;
wsa->hw.init = &init;
hw = &wsa->hw;
- ret = clk_hw_register(wsa->dev, hw);
+ ret = devm_clk_hw_register(wsa->dev, hw);
if (ret)
return ret;
@@ -2771,28 +2773,31 @@ static int wsa_macro_probe(struct platform_device *pdev)
wsa->dev = dev;
/* set MCLK and NPL rates */
- clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ);
- clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ);
-
- ret = clk_prepare_enable(wsa->macro);
+ ret = clk_set_rate(wsa->mclk, WSA_MACRO_MCLK_FREQ);
if (ret)
- goto err;
+ return ret;
- ret = clk_prepare_enable(wsa->dcodec);
+ ret = clk_set_rate(wsa->npl, WSA_MACRO_MCLK_FREQ);
if (ret)
- goto err_dcodec;
+ return ret;
- ret = clk_prepare_enable(wsa->mclk);
+ ret = devm_pm_clk_create(dev);
if (ret)
- goto err_mclk;
+ return ret;
- ret = clk_prepare_enable(wsa->npl);
- if (ret)
- goto err_npl;
+ ret = of_pm_clk_add_clks(dev);
+ if (ret < 0)
+ return ret;
- ret = clk_prepare_enable(wsa->fsgen);
+ pm_runtime_set_autosuspend_delay(dev, 100);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
- goto err_fsgen;
+ return ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
/* reset swr ip */
regmap_update_bits(wsa->regmap, CDC_WSA_CLK_RST_CTRL_SWR_CONTROL,
@@ -2809,56 +2814,37 @@ static int wsa_macro_probe(struct platform_device *pdev)
wsa_macro_dai,
ARRAY_SIZE(wsa_macro_dai));
if (ret)
- goto err_clkout;
-
- pm_runtime_set_autosuspend_delay(dev, 3000);
- pm_runtime_use_autosuspend(dev);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ goto err_rpm_put;
ret = wsa_macro_register_mclk_output(wsa);
if (ret)
- goto err_clkout;
+ goto err_rpm_put;
- return 0;
+ ret = pm_runtime_put_autosuspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "runtime PM put failed after probe: %d\n", ret);
-err_clkout:
- clk_disable_unprepare(wsa->fsgen);
-err_fsgen:
- clk_disable_unprepare(wsa->npl);
-err_npl:
- clk_disable_unprepare(wsa->mclk);
-err_mclk:
- clk_disable_unprepare(wsa->dcodec);
-err_dcodec:
- clk_disable_unprepare(wsa->macro);
-err:
+ return 0;
+err_rpm_put:
+ if (pm_runtime_put_sync_suspend(dev) < 0)
+ dev_warn(dev, "runtime PM sync suspend failed in probe unwind\n");
return ret;
-
-}
-
-static void wsa_macro_remove(struct platform_device *pdev)
-{
- struct wsa_macro *wsa = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(wsa->macro);
- clk_disable_unprepare(wsa->dcodec);
- clk_disable_unprepare(wsa->mclk);
- clk_disable_unprepare(wsa->npl);
- clk_disable_unprepare(wsa->fsgen);
}
static int wsa_macro_runtime_suspend(struct device *dev)
{
struct wsa_macro *wsa = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(wsa->regmap, true);
- regcache_mark_dirty(wsa->regmap);
- clk_disable_unprepare(wsa->fsgen);
- clk_disable_unprepare(wsa->npl);
- clk_disable_unprepare(wsa->mclk);
+ ret = pm_clk_suspend(dev);
+ if (ret) {
+ regcache_cache_only(wsa->regmap, false);
+ return ret;
+ }
+
+ regcache_mark_dirty(wsa->regmap);
return 0;
}
@@ -2866,36 +2852,29 @@ static int wsa_macro_runtime_suspend(struct device *dev)
static int wsa_macro_runtime_resume(struct device *dev)
{
struct wsa_macro *wsa = dev_get_drvdata(dev);
- int ret;
+ int ret, sret;
- ret = clk_prepare_enable(wsa->mclk);
+ ret = pm_clk_resume(dev);
if (ret) {
- dev_err(dev, "unable to prepare mclk\n");
+ regcache_cache_only(wsa->regmap, true);
+ regcache_mark_dirty(wsa->regmap);
return ret;
}
+ regcache_cache_only(wsa->regmap, false);
- ret = clk_prepare_enable(wsa->npl);
- if (ret) {
- dev_err(dev, "unable to prepare mclkx2\n");
- goto err_npl;
- }
-
- ret = clk_prepare_enable(wsa->fsgen);
+ ret = regcache_sync(wsa->regmap);
if (ret) {
- dev_err(dev, "unable to prepare fsgen\n");
- goto err_fsgen;
+ regcache_cache_only(wsa->regmap, true);
+ regcache_mark_dirty(wsa->regmap);
+ sret = pm_clk_suspend(dev);
+ if (sret)
+ dev_err(dev,
+ "failed to suspend clocks after regcache sync failure: %d\n",
+ sret);
+ return ret;
}
- regcache_cache_only(wsa->regmap, false);
- regcache_sync(wsa->regmap);
-
return 0;
-err_fsgen:
- clk_disable_unprepare(wsa->npl);
-err_npl:
- clk_disable_unprepare(wsa->mclk);
-
- return ret;
}
static const struct dev_pm_ops wsa_macro_pm_ops = {
@@ -2929,7 +2908,6 @@ static struct platform_driver wsa_macro_driver = {
.pm = pm_ptr(&wsa_macro_pm_ops),
},
.probe = wsa_macro_probe,
- .remove = wsa_macro_remove,
};
module_platform_driver(wsa_macro_driver);
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index 98d72db599d8..58255844b4df 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -6,6 +6,7 @@
// Cirrus Logic International Semiconductor Ltd.
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
@@ -513,7 +514,7 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,
* We can't rely on the DAPM mutex for locking because we need a lock
* that can safely be called in hw_params
*/
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@@ -532,8 +533,6 @@ int madera_domain_clk_ev(struct snd_soc_dapm_widget *w,
madera_debug_dump_domain_groups(priv);
- mutex_unlock(&priv->rate_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(madera_domain_clk_ev);
@@ -875,9 +874,8 @@ static int madera_adsp_rate_get(struct snd_kcontrol *kcontrol,
const int adsp_num = e->shift_l;
int item;
- mutex_lock(&priv->rate_lock);
- cached_rate = priv->adsp_rate_cache[adsp_num];
- mutex_unlock(&priv->rate_lock);
+ scoped_guard(mutex, &priv->rate_lock)
+ cached_rate = priv->adsp_rate_cache[adsp_num];
item = snd_soc_enum_val_to_item(e, cached_rate);
ucontrol->value.enumerated.item[0] = item;
@@ -893,7 +891,6 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
const int adsp_num = e->shift_l;
const unsigned int item = ucontrol->value.enumerated.item[0];
- int ret = 0;
if (item >= e->items)
return -EINVAL;
@@ -903,22 +900,20 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
* maintain consistent behaviour that rate domains cannot be changed
* while in use since this is a hardware requirement
*/
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
if (!madera_can_change_grp_rate(priv, priv->adsp[adsp_num].cs_dsp.base)) {
dev_warn(priv->madera->dev,
"Cannot change '%s' while in use by active audio paths\n",
kcontrol->id.name);
- ret = -EBUSY;
+ return -EBUSY;
} else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) {
/* Volatile register so defer until the codec is powered up */
priv->adsp_rate_cache[adsp_num] = e->values[item];
- ret = 1;
+ return 1;
}
- mutex_unlock(&priv->rate_lock);
-
- return ret;
+ return 0;
}
static const struct soc_enum madera_adsp_rate_enum[] = {
@@ -1061,15 +1056,13 @@ int madera_rate_put(struct snd_kcontrol *kcontrol,
* Prevent the domain powering up while we're checking whether it's
* safe to change rate domain
*/
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
val = snd_soc_component_read(component, e->reg);
val >>= e->shift_l;
val &= e->mask;
- if (snd_soc_enum_item_to_val(e, item) == val) {
- ret = 0;
- goto out;
- }
+ if (snd_soc_enum_item_to_val(e, item) == val)
+ return 0;
if (!madera_can_change_grp_rate(priv, e->reg)) {
dev_warn(priv->madera->dev,
@@ -1082,8 +1075,6 @@ int madera_rate_put(struct snd_kcontrol *kcontrol,
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
madera_spin_sysclk(priv);
}
-out:
- mutex_unlock(&priv->rate_lock);
return ret;
}
@@ -3041,12 +3032,11 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream,
if ((cur & MADERA_AIF1_RATE_MASK) == (tar & MADERA_AIF1_RATE_MASK))
return 0;
- mutex_lock(&priv->rate_lock);
+ guard(mutex)(&priv->rate_lock);
if (!madera_can_change_grp_rate(priv, base + MADERA_AIF_RATE_CTRL)) {
madera_aif_warn(dai, "Cannot change rate while active\n");
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
/* Guard the rate change with SYSCLK cycles */
@@ -3055,9 +3045,6 @@ static int madera_hw_params_rate(struct snd_pcm_substream *substream,
MADERA_AIF1_RATE_MASK, tar);
madera_spin_sysclk(priv);
-out:
- mutex_unlock(&priv->rate_lock);
-
return ret;
}
@@ -3345,6 +3332,16 @@ static int madera_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
return 0;
}
+static const u64 madera_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_NB_IF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_NF |
+ SND_SOC_POSSIBLE_DAIFMT_IB_IF;
+
const struct snd_soc_dai_ops madera_dai_ops = {
.startup = &madera_startup,
.set_fmt = &madera_set_fmt,
@@ -3352,6 +3349,8 @@ const struct snd_soc_dai_ops madera_dai_ops = {
.hw_params = &madera_hw_params,
.set_sysclk = &madera_dai_set_sysclk,
.set_tristate = &madera_set_tristate,
+ .auto_selectable_formats = &madera_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
EXPORT_SYMBOL_GPL(madera_dai_ops);
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 57bd5a1c34c8..64dc442e9066 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2341,6 +2341,7 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
*
* @component: MAX98090 component
* @jack: jack to report detection events on
+ * @data: can be used if codec driver need extra data for configuring jack
*
* Enable microphone detection via IRQ on the MAX98090. If GPIOs are
* being used to bring out signals to the processor then only platform
@@ -2646,12 +2647,18 @@ static void max98090_i2c_remove(struct i2c_client *client)
static int max98090_runtime_resume(struct device *dev)
{
struct max98090_priv *max98090 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98090->regmap, false);
max98090_reset(max98090);
- regcache_sync(max98090->regmap);
+ ret = regcache_sync(max98090->regmap);
+ if (ret < 0) {
+ regcache_cache_only(max98090->regmap, true);
+ regcache_mark_dirty(max98090->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 130b6694a634..d93436046849 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -5,6 +5,7 @@
* Copyright 2011 Maxim Integrated Products
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -1532,15 +1533,17 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL);
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
- mutex_lock(&max98095->lock);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
- m98095_eq_band(component, channel, 0, coef_set->band1);
- m98095_eq_band(component, channel, 1, coef_set->band2);
- m98095_eq_band(component, channel, 2, coef_set->band3);
- m98095_eq_band(component, channel, 3, coef_set->band4);
- m98095_eq_band(component, channel, 4, coef_set->band5);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
- mutex_unlock(&max98095->lock);
+ scoped_guard(mutex, &max98095->lock) {
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, M98095_SEG);
+ m98095_eq_band(component, channel, 0, coef_set->band1);
+ m98095_eq_band(component, channel, 1, coef_set->band2);
+ m98095_eq_band(component, channel, 2, coef_set->band3);
+ m98095_eq_band(component, channel, 3, coef_set->band4);
+ m98095_eq_band(component, channel, 4, coef_set->band5);
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, 0);
+ }
/* Restore the original on/off state */
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
@@ -1683,12 +1686,14 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
regsave = snd_soc_component_read(component, M98095_088_CFG_LEVEL);
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, 0);
- mutex_lock(&max98095->lock);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
- m98095_biquad_band(component, channel, 0, coef_set->band1);
- m98095_biquad_band(component, channel, 1, coef_set->band2);
- snd_soc_component_update_bits(component, M98095_00F_HOST_CFG, M98095_SEG, 0);
- mutex_unlock(&max98095->lock);
+ scoped_guard(mutex, &max98095->lock) {
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, M98095_SEG);
+ m98095_biquad_band(component, channel, 0, coef_set->band1);
+ m98095_biquad_band(component, channel, 1, coef_set->band2);
+ snd_soc_component_update_bits(component, M98095_00F_HOST_CFG,
+ M98095_SEG, 0);
+ }
/* Restore the original on/off state */
snd_soc_component_update_bits(component, M98095_088_CFG_LEVEL, regmask, regsave);
diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c
index 099dc5bf6195..0e32b7a94cb0 100644
--- a/sound/soc/codecs/max98363.c
+++ b/sound/soc/codecs/max98363.c
@@ -100,7 +100,12 @@ static int max98363_resume(struct device *dev)
return ret;
regcache_cache_only(max98363->regmap, false);
- regcache_sync(max98363->regmap);
+ ret = regcache_sync(max98363->regmap);
+ if (ret) {
+ regcache_cache_only(max98363->regmap, true);
+ regcache_mark_dirty(max98363->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 8805bd01153c..cbd7ebffa6d6 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -488,10 +488,17 @@ static int max98373_suspend(struct device *dev)
static int max98373_resume(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98373->regmap, false);
max98373_reset(max98373, dev);
- regcache_sync(max98373->regmap);
+ ret = regcache_sync(max98373->regmap);
+ if (ret) {
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 8fe9c58e1a62..638ef343813b 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -277,7 +277,12 @@ static int max98373_resume(struct device *dev)
}
regcache_cache_only(max98373->regmap, false);
- regcache_sync(max98373->regmap);
+ ret = regcache_sync(max98373->regmap);
+ if (ret) {
+ regcache_cache_only(max98373->regmap, true);
+ regcache_mark_dirty(max98373->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c
index a4c57152d25f..d97dab41bf0f 100644
--- a/sound/soc/codecs/max98388.c
+++ b/sound/soc/codecs/max98388.c
@@ -863,10 +863,16 @@ static int max98388_suspend(struct device *dev)
static int max98388_resume(struct device *dev)
{
struct max98388_priv *max98388 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(max98388->regmap, false);
max98388_reset(max98388, dev);
- regcache_sync(max98388->regmap);
+ ret = regcache_sync(max98388->regmap);
+ if (ret) {
+ regcache_cache_only(max98388->regmap, true);
+ regcache_mark_dirty(max98388->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 2bbedf84ee5d..2295fc057c71 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -788,7 +788,6 @@ static int max98390_dsm_init(struct snd_soc_component *component)
const char *vendor, *product;
struct max98390_priv *max98390 =
snd_soc_component_get_drvdata(component);
- const struct firmware *fw;
char *dsm_param;
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
@@ -805,6 +804,8 @@ static int max98390_dsm_init(struct snd_soc_component *component)
snprintf(filename, sizeof(filename), "%s",
max98390->dsm_param_name);
}
+
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, filename, component->dev);
if (ret) {
ret = request_firmware(&fw, "dsm_param.bin", component->dev);
@@ -812,7 +813,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
ret = request_firmware(&fw, "dsmparam.bin",
component->dev);
if (ret)
- goto err;
+ return ret;
}
}
@@ -822,8 +823,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
if (fw->size < MAX98390_DSM_PARAM_MIN_SIZE) {
dev_err(component->dev,
"param fw is invalid.\n");
- ret = -EINVAL;
- goto err_alloc;
+ return -EINVAL;
}
dsm_param = (char *)fw->data;
param_start_addr = (dsm_param[0] & 0xff) | (dsm_param[1] & 0xff) << 8;
@@ -833,8 +833,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
fw->size < param_size + MAX98390_DSM_PAYLOAD_OFFSET) {
dev_err(component->dev,
"param fw is invalid.\n");
- ret = -EINVAL;
- goto err_alloc;
+ return -EINVAL;
}
regmap_write(max98390->regmap, MAX98390_R203A_AMP_EN, 0x80);
dsm_param += MAX98390_DSM_PAYLOAD_OFFSET;
@@ -842,10 +841,7 @@ static int max98390_dsm_init(struct snd_soc_component *component)
dsm_param, param_size);
regmap_write(max98390->regmap, MAX98390_R23E1_DSP_GLOBAL_EN, 0x01);
-err_alloc:
- release_firmware(fw);
-err:
- return ret;
+ return 0;
}
static void max98390_init_regs(struct snd_soc_component *component)
@@ -952,11 +948,17 @@ static int max98390_suspend(struct device *dev)
static int max98390_resume(struct device *dev)
{
struct max98390_priv *max98390 = dev_get_drvdata(dev);
+ int ret;
dev_dbg(dev, "%s:Enter\n", __func__);
regcache_cache_only(max98390->regmap, false);
- regcache_sync(max98390->regmap);
+ ret = regcache_sync(max98390->regmap);
+ if (ret) {
+ regcache_cache_only(max98390->regmap, true);
+ regcache_mark_dirty(max98390->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index 9c1d7213410c..e5a2fe824c03 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1600,19 +1600,37 @@ static int max98396_resume(struct device *dev)
if (max98396->pvdd) {
ret = regulator_enable(max98396->pvdd);
if (ret < 0)
- return ret;
+ goto err_core_supplies;
}
if (max98396->vbat) {
ret = regulator_enable(max98396->vbat);
if (ret < 0)
- return ret;
+ goto err_pvdd;
}
regcache_cache_only(max98396->regmap, false);
max98396_reset(max98396, dev);
- regcache_sync(max98396->regmap);
+ ret = regcache_sync(max98396->regmap);
+ if (ret < 0) {
+ regcache_cache_only(max98396->regmap, true);
+ regcache_mark_dirty(max98396->regmap);
+ goto err_vbat;
+ }
+
return 0;
+
+err_vbat:
+ if (max98396->vbat)
+ regulator_disable(max98396->vbat);
+err_pvdd:
+ if (max98396->pvdd)
+ regulator_disable(max98396->pvdd);
+err_core_supplies:
+ regulator_bulk_disable(MAX98396_NUM_CORE_SUPPLIES,
+ max98396->core_supplies);
+
+ return ret;
}
static const struct dev_pm_ops max98396_pm = {
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 0d7ac37850bb..20e288e38669 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -48,7 +48,6 @@ static int max9860_dvddio_event(struct notifier_block *nb,
}
static const struct reg_default max9860_reg_defaults[] = {
- { MAX9860_PWRMAN, 0x00 },
{ MAX9860_INTEN, 0x00 },
{ MAX9860_SYSCLK, 0x00 },
{ MAX9860_AUDIOCLKHIGH, 0x00 },
@@ -62,6 +61,7 @@ static const struct reg_default max9860_reg_defaults[] = {
{ MAX9860_MICGAIN, 0x00 },
{ MAX9860_MICADC, 0x00 },
{ MAX9860_NOISEGATE, 0x00 },
+ { MAX9860_PWRMAN, 0x00 },
};
static bool max9860_readable(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 65e6fdb30eec..524300d8fb0b 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -742,11 +742,17 @@ static int max98927_suspend(struct device *dev)
static int max98927_resume(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
+ int ret;
regmap_write(max98927->regmap, MAX98927_R0100_SOFT_RESET,
MAX98927_SOFT_RESET);
regcache_cache_only(max98927->regmap, false);
- regcache_sync(max98927->regmap);
+ ret = regcache_sync(max98927->regmap);
+ if (ret) {
+ regcache_cache_only(max98927->regmap, true);
+ regcache_mark_dirty(max98927->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
index 8a14626d43ff..7209b47c2029 100644
--- a/sound/soc/codecs/ml26124.c
+++ b/sound/soc/codecs/ml26124.c
@@ -224,7 +224,6 @@ static const struct reg_default ml26124_reg[] = {
/* Analog Path Control Register */
{0x54, 0x00}, /* Speaker AMP Output Control */
{0x5a, 0x00}, /* Mic IF Control */
- {0xe8, 0x01}, /* Mic Select Control */
/* Audio Interface Control Register */
{0x60, 0x00}, /* SAI-Trans Control */
@@ -287,6 +286,9 @@ static const struct reg_default ml26124_reg[] = {
{0xd0, 0x01}, /* VIDEO AMP Gain Control */
{0xd2, 0x01}, /* VIDEO AMP Setup 1 */
{0xd4, 0x01}, /* VIDEO AMP Control2 */
+
+ /* Analog Path Control Register */
+ {0xe8, 0x01}, /* Mic Select Control */
};
/* Get sampling rate value of sampling rate setting register (0x0) */
diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c
index 9ca381812975..87f8a47cc293 100644
--- a/sound/soc/codecs/msm8916-wcd-analog.c
+++ b/sound/soc/codecs/msm8916-wcd-analog.c
@@ -217,9 +217,11 @@
#define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195)
#define CDC_A_RX_HPH_BIAS_CNP (0xf196)
#define CDC_A_RX_HPH_CNP_EN (0xf197)
+#define CDC_A_RX_HPH_L_TEST (0xf19A)
#define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B)
#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1)
+#define CDC_A_RX_HPH_R_TEST (0xf19C)
#define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D)
#define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1)
#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1)
@@ -232,6 +234,8 @@
#define RX_EAR_CTL_PA_SEL_MASK BIT(7)
#define RX_EAR_CTL_PA_SEL BIT(7)
+#define CDC_A_RX_EAR_STATUS (0xf1A1)
+
#define CDC_A_SPKR_DAC_CTL (0xf1B0)
#define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4)
#define SPKR_DAC_CTL_DAC_RESET_NORMAL 0
@@ -250,6 +254,7 @@
SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \
SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \
SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET)
+#define CDC_A_SPKR_ANA_BIAS_SET (0xf1B3)
#define CDC_A_SPKR_OCP_CTL (0xf1B4)
#define CDC_A_SPKR_PWRSTG_CTL (0xf1B5)
#define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0)
@@ -264,6 +269,7 @@
#define CDC_A_SPKR_DRV_DBG (0xf1B7)
#define CDC_A_CURRENT_LIMIT (0xf1C0)
+#define CDC_A_BYPASS_MODE (0xf1C2)
#define CDC_A_BOOST_EN_CTL (0xf1C3)
#define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4)
#define CDC_A_SEC_ACCESS (0xf1D0)
@@ -286,6 +292,11 @@ static const char * const supply_names[] = {
#define MBHC_MAX_BUTTONS (5)
+struct wcd_reg_seq {
+ const struct reg_default *seq;
+ int seq_size;
+};
+
struct pm8916_wcd_analog_priv {
u16 pmic_rev;
u16 codec_version;
@@ -696,6 +707,59 @@ static int pm8916_wcd_analog_enable_ear_pa(struct snd_soc_dapm_widget *w,
return 0;
}
+static int pm8916_wcd_analog_enable_hphl_pa(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 pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+
+ /* This quirk is not required for revisions prior to CAJON_2_0 */
+ if (priv->codec_version < 4)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(7000, 7100);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST,
+ 0x04, 0x04);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* wait 20 ms after the digital codec has powered down */
+ msleep(20);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_L_TEST,
+ 0x04, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static int pm8916_wcd_analog_enable_hphr_pa(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 pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+
+ /* This quirk is not required for revisions prior to CAJON_2_0 */
+ if (priv->codec_version < 4)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ usleep_range(7000, 7100);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST,
+ 0x04, 0x04);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ msleep(20);
+ snd_soc_component_update_bits(component, CDC_A_RX_HPH_R_TEST,
+ 0x04, 0x00);
+ break;
+ }
+ return 0;
+}
+
static const struct reg_default wcd_reg_defaults_2_0[] = {
{CDC_A_RX_COM_OCP_CTL, 0xD1},
{CDC_A_RX_COM_OCP_COUNT, 0xFF},
@@ -715,9 +779,69 @@ static const struct reg_default wcd_reg_defaults_2_0[] = {
{CDC_A_MASTER_BIAS_CTL, 0x30},
};
+static const struct wcd_reg_seq pm8916_data = {
+ .seq = wcd_reg_defaults_2_0,
+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_2_0),
+};
+
+static const struct reg_default wcd_reg_defaults_pm8950[] = {
+ {CDC_A_RX_COM_OCP_CTL, 0xd1},
+ {CDC_A_RX_COM_OCP_COUNT, 0xff},
+ {CDC_D_SEC_ACCESS, 0xa5},
+ {CDC_D_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c},
+ {CDC_A_NCP_FBCTRL, 0xa8},
+ {CDC_A_NCP_VCTRL, 0xa4},
+ {CDC_A_SPKR_DRV_CTL, 0x69},
+ {CDC_A_SPKR_DRV_DBG, 0x01},
+ {CDC_A_SEC_ACCESS, 0xa5},
+ {CDC_A_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_CURRENT_LIMIT, 0x82},
+ {CDC_A_SPKR_ANA_BIAS_SET, 0x41},
+ {CDC_A_SPKR_DAC_CTL, 0x03},
+ {CDC_A_SPKR_OCP_CTL, 0xe1},
+ {CDC_A_RX_HPH_BIAS_PA, 0xfa},
+ {CDC_A_MASTER_BIAS_CTL, 0x30},
+ {CDC_A_MICB_1_INT_RBIAS, 0x00},
+};
+
+static const struct wcd_reg_seq pm8950_data = {
+ .seq = wcd_reg_defaults_pm8950,
+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8950),
+};
+
+static const struct reg_default wcd_reg_defaults_pm8953[] = {
+ {CDC_A_RX_COM_OCP_CTL, 0xd1},
+ {CDC_A_RX_COM_OCP_COUNT, 0xff},
+ {CDC_D_SEC_ACCESS, 0xa5},
+ {CDC_D_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_TX_1_2_OPAMP_BIAS, 0x4c},
+ {CDC_A_NCP_FBCTRL, 0xa8},
+ {CDC_A_NCP_VCTRL, 0xa4},
+ {CDC_A_SPKR_DRV_CTL, 0x69},
+ {CDC_A_SPKR_DRV_DBG, 0x01},
+ {CDC_A_SEC_ACCESS, 0xa5},
+ {CDC_A_PERPH_RESET_CTL3, 0x0f},
+ {CDC_A_CURRENT_LIMIT, 0xa2},
+ {CDC_A_BYPASS_MODE, 0x18},
+ {CDC_A_SPKR_ANA_BIAS_SET, 0x41},
+ {CDC_A_SPKR_DAC_CTL, 0x03},
+ {CDC_A_SPKR_OCP_CTL, 0xe1},
+ {CDC_A_RX_HPH_BIAS_PA, 0xfa},
+ {CDC_A_RX_EAR_STATUS, 0x10},
+ {CDC_A_MASTER_BIAS_CTL, 0x30},
+ {CDC_A_MICB_1_INT_RBIAS, 0x00},
+};
+
+static const struct wcd_reg_seq pm8953_data = {
+ .seq = wcd_reg_defaults_pm8953,
+ .seq_size = ARRAY_SIZE(wcd_reg_defaults_pm8953),
+};
+
static int pm8916_wcd_analog_probe(struct snd_soc_component *component)
{
struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(component->dev);
+ const struct wcd_reg_seq *wcd_reg_init_data;
int err, reg;
err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies);
@@ -738,9 +862,11 @@ static int pm8916_wcd_analog_probe(struct snd_soc_component *component)
snd_soc_component_write(component, CDC_D_PERPH_RESET_CTL4, 0x01);
snd_soc_component_write(component, CDC_A_PERPH_RESET_CTL4, 0x01);
- for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++)
- snd_soc_component_write(component, wcd_reg_defaults_2_0[reg].reg,
- wcd_reg_defaults_2_0[reg].def);
+ wcd_reg_init_data = of_device_get_match_data(component->dev);
+
+ for (reg = 0; reg < wcd_reg_init_data->seq_size; reg++)
+ snd_soc_component_write(component, wcd_reg_init_data->seq[reg].reg,
+ wcd_reg_init_data->seq[reg].def);
priv->component = component;
@@ -883,11 +1009,15 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = {
SND_SOC_DAPM_MUX("EAR_S", SND_SOC_NOPM, 0, 0, &ear_mux),
SND_SOC_DAPM_SUPPLY("EAR CP", CDC_A_NCP_EN, 4, 0, NULL, 0),
- SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+ pm8916_wcd_analog_enable_hphl_pa,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux),
SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL,
0),
- SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+ pm8916_wcd_analog_enable_hphr_pa,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux),
SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL,
0),
@@ -1259,7 +1389,9 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev)
}
static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = {
- { .compatible = "qcom,pm8916-wcd-analog-codec", },
+ { .compatible = "qcom,pm8916-wcd-analog-codec", .data = &pm8916_data },
+ { .compatible = "qcom,pm8950-wcd-analog-codec", .data = &pm8950_data },
+ { .compatible = "qcom,pm8953-wcd-analog-codec", .data = &pm8953_data },
{ }
};
diff --git a/sound/soc/codecs/mt6357.c b/sound/soc/codecs/mt6357.c
index 674cf7df9df4..3b07087e1cab 100644
--- a/sound/soc/codecs/mt6357.c
+++ b/sound/soc/codecs/mt6357.c
@@ -1834,8 +1834,8 @@ static int mt6357_platform_driver_probe(struct platform_device *pdev)
}
static const struct platform_device_id mt6357_platform_ids[] = {
- {"mt6357-sound", 0},
- { /* sentinel */ },
+ { .name = "mt6357-sound" },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, mt6357_platform_ids);
diff --git a/sound/soc/codecs/mt6359-accdet.c b/sound/soc/codecs/mt6359-accdet.c
index ed34cc15b80e..e1190c644021 100644
--- a/sound/soc/codecs/mt6359-accdet.c
+++ b/sound/soc/codecs/mt6359-accdet.c
@@ -6,6 +6,7 @@
// Author: Argus Lin <argus.lin@mediatek.com>
//
+#include <linux/cleanup.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/kthread.h>
@@ -398,14 +399,13 @@ static void mt6359_accdet_work(struct work_struct *work)
struct mt6359_accdet *priv =
container_of(work, struct mt6359_accdet, accdet_work);
- mutex_lock(&priv->res_lock);
+ guard(mutex)(&priv->res_lock);
priv->pre_accdet_status = priv->accdet_status;
check_jack_btn_type(priv);
if (priv->jack_plugged &&
priv->pre_accdet_status != priv->accdet_status)
mt6359_accdet_jack_report(priv);
- mutex_unlock(&priv->res_lock);
}
static void mt6359_accdet_jd_work(struct work_struct *work)
@@ -416,7 +416,7 @@ static void mt6359_accdet_jd_work(struct work_struct *work)
struct mt6359_accdet *priv =
container_of(work, struct mt6359_accdet, jd_work);
- mutex_lock(&priv->res_lock);
+ guard(mutex)(&priv->res_lock);
if (priv->jd_sts == M_PLUG_IN) {
priv->jack_plugged = true;
@@ -450,7 +450,6 @@ static void mt6359_accdet_jd_work(struct work_struct *work)
if (priv->caps & ACCDET_PMIC_EINT_IRQ)
recover_eint_setting(priv);
- mutex_unlock(&priv->res_lock);
}
static irqreturn_t mt6359_accdet_irq(int irq, void *data)
@@ -459,7 +458,7 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
unsigned int irq_val = 0, val = 0, value = 0;
int ret;
- mutex_lock(&priv->res_lock);
+ guard(mutex)(&priv->res_lock);
regmap_read(priv->regmap, ACCDET_IRQ_ADDR, &irq_val);
if (irq_val & ACCDET_IRQ_MASK_SFT) {
@@ -474,7 +473,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
1000);
if (ret) {
dev_err(priv->dev, "%s(), ret %d\n", __func__, ret);
- mutex_unlock(&priv->res_lock);
return IRQ_NONE;
}
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -498,7 +496,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
if (ret) {
dev_err(priv->dev, "%s(), ret %d\n", __func__,
ret);
- mutex_unlock(&priv->res_lock);
return IRQ_NONE;
}
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -521,7 +518,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
if (ret) {
dev_err(priv->dev, "%s(), ret %d\n", __func__,
ret);
- mutex_unlock(&priv->res_lock);
return IRQ_NONE;
}
regmap_update_bits(priv->regmap, ACCDET_IRQ_ADDR,
@@ -540,7 +536,6 @@ static irqreturn_t mt6359_accdet_irq(int irq, void *data)
queue_work(priv->jd_workqueue, &priv->jd_work);
}
- mutex_unlock(&priv->res_lock);
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/ntpfw.c b/sound/soc/codecs/ntpfw.c
index 5ced2e966ab7..b6443e24ae8e 100644
--- a/sound/soc/codecs/ntpfw.c
+++ b/sound/soc/codecs/ntpfw.c
@@ -89,7 +89,7 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
{
struct device *dev = &i2c->dev;
const struct ntpfw_chunk *chunk;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
const u8 *data;
size_t leftover;
int ret;
@@ -101,10 +101,8 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
return ret;
}
- if (!ntpfw_verify(dev, fw->data, fw->size, magic)) {
- ret = -EINVAL;
- goto done;
- }
+ if (!ntpfw_verify(dev, fw->data, fw->size, magic))
+ return -EINVAL;
data = fw->data + sizeof(struct ntpfw_header);
leftover = fw->size - sizeof(struct ntpfw_header);
@@ -112,23 +110,18 @@ int ntpfw_load(struct i2c_client *i2c, const char *name, u32 magic)
while (leftover) {
chunk = (struct ntpfw_chunk *)data;
- if (!ntpfw_verify_chunk(dev, chunk, leftover)) {
- ret = -EINVAL;
- goto done;
- }
+ if (!ntpfw_verify_chunk(dev, chunk, leftover))
+ return -EINVAL;
ret = ntpfw_send_chunk(i2c, chunk);
if (ret)
- goto done;
+ return ret;
data += be16_to_cpu(chunk->length) + sizeof(*chunk);
leftover -= be16_to_cpu(chunk->length) + sizeof(*chunk);
}
-done:
- release_firmware(fw);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(ntpfw_load);
diff --git a/sound/soc/codecs/ntpfw.h b/sound/soc/codecs/ntpfw.h
index 1cf10d5480ee..efbe9aa1eca5 100644
--- a/sound/soc/codecs/ntpfw.h
+++ b/sound/soc/codecs/ntpfw.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/**
+/*
* ntpfw.h - Firmware helper functions for Neofidelity codecs
*
* Copyright (c) 2024, SaluteDevices. All Rights Reserved.
@@ -13,10 +13,11 @@
/**
* ntpfw_load - load firmware to amplifier over i2c interface.
*
- * @i2c Pointer to amplifier's I2C client.
- * @name Firmware file name.
- * @magic Magic number to validate firmware.
- * @return 0 or error code upon error.
+ * @i2c: Pointer to amplifier's I2C client.
+ * @name: Firmware file name.
+ * @magic: Magic number to validate firmware.
+ *
+ * Returns: 0 or error code upon error.
*/
int ntpfw_load(struct i2c_client *i2c, const char *name, const u32 magic);
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index cb923cecb47f..60fdbe5c4e05 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -199,10 +199,17 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream,
return pcm1681_set_deemph(component);
}
+static const u64 pcm1681_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops pcm1681_dai_ops = {
.set_fmt = pcm1681_set_dai_fmt,
.hw_params = pcm1681_hw_params,
.mute_stream = pcm1681_mute,
+ .auto_selectable_formats = &pcm1681_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm1754.c b/sound/soc/codecs/pcm1754.c
index b68a528000be..bb15da1c24aa 100644
--- a/sound/soc/codecs/pcm1754.c
+++ b/sound/soc/codecs/pcm1754.c
@@ -78,10 +78,16 @@ static int pcm1754_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
return 0;
}
+static const u64 pcm1754_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
static const struct snd_soc_dai_ops pcm1754_dai_ops = {
.set_fmt = pcm1754_set_dai_fmt,
.hw_params = pcm1754_hw_params,
.mute_stream = pcm1754_mute_stream,
+ .auto_selectable_formats = &pcm1754_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static const struct snd_soc_dai_driver pcm1754_dai = {
diff --git a/sound/soc/codecs/pcm1789.c b/sound/soc/codecs/pcm1789.c
index 3ab381e9a856..f06e353743aa 100644
--- a/sound/soc/codecs/pcm1789.c
+++ b/sound/soc/codecs/pcm1789.c
@@ -164,11 +164,18 @@ static int pcm1789_trigger(struct snd_pcm_substream *substream, int cmd,
return ret;
}
+static const u64 pcm1789_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops pcm1789_dai_ops = {
.set_fmt = pcm1789_set_dai_fmt,
.hw_params = pcm1789_hw_params,
.mute_stream = pcm1789_mute,
.trigger = pcm1789_trigger,
+ .auto_selectable_formats = &pcm1789_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c
index f52ff66b6e64..cb70927872aa 100644
--- a/sound/soc/codecs/pcm179x.c
+++ b/sound/soc/codecs/pcm179x.c
@@ -142,10 +142,16 @@ static int pcm179x_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static const u64 pcm179x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J;
+
static const struct snd_soc_dai_ops pcm179x_dai_ops = {
.set_fmt = pcm179x_set_dai_fmt,
.hw_params = pcm179x_hw_params,
.mute_stream = pcm179x_mute,
+ .auto_selectable_formats = &pcm179x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm186x.c b/sound/soc/codecs/pcm186x.c
index 0d1103fe4e04..461ec74e8752 100644
--- a/sound/soc/codecs/pcm186x.c
+++ b/sound/soc/codecs/pcm186x.c
@@ -473,11 +473,20 @@ static int pcm186x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
return 0;
}
+static const u64 pcm186x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops pcm186x_dai_ops = {
.set_sysclk = pcm186x_set_dai_sysclk,
.set_tdm_slot = pcm186x_set_tdm_slot,
.set_fmt = pcm186x_set_fmt,
.hw_params = pcm186x_hw_params,
+ .auto_selectable_formats = &pcm186x_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver pcm1863_dai = {
diff --git a/sound/soc/codecs/pcm3060.c b/sound/soc/codecs/pcm3060.c
index 8974200652e7..f01c46583e89 100644
--- a/sound/soc/codecs/pcm3060.c
+++ b/sound/soc/codecs/pcm3060.c
@@ -164,10 +164,18 @@ val_ready:
return 0;
}
+static const u64 pcm3060_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_NB_NF;
+
static const struct snd_soc_dai_ops pcm3060_dai_ops = {
.set_sysclk = pcm3060_set_sysclk,
.set_fmt = pcm3060_set_fmt,
.hw_params = pcm3060_hw_params,
+ .auto_selectable_formats = &pcm3060_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
#define PCM3060_DAI_RATES_ADC (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index fe3b5011fa16..f3e20919042b 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -6,7 +6,7 @@
* Copyright 2014 Linaro Ltd
*/
-
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/clk.h>
@@ -78,28 +78,10 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_POWER, 0x00 },
{ PCM512x_MUTE, 0x00 },
{ PCM512x_DSP, 0x00 },
- { PCM512x_PLL_REF, 0x00 },
- { PCM512x_DAC_REF, 0x00 },
- { PCM512x_DAC_ROUTING, 0x11 },
- { PCM512x_DSP_PROGRAM, 0x01 },
- { PCM512x_CLKDET, 0x00 },
- { PCM512x_AUTO_MUTE, 0x00 },
- { PCM512x_ERROR_DETECT, 0x00 },
- { PCM512x_DIGITAL_VOLUME_1, 0x00 },
- { PCM512x_DIGITAL_VOLUME_2, 0x30 },
- { PCM512x_DIGITAL_VOLUME_3, 0x30 },
- { PCM512x_DIGITAL_MUTE_1, 0x22 },
- { PCM512x_DIGITAL_MUTE_2, 0x00 },
- { PCM512x_DIGITAL_MUTE_3, 0x07 },
- { PCM512x_OUTPUT_AMPLITUDE, 0x00 },
- { PCM512x_ANALOG_GAIN_CTRL, 0x00 },
- { PCM512x_UNDERVOLTAGE_PROT, 0x00 },
- { PCM512x_ANALOG_MUTE_CTRL, 0x00 },
- { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
- { PCM512x_VCOM_CTRL_1, 0x00 },
- { PCM512x_VCOM_CTRL_2, 0x01 },
{ PCM512x_BCLK_LRCLK_CFG, 0x00 },
{ PCM512x_MASTER_MODE, 0x7c },
+ { PCM512x_PLL_REF, 0x00 },
+ { PCM512x_DAC_REF, 0x00 },
{ PCM512x_GPIO_DACIN, 0x00 },
{ PCM512x_GPIO_PLLIN, 0x00 },
{ PCM512x_SYNCHRONIZE, 0x10 },
@@ -117,8 +99,26 @@ static const struct reg_default pcm512x_reg_defaults[] = {
{ PCM512x_FS_SPEED_MODE, 0x00 },
{ PCM512x_IDAC_1, 0x01 },
{ PCM512x_IDAC_2, 0x00 },
+ { PCM512x_ERROR_DETECT, 0x00 },
{ PCM512x_I2S_1, 0x02 },
{ PCM512x_I2S_2, 0x00 },
+ { PCM512x_DAC_ROUTING, 0x11 },
+ { PCM512x_DSP_PROGRAM, 0x01 },
+ { PCM512x_CLKDET, 0x00 },
+ { PCM512x_AUTO_MUTE, 0x00 },
+ { PCM512x_DIGITAL_VOLUME_1, 0x00 },
+ { PCM512x_DIGITAL_VOLUME_2, 0x30 },
+ { PCM512x_DIGITAL_VOLUME_3, 0x30 },
+ { PCM512x_DIGITAL_MUTE_1, 0x22 },
+ { PCM512x_DIGITAL_MUTE_2, 0x00 },
+ { PCM512x_DIGITAL_MUTE_3, 0x07 },
+ { PCM512x_OUTPUT_AMPLITUDE, 0x00 },
+ { PCM512x_ANALOG_GAIN_CTRL, 0x00 },
+ { PCM512x_UNDERVOLTAGE_PROT, 0x00 },
+ { PCM512x_ANALOG_MUTE_CTRL, 0x00 },
+ { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
+ { PCM512x_VCOM_CTRL_1, 0x00 },
+ { PCM512x_VCOM_CTRL_2, 0x01 },
};
static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -399,10 +399,9 @@ static int pcm512x_digital_playback_switch_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
- mutex_lock(&pcm512x->mutex);
+ guard(mutex)(&pcm512x->mutex);
ucontrol->value.integer.value[0] = !(pcm512x->mute & 0x4);
ucontrol->value.integer.value[1] = !(pcm512x->mute & 0x2);
- mutex_unlock(&pcm512x->mutex);
return 0;
}
@@ -414,7 +413,7 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
int ret, changed = 0;
- mutex_lock(&pcm512x->mutex);
+ guard(mutex)(&pcm512x->mutex);
if ((pcm512x->mute & 0x4) == (ucontrol->value.integer.value[0] << 2)) {
pcm512x->mute ^= 0x4;
@@ -430,13 +429,10 @@ static int pcm512x_digital_playback_switch_put(struct snd_kcontrol *kcontrol,
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
- mutex_unlock(&pcm512x->mutex);
return ret;
}
}
- mutex_unlock(&pcm512x->mutex);
-
return changed;
}
@@ -1465,7 +1461,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
int ret;
unsigned int mute_det;
- mutex_lock(&pcm512x->mutex);
+ guard(mutex)(&pcm512x->mutex);
if (mute) {
pcm512x->mute |= 0x1;
@@ -1475,7 +1471,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
if (ret != 0) {
dev_err(component->dev,
"Failed to set digital mute: %d\n", ret);
- goto unlock;
+ return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
@@ -1488,7 +1484,7 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
if (ret != 0) {
dev_err(component->dev,
"Failed to update digital mute: %d\n", ret);
- goto unlock;
+ return ret;
}
regmap_read_poll_timeout(pcm512x->regmap,
@@ -1499,18 +1495,24 @@ static int pcm512x_mute(struct snd_soc_dai *dai, int mute, int direction)
200, 10000);
}
-unlock:
- mutex_unlock(&pcm512x->mutex);
-
return ret;
}
+static const u64 pcm512x_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.startup = pcm512x_dai_startup,
.hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt,
.mute_stream = pcm512x_mute,
.set_bclk_ratio = pcm512x_set_bclk_ratio,
+ .auto_selectable_formats = &pcm512x_selectable_formats,
+ .num_auto_selectable_formats = 1,
.no_capture_mute = 1,
};
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index 4ac4448ac3c8..db85ae2f8aed 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -12,6 +12,7 @@
// Author: Shenghao Ding <shenghao-ding@ti.com>
//
+#include <linux/cleanup.h>
#include <linux/unaligned.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -605,7 +606,7 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
unsigned int reg = mc->reg;
unsigned int val;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
if (pcm_dev->chip_id == PCM1690) {
ret = pcmdev_dev_read(pcm_dev, dev_no, PCM1690_REG_MODE_CTRL,
@@ -613,18 +614,18 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
if (ret) {
dev_err(pcm_dev->dev, "%s: read mode err=%d\n",
__func__, ret);
- goto out;
+ return ret;
}
val &= PCM1690_REG_MODE_CTRL_DAMS_MSK;
/* Set to wide-range mode, before using vol ctrl. */
if (!val && vol_ctrl_type == PCMDEV_PCM1690_VOL_CTRL) {
ucontrol->value.integer.value[0] = -25500;
- goto out;
+ return ret;
}
/* Set to fine mode, before using fine vol ctrl. */
if (val && vol_ctrl_type == PCMDEV_PCM1690_FINE_VOL_CTRL) {
ucontrol->value.integer.value[0] = -12750;
- goto out;
+ return ret;
}
}
@@ -632,15 +633,14 @@ static int pcmdev_get_volsw(struct snd_kcontrol *kcontrol,
if (ret) {
dev_err(pcm_dev->dev, "%s: read err=%d\n",
__func__, ret);
- goto out;
+ return ret;
}
val = (val >> shift) & mask;
val = (val > max) ? max : val;
val = mc->invert ? max - val : val;
ucontrol->value.integer.value[0] = val;
-out:
- mutex_unlock(&pcm_dev->codec_lock);
+
return ret;
}
@@ -678,7 +678,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val, val_mask;
unsigned int reg = mc->reg;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
val = ucontrol->value.integer.value[0] & mask;
val = (val > max) ? max : val;
val = mc->invert ? max - val : val;
@@ -702,7 +702,7 @@ static int pcmdev_put_volsw(struct snd_kcontrol *kcontrol,
__func__, rc);
else
rc = 1;
- mutex_unlock(&pcm_dev->codec_lock);
+
return rc;
}
@@ -1577,10 +1577,10 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp)
{
struct pcmdevice_priv *pcm_dev = snd_soc_component_get_drvdata(comp);
struct i2c_adapter *adap = pcm_dev->client->adapter;
- const struct firmware *fw_entry = NULL;
+ const struct firmware *fw_entry __free(firmware) = NULL;
int ret, i, j;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
pcm_dev->component = comp;
@@ -1588,7 +1588,7 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp)
for (j = 0; j < 2; j++) {
ret = pcmdev_gain_ctrl_add(pcm_dev, i, j);
if (ret < 0)
- goto out;
+ return ret;
}
}
@@ -1621,21 +1621,17 @@ static int pcmdevice_comp_probe(struct snd_soc_component *comp)
if (ret) {
dev_err(pcm_dev->dev, "%s: request %s err = %d\n", __func__,
pcm_dev->bin_name, ret);
- goto out;
+ return ret;
}
ret = pcmdev_regbin_ready(fw_entry, pcm_dev);
if (ret) {
dev_err(pcm_dev->dev, "%s: %s parse err = %d\n", __func__,
pcm_dev->bin_name, ret);
- goto out;
+ return ret;
}
- ret = pcmdev_profile_ctrl_add(pcm_dev);
-out:
- release_firmware(fw_entry);
- mutex_unlock(&pcm_dev->codec_lock);
- return ret;
+ return pcmdev_profile_ctrl_add(pcm_dev);
}
@@ -1645,9 +1641,8 @@ static void pcmdevice_comp_remove(struct snd_soc_component *codec)
if (!pcm_dev)
return;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
pcmdevice_config_info_remove(pcm_dev);
- mutex_unlock(&pcm_dev->codec_lock);
}
static const struct snd_soc_dapm_widget pcmdevice_dapm_widgets[] = {
@@ -1890,9 +1885,9 @@ static int pcmdevice_mute(struct snd_soc_dai *dai, int mute, int stream)
else
block_type = PCMDEVICE_BIN_BLK_PRE_POWER_UP;
- mutex_lock(&pcm_dev->codec_lock);
+ guard(mutex)(&pcm_dev->codec_lock);
pcmdevice_select_cfg_blk(pcm_dev, pcm_dev->cur_conf, block_type);
- mutex_unlock(&pcm_dev->codec_lock);
+
return 0;
}
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index 2d71d204d8fa..f1ded68c2d75 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -6,6 +6,7 @@
//
// Author: Herve Codina <herve.codina@bootlin.com>
+#include <linux/cleanup.h>
#include <linux/unaligned.h>
#include <linux/clk.h>
#include <linux/firmware.h>
@@ -1537,17 +1538,14 @@ static int peb2466_fw_parse(struct snd_soc_component *component,
static int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw, fw_name, component->dev);
if (ret)
return ret;
- ret = peb2466_fw_parse(component, fw->data, fw->size);
- release_firmware(fw);
-
- return ret;
+ return peb2466_fw_parse(component, fw->data, fw->size);
}
static int peb2466_component_probe(struct snd_soc_component *component)
@@ -1704,13 +1702,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x
* So, a specific cache value is used.
*/
- mutex_lock(&peb2466->gpio.lock);
+ guard(mutex)(&peb2466->gpio.lock);
cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg);
- if (!cache) {
- ret = -EINVAL;
- goto end;
- }
+ if (!cache)
+ return -EINVAL;
tmp = *cache;
tmp &= ~mask;
@@ -1718,14 +1714,11 @@ static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int x
ret = regmap_write(peb2466->regmap, xr_reg, tmp);
if (ret)
- goto end;
+ return ret;
*cache = tmp;
- ret = 0;
-end:
- mutex_unlock(&peb2466->gpio.lock);
- return ret;
+ return 0;
}
static int peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset,
diff --git a/sound/soc/codecs/pm4125-sdw.c b/sound/soc/codecs/pm4125-sdw.c
index 1c612ae4a4b2..182ff396301a 100644
--- a/sound/soc/codecs/pm4125-sdw.c
+++ b/sound/soc/codecs/pm4125-sdw.c
@@ -126,8 +126,8 @@ static const struct reg_default pm4125_defaults[] = {
{ PM4125_ANA_HPHPA_FSM_CLK, 0x12 },
{ PM4125_ANA_HPHPA_L_GAIN, 0x00 },
{ PM4125_ANA_HPHPA_R_GAIN, 0x00 },
- { PM4125_SWR_HPHPA_HD2, 0x1B },
{ PM4125_ANA_HPHPA_SPARE_CTL, 0x02 },
+ { PM4125_SWR_HPHPA_HD2, 0x1B },
{ PM4125_ANA_SURGE_EN, 0x38 },
{ PM4125_ANA_COMBOPA_CTL, 0x35 },
{ PM4125_ANA_COMBOPA_CTL_4, 0x84 },
@@ -464,10 +464,16 @@ static int __maybe_unused pm4125_sdw_runtime_suspend(struct device *dev)
static int __maybe_unused pm4125_sdw_runtime_resume(struct device *dev)
{
struct pm4125_sdw_priv *priv = dev_get_drvdata(dev);
+ int ret;
if (priv->regmap) {
regcache_cache_only(priv->regmap, false);
- regcache_sync(priv->regmap);
+ ret = regcache_sync(priv->regmap);
+ if (ret) {
+ regcache_cache_only(priv->regmap, true);
+ regcache_mark_dirty(priv->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/pm4125.c b/sound/soc/codecs/pm4125.c
index 29655175ea28..674a2fbc4eda 100644
--- a/sound/soc/codecs/pm4125.c
+++ b/sound/soc/codecs/pm4125.c
@@ -5,6 +5,7 @@
#include <linux/component.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -1295,7 +1296,7 @@ static const struct irq_domain_ops pm4125_domain_ops = {
static int pm4125_irq_init(struct pm4125_priv *pm4125, struct device *dev)
{
- pm4125->virq = irq_domain_add_linear(NULL, 1, &pm4125_domain_ops, NULL);
+ pm4125->virq = irq_domain_create_linear(NULL, 1, &pm4125_domain_ops, NULL);
if (!(pm4125->virq)) {
dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
return -EINVAL;
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index 95405cea8143..caf75e5657ef 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -784,7 +784,12 @@ static int rt1017_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt1017->regmap, false);
- regcache_sync(rt1017->regmap);
+ ret = regcache_sync(rt1017->regmap);
+ if (ret) {
+ regcache_cache_only(rt1017->regmap, true);
+ regcache_mark_dirty(rt1017->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.h b/sound/soc/codecs/rt1017-sdca-sdw.h
index 4932b5dbe3c0..1604e1cfd85e 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.h
+++ b/sound/soc/codecs/rt1017-sdca-sdw.h
@@ -165,19 +165,19 @@ static const struct reg_default rt1017_sdca_reg_defaults[] = {
{ 0xdb09, 0x0f },
{ 0xdb0a, 0xff },
{ 0xdb14, 0x00 },
-
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
- RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_FU,
RT1017_SDCA_CTL_FU_MUTE, 0x01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_XU22,
RT1017_SDCA_CTL_BYPASS, 0), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
- RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE23,
RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_PDE22,
RT1017_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_UDMPU21,
+ RT1017_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1017_SDCA_ENT_CS21,
+ RT1017_SDCA_CTL_FS_INDEX, 0), 0x09 },
};
#endif /* __RT1017_SDW_H__ */
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index ca318dbd946e..2ef47a82c984 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -59,13 +59,13 @@ static const struct reg_default rt1316_reg_defaults[] = {
{ 0xd101, 0x00 },
{ 0xd102, 0x30 },
{ 0xd103, 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_FU21, RT1316_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_XU24, RT1316_SDCA_CTL_BYPASS, 0), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE23, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE22, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_PDE24, RT1316_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1316_SDCA_ENT_UDMPU21, RT1316_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
};
static const struct reg_sequence rt1316_blind_write[] = {
@@ -756,7 +756,12 @@ static int rt1316_dev_resume(struct device *dev)
}
regcache_cache_only(rt1316->regmap, false);
- regcache_sync(rt1316->regmap);
+ ret = regcache_sync(rt1316->regmap);
+ if (ret) {
+ regcache_cache_only(rt1316->regmap, true);
+ regcache_mark_dirty(rt1316->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index c038ac0e3b76..efadb6b1b82d 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -235,10 +235,10 @@ static const struct reg_default rt1318_reg_defaults[] = {
{ 0xf805, 0x00 },
{ 0xf806, 0x07 },
{ 0xf807, 0xff },
- { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_FU21, RT1318_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_PDE23, RT1318_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_UDMPU21, RT1318_SDCA_CTL_UDMPU_CLUSTER, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, RT1318_SDCA_ENT_CS21, RT1318_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
};
@@ -830,7 +830,12 @@ static int rt1318_dev_resume(struct device *dev)
return ret;
regcache_cache_only(rt1318->regmap, false);
- regcache_sync(rt1318->regmap);
+ ret = regcache_sync(rt1318->regmap);
+ if (ret) {
+ regcache_cache_only(rt1318->regmap, true);
+ regcache_mark_dirty(rt1318->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
index d13fd0e14125..55607f1b9a1e 100644
--- a/sound/soc/codecs/rt1318.c
+++ b/sound/soc/codecs/rt1318.c
@@ -337,6 +337,8 @@ static const struct reg_default rt1318_reg[] = {
{ 0xdd08, 0x40 },
{ 0xdd12, 0x00 },
{ 0xdd35, 0x00 },
+ { 0xdd93, 0x00 },
+ { 0xdd94, 0x64 },
{ 0xddb5, 0x00 },
{ 0xddb6, 0x40 },
{ 0xddb7, 0x00 },
@@ -345,8 +347,6 @@ static const struct reg_default rt1318_reg[] = {
{ 0xddc6, 0x00 },
{ 0xddc7, 0x00 },
{ 0xddc8, 0x00 },
- { 0xdd93, 0x00 },
- { 0xdd94, 0x64 },
{ 0xdf00, 0x00 },
{ 0xdf5f, 0x00 },
{ 0xdf60, 0x00 },
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 42acb6cef77a..90333779971d 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -410,6 +410,402 @@ static const struct reg_sequence rt1321_blind_write[] = {
{ 0x41001988, 0x03 },
};
+static const struct reg_sequence rt1321_va1_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca06, 0x11 },
+ { 0x0000ca07, 0x1e },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca26, 0x11 },
+ { 0x0000ca27, 0x1e },
+ { 0x0000cd00, 0x05 },
+ { 0x0000cd81, 0x49 },
+ { 0x0000cd82, 0x49 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x3d },
+ { 0x0000d474, 0x11 },
+ { 0x0000d475, 0x32 },
+ { 0x0000d476, 0x64 },
+ { 0x0000d477, 0x10 },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x0000d73c, 0xb7 },
+ { 0x0000d73d, 0xd7 },
+ { 0x0000d73e, 0x00 },
+ { 0x0000d73f, 0x10 },
+ { 0x1000cd56, 0x00 },
+ { 0x3fc2dfc0, 0x03 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2df80, 0x00 },
+ { 0x3fc2df81, 0x00 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df83, 0x00 },
+ { 0x0000d541, 0x40 },
+ { 0x0000d486, 0x43 },
+ { 0x1000db00, 0x04 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x0d },
+ { 0x1000db07, 0x01 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0xbf },
+ { 0x1000db0b, 0x0b },
+ { 0x1000db0c, 0x11 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x1000db10, 0x2c },
+ { 0x1000db11, 0xfa },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x09 },
+ { 0x0000d540, 0x21 },
+ { 0x0000c570, 0x08 },
+ { 0x0000d714, 0x17 },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c8, 0x03 },
+ { 0x20009012, 0x00 },
+ { 0x0000dd08, 0x17 },
+ { 0x0000dd09, 0x0e },
+ { 0x0000dd0a, 0x17 },
+ { 0x0000dd0b, 0x0e },
+ { 0x0000c570, 0x08 },
+ { 0x0000d471, 0x3a },
+ { 0x0000db00, 0x00 },
+ { 0x0000db01, 0x00 },
+ { 0x0000db02, 0x73 },
+ { 0x0000db03, 0x00 },
+ { 0x0000db04, 0x00 },
+ { 0x0000db05, 0x00 },
+ { 0x0000db06, 0x00 },
+ { 0x0000db07, 0x00 },
+ { 0x0000db08, 0x7f },
+ { 0x0000db09, 0x00 },
+ { 0x0000db1a, 0x00 },
+ { 0x0000db1b, 0x00 },
+ { 0x0000db19, 0x00 },
+};
+
+static const struct reg_sequence rt1321_va2_blind_write[] = {
+ { 0x0000c003, 0xf0 },
+ { 0x0000c01b, 0xfc },
+ { 0x0000c5c3, 0xf2 },
+ { 0x0000c5c2, 0x00 },
+ { 0x0000c5c1, 0x10 },
+ { 0x0000c5c0, 0x04 },
+ { 0x0000c5c7, 0x03 },
+ { 0x0000c5c6, 0x10 },
+ { 0x0000c526, 0x47 },
+ { 0x0000c5c4, 0x12 },
+ { 0x0000c5c5, 0x60 },
+ { 0x0000c520, 0x10 },
+ { 0x0000c521, 0x32 },
+ { 0x0000c5c7, 0x00 },
+ { 0x0000c5c8, 0x03 },
+ { 0x0000c5d3, 0x08 },
+ { 0x0000c5d2, 0x0a },
+ { 0x0000c5d1, 0x49 },
+ { 0x0000c5d0, 0x0f },
+ { 0x0000c580, 0x10 },
+ { 0x0000c581, 0x32 },
+ { 0x0000c582, 0x01 },
+ { 0x0000c682, 0x60 },
+ { 0x0000c019, 0x10 },
+ { 0x0000c5f0, 0x01 },
+ { 0x0000c5f7, 0x22 },
+ { 0x0000c5f6, 0x22 },
+ { 0x0000c057, 0x51 },
+ { 0x0000c054, 0x55 },
+ { 0x0000c053, 0x55 },
+ { 0x0000c052, 0x55 },
+ { 0x0000c051, 0x01 },
+ { 0x0000c050, 0x15 },
+ { 0x0000c060, 0x99 },
+ { 0x0000c030, 0x55 },
+ { 0x0000c061, 0x55 },
+ { 0x0000c063, 0x55 },
+ { 0x0000c065, 0xa5 },
+ { 0x0000c06b, 0x0a },
+ { 0x0000ca05, 0xd6 },
+ { 0x0000ca06, 0x11 },
+ { 0x0000ca07, 0x1e },
+ { 0x0000ca25, 0xd6 },
+ { 0x0000ca26, 0x11 },
+ { 0x0000ca27, 0x1e },
+ { 0x0000cd00, 0x05 },
+ { 0x0000cd81, 0x49 },
+ { 0x0000cd82, 0x49 },
+ { 0x0000c604, 0x40 },
+ { 0x0000c609, 0x40 },
+ { 0x0000c046, 0xf7 },
+ { 0x0000c045, 0xff },
+ { 0x0000c044, 0xff },
+ { 0x0000c043, 0xff },
+ { 0x0000c042, 0xff },
+ { 0x0000c041, 0xff },
+ { 0x0000c040, 0xff },
+ { 0x0000c049, 0xff },
+ { 0x0000c028, 0x3f },
+ { 0x0000c020, 0x3f },
+ { 0x0000c032, 0x13 },
+ { 0x0000c033, 0x01 },
+ { 0x0000cc10, 0x01 },
+ { 0x0000dc20, 0x03 },
+ { 0x0000de03, 0x05 },
+ { 0x0000dc00, 0x00 },
+ { 0x0000c700, 0xf0 },
+ { 0x0000c701, 0x13 },
+ { 0x0000c900, 0xc3 },
+ { 0x0000c570, 0x08 },
+ { 0x0000c086, 0x02 },
+ { 0x0000c085, 0x7f },
+ { 0x0000c084, 0x00 },
+ { 0x0000c081, 0xff },
+ { 0x0000f084, 0x0f },
+ { 0x0000f083, 0xff },
+ { 0x0000f082, 0xff },
+ { 0x0000f081, 0xff },
+ { 0x0000f080, 0xff },
+ { 0x20003003, 0x3f },
+ { 0x20005818, 0x81 },
+ { 0x20009018, 0x81 },
+ { 0x2000301c, 0x81 },
+ { 0x0000c003, 0xc0 },
+ { 0x0000c047, 0x80 },
+ { 0x0000d541, 0x80 },
+ { 0x0000d487, 0x0b },
+ { 0x0000d487, 0x3b },
+ { 0x0000d486, 0xc3 },
+ { 0x0000d470, 0x89 },
+ { 0x0000d471, 0x3a },
+ { 0x0000d472, 0x3d },
+ { 0x0000d474, 0x11 },
+ { 0x0000d475, 0x32 },
+ { 0x0000d476, 0x64 },
+ { 0x0000d477, 0x10 },
+ { 0x0000d478, 0xff },
+ { 0x0000d479, 0x20 },
+ { 0x0000d47a, 0x10 },
+ { 0x10008000, 0x67 },
+ { 0x10008001, 0x80 },
+ { 0x10008002, 0x00 },
+ { 0x10008003, 0x00 },
+ { 0x1000cd56, 0x00 },
+ { 0x0000d486, 0x43 },
+ { 0x3fc2dfc3, 0x00 },
+ { 0x3fc2dfc2, 0x00 },
+ { 0x3fc2dfc1, 0x00 },
+ { 0x3fc2dfc0, 0x03 },
+ { 0x3fc2dfc7, 0x00 },
+ { 0x3fc2dfc6, 0x00 },
+ { 0x3fc2dfc5, 0x00 },
+ { 0x3fc2dfc4, 0x01 },
+ { 0x3fc2dfa3, 0x00 },
+ { 0x3fc2dfa2, 0x00 },
+ { 0x3fc2dfa1, 0x00 },
+ { 0x3fc2dfa0, 0x00 },
+ { 0x3fc2df80, 0x10 },
+ { 0x3fc2df81, 0x20 },
+ { 0x3fc2df82, 0x00 },
+ { 0x3fc2df83, 0x00 },
+ { 0x3fc2df84, 0x50 },
+ { 0x3fc2df85, 0x19 },
+ { 0x3fc2df86, 0x00 },
+ { 0x3fc2df87, 0x00 },
+ { 0x3fc2df88, 0x52 },
+ { 0x3fc2df89, 0x23 },
+ { 0x3fc2df8a, 0x00 },
+ { 0x3fc2df8b, 0x00 },
+ { 0x3fc2df8c, 0xe0 },
+ { 0x3fc2df8d, 0x2e },
+ { 0x3fc2df8e, 0x00 },
+ { 0x3fc2df8f, 0x00 },
+ { 0x3fc2df90, 0xe0 },
+ { 0x3fc2df91, 0x2e },
+ { 0x3fc2df92, 0x00 },
+ { 0x3fc2df93, 0x00 },
+ { 0x3fc2df94, 0x01 },
+ { 0x3fc2df95, 0x08 },
+ { 0x3fc2df96, 0x00 },
+ { 0x3fc2df97, 0x00 },
+ { 0x3fc2df40, 0x80 },
+ { 0x3fc2df41, 0xbb },
+ { 0x3fc2df42, 0x00 },
+ { 0x3fc2df43, 0x00 },
+ { 0x3fc2df44, 0xc0 },
+ { 0x3fc2df45, 0x99 },
+ { 0x3fc2df46, 0x01 },
+ { 0x3fc2df47, 0x00 },
+ { 0x3fc2df48, 0x00 },
+ { 0x3fc2df49, 0x00 },
+ { 0x3fc2df4a, 0x00 },
+ { 0x3fc2df4b, 0x00 },
+ { 0x3fc2df4c, 0x00 },
+ { 0x3fc2df4d, 0x00 },
+ { 0x3fc2df4e, 0x00 },
+ { 0x3fc2df4f, 0x00 },
+ { 0x3fc2df50, 0x01 },
+ { 0x3fc2df51, 0x00 },
+ { 0x3fc2df52, 0x00 },
+ { 0x3fc2df53, 0x00 },
+ { 0x3fc2df54, 0x01 },
+ { 0x3fc2df55, 0x00 },
+ { 0x3fc2df56, 0x00 },
+ { 0x3fc2df57, 0x00 },
+ { 0x3fc2df58, 0x00 },
+ { 0x3fc2df59, 0x00 },
+ { 0x3fc2df5a, 0x00 },
+ { 0x3fc2df5b, 0x00 },
+ { 0x3fc2df5c, 0x01 },
+ { 0x3fc2df5d, 0x00 },
+ { 0x3fc2df5e, 0x00 },
+ { 0x3fc2df5f, 0x00 },
+ { 0x3fc2df60, 0x00 },
+ { 0x3fc2df61, 0x00 },
+ { 0x3fc2df62, 0x00 },
+ { 0x3fc2df63, 0x00 },
+ { 0x3fc2df64, 0x00 },
+ { 0x3fc2df65, 0x00 },
+ { 0x3fc2df66, 0x00 },
+ { 0x3fc2df67, 0x10 },
+ { 0x3fc2df68, 0x01 },
+ { 0x3fc2df69, 0x00 },
+ { 0x3fc2df6a, 0x00 },
+ { 0x3fc2df6b, 0x00 },
+ { 0x3fc2df6c, 0x01 },
+ { 0x3fc2df6d, 0x00 },
+ { 0x3fc2df6e, 0x00 },
+ { 0x3fc2df6f, 0x00 },
+ { 0x3fc2df70, 0x04 },
+ { 0x3fc2df71, 0x00 },
+ { 0x3fc2df72, 0x00 },
+ { 0x3fc2df73, 0x00 },
+ { 0x3fc2df74, 0x01 },
+ { 0x3fc2df75, 0x00 },
+ { 0x3fc2df76, 0x00 },
+ { 0x3fc2df77, 0x00 },
+ { 0x1000db00, 0x04 },
+ { 0x1000db01, 0x00 },
+ { 0x1000db02, 0x10 },
+ { 0x1000db03, 0x00 },
+ { 0x1000db04, 0x00 },
+ { 0x1000db05, 0x45 },
+ { 0x1000db06, 0x0d },
+ { 0x1000db07, 0x01 },
+ { 0x1000db08, 0x00 },
+ { 0x1000db09, 0x00 },
+ { 0x1000db0a, 0xbf },
+ { 0x1000db0b, 0x0b },
+ { 0x1000db0c, 0x11 },
+ { 0x1000db0d, 0x00 },
+ { 0x1000db0e, 0x00 },
+ { 0x1000db0f, 0x00 },
+ { 0x1000db10, 0x2c },
+ { 0x1000db11, 0xfa },
+ { 0x1000db12, 0x00 },
+ { 0x1000db13, 0x00 },
+ { 0x1000db14, 0x09 },
+ { 0x0000d540, 0x21 },
+ { 0x0000d714, 0x17 },
+ { 0x0000dd0b, 0x0d },
+ { 0x0000dd0a, 0xff },
+ { 0x0000dd09, 0x0d },
+ { 0x0000dd08, 0xff },
+ { 0x0000c5fb, 0x12 },
+ { 0x0000c570, 0x08 },
+};
+
static const struct reg_default rt1320_reg_defaults[] = {
{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
@@ -440,6 +836,7 @@ static const struct reg_default rt1320_mbq_defaults[] = {
static bool rt1320_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case 0x004d:
case 0xc000 ... 0xc086:
case 0xc400 ... 0xc409:
case 0xc480 ... 0xc48f:
@@ -497,10 +894,15 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg)
case RT1321_PATCH_MAIN_VER ... RT1321_PATCH_BETA_VER:
case 0x1000f008:
case 0x1000f021:
- case 0x2000300f:
+ case 0x20003000 ... 0x2000300f:
case 0x2000301c:
- case 0x2000900f:
+ case 0x20003040 ... 0x20003059:
+ case 0x20005800 ... 0x2000580f:
+ case 0x20005818:
+ case 0x20005840 ... 0x20005859:
+ case 0x20009000 ... 0x2000900f:
case 0x20009018:
+ case 0x20009040 ... 0x20009059:
case 0x3fc000c0 ... 0x3fc2dfc8:
case 0x3fe00000 ... 0x3fe36fff:
/* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */
@@ -545,6 +947,7 @@ static bool rt1320_readable_register(struct device *dev, unsigned int reg)
static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case 0x004d:
case 0xc000:
case 0xc003:
case 0xc081:
@@ -596,15 +999,20 @@ static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
case 0x1000c000 ... 0x1000dfff:
case 0x1000f008:
case 0x1000f021:
- case 0x2000300f:
+ case 0x2000300e ... 0x2000300f:
case 0x2000301c:
- case 0x2000900f:
+ case 0x20003040 ... 0x20003059:
+ case 0x2000580e ... 0x2000580f:
+ case 0x20005818:
+ case 0x20005840 ... 0x20005859:
+ case 0x2000900e ... 0x2000900f:
case 0x20009018:
+ case 0x20009040 ... 0x20009059:
case 0x3fc2ab80 ... 0x3fc2ac4c:
case 0x3fc2b780:
case 0x3fc2bf80 ... 0x3fc2bf83:
case 0x3fc2bfc0 ... 0x3fc2bfc8:
- case 0x3fc2d300 ... 0x3fc2d354:
+ case 0x3fc2d300 ... 0x3fc2d3cc:
case 0x3fc2dfc0 ... 0x3fc2dfc8:
case 0x3fe2e000 ... 0x3fe2e003:
case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
@@ -892,6 +1300,42 @@ static int rt1320_check_fw_ready(struct rt1320_sdw_priv *rt1320)
return 0;
}
+static int rt1320_dspfw_status(struct rt1320_sdw_priv *rt1320)
+{
+ struct device *dev = &rt1320->sdw_slave->dev;
+ unsigned int fw_status_addr, fw_ready;
+ unsigned int dspfw_run;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
+ break;
+ case RT1321_DEV_ID:
+ fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+
+ regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
+ fw_ready &= 0x1;
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_read(rt1320->regmap, 0xf01e, &dspfw_run);
+ dspfw_run &= 0x1;
+ fw_ready = (!dspfw_run && fw_ready);
+ }
+
+ if (fw_ready) {
+ dev_dbg(dev, "%s, DSP FW was already\n", __func__);
+ return 1;
+ }
+
+ dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__);
+ return 0;
+}
+
static int rt1320_check_power_state_ready(struct rt1320_sdw_priv *rt1320, enum rt1320_power_state ps)
{
struct device *dev = &rt1320->sdw_slave->dev;
@@ -982,6 +1426,9 @@ static int rt1320_fw_param_protocol(struct rt1320_sdw_priv *rt1320, enum rt1320_
if (!tempbuf)
return -ENOMEM;
+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2)
+ paramid += 0x0bff0000;
+
paramhr.moudleid = 1;
paramhr.commandtype = cmdid;
/* 8 is "sizeof(paramid) + sizeof(paramlength)" */
@@ -1120,45 +1567,73 @@ static void rt1320_calc_r0(struct rt1320_sdw_priv *rt1320)
l_calir0, l_calir0_lo, r_calir0, r_calir0_lo);
}
+static int rt1320_pilot_tone_output(struct rt1320_sdw_priv *rt1320)
+{
+ struct device *dev = &rt1320->sdw_slave->dev;
+ int l_targetpostgain, r_targetpostgain;
+ unsigned long long factor = (1 << 12);
+ int l_pilotgain[9], r_pilotgain[9];
+ const int postgain_step = 234;
+ int targetGain;
+
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ targetGain = -320000;
+ break;
+ case RT1321_DEV_ID:
+ targetGain = -420000;
+ if (rt1320->version_id == RT1321_VA0)
+ targetGain = -320000;
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
+ }
+
+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 70, &l_pilotgain[0], sizeof(l_pilotgain));
+ rt1320_fw_param_protocol(rt1320, RT1320_GET_PARAM, 71, &r_pilotgain[0], sizeof(r_pilotgain));
+ dev_dbg(dev, "%s, LR pilotgain %d, %d\n", __func__, l_pilotgain[2], r_pilotgain[2]);
+
+ /* calculate pilot tone gain */
+ l_pilotgain[2] = (l_pilotgain[2] * 10000) / factor;
+ r_pilotgain[2] = (r_pilotgain[2] * 10000) / factor;
+
+ /* calculate post gain to meet target gain */
+ l_targetpostgain = abs(targetGain - l_pilotgain[2]) / postgain_step;
+ r_targetpostgain = abs(targetGain - r_pilotgain[2]) / postgain_step;
+ l_targetpostgain = 0xfff - l_targetpostgain;
+ r_targetpostgain = 0xfff - r_targetpostgain;
+ dev_dbg(dev, "%s, LR targetpostgain=0x%x, 0x%x\n", __func__, l_targetpostgain, r_targetpostgain);
+
+ regmap_write(rt1320->regmap, 0xdd0b, (l_targetpostgain & 0xf00) >> 8);
+ regmap_write(rt1320->regmap, 0xdd0a, l_targetpostgain & 0xff);
+ regmap_write(rt1320->regmap, 0xdd09, (r_targetpostgain & 0xf00) >> 8);
+ regmap_write(rt1320->regmap, 0xdd08, r_targetpostgain & 0xff);
+
+ return 0;
+}
+
static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
{
struct device *dev = &rt1320->sdw_slave->dev;
struct rt1320_datafixpoint audfixpoint[2];
unsigned int reg_c5fb, reg_c570, reg_cd00;
- unsigned int vol_reg[4], fw_ready;
+ unsigned int vol_reg[4];
unsigned long long l_meanr0, r_meanr0;
- unsigned int fw_status_addr;
int l_re[5], r_re[5];
int ret, tmp;
unsigned long long factor = (1 << 27);
unsigned short l_advancegain, r_advancegain;
unsigned int delay_s = 7; /* delay seconds for the calibration */
+ int dspfw_status;
if (!rt1320->component)
return;
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
-
- /* set volume 0dB */
regmap_read(rt1320->regmap, 0xdd0b, &vol_reg[3]);
regmap_read(rt1320->regmap, 0xdd0a, &vol_reg[2]);
regmap_read(rt1320->regmap, 0xdd09, &vol_reg[1]);
regmap_read(rt1320->regmap, 0xdd08, &vol_reg[0]);
- regmap_write(rt1320->regmap, 0xdd0b, 0x0f);
- regmap_write(rt1320->regmap, 0xdd0a, 0xff);
- regmap_write(rt1320->regmap, 0xdd09, 0x0f);
- regmap_write(rt1320->regmap, 0xdd08, 0xff);
-
regmap_read(rt1320->regmap, 0xc5fb, &reg_c5fb);
regmap_read(rt1320->regmap, 0xc570, &reg_c570);
regmap_read(rt1320->regmap, 0xcd00, &reg_cd00);
@@ -1171,9 +1646,8 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
goto _finish_;
}
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_dbg(dev, "%s, DSP FW is NOT ready. Please load DSP FW first\n", __func__);
goto _finish_;
}
@@ -1184,8 +1658,19 @@ static void rt1320_calibrate(struct rt1320_sdw_priv *rt1320)
goto _finish_;
}
- if (rt1320->dev_id == RT1320_DEV_ID)
- regmap_write(rt1320->regmap, 0xc5fb, 0x00);
+ /* fine tune pilot tone output */
+ ret = rt1320_pilot_tone_output(rt1320);
+ if (ret < 0) {
+ dev_dbg(dev, "%s, Failed to tune pilot tone output\n", __func__);
+ goto _finish_;
+ }
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00);
+ regmap_write(rt1320->regmap, 0xc5c4, 0x12);
+ }
+
+ regmap_write(rt1320->regmap, 0xc5fb, 0x00);
regmap_write(rt1320->regmap, 0xc570, 0x0b);
regmap_write(rt1320->regmap, 0xcd00, 0xc5);
@@ -1246,6 +1731,11 @@ _finish_:
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x03);
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
+ regmap_write(rt1320->regmap, 0xc5c4, 0x10);
+ }
+
/* advance gain will be set when R0 load, not here */
regmap_write(rt1320->regmap, 0xdd0b, vol_reg[3]);
regmap_write(rt1320->regmap, 0xdd0a, vol_reg[2]);
@@ -1296,7 +1786,7 @@ static int rt1320_r0_cali_put(struct snd_kcontrol *kcontrol,
static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
{
struct sdw_slave *slave = rt1320->sdw_slave;
- const struct firmware *patch;
+ const struct firmware *patch __free(firmware) = NULL;
const char *filename;
unsigned int addr, val, min_addr, max_addr;
const unsigned char *ptr;
@@ -1312,6 +1802,9 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
max_addr = 0x10007fff;
break;
case RT1321_DEV_ID:
+ if (rt1320->version_id == RT1321_VA2)
+ return;
+
filename = RT1321_VA_MCU_PATCH;
min_addr = 0x10008000;
max_addr = 0x10008fff;
@@ -1347,17 +1840,15 @@ static void rt1320_load_mcu_patch(struct rt1320_sdw_priv *rt1320)
if (addr > max_addr || addr < min_addr) {
dev_err(&slave->dev, "%s: the address 0x%x is wrong", __func__, addr);
- goto _exit_;
+ return;
}
if (val > 0xff) {
dev_err(&slave->dev, "%s: the value 0x%x is wrong", __func__, val);
- goto _exit_;
+ return;
}
regmap_write(rt1320->regmap, addr, val);
}
}
-_exit_:
- release_firmware(patch);
}
}
@@ -1382,30 +1873,17 @@ static void rt1320_vab_preset(struct rt1320_sdw_priv *rt1320)
static void rt1320_t0_load(struct rt1320_sdw_priv *rt1320, unsigned int l_t0, unsigned int r_t0)
{
struct device *dev = &rt1320->sdw_slave->dev;
- unsigned int factor = (1 << 22), fw_ready;
+ unsigned int factor = (1 << 22);
int l_t0_data[38], r_t0_data[38];
- unsigned int fw_status_addr;
-
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
+ int dspfw_status;
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_warn(dev, "%s, DSP FW is NOT ready\n", __func__);
goto _exit_;
}
@@ -1444,7 +1922,7 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
struct device *dev = &rt1320->sdw_slave->dev;
static const char func_tag[] = "FUNC";
static const char xu_tag[] = "XU";
- const struct firmware *rae_fw = NULL;
+ const struct firmware *rae_fw __free(firmware) = NULL;
unsigned int fw_offset;
unsigned char *fw_data;
unsigned char *param_data;
@@ -1483,22 +1961,46 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
request_firmware(&rae_fw, rae_filename, dev);
if (rae_fw) {
- /* RAE CRC clear */
- regmap_write(rt1320->regmap, 0xe80b, 0x0f);
-
- /* RAE stop & CRC disable */
- regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00);
-
- while (--retry) {
- regmap_read(rt1320->regmap, 0xe83f, &value);
- if (value & 0x40)
- break;
- usleep_range(1000, 1100);
- }
- if (!retry && !(value & 0x40)) {
- dev_err(dev, "%s: RAE is not ready to load\n", __func__);
- release_firmware(rae_fw);
- return -ETIMEDOUT;
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ /* RAE CRC clear */
+ regmap_write(rt1320->regmap, 0xe80b, 0x0f);
+ /* RAE stop & CRC disable */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0xbc, 0x00);
+ while (--retry) {
+ regmap_read(rt1320->regmap, 0xe83f, &value);
+ if (value & 0x40)
+ break;
+ usleep_range(1000, 1100);
+ }
+ if (!retry && !(value & 0x40)) {
+ dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ return -ETIMEDOUT;
+ }
+ break;
+ case RT1321_DEV_ID:
+ /* RAE CRC clear */
+ regmap_write(rt1320->regmap, 0x2000300e, 0xc0);
+ regmap_write(rt1320->regmap, 0x2000300f, 0x0f);
+ /* RAE stop & Phase sync & CRC disable */
+ regmap_update_bits(rt1320->regmap, 0x20003003, 0xfe, 0x00);
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x00);
+ /* check whether write state is ready */
+ while (--retry) {
+ regmap_read(rt1320->regmap, 0x20003043, &value);
+ if (value & 0x40)
+ break;
+ usleep_range(1000, 1100);
+ }
+ if (!retry && !(value & 0x40)) {
+ dev_err(dev, "%s: RAE is not ready to load\n", __func__);
+ return -ETIMEDOUT;
+ }
+ break;
+ default:
+ dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
+ return -EINVAL;
}
dev_dbg(dev, "%s, rae_fw size=0x%zx\n", __func__, rae_fw->size);
@@ -1551,7 +2053,6 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
}
regcache_cache_bypass(rt1320->regmap, false);
- release_firmware(rae_fw);
} else {
dev_err(dev, "%s: Failed to load %s firmware\n", __func__, rae_filename);
@@ -1559,18 +2060,34 @@ static int rt1320_rae_load(struct rt1320_sdw_priv *rt1320)
goto _exit_;
}
- /* RAE CRC enable */
- regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c);
-
- /* RAE update */
- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00);
- regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80);
-
- /* RAE run */
- regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80);
-
- regmap_read(rt1320->regmap, 0xe80b, &value);
- dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value);
+ switch (rt1320->dev_id) {
+ case RT1320_DEV_ID:
+ /* RAE CRC enable */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0x0c, 0x0c);
+ /* RAE update */
+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0xe80b, 0x80, 0x80);
+ /* RAE run */
+ regmap_update_bits(rt1320->regmap, 0xe803, 0x80, 0x80);
+ regmap_read(rt1320->regmap, 0xe80b, &value);
+ dev_dbg(dev, "%s: CAE run => 0xe80b reg = 0x%x\n", __func__, value);
+ break;
+ case RT1321_DEV_ID:
+ /* RAE CRC enable */
+ regmap_update_bits(rt1320->regmap, 0x20003003, 0x30, 0x30);
+ /* RAE update */
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x80, 0x80);
+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x20009018, 0x80, 0x80);
+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x00);
+ regmap_update_bits(rt1320->regmap, 0x20005818, 0x80, 0x80);
+ /* RAE run */
+ regmap_update_bits(rt1320->regmap, 0x2000301c, 0x01, 0x01);
+ /* Phase sync eanble */
+ regmap_update_bits(rt1320->regmap, 0xc047, 0x80, 0x80);
+ break;
+ }
rt1320->rae_update_done = true;
@@ -1598,32 +2115,21 @@ struct rt1320_dspfwheader {
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt1320->component);
struct device *dev = &rt1320->sdw_slave->dev;
- unsigned int val, i, fw_offset, fw_ready;
- unsigned int fw_status_addr;
+ unsigned int val, i, fw_offset;
struct rt1320_dspfwheader *fwheader;
struct rt1320_imageinfo *ptr_img;
struct sdw_bpt_section sec[10];
- const struct firmware *fw = NULL;
+ const struct firmware *fw __free(firmware) = NULL;
unsigned char *fw_data;
bool dev_fw_match = false;
static const char hdr_sig[] = "AFX";
unsigned int hdr_size = 0;
const char *dmi_vendor, *dmi_product, *dmi_sku;
int len_vendor, len_product, len_sku;
+ unsigned char boot_mode = 0; /* 0: from RAM; 1: from ROM */
+ unsigned char has_0x3fc00000 = 0;
char filename[512];
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return;
- }
-
dmi_vendor = dmi_get_system_info(DMI_SYS_VENDOR);
dmi_product = dmi_get_system_info(DMI_PRODUCT_NAME);
dmi_sku = dmi_get_system_info(DMI_PRODUCT_SKU);
@@ -1653,17 +2159,12 @@ struct rt1320_dspfwheader {
RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (fw_ready) {
+ if (rt1320_dspfw_status(rt1320)) {
dev_dbg(dev, "%s, DSP FW was already\n", __func__);
rt1320->fw_load_done = true;
goto _exit_;
}
- /* change to IRAM */
- regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00);
-
request_firmware(&fw, filename, dev);
if (fw) {
fwheader = (struct rt1320_dspfwheader *)fw->data;
@@ -1672,7 +2173,6 @@ struct rt1320_dspfwheader {
if (fwheader->sync != 0x0a1c5679) {
dev_err(dev, "%s: FW sync error\n", __func__);
- release_firmware(fw);
goto _exit_;
}
@@ -1709,9 +2209,11 @@ struct rt1320_dspfwheader {
dev_fw_match = true;
break;
case RT1321_DEV_ID:
- if (ptr_img->addr == 0x3fc00000)
- if (fw_data[9] == '1')
+ if (ptr_img->addr == 0x3fc00000) {
+ if (fw_data[7] == '1')
dev_fw_match = true;
+ has_0x3fc00000 = 1;
+ }
break;
default:
dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
@@ -1721,6 +2223,22 @@ struct rt1320_dspfwheader {
fw_offset += ptr_img->size;
}
+ if (rt1320->dev_id == RT1321_DEV_ID && rt1320->version_id == RT1321_VA2) {
+ /*
+ * For 1321 VA2, if the FW doesn't include the section for address 0x3fc00000,
+ * it means the FW will boot from ROM and force dev_fw_match to true to download FW by BRA.
+ */
+ if (!has_0x3fc00000) {
+ boot_mode = 1;
+ dev_fw_match = true;
+ }
+ dev_dbg(dev, "%s: Boot from %s for VA2\n", __func__, (boot_mode ? "ROM" : "RAM"));
+ }
+
+ /* change to IRAM */
+ if (!boot_mode)
+ regmap_update_bits(rt1320->regmap, 0xf01e, 0x80, 0x00);
+
if (dev_fw_match) {
dev_dbg(dev, "%s, starting BRA downloading FW..\n", __func__);
rt1320->bra_msg.dev_num = rt1320->sdw_slave->dev_num;
@@ -1732,7 +2250,6 @@ struct rt1320_dspfwheader {
}
regcache_cache_bypass(rt1320->regmap, false);
- release_firmware(fw);
if (!dev_fw_match) {
dev_err(dev, "%s: FW file doesn't match to device\n", __func__);
@@ -1743,24 +2260,39 @@ struct rt1320_dspfwheader {
goto _exit_;
}
- /* run RAM code */
- regmap_read(rt1320->regmap, 0x3fc2bfc0, &val);
- val |= 0x8;
- regmap_write(rt1320->regmap, 0x3fc2bfc0, val);
-
- /* clear frame counter */
switch (rt1320->dev_id) {
case RT1320_DEV_ID:
+ /* run RAM code */
+ regmap_read(rt1320->regmap, 0x3fc2bfc0, &val);
+ val |= 0x8;
+ regmap_write(rt1320->regmap, 0x3fc2bfc0, val);
+ /* clear frame counter */
regmap_write(rt1320->regmap, 0x3fc2bfcb, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfca, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfc9, 0x00);
regmap_write(rt1320->regmap, 0x3fc2bfc8, 0x00);
break;
case RT1321_DEV_ID:
+ if (!boot_mode) {
+ /* run RAM code */
+ regmap_read(rt1320->regmap, 0x3fc2dfc0, &val);
+ val |= 0x8;
+ regmap_write(rt1320->regmap, 0x3fc2dfc0, val);
+ }
+ /* clear frame counter */
regmap_write(rt1320->regmap, 0x3fc2dfcb, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfca, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfc9, 0x00);
regmap_write(rt1320->regmap, 0x3fc2dfc8, 0x00);
+ /* enable handshake */
+ regmap_write(rt1320->regmap, 0x3fc2dfc4, 0x00);
+ regmap_write(rt1320->regmap, 0xd470, 0xad);
+ /* minimum phase settings */
+ regmap_write(rt1320->regmap, 0xc5c4, 0x10);
+ regmap_write(rt1320->regmap, 0x20003003, 0x31);
+ regmap_update_bits(rt1320->regmap, 0x20003002, 0x40, 0x00);
+ regmap_write(rt1320->regmap, 0xc5b3, 0x01);
+ regmap_write(rt1320->regmap, 0xc052, 0x11);
break;
}
@@ -1843,14 +2375,35 @@ static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
static void rt1321_preset(struct rt1320_sdw_priv *rt1320)
{
+ const struct reg_sequence *blindwrite;
unsigned int i, reg, val, delay;
+ unsigned int array_size;
+
+ switch (rt1320->version_id) {
+ case RT1321_VA0:
+ blindwrite = rt1321_blind_write;
+ array_size = ARRAY_SIZE(rt1321_blind_write);
+ break;
+ case RT1321_VA1:
+ blindwrite = rt1321_va1_blind_write;
+ array_size = ARRAY_SIZE(rt1321_va1_blind_write);
+ break;
+ case RT1321_VA2:
+ blindwrite = rt1321_va2_blind_write;
+ array_size = ARRAY_SIZE(rt1321_va2_blind_write);
+ break;
+ default:
+ dev_err(&rt1320->sdw_slave->dev, "%s: Unknown version ID %d\n",
+ __func__, rt1320->version_id);
+ return;
+ }
- for (i = 0; i < ARRAY_SIZE(rt1321_blind_write); i++) {
- reg = rt1321_blind_write[i].reg;
- val = rt1321_blind_write[i].def;
- delay = rt1321_blind_write[i].delay_us;
+ for (i = 0; i < array_size; i++) {
+ reg = blindwrite[i].reg;
+ val = blindwrite[i].def;
+ delay = blindwrite[i].delay_us;
- if (reg == 0x3fc2dfc3)
+ if (reg == 0x1000cd56)
rt1320_load_mcu_patch(rt1320);
regmap_write(rt1320->regmap, reg, val);
@@ -1892,6 +2445,24 @@ static int rt1320_io_init(struct device *dev, struct sdw_slave *slave)
regmap_read(rt1320->regmap, RT1320_DEV_ID_0, &val);
regmap_read(rt1320->regmap, RT1320_DEV_ID_1, &tmp);
rt1320->dev_id = (val << 8) | tmp;
+
+ /* This is a workaround that reads the value twice to obtain the correct result. */
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_0, &val);
+ rt1320_pr_read(rt1320, RT1320_HV_DEV_ID_1, &tmp);
+ val = (val << 8) | tmp;
+
+ if (rt1320->dev_id == RT1321_DEV_ID) {
+ if (rt1320->version_id == 0x01)
+ rt1320->version_id = RT1321_VA2;
+ else if (val == RT1321_DEV_HV_VA0_ID)
+ rt1320->version_id = RT1321_VA0;
+ else if (val == RT1321_DEV_HV_VA1_ID)
+ rt1320->version_id = RT1321_VA1;
+ else
+ dev_err(dev, "%s: Unknown version ID 0x%x for RT1321\n", __func__, rt1320->version_id);
+ }
}
regmap_read(rt1320->regmap,
@@ -2326,25 +2897,12 @@ static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320)
{
struct device *dev = regmap_get_device(rt1320->regmap);
- unsigned int fw_status_addr;
- unsigned int fw_ready;
+ int dspfw_status;
int ret = 0;
if (!rt1320->r0_l_reg || !rt1320->r0_r_reg)
return -EINVAL;
- switch (rt1320->dev_id) {
- case RT1320_DEV_ID:
- fw_status_addr = RT1320_DSPFW_STATUS_ADDR;
- break;
- case RT1321_DEV_ID:
- fw_status_addr = RT1321_DSPFW_STATUS_ADDR;
- break;
- default:
- dev_err(dev, "%s: Unknown device ID %d\n", __func__, rt1320->dev_id);
- return -EINVAL;
- }
-
regmap_write(rt1320->regmap,
SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x00);
ret = rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, 0x00);
@@ -2353,9 +2911,8 @@ static int rt1320_r0_load(struct rt1320_sdw_priv *rt1320)
goto _timeout_;
}
- regmap_read(rt1320->regmap, fw_status_addr, &fw_ready);
- fw_ready &= 0x1;
- if (!fw_ready) {
+ dspfw_status = rt1320_dspfw_status(rt1320);
+ if (dspfw_status <= 0) {
dev_dbg(dev, "%s, DSP FW is NOT ready\n", __func__);
goto _timeout_;
}
@@ -2458,7 +3015,7 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol,
if (!rt1320->hw_init)
return 0;
- ret = pm_runtime_resume(component->dev);
+ ret = pm_runtime_resume_and_get(component->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -2469,6 +3026,8 @@ static int rt1320_dspfw_load_put(struct snd_kcontrol *kcontrol,
if (!ucontrol->value.integer.value[0])
rt1320->fw_load_done = false;
+ pm_runtime_mark_last_busy(component->dev);
+ pm_runtime_put_autosuspend(component->dev);
return 0;
}
@@ -2819,6 +3378,37 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
return 0;
}
+static int rt1320_bus_config(struct sdw_slave *slave,
+ struct sdw_bus_params *params)
+{
+ struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(&slave->dev);
+ unsigned int clk_base;
+
+ regmap_read(rt1320->regmap, 0x004d, &clk_base);
+ dev_dbg(&rt1320->sdw_slave->dev, "%s clk_base=%x", __func__, clk_base);
+
+ switch (clk_base) {
+ case RT1320_CLK_FREQ_19_2_MHZ:
+ case RT1320_CLK_FREQ_24MHZ:
+ regmap_write(rt1320->regmap, 0xc600, 0x04);
+ regmap_write(rt1320->regmap, 0xc601, 0x83);
+ regmap_write(rt1320->regmap, 0xc602, 0x1f);
+ regmap_write(rt1320->regmap, 0xc603, 0x40);
+ break;
+ case RT1320_CLK_FREQ_24_576MHZ:
+ case RT1320_CLK_FREQ_22_5792MHZ:
+ regmap_write(rt1320->regmap, 0xc600, 0x07);
+ regmap_write(rt1320->regmap, 0xc601, 0x80);
+ regmap_write(rt1320->regmap, 0xc602, 0x0f);
+ regmap_write(rt1320->regmap, 0xc603, 0x40);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* slave_ops: callbacks for get_clock_stop_mode, clock_stop and
* port_prep are not defined for now
@@ -2826,12 +3416,13 @@ static int rt1320_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
static const struct sdw_slave_ops rt1320_slave_ops = {
.read_prop = rt1320_read_prop,
.update_status = rt1320_update_status,
+ .bus_config = rt1320_bus_config,
};
static int rt1320_sdw_component_probe(struct snd_soc_component *component)
{
- int ret;
struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+ int ret;
rt1320->component = component;
@@ -3062,10 +3653,23 @@ static int rt1320_dev_resume(struct device *dev)
return ret;
regcache_cache_only(rt1320->regmap, false);
- regcache_sync(rt1320->regmap);
+ ret = regcache_sync(rt1320->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt1320->mbq_regmap, false);
- regcache_sync(rt1320->mbq_regmap);
+ ret = regcache_sync(rt1320->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt1320->regmap, true);
+ regcache_cache_only(rt1320->mbq_regmap, true);
+ regcache_mark_dirty(rt1320->regmap);
+ regcache_mark_dirty(rt1320->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt1320_pm = {
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
index a7b573883dd0..df9ccdf92d36 100644
--- a/sound/soc/codecs/rt1320-sdw.h
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -17,12 +17,17 @@
#define RT1320_DEV_ID 0x6981
#define RT1321_DEV_ID 0x7045
+#define RT1321_DEV_HV_VA0_ID 0x6997
+#define RT1321_DEV_HV_VA1_ID 0x7071
/* imp-defined registers */
#define RT1320_DEV_VERSION_ID_1 0xc404
#define RT1320_DEV_ID_1 0xc405
#define RT1320_DEV_ID_0 0xc406
+#define RT1320_HV_DEV_ID_0 0xf622
+#define RT1320_HV_DEV_ID_1 0xf623
+
#define RT1320_POWER_STATE 0xc560
#define RT1321_PATCH_MAIN_VER 0x1000cffe
@@ -94,6 +99,12 @@ enum rt1320_version_id {
RT1320_VC,
};
+enum rt1321_version_id {
+ RT1321_VA0,
+ RT1321_VA1,
+ RT1321_VA2,
+};
+
#define RT1320_VER_B_ID 0x07392238
#define RT1320_VAB_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vab.bin"
#define RT1320_VC_MCU_PATCH "realtek/rt1320/rt1320-patch-code-vc.bin"
@@ -121,6 +132,7 @@ struct rt1320_datafixpoint {
int invrs;
};
+/* FW parameter id 1300 */
typedef struct FwPara_HwSwGain {
unsigned int SwAdvGain;
unsigned int SwBasGain;
@@ -163,6 +175,13 @@ enum rt1320_rw_type {
RT1320_PARAM_READ = 3,
};
+enum {
+ RT1320_CLK_FREQ_19_2_MHZ = 1,
+ RT1320_CLK_FREQ_24MHZ = 2,
+ RT1320_CLK_FREQ_24_576MHZ = 3,
+ RT1320_CLK_FREQ_22_5792MHZ = 4,
+};
+
struct rt1320_sdw_priv {
struct snd_soc_component *component;
struct regmap *regmap;
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index 63b5fc439773..f8c370106504 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -184,8 +184,10 @@ static const struct reg_default rt274_reg[] = {
{ 0x0023a000, 0x00000057 },
{ 0x00270500, 0x00000400 },
{ 0x00370500, 0x00000400 },
+ { 0x00830000, 0x00000097 },
{ 0x00870500, 0x00000400 },
{ 0x00920000, 0x00000031 },
+ { 0x00930000, 0x00000097 },
{ 0x00935000, 0x00000097 },
{ 0x00936000, 0x00000097 },
{ 0x00970500, 0x00000400 },
@@ -195,10 +197,12 @@ static const struct reg_default rt274_reg[] = {
{ 0x00c37000, 0x00000400 },
{ 0x00c37100, 0x00000400 },
{ 0x01270500, 0x00000400 },
+ { 0x01270700, 0x00000000 },
{ 0x01370500, 0x00000400 },
{ 0x01371f00, 0x411111f0 },
{ 0x01937000, 0x00000000 },
{ 0x01970500, 0x00000400 },
+ { 0x01970700, 0x00000020 },
{ 0x02050000, 0x0000001b },
{ 0x02139000, 0x00000080 },
{ 0x0213a000, 0x00000080 },
@@ -207,10 +211,6 @@ static const struct reg_default rt274_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x01970700, 0x00000020 },
- { 0x00830000, 0x00000097 },
- { 0x00930000, 0x00000097 },
- { 0x01270700, 0x00000000 },
};
static bool rt274_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index ded0ea332480..4217467904d6 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -77,8 +77,10 @@ static const struct reg_default rt286_reg[] = {
{ 0x0023a000, 0x0000007f },
{ 0x00270500, 0x00000400 },
{ 0x00370500, 0x00000400 },
+ { 0x00830000, 0x000000c3 },
{ 0x00870500, 0x00000400 },
{ 0x00920000, 0x00000031 },
+ { 0x00930000, 0x000000c3 },
{ 0x00935000, 0x000000c3 },
{ 0x00936000, 0x000000c3 },
{ 0x00970500, 0x00000400 },
@@ -88,16 +90,18 @@ static const struct reg_default rt286_reg[] = {
{ 0x00c37000, 0x00000000 },
{ 0x00c37100, 0x00000080 },
{ 0x01270500, 0x00000400 },
+ { 0x01270700, 0x00000000 },
{ 0x01370500, 0x00000400 },
{ 0x01371f00, 0x411111f0 },
{ 0x01439000, 0x00000080 },
{ 0x0143a000, 0x00000080 },
- { 0x01470700, 0x00000000 },
+ { 0x01470100, 0x00000000 },
{ 0x01470500, 0x00000400 },
+ { 0x01470700, 0x00000000 },
{ 0x01470c00, 0x00000000 },
- { 0x01470100, 0x00000000 },
{ 0x01837000, 0x00000000 },
{ 0x01870500, 0x00000400 },
+ { 0x01870700, 0x00000020 },
{ 0x02050000, 0x00000000 },
{ 0x02139000, 0x00000080 },
{ 0x0213a000, 0x00000080 },
@@ -106,10 +110,6 @@ static const struct reg_default rt286_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x01870700, 0x00000020 },
- { 0x00830000, 0x000000c3 },
- { 0x00930000, 0x000000c3 },
- { 0x01270700, 0x00000000 },
};
static bool rt286_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index 5414a1712b57..09aed08b5b79 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -78,8 +78,10 @@ static const struct reg_default rt298_reg[] = {
{ 0x0023a000, 0x0000007f },
{ 0x00270500, 0x00000400 },
{ 0x00370500, 0x00000400 },
+ { 0x00830000, 0x000000c3 },
{ 0x00870500, 0x00000400 },
{ 0x00920000, 0x00000031 },
+ { 0x00930000, 0x000000c3 },
{ 0x00935000, 0x000000c3 },
{ 0x00936000, 0x000000c3 },
{ 0x00970500, 0x00000400 },
@@ -89,16 +91,18 @@ static const struct reg_default rt298_reg[] = {
{ 0x00c37000, 0x00000000 },
{ 0x00c37100, 0x00000080 },
{ 0x01270500, 0x00000400 },
+ { 0x01270700, 0x00000000 },
{ 0x01370500, 0x00000400 },
{ 0x01371f00, 0x411111f0 },
{ 0x01439000, 0x00000080 },
{ 0x0143a000, 0x00000080 },
- { 0x01470700, 0x00000000 },
+ { 0x01470100, 0x00000000 },
{ 0x01470500, 0x00000400 },
+ { 0x01470700, 0x00000000 },
{ 0x01470c00, 0x00000000 },
- { 0x01470100, 0x00000000 },
{ 0x01837000, 0x00000000 },
{ 0x01870500, 0x00000400 },
+ { 0x01870700, 0x00000020 },
{ 0x02050000, 0x00000000 },
{ 0x02139000, 0x00000080 },
{ 0x0213a000, 0x00000080 },
@@ -107,10 +111,6 @@ static const struct reg_default rt298_reg[] = {
{ 0x02170700, 0x00000000 },
{ 0x02270100, 0x00000000 },
{ 0x02370100, 0x00000000 },
- { 0x01870700, 0x00000020 },
- { 0x00830000, 0x000000c3 },
- { 0x00930000, 0x000000c3 },
- { 0x01270700, 0x00000000 },
};
static bool rt298_volatile_register(struct device *dev, unsigned int reg)
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index 199507d12841..91290bfe8daa 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -6,6 +6,7 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
@@ -79,17 +80,17 @@ static void rt5514_spi_copy_work(struct work_struct *work)
unsigned int cur_wp, remain_data;
u8 buf[8];
- mutex_lock(&rt5514_dsp->dma_lock);
+ guard(mutex)(&rt5514_dsp->dma_lock);
if (!rt5514_dsp->substream) {
dev_err(rt5514_dsp->dev, "No pcm substream\n");
- goto done;
+ return;
}
runtime = rt5514_dsp->substream->runtime;
period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream);
if (!period_bytes) {
schedule_delayed_work(&rt5514_dsp->copy_work, 5);
- goto done;
+ return;
}
if (rt5514_dsp->buf_size % period_bytes)
@@ -111,7 +112,7 @@ static void rt5514_spi_copy_work(struct work_struct *work)
if (remain_data < period_bytes) {
schedule_delayed_work(&rt5514_dsp->copy_work, 5);
- goto done;
+ return;
}
}
@@ -146,9 +147,6 @@ static void rt5514_spi_copy_work(struct work_struct *work)
snd_pcm_period_elapsed(rt5514_dsp->substream);
schedule_delayed_work(&rt5514_dsp->copy_work, 5);
-
-done:
- mutex_unlock(&rt5514_dsp->dma_lock);
}
static void rt5514_schedule_copy(struct rt5514_dsp *rt5514_dsp)
@@ -216,7 +214,7 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component,
snd_soc_component_get_drvdata(component);
u8 buf[8];
- mutex_lock(&rt5514_dsp->dma_lock);
+ guard(mutex)(&rt5514_dsp->dma_lock);
rt5514_dsp->substream = substream;
rt5514_dsp->dma_offset = 0;
@@ -225,8 +223,6 @@ static int rt5514_spi_hw_params(struct snd_soc_component *component,
if (buf[0] & RT5514_IRQ_STATUS_BIT)
rt5514_schedule_copy(rt5514_dsp);
- mutex_unlock(&rt5514_dsp->dma_lock);
-
return 0;
}
@@ -236,9 +232,8 @@ static int rt5514_spi_hw_free(struct snd_soc_component *component,
struct rt5514_dsp *rt5514_dsp =
snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5514_dsp->dma_lock);
- rt5514_dsp->substream = NULL;
- mutex_unlock(&rt5514_dsp->dma_lock);
+ scoped_guard(mutex, &rt5514_dsp->dma_lock)
+ rt5514_dsp->substream = NULL;
cancel_delayed_work_sync(&rt5514_dsp->copy_work);
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 00a4a208d2fa..58aecd4c83a6 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1073,12 +1073,18 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
* settings to make sure recording properly.
*/
if (rt5514->dsp_enabled) {
- rt5514->dsp_enabled = 0;
- regmap_multi_reg_write(rt5514->i2c_regmap,
- rt5514_i2c_patch,
- ARRAY_SIZE(rt5514_i2c_patch));
+ ret = regmap_multi_reg_write(rt5514->i2c_regmap,
+ rt5514_i2c_patch,
+ ARRAY_SIZE(rt5514_i2c_patch));
+ if (ret)
+ return ret;
+
regcache_mark_dirty(rt5514->regmap);
- regcache_sync(rt5514->regmap);
+ ret = regcache_sync(rt5514->regmap);
+ if (ret)
+ return ret;
+
+ rt5514->dsp_enabled = 0;
}
}
break;
diff --git a/sound/soc/codecs/rt5575-spi.c b/sound/soc/codecs/rt5575-spi.c
index d5b3a57c8866..750f1f7169e6 100644
--- a/sound/soc/codecs/rt5575-spi.c
+++ b/sound/soc/codecs/rt5575-spi.c
@@ -93,7 +93,6 @@ static void rt5575_spi_burst_write(struct spi_device *spi, u32 addr, const u8 *t
int rt5575_spi_fw_load(struct spi_device *spi)
{
struct device *dev = &spi->dev;
- const struct firmware *firmware;
int i, ret;
static const char * const fw_path[] = {
"realtek/rt5575/rt5575_fw1.bin",
@@ -104,6 +103,7 @@ int rt5575_spi_fw_load(struct spi_device *spi)
static const u32 fw_addr[] = { 0x5f400000, 0x5f600000, 0x5f7fe000, 0x5f7ff000 };
for (i = 0; i < ARRAY_SIZE(fw_addr); i++) {
+ const struct firmware *firmware __free(firmware) = NULL;
ret = request_firmware(&firmware, fw_path[i], dev);
if (ret) {
dev_err(dev, "Request firmware failure: %d\n", ret);
@@ -111,7 +111,6 @@ int rt5575_spi_fw_load(struct spi_device *spi)
}
rt5575_spi_burst_write(spi, fw_addr[i], firmware->data, firmware->size);
- release_firmware(firmware);
}
return 0;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index e7e39671a576..7313ea71c958 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -6,6 +6,7 @@
* Author: Bard Liao <bardliao@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -3323,93 +3324,90 @@ static void rt5645_jack_detect_work(struct work_struct *work)
if (!rt5645->component)
return;
- mutex_lock(&rt5645->jd_mutex);
-
- switch (rt5645->pdata.jd_mode) {
- case 0: /* Not using rt5645 JD */
- if (rt5645->gpiod_hp_det) {
- gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
- if (rt5645->pdata.inv_hp_pol)
- gpio_state ^= 1;
- dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
- gpio_state);
- report = rt5645_jack_detect(rt5645->component, gpio_state);
+ scoped_guard(mutex, &rt5645->jd_mutex) {
+ switch (rt5645->pdata.jd_mode) {
+ case 0: /* Not using rt5645 JD */
+ if (rt5645->gpiod_hp_det) {
+ gpio_state = gpiod_get_value(rt5645->gpiod_hp_det);
+ if (rt5645->pdata.inv_hp_pol)
+ gpio_state ^= 1;
+ dev_dbg(rt5645->component->dev, "gpio_state = %d\n",
+ gpio_state);
+ report = rt5645_jack_detect(rt5645->component, gpio_state);
+ }
+ snd_soc_jack_report(rt5645->hp_jack,
+ report, SND_JACK_HEADPHONE);
+ snd_soc_jack_report(rt5645->mic_jack,
+ report, SND_JACK_MICROPHONE);
+ return;
+ case 4:
+ val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
+ break;
+ default: /* read rt5645 jd1_1 status */
+ val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000;
+ break;
}
- snd_soc_jack_report(rt5645->hp_jack,
- report, SND_JACK_HEADPHONE);
- snd_soc_jack_report(rt5645->mic_jack,
- report, SND_JACK_MICROPHONE);
- mutex_unlock(&rt5645->jd_mutex);
- return;
- case 4:
- val = snd_soc_component_read(rt5645->component, RT5645_A_JD_CTRL1) & 0x0020;
- break;
- default: /* read rt5645 jd1_1 status */
- val = snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x1000;
- break;
- }
-
- if (!val && (rt5645->jack_type == 0)) { /* jack in */
- report = rt5645_jack_detect(rt5645->component, 1);
- } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) {
- /* for push button and jack out */
- btn_type = 0;
- if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
- /* button pressed */
- report = SND_JACK_HEADSET;
- btn_type = rt5645_button_detect(rt5645->component);
- /* rt5650 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:
- report |= SND_JACK_BTN_0;
- break;
- case 0x1000:
- case 0x0800:
- case 0x0400:
- report |= SND_JACK_BTN_1;
- break;
- case 0x0200:
- case 0x0100:
- case 0x0080:
- report |= SND_JACK_BTN_2;
- break;
- case 0x0040:
- case 0x0020:
- case 0x0010:
- report |= SND_JACK_BTN_3;
- break;
- case 0x0000: /* unpressed */
- break;
- default:
- dev_err(rt5645->component->dev,
- "Unexpected button code 0x%04x\n",
- btn_type);
- break;
+ if (!val && rt5645->jack_type == 0) { /* jack in */
+ report = rt5645_jack_detect(rt5645->component, 1);
+ } else if (!val && rt5645->jack_type == SND_JACK_HEADSET) {
+ /* for push button and jack out */
+ btn_type = 0;
+ if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
+ /* button pressed */
+ report = SND_JACK_HEADSET;
+ btn_type = rt5645_button_detect(rt5645->component);
+ /*
+ * rt5650 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:
+ report |= SND_JACK_BTN_0;
+ break;
+ case 0x1000:
+ case 0x0800:
+ case 0x0400:
+ report |= SND_JACK_BTN_1;
+ break;
+ case 0x0200:
+ case 0x0100:
+ case 0x0080:
+ report |= SND_JACK_BTN_2;
+ break;
+ case 0x0040:
+ case 0x0020:
+ case 0x0010:
+ report |= SND_JACK_BTN_3;
+ break;
+ case 0x0000: /* unpressed */
+ break;
+ default:
+ dev_err(rt5645->component->dev,
+ "Unexpected button code 0x%04x\n",
+ btn_type);
+ break;
+ }
}
+ if (btn_type == 0)/* button release */
+ report = rt5645->jack_type;
+ else
+ mod_timer(&rt5645->btn_check_timer,
+ msecs_to_jiffies(100));
+ } else {
+ /* jack out */
+ report = 0;
+ snd_soc_component_update_bits(rt5645->component,
+ RT5645_INT_IRQ_ST, 0x1, 0x0);
+ rt5645_jack_detect(rt5645->component, 0);
}
- if (btn_type == 0)/* button release */
- report = rt5645->jack_type;
- else {
- mod_timer(&rt5645->btn_check_timer,
- msecs_to_jiffies(100));
- }
- } else {
- /* jack out */
- report = 0;
- snd_soc_component_update_bits(rt5645->component,
- RT5645_INT_IRQ_ST, 0x1, 0x0);
- rt5645_jack_detect(rt5645->component, 0);
}
- mutex_unlock(&rt5645->jd_mutex);
-
snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
if (rt5645->en_button_func)
@@ -3522,9 +3520,15 @@ static int rt5645_suspend(struct snd_soc_component *component)
static int rt5645_resume(struct snd_soc_component *component)
{
struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+ int ret;
regcache_cache_only(rt5645->regmap, false);
- regcache_sync(rt5645->regmap);
+ ret = regcache_sync(rt5645->regmap);
+ if (ret) {
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return ret;
+ }
return 0;
}
@@ -4335,9 +4339,15 @@ static int rt5645_sys_suspend(struct device *dev)
static int rt5645_sys_resume(struct device *dev)
{
struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
+ int ret;
regcache_cache_only(rt5645->regmap, false);
- regcache_sync(rt5645->regmap);
+ ret = regcache_sync(rt5645->regmap);
+ if (ret) {
+ regcache_cache_only(rt5645->regmap, true);
+ regcache_mark_dirty(rt5645->regmap);
+ return ret;
+ }
if (rt5645->hp_jack) {
rt5645->jack_type = 0;
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 48f57cd0920d..1d987472ba42 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -6,6 +6,7 @@
* Author: Bard Liao <bardliao@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -1208,7 +1209,7 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
usleep_range(10000, 15000);
}
- mutex_lock(&rt5665->calibrate_mutex);
+ guard(mutex)(&rt5665->calibrate_mutex);
val = snd_soc_component_read(rt5665->component, RT5665_AJD1_CTRL) & 0x0010;
if (!val) {
@@ -1274,8 +1275,6 @@ static void rt5665_jack_detect_handler(struct work_struct *work)
schedule_delayed_work(&rt5665->jd_check_work, 0);
else
cancel_delayed_work_sync(&rt5665->jd_check_work);
-
- mutex_unlock(&rt5665->calibrate_mutex);
}
static const char * const rt5665_clk_sync[] = {
@@ -4564,7 +4563,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
{
int value, count;
- mutex_lock(&rt5665->calibrate_mutex);
+ guard(mutex)(&rt5665->calibrate_mutex);
regcache_cache_bypass(rt5665->regmap, true);
@@ -4601,7 +4600,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
pr_err("HP Calibration Failure\n");
regmap_write(rt5665->regmap, RT5665_RESET, 0);
regcache_cache_bypass(rt5665->regmap, false);
- goto out_unlock;
+ rt5665->calibration_done = true;
+ return;
}
count++;
@@ -4620,7 +4620,8 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
pr_err("MONO Calibration Failure\n");
regmap_write(rt5665->regmap, RT5665_RESET, 0);
regcache_cache_bypass(rt5665->regmap, false);
- goto out_unlock;
+ rt5665->calibration_done = true;
+ return;
}
count++;
@@ -4635,9 +4636,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665)
regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602);
regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120);
-out_unlock:
rt5665->calibration_done = true;
- mutex_unlock(&rt5665->calibrate_mutex);
}
static void rt5665_calibrate_handler(struct work_struct *work)
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index fed6de40b8c8..4154bad27610 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -6,6 +6,7 @@
* Author: Bard Liao <bardliao@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -986,7 +987,7 @@ static void rt5668_jack_detect_handler(struct work_struct *work)
return;
}
- mutex_lock(&rt5668->calibrate_mutex);
+ guard(mutex)(&rt5668->calibrate_mutex);
val = snd_soc_component_read(rt5668->component, RT5668_AJD1_CTRL)
& RT5668_JDH_RS_MASK;
@@ -1053,8 +1054,6 @@ static void rt5668_jack_detect_handler(struct work_struct *work)
schedule_delayed_work(&rt5668->jd_check_work, 0);
else
cancel_delayed_work_sync(&rt5668->jd_check_work);
-
- mutex_unlock(&rt5668->calibrate_mutex);
}
static const struct snd_kcontrol_new rt5668_snd_controls[] = {
@@ -2356,7 +2355,7 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668)
{
int value, count;
- mutex_lock(&rt5668->calibrate_mutex);
+ guard(mutex)(&rt5668->calibrate_mutex);
rt5668_reset(rt5668->regmap);
regmap_write(rt5668->regmap, RT5668_PWR_ANLG_1, 0xa2bf);
@@ -2400,9 +2399,6 @@ static void rt5668_calibrate(struct rt5668_priv *rt5668)
/* restore settings */
regmap_write(rt5668->regmap, RT5668_STO1_ADC_MIXER, 0xc0c4);
regmap_write(rt5668->regmap, RT5668_PWR_DIG_1, 0x0000);
-
- mutex_unlock(&rt5668->calibrate_mutex);
-
}
static int rt5668_i2c_probe(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index 1bcafd5f4468..ebc527115ea5 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -6,6 +6,7 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
@@ -133,9 +134,8 @@ static int rt5677_spi_hw_params(
struct rt5677_dsp *rt5677_dsp =
snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5677_dsp->dma_lock);
+ guard(mutex)(&rt5677_dsp->dma_lock);
rt5677_dsp->substream = substream;
- mutex_unlock(&rt5677_dsp->dma_lock);
return 0;
}
@@ -147,9 +147,8 @@ static int rt5677_spi_hw_free(
struct rt5677_dsp *rt5677_dsp =
snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5677_dsp->dma_lock);
+ guard(mutex)(&rt5677_dsp->dma_lock);
rt5677_dsp->substream = NULL;
- mutex_unlock(&rt5677_dsp->dma_lock);
return 0;
}
@@ -311,17 +310,17 @@ static void rt5677_spi_copy_work(struct work_struct *work)
int ret = 0;
/* Ensure runtime->dma_area buffer does not go away while copying. */
- mutex_lock(&rt5677_dsp->dma_lock);
+ guard(mutex)(&rt5677_dsp->dma_lock);
if (!rt5677_dsp->substream) {
dev_err(rt5677_dsp->dev, "No pcm substream\n");
- goto done;
+ return;
}
runtime = rt5677_dsp->substream->runtime;
if (rt5677_spi_mic_write_offset(&mic_write_offset)) {
dev_err(rt5677_dsp->dev, "No mic_write_offset\n");
- goto done;
+ return;
}
/* If this is the first time that we've asked for streaming data after
@@ -355,7 +354,7 @@ static void rt5677_spi_copy_work(struct work_struct *work)
ret = rt5677_spi_copy(rt5677_dsp, copy_bytes);
if (ret) {
dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret);
- goto done;
+ return;
}
rt5677_dsp->avail_bytes += copy_bytes;
if (rt5677_dsp->avail_bytes >= period_bytes) {
@@ -367,8 +366,6 @@ static void rt5677_spi_copy_work(struct work_struct *work)
delay = bytes_to_frames(runtime, period_bytes) / runtime->rate;
schedule_delayed_work(&rt5677_dsp->copy_work, secs_to_jiffies(delay));
-done:
- mutex_unlock(&rt5677_dsp->dma_lock);
}
static int rt5677_spi_pcm_new(struct snd_soc_component *component,
@@ -507,10 +504,8 @@ int rt5677_spi_read(u32 addr, void *rxbuf, size_t len)
header[3] = ((addr + offset) & 0x0000ff00) >> 8;
header[4] = ((addr + offset) & 0x000000ff) >> 0;
- mutex_lock(&spi_mutex);
- status |= spi_sync(g_spi, &m);
- mutex_unlock(&spi_mutex);
-
+ scoped_guard(mutex, &spi_mutex)
+ status |= spi_sync(g_spi, &m);
/* Copy data back to caller buffer */
rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len);
@@ -564,9 +559,8 @@ int rt5677_spi_write(u32 addr, const void *txbuf, size_t len)
offset += t.len;
t.len += RT5677_SPI_HEADER + 1;
- mutex_lock(&spi_mutex);
- status |= spi_sync(g_spi, &m);
- mutex_unlock(&spi_mutex);
+ scoped_guard(mutex, &spi_mutex)
+ status |= spi_sync(g_spi, &m);
}
return status;
}
@@ -591,10 +585,10 @@ void rt5677_spi_hotword_detected(void)
return;
}
- mutex_lock(&rt5677_dsp->dma_lock);
- dev_info(rt5677_dsp->dev, "Hotword detected\n");
- rt5677_dsp->new_hotword = true;
- mutex_unlock(&rt5677_dsp->dma_lock);
+ scoped_guard(mutex, &rt5677_dsp->dma_lock) {
+ dev_info(rt5677_dsp->dev, "Hotword detected\n");
+ rt5677_dsp->new_hotword = true;
+ }
schedule_delayed_work(&rt5677_dsp->copy_work, 0);
}
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index ac084ca008f3..4757017cc83d 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -6,6 +6,8 @@
* Author: Oder Chiou <oder_chiou@realtek.com>
*/
+#include <linux/cleanup.h>
+#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/fs.h>
@@ -563,46 +565,43 @@ static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
struct snd_soc_component *component = rt5677->component;
int ret;
- mutex_lock(&rt5677->dsp_cmd_lock);
+ guard(mutex)(&rt5677->dsp_cmd_lock);
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
addr >> 16);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
addr & 0xffff);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
value >> 16);
if (ret < 0) {
dev_err(component->dev, "Failed to set data msb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
value & 0xffff);
if (ret < 0) {
dev_err(component->dev, "Failed to set data lsb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
opcode);
if (ret < 0) {
dev_err(component->dev, "Failed to set op code value: %d\n", ret);
- goto err;
+ return ret;
}
-err:
- mutex_unlock(&rt5677->dsp_cmd_lock);
-
return ret;
}
@@ -622,36 +621,33 @@ static int rt5677_dsp_mode_i2c_read_addr(
int ret;
unsigned int msb, lsb;
- mutex_lock(&rt5677->dsp_cmd_lock);
+ guard(mutex)(&rt5677->dsp_cmd_lock);
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
addr >> 16);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr msb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
addr & 0xffff);
if (ret < 0) {
dev_err(component->dev, "Failed to set addr lsb value: %d\n", ret);
- goto err;
+ return ret;
}
ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
0x0002);
if (ret < 0) {
dev_err(component->dev, "Failed to set op code value: %d\n", ret);
- goto err;
+ return ret;
}
regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb);
regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb);
*value = (msb << 16) | lsb;
-err:
- mutex_unlock(&rt5677->dsp_cmd_lock);
-
return ret;
}
@@ -853,11 +849,11 @@ static int rt5677_parse_and_load_dsp(struct rt5677_priv *rt5677, const u8 *buf,
static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677)
{
- const struct firmware *fwp;
struct device *dev = rt5677->component->dev;
- int ret = 0;
+ int ret;
/* Load dsp firmware from rt5677_elf_vad file */
+ const struct firmware *fwp __free(firmware) = NULL;
ret = request_firmware(&fwp, "rt5677_elf_vad", dev);
if (ret) {
dev_err(dev, "Request rt5677_elf_vad failed %d\n", ret);
@@ -865,9 +861,7 @@ static int rt5677_load_dsp_from_file(struct rt5677_priv *rt5677)
}
dev_info(dev, "Requested rt5677_elf_vad (%zu)\n", fwp->size);
- ret = rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size);
- release_firmware(fwp);
- return ret;
+ return rt5677_parse_and_load_dsp(rt5677, fwp->data, fwp->size);
}
static int rt5677_set_dsp_vad(struct snd_soc_component *component, bool on)
@@ -940,21 +934,20 @@ static void rt5677_dsp_work(struct work_struct *work)
activity = false;
/* Don't turn off the DSP while handling irqs */
- mutex_lock(&rt5677->irq_lock);
- /* Set DSP CPU to Stop */
- regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1,
- RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU);
+ scoped_guard(mutex, &rt5677->irq_lock) {
+ /* Set DSP CPU to Stop */
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1,
+ RT5677_PWR_DSP_CPU, RT5677_PWR_DSP_CPU);
- rt5677_set_dsp_mode(rt5677, false);
+ rt5677_set_dsp_mode(rt5677, false);
- /* Disable and clear VAD interrupt */
- regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184);
-
- /* Set GPIO1 pin back to be IRQ output for jack detect */
- regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1,
- RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);
+ /* Disable and clear VAD interrupt */
+ regmap_write(rt5677->regmap, RT5677_VAD_CTRL1, 0x2184);
- mutex_unlock(&rt5677->irq_lock);
+ /* Set GPIO1 pin back to be IRQ output for jack detect */
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1,
+ RT5677_GPIO1_PIN_MASK, RT5677_GPIO1_PIN_IRQ);
+ }
}
}
@@ -4767,6 +4760,21 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
return rt5677_update_gpio_bits(rt5677, offset, m, v);
}
+static int rt5677_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ struct rt5677_priv *rt5677 = gpiochip_get_data(chip);
+ unsigned int shift = RT5677_GPIOx_DIR_SFT + (offset % 5) * 3;
+ unsigned int bank = offset / 5;
+ unsigned int reg = bank ? RT5677_GPIO_CTRL3 : RT5677_GPIO_CTRL2;
+ int ret;
+
+ ret = regmap_test_bits(rt5677->regmap, reg, BIT(shift));
+ if (ret < 0)
+ return ret;
+
+ return ret ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
/*
* Configures the GPIO as
* 0 - floating
@@ -4834,6 +4842,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
static const struct gpio_chip rt5677_template_chip = {
.label = RT5677_DRV_NAME,
.owner = THIS_MODULE,
+ .get_direction = rt5677_gpio_get_direction,
.direction_output = rt5677_gpio_direction_out,
.set = rt5677_gpio_set,
.direction_input = rt5677_gpio_direction_in,
@@ -4980,11 +4989,11 @@ static int rt5677_read(void *context, unsigned int reg, unsigned int *val)
if (rt5677->is_dsp_mode) {
if (reg > 0xff) {
- mutex_lock(&rt5677->dsp_pri_lock);
- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
- reg & 0xff);
- rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
- mutex_unlock(&rt5677->dsp_pri_lock);
+ scoped_guard(mutex, &rt5677->dsp_pri_lock) {
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+ reg & 0xff);
+ rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
+ }
} else {
rt5677_dsp_mode_i2c_read(rt5677, reg, val);
}
@@ -5002,12 +5011,12 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val)
if (rt5677->is_dsp_mode) {
if (reg > 0xff) {
- mutex_lock(&rt5677->dsp_pri_lock);
- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
- reg & 0xff);
- rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
- val);
- mutex_unlock(&rt5677->dsp_pri_lock);
+ scoped_guard(mutex, &rt5677->dsp_pri_lock) {
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+ reg & 0xff);
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
+ val);
+ }
} else {
rt5677_dsp_mode_i2c_write(rt5677, reg, val);
}
@@ -5399,7 +5408,7 @@ static void rt5677_resume_irq_check(struct work_struct *work)
* Without this explicit check, unplug the headset right after suspend
* starts, then after resume the headset is still shown as plugged in.
*/
- mutex_lock(&rt5677->irq_lock);
+ guard(mutex)(&rt5677->irq_lock);
for (i = 0; i < RT5677_IRQ_NUM; i++) {
if (rt5677->irq_en & rt5677_irq_descs[i].enable_mask) {
virq = irq_find_mapping(rt5677->domain, i);
@@ -5407,7 +5416,6 @@ static void rt5677_resume_irq_check(struct work_struct *work)
handle_nested_irq(virq);
}
}
- mutex_unlock(&rt5677->irq_lock);
}
static void rt5677_irq_bus_lock(struct irq_data *data)
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index dec8c2147d68..23c7d2a9dbee 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -6,6 +6,7 @@
// Author: Oder Chiou <oder_chiou@realtek.com>
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -410,7 +411,9 @@ static int rt5682_io_init(struct device *dev, struct sdw_slave *slave)
if (rt5682->first_hw_init) {
regcache_cache_bypass(rt5682->regmap, false);
regcache_mark_dirty(rt5682->regmap);
- regcache_sync(rt5682->regmap);
+ ret = regcache_sync(rt5682->regmap);
+ if (ret)
+ goto err_sync;
/* volatile registers */
regmap_update_bits(rt5682->regmap, RT5682_CBJ_CTRL_2,
@@ -472,8 +475,16 @@ reinit:
/* Mark Slave initialization complete */
rt5682->hw_init = true;
rt5682->first_hw_init = true;
+ goto out;
+
+err_sync:
+ regcache_cache_bypass(rt5682->regmap, false);
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
err_nodev:
+out:
pm_runtime_put_autosuspend(&slave->dev);
dev_dbg(&slave->dev, "%s hw_init complete: %d\n", __func__, ret);
@@ -660,12 +671,11 @@ static int rt5682_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
- mutex_lock(&rt5682->disable_irq_lock);
+ guard(mutex)(&rt5682->disable_irq_lock);
if (status->control_port & 0x4 && !rt5682->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(rt5682->irq_work_delay_time));
}
- mutex_unlock(&rt5682->disable_irq_lock);
return 0;
}
@@ -736,11 +746,11 @@ static int rt5682_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt5682->disable_irq_lock);
- rt5682->disable_irq = true;
- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
- SDW_SCP_INT1_IMPL_DEF, 0);
- mutex_unlock(&rt5682->disable_irq_lock);
+ scoped_guard(mutex, &rt5682->disable_irq_lock) {
+ rt5682->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ }
if (ret < 0) {
/* log but don't prevent suspend from happening */
@@ -760,12 +770,12 @@ static int rt5682_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt5682->disable_irq_lock);
- if (rt5682->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
- rt5682->disable_irq = false;
+ scoped_guard(mutex, &rt5682->disable_irq_lock) {
+ if (rt5682->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
+ rt5682->disable_irq = false;
+ }
}
- mutex_unlock(&rt5682->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
@@ -776,7 +786,13 @@ static int rt5682_dev_resume(struct device *dev)
regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);
- regcache_sync(rt5682->regmap);
+ ret = regcache_sync(rt5682->regmap);
+ if (ret) {
+ regcache_cache_only(rt5682->sdw_regmap, true);
+ regcache_cache_only(rt5682->regmap, true);
+ regcache_mark_dirty(rt5682->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index 4b82e07d3b2c..6f7e68c20d13 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -6,6 +6,7 @@
// Author: Bard Liao <bardliao@realtek.com>
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -3125,7 +3126,7 @@ void rt5682_calibrate(struct rt5682_priv *rt5682)
{
int value, count;
- mutex_lock(&rt5682->calibrate_mutex);
+ guard(mutex)(&rt5682->calibrate_mutex);
rt5682_reset(rt5682);
regmap_write(rt5682->regmap, RT5682_I2C_CTRL, 0x000f);
@@ -3175,8 +3176,6 @@ void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0xc0c4);
regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0c0c);
-
- mutex_unlock(&rt5682->calibrate_mutex);
}
EXPORT_SYMBOL_GPL(rt5682_calibrate);
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index 3624067950c0..34997cfb465b 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -6,6 +6,7 @@
// Author: Derek Fang <derek.fang@realtek.com>
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -648,7 +649,7 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode
{
struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
- mutex_lock(&rt5682s->sar_mutex);
+ guard(mutex)(&rt5682s->sar_mutex);
switch (mode) {
case SAR_PWR_SAVING:
@@ -695,8 +696,6 @@ static void rt5682s_sar_power_mode(struct snd_soc_component *component, int mode
dev_err(component->dev, "Invalid SAR Power mode: %d\n", mode);
break;
}
-
- mutex_unlock(&rt5682s->sar_mutex);
}
static void rt5682s_enable_push_button_irq(struct snd_soc_component *component)
@@ -2534,7 +2533,7 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw)
if (!rt5682s_clk_check(rt5682s))
return -EINVAL;
- mutex_lock(&rt5682s->wclk_mutex);
+ guard(mutex)(&rt5682s->wclk_mutex);
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB,
@@ -2556,8 +2555,6 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw)
rt5682s->wclk_enabled = 1;
- mutex_unlock(&rt5682s->wclk_mutex);
-
return 0;
}
@@ -2570,7 +2567,7 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw)
if (!rt5682s_clk_check(rt5682s))
return;
- mutex_lock(&rt5682s->wclk_mutex);
+ guard(mutex)(&rt5682s->wclk_mutex);
if (!rt5682s->jack_type)
snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
@@ -2585,8 +2582,6 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw)
rt5682s_set_pllb_power(rt5682s, 0);
rt5682s->wclk_enabled = 0;
-
- mutex_unlock(&rt5682s->wclk_mutex);
}
static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw,
@@ -2997,7 +2992,7 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s)
{
unsigned int count, value;
- mutex_lock(&rt5682s->calibrate_mutex);
+ guard(mutex)(&rt5682s->calibrate_mutex);
regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0xaa80);
usleep_range(15000, 20000);
@@ -3034,8 +3029,6 @@ static void rt5682s_calibrate(struct rt5682s_priv *rt5682s)
regmap_write(rt5682s->regmap, RT5682S_PWR_DIG_1, 0x00c0);
regmap_write(rt5682s->regmap, RT5682S_PWR_ANLG_1, 0x0800);
regmap_write(rt5682s->regmap, RT5682S_GLB_CLK, 0x0000);
-
- mutex_unlock(&rt5682s->calibrate_mutex);
}
static const struct regmap_config rt5682s_regmap = {
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index a451d5d1f8ab..3ba0cc37acd9 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soundwire/sdw.h>
@@ -415,12 +416,11 @@ static int rt700_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
- mutex_lock(&rt700->disable_irq_lock);
+ guard(mutex)(&rt700->disable_irq_lock);
if (status->control_port & 0x4 && !rt700->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt700->jack_detect_work, msecs_to_jiffies(250));
}
- mutex_unlock(&rt700->disable_irq_lock);
return 0;
}
@@ -458,10 +458,8 @@ static void rt700_sdw_remove(struct sdw_slave *slave)
{
struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
- if (rt700->hw_init) {
- cancel_delayed_work_sync(&rt700->jack_detect_work);
- cancel_delayed_work_sync(&rt700->jack_btn_check_work);
- }
+ cancel_delayed_work_sync(&rt700->jack_detect_work);
+ cancel_delayed_work_sync(&rt700->jack_btn_check_work);
pm_runtime_disable(&slave->dev);
}
@@ -501,11 +499,11 @@ static int rt700_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt700->disable_irq_lock);
- rt700->disable_irq = true;
- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
- SDW_SCP_INT1_IMPL_DEF, 0);
- mutex_unlock(&rt700->disable_irq_lock);
+ scoped_guard(mutex, &rt700->disable_irq_lock) {
+ rt700->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ }
if (ret < 0) {
/* log but don't prevent suspend from happening */
diff --git a/sound/soc/codecs/rt700-sdw.h b/sound/soc/codecs/rt700-sdw.h
index 4ad0dcfd16fd..002f94493b01 100644
--- a/sound/soc/codecs/rt700-sdw.h
+++ b/sound/soc/codecs/rt700-sdw.h
@@ -313,17 +313,16 @@ static const struct reg_default rt700_reg_defaults[] = {
{ 0x3122, 0x0000 },
{ 0x3123, 0x0000 },
{ 0x7303, 0x0057 },
- { 0x7303, 0x0057 },
- { 0x8383, 0x0057 },
{ 0x7308, 0x0097 },
- { 0x8388, 0x0097 },
{ 0x7309, 0x0097 },
- { 0x8389, 0x0097 },
{ 0x7312, 0x0000 },
- { 0x8392, 0x0000 },
{ 0x7313, 0x0000 },
- { 0x8393, 0x0000 },
{ 0x7319, 0x0000 },
+ { 0x8383, 0x0057 },
+ { 0x8388, 0x0097 },
+ { 0x8389, 0x0097 },
+ { 0x8392, 0x0000 },
+ { 0x8393, 0x0000 },
{ 0x8399, 0x0000 },
{ 0x75201a, 0x8003 },
{ 0x752045, 0x5289 },
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index e028a1c3a9ac..e292b28b029e 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soundwire/sdw_registers.h>
@@ -415,13 +416,13 @@ static int rt711_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt711_sdca->disable_irq_lock);
- rt711_sdca->disable_irq = true;
- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
- SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
- mutex_unlock(&rt711_sdca->disable_irq_lock);
+ scoped_guard(mutex, &rt711_sdca->disable_irq_lock) {
+ rt711_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -443,13 +444,15 @@ static int rt711_sdca_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt711->disable_irq_lock);
- if (rt711->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
- rt711->disable_irq = false;
+ scoped_guard(mutex, &rt711->disable_irq_lock) {
+ if (rt711->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt711->disable_irq = false;
+ }
}
- mutex_unlock(&rt711->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
diff --git a/sound/soc/codecs/rt711-sdca-sdw.h b/sound/soc/codecs/rt711-sdca-sdw.h
index 0d774e473ab9..9aa22b52d556 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.h
+++ b/sound/soc/codecs/rt711-sdca-sdw.h
@@ -58,12 +58,12 @@ static const struct reg_default rt711_sdca_reg_defaults[] = {
{ 0x2f0f, 0x00 },
{ 0x2f50, 0x03 },
{ 0x2f5a, 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PDE28, RT711_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_CS01, RT711_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
};
@@ -86,14 +86,14 @@ static const struct reg_default rt711_sdca_mbq_defaults[] = {
{ 0x610003f, 0xff12 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU05, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_USER_FU0F, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT711_SDCA_ENT_PLATFORM_FU44, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_L), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_PLATFORM_FU15, RT711_SDCA_CTL_FU_CH_GAIN, CH_R), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_L), 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT711_SDCA_ENT_USER_FU1E, RT711_SDCA_CTL_FU_VOLUME, CH_R), 0x00 },
};
#endif /* __RT711_SDW_SDCA_H__ */
diff --git a/sound/soc/codecs/rt711-sdca.c b/sound/soc/codecs/rt711-sdca.c
index 3a26c782d800..9781f289f8ad 100644
--- a/sound/soc/codecs/rt711-sdca.c
+++ b/sound/soc/codecs/rt711-sdca.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -450,7 +451,7 @@ io_error:
static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711)
{
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
if (rt711->hs_jack) {
/* Enable HID1 event & set button RTC mode */
@@ -515,8 +516,6 @@ static void rt711_sdca_jack_init(struct rt711_sdca_priv *rt711)
dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__);
}
-
- mutex_unlock(&rt711->calibrate_mutex);
}
static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index a0c6a9efa840..4ad2b1da1954 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/soundwire/sdw.h>
@@ -422,12 +423,11 @@ static int rt711_interrupt_callback(struct sdw_slave *slave,
dev_dbg(&slave->dev,
"%s control_port_stat=%x", __func__, status->control_port);
- mutex_lock(&rt711->disable_irq_lock);
+ guard(mutex)(&rt711->disable_irq_lock);
if (status->control_port & 0x4 && !rt711->disable_irq) {
mod_delayed_work(system_power_efficient_wq,
&rt711->jack_detect_work, msecs_to_jiffies(250));
}
- mutex_unlock(&rt711->disable_irq_lock);
return 0;
}
@@ -509,11 +509,11 @@ static int rt711_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt711->disable_irq_lock);
- rt711->disable_irq = true;
- ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
- SDW_SCP_INT1_IMPL_DEF, 0);
- mutex_unlock(&rt711->disable_irq_lock);
+ scoped_guard(mutex, &rt711->disable_irq_lock) {
+ rt711->disable_irq = true;
+ ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1,
+ SDW_SCP_INT1_IMPL_DEF, 0);
+ }
if (ret < 0) {
/* log but don't prevent suspend from happening */
@@ -535,12 +535,12 @@ static int rt711_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt711->disable_irq_lock);
- if (rt711->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
- rt711->disable_irq = false;
+ scoped_guard(mutex, &rt711->disable_irq_lock) {
+ if (rt711->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF);
+ rt711->disable_irq = false;
+ }
}
- mutex_unlock(&rt711->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
diff --git a/sound/soc/codecs/rt711-sdw.h b/sound/soc/codecs/rt711-sdw.h
index 6acf9858330d..82da0e62d9d7 100644
--- a/sound/soc/codecs/rt711-sdw.h
+++ b/sound/soc/codecs/rt711-sdw.h
@@ -256,16 +256,16 @@ static const struct reg_default rt711_reg_defaults[] = {
{ 0x3122, 0x00 },
{ 0x3123, 0x00 },
{ 0x7303, 0x57 },
- { 0x8383, 0x57 },
{ 0x7308, 0x97 },
- { 0x8388, 0x97 },
{ 0x7309, 0x97 },
- { 0x8389, 0x97 },
{ 0x7312, 0x00 },
- { 0x8392, 0x00 },
{ 0x7313, 0x00 },
- { 0x8393, 0x00 },
{ 0x7319, 0x00 },
+ { 0x8383, 0x57 },
+ { 0x8388, 0x97 },
+ { 0x8389, 0x97 },
+ { 0x8392, 0x00 },
+ { 0x8393, 0x00 },
{ 0x8399, 0x00 },
{ 0x752008, 0xa807 },
{ 0x752009, 0x1029 },
diff --git a/sound/soc/codecs/rt711.c b/sound/soc/codecs/rt711.c
index 5dbe9b67703e..3e49c3d0f25b 100644
--- a/sound/soc/codecs/rt711.c
+++ b/sound/soc/codecs/rt711.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -89,24 +90,24 @@ static int rt711_calibration(struct rt711_priv *rt711)
struct regmap *regmap = rt711->regmap;
int ret = 0;
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
dev = regmap_get_device(regmap);
/* Calibration manual mode */
rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL,
- 0xf, 0x0);
+ 0xf, 0x0);
/* trigger */
rt711_index_update_bits(regmap, RT711_VENDOR_CALI,
- RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER,
- RT711_DAC_DC_CALI_TRIGGER);
+ RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER,
+ RT711_DAC_DC_CALI_TRIGGER);
/* wait for calibration process */
rt711_index_read(regmap, RT711_VENDOR_CALI,
- RT711_DAC_DC_CALI_CTL1, &val);
+ RT711_DAC_DC_CALI_CTL1, &val);
while (val & RT711_DAC_DC_CALI_TRIGGER) {
if (loop >= 500) {
@@ -119,16 +120,15 @@ static int rt711_calibration(struct rt711_priv *rt711)
usleep_range(10000, 11000);
rt711_index_read(regmap, RT711_VENDOR_CALI,
- RT711_DAC_DC_CALI_CTL1, &val);
+ RT711_DAC_DC_CALI_CTL1, &val);
}
/* depop mode */
rt711_index_update_bits(regmap, RT711_VENDOR_REG,
- RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL);
+ RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL);
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret);
return ret;
@@ -362,24 +362,24 @@ static void rt711_jack_init(struct rt711_priv *rt711)
{
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(rt711->component);
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
/* power on */
if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
if (rt711->hs_jack) {
/* unsolicited response & IRQ control */
regmap_write(rt711->regmap,
- RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82);
+ RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82);
regmap_write(rt711->regmap,
- RT711_SET_HP_UNSOLICITED_ENABLE, 0x81);
+ RT711_SET_HP_UNSOLICITED_ENABLE, 0x81);
regmap_write(rt711->regmap,
- RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83);
+ RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83);
rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
- 0x10, 0x2420);
+ 0x10, 0x2420);
rt711_index_write(rt711->regmap, RT711_VENDOR_REG,
- 0x19, 0x2e11);
+ 0x19, 0x2e11);
switch (rt711->jd_src) {
case RT711_JD1:
@@ -449,8 +449,7 @@ static void rt711_jack_init(struct rt711_priv *rt711)
/* power off */
if (snd_soc_dapm_get_bias_level(dapm) <= SND_SOC_BIAS_STANDBY)
regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
+ RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
}
static int rt711_set_jack_detect(struct snd_soc_component *component,
@@ -511,7 +510,7 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
unsigned int read_ll, read_rl;
int i;
- mutex_lock(&rt711->calibrate_mutex);
+ guard(mutex)(&rt711->calibrate_mutex);
/* Can't use update bit function, so read the original value first */
addr_h = mc->reg;
@@ -599,7 +598,6 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
regmap_write(rt711->regmap,
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
return 0;
}
@@ -908,11 +906,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
- mutex_lock(&rt711->calibrate_mutex);
- regmap_write(rt711->regmap,
- RT711_SET_AUDIO_POWER_STATE,
- AC_PWRST_D3);
- mutex_unlock(&rt711->calibrate_mutex);
+ scoped_guard(mutex, &rt711->calibrate_mutex) {
+ regmap_write(rt711->regmap,
+ RT711_SET_AUDIO_POWER_STATE,
+ AC_PWRST_D3);
+ }
break;
default:
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 85779547653e..8860d81134e7 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -916,10 +916,23 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
}
regcache_cache_only(rt712->regmap, false);
- regcache_sync(rt712->regmap);
+ ret = regcache_sync(rt712->regmap);
+ if (ret)
+ goto err_sync;
+
regcache_cache_only(rt712->mbq_regmap, false);
- regcache_sync(rt712->mbq_regmap);
+ ret = regcache_sync(rt712->mbq_regmap);
+ if (ret)
+ goto err_sync;
+
return 0;
+
+err_sync:
+ regcache_cache_only(rt712->regmap, true);
+ regcache_cache_only(rt712->mbq_regmap, true);
+ regcache_mark_dirty(rt712->regmap);
+ regcache_mark_dirty(rt712->mbq_regmap);
+ return ret;
}
static const struct dev_pm_ops rt712_sdca_dmic_pm = {
diff --git a/sound/soc/codecs/rt712-sdca-dmic.h b/sound/soc/codecs/rt712-sdca-dmic.h
index 110154e74efe..2f08e58ed519 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.h
+++ b/sound/soc/codecs/rt712-sdca-dmic.h
@@ -36,6 +36,7 @@ struct rt712_sdca_dmic_kctrl_priv {
#define CH_03 0x03
#define CH_04 0x04
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_dmic_reg_defaults[] = {
{ 0x201a, 0x00 },
{ 0x201b, 0x00 },
@@ -72,15 +73,16 @@ static const struct reg_default rt712_sdca_dmic_reg_defaults[] = {
{ 0x2f59, 0x07 },
{ 0x3201, 0x01 },
{ 0x320c, 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT26, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_dmic_mbq_defaults[] = {
{ 0x0590001e, 0x0020 },
{ 0x06100000, 0x0010 },
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 70d661ce2ef2..c50e74e20a88 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
@@ -427,13 +428,13 @@ static int rt712_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt712_sdca->disable_irq_lock);
- rt712_sdca->disable_irq = true;
- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
- SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
- mutex_unlock(&rt712_sdca->disable_irq_lock);
+ scoped_guard(mutex, &rt712_sdca->disable_irq_lock) {
+ rt712_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -455,14 +456,15 @@ static int rt712_sdca_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt712->disable_irq_lock);
- if (rt712->disable_irq == true) {
-
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
- rt712->disable_irq = false;
+ scoped_guard(mutex, &rt712->disable_irq_lock) {
+ if (rt712->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt712->disable_irq = false;
+ }
}
- mutex_unlock(&rt712->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
@@ -472,9 +474,20 @@ static int rt712_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt712->regmap, false);
- regcache_sync(rt712->regmap);
+ ret = regcache_sync(rt712->regmap);
+ if (ret) {
+ regcache_cache_only(rt712->regmap, true);
+ return ret;
+ }
+
regcache_cache_only(rt712->mbq_regmap, false);
- regcache_sync(rt712->mbq_regmap);
+ ret = regcache_sync(rt712->mbq_regmap);
+ if (ret) {
+ regcache_cache_only(rt712->mbq_regmap, true);
+ regcache_cache_only(rt712->regmap, true);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index 99fd2d67f04d..7ad25cc27f62 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -11,21 +11,21 @@
#include <linux/regmap.h>
#include <linux/soundwire/sdw_registers.h>
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_reg_defaults[] = {
-
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
@@ -34,6 +34,7 @@ static const struct reg_default rt712_sdca_reg_defaults[] = {
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
+/* must stay sorted by register address, regcache_lookup_reg() does a bsearch() */
static const struct reg_default rt712_sdca_mbq_defaults[] = {
{ 0x2000004, 0xaa01 },
{ 0x200000e, 0x21e0 },
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index d6353af07380..2218f9918ae3 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -7,6 +7,7 @@
//
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <sound/core.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -403,7 +404,7 @@ io_error:
static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
{
- mutex_lock(&rt712->calibrate_mutex);
+ guard(mutex)(&rt712->calibrate_mutex);
if (rt712->hs_jack) {
/* Enable HID1 event & set button RTC mode */
@@ -450,8 +451,6 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
dev_dbg(&rt712->slave->dev, "in %s disable\n", __func__);
}
-
- mutex_unlock(&rt712->calibrate_mutex);
}
static int rt712_sdca_set_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt715-sdca-sdw.h b/sound/soc/codecs/rt715-sdca-sdw.h
index 0cbc14844f8c..d408f2d7d0f2 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.h
+++ b/sound/soc/codecs/rt715-sdca-sdw.h
@@ -76,8 +76,6 @@ static const struct reg_default rt715_reg_defaults_sdca[] = {
{ 0x2f52, 0x01 },
{ 0x2f5a, 0x02 },
{ 0x2f5b, 0x05 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
- RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC8_9_VOL,
@@ -98,14 +96,12 @@ static const struct reg_default rt715_reg_defaults_sdca[] = {
RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_CX_CLK_SEL_EN,
+ RT715_SDCA_CX_CLK_SEL_CTRL, CH_00), 0x1 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
RT715_SDCA_SMPU_TRIG_EN_CTRL, CH_00), 0x02 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_SMPU_TRIG_ST_EN,
RT715_SDCA_SMPU_TRIG_ST_CTRL, CH_00), 0x00 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
- RT715_SDCA_FU_MUTE_CTRL, CH_01), 0x01 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_ADC7_27_VOL,
- RT715_SDCA_FU_MUTE_CTRL, CH_02), 0x01 },
};
static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
@@ -149,8 +145,6 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
- { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
- RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_01), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
@@ -165,6 +159,8 @@ static const struct reg_default rt715_mbq_reg_defaults_sdca[] = {
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_06), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_07), 0x00 },
+ { SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_AMIC_GAIN_EN,
+ RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
{ SDW_SDCA_CTL(FUN_MIC_ARRAY, RT715_SDCA_FU_DMIC_GAIN_EN,
RT715_SDCA_FU_DMIC_GAIN_CTRL, CH_08), 0x00 },
};
diff --git a/sound/soc/codecs/rt715-sdw.h b/sound/soc/codecs/rt715-sdw.h
index 5d7661e335ae..f19fafb913f0 100644
--- a/sound/soc/codecs/rt715-sdw.h
+++ b/sound/soc/codecs/rt715-sdw.h
@@ -281,8 +281,8 @@ static const struct reg_default rt715_reg_defaults[] = {
{ 0x371b, 0x00 },
{ 0x371d, 0x00 },
{ 0x3729, 0x00 },
- { 0x385e, 0x00 },
{ 0x3859, 0x00 },
+ { 0x385e, 0x00 },
{ 0x4c12, 0x411111f0 },
{ 0x4c13, 0x411111f0 },
{ 0x4c1d, 0x411111f0 },
@@ -300,36 +300,36 @@ static const struct reg_default rt715_reg_defaults[] = {
{ 0x4f1d, 0x411111f0 },
{ 0x4f29, 0x411111f0 },
{ 0x7207, 0x00 },
- { 0x8287, 0x00 },
{ 0x7208, 0x00 },
- { 0x8288, 0x00 },
{ 0x7209, 0x00 },
- { 0x8289, 0x00 },
{ 0x7227, 0x00 },
- { 0x82a7, 0x00 },
{ 0x7307, 0x97 },
- { 0x8387, 0x97 },
{ 0x7308, 0x97 },
- { 0x8388, 0x97 },
{ 0x7309, 0x97 },
- { 0x8389, 0x97 },
{ 0x7312, 0x00 },
- { 0x8392, 0x00 },
{ 0x7313, 0x00 },
- { 0x8393, 0x00 },
{ 0x7318, 0x00 },
- { 0x8398, 0x00 },
{ 0x7319, 0x00 },
- { 0x8399, 0x00 },
{ 0x731a, 0x00 },
- { 0x839a, 0x00 },
{ 0x731b, 0x00 },
- { 0x839b, 0x00 },
{ 0x731d, 0x00 },
- { 0x839d, 0x00 },
{ 0x7327, 0x97 },
- { 0x83a7, 0x97 },
{ 0x7329, 0x00 },
+ { 0x8287, 0x00 },
+ { 0x8288, 0x00 },
+ { 0x8289, 0x00 },
+ { 0x82a7, 0x00 },
+ { 0x8387, 0x97 },
+ { 0x8388, 0x97 },
+ { 0x8389, 0x97 },
+ { 0x8392, 0x00 },
+ { 0x8393, 0x00 },
+ { 0x8398, 0x00 },
+ { 0x8399, 0x00 },
+ { 0x839a, 0x00 },
+ { 0x839b, 0x00 },
+ { 0x839d, 0x00 },
+ { 0x83a7, 0x97 },
{ 0x83a9, 0x00 },
{ 0x752039, 0xa500 },
};
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index 041b381e582b..eae7d662efae 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
@@ -466,13 +467,13 @@ static int rt721_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt721_sdca->disable_irq_lock);
- rt721_sdca->disable_irq = true;
- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
- SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
- mutex_unlock(&rt721_sdca->disable_irq_lock);
+ scoped_guard(mutex, &rt721_sdca->disable_irq_lock) {
+ rt721_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -494,13 +495,15 @@ static int rt721_sdca_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt721->disable_irq_lock);
- if (rt721->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
- rt721->disable_irq = false;
+ scoped_guard(mutex, &rt721->disable_irq_lock) {
+ if (rt721->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt721->disable_irq = false;
+ }
}
- mutex_unlock(&rt721->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
@@ -510,9 +513,20 @@ static int rt721_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt721->regmap, false);
- regcache_sync(rt721->regmap);
+ ret = regcache_sync(rt721->regmap);
+ if (ret) {
+ regcache_cache_only(rt721->regmap, true);
+ return ret;
+ }
+
regcache_cache_only(rt721->mbq_regmap, false);
- regcache_sync(rt721->mbq_regmap);
+ ret = regcache_sync(rt721->mbq_regmap);
+ if (ret) {
+ regcache_cache_only(rt721->mbq_regmap, true);
+ regcache_cache_only(rt721->regmap, true);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt721-sdca-sdw.h b/sound/soc/codecs/rt721-sdca-sdw.h
index 214b31b82583..13d6227f3392 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.h
+++ b/sound/soc/codecs/rt721-sdca-sdw.h
@@ -29,14 +29,6 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
{ 0x2f5b, 0x07 },
{ 0x2f5c, 0x27 },
{ 0x2f5d, 0x07 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
- RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
- RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
- RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
- RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU05,
@@ -45,6 +37,14 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_USER_FU0F,
RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS01,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_CS11,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
@@ -53,30 +53,30 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
RT721_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_USER_FU1E,
RT721_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+ RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_CS1F,
RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_IT26,
RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
- RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
- RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
- RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_CS31,
+ RT721_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_FU55,
RT721_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_OT23,
+ RT721_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
static const struct reg_default rt721_sdca_mbq_defaults[] = {
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
index 35960c225224..159c35d19dba 100644
--- a/sound/soc/codecs/rt721-sdca.c
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -5,7 +5,7 @@
// Copyright(c) 2024 Realtek Semiconductor Corp.
//
//
-
+#include <linux/cleanup.h>
#include <linux/bitops.h>
#include <sound/core.h>
#include <linux/delay.h>
@@ -289,7 +289,7 @@ static void rt721_sdca_jack_preset(struct rt721_sdca_priv *rt721)
static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
{
- mutex_lock(&rt721->calibrate_mutex);
+ guard(mutex)(&rt721->calibrate_mutex);
if (rt721->hs_jack) {
sdw_write_no_pm(rt721->slave, SDW_SCP_SDCA_INTMASK1,
SDW_SCP_SDCA_INTMASK_SDCA_0);
@@ -309,7 +309,6 @@ static void rt721_sdca_jack_init(struct rt721_sdca_priv *rt721)
rt_sdca_index_update_bits(rt721->mbq_regmap, RT721_HDA_SDCA_FLOAT,
RT721_GE_REL_CTRL1, 0x4000, 0x4000);
}
- mutex_unlock(&rt721->calibrate_mutex);
}
static int rt721_sdca_set_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 7482a9a8d198..5bc9aed58d14 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
@@ -517,13 +518,13 @@ static int rt722_sdca_dev_system_suspend(struct device *dev)
* deferred work completes and before the parent disables
* interrupts on the link
*/
- mutex_lock(&rt722_sdca->disable_irq_lock);
- rt722_sdca->disable_irq = true;
- ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
- SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
- ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
- SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
- mutex_unlock(&rt722_sdca->disable_irq_lock);
+ scoped_guard(mutex, &rt722_sdca->disable_irq_lock) {
+ rt722_sdca->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8, 0);
+ }
if (ret1 < 0 || ret2 < 0) {
/* log but don't prevent suspend from happening */
@@ -545,13 +546,15 @@ static int rt722_sdca_dev_resume(struct device *dev)
return 0;
if (!slave->unattach_request) {
- mutex_lock(&rt722->disable_irq_lock);
- if (rt722->disable_irq == true) {
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1, SDW_SCP_SDCA_INTMASK_SDCA_0);
- sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2, SDW_SCP_SDCA_INTMASK_SDCA_8);
- rt722->disable_irq = false;
+ scoped_guard(mutex, &rt722->disable_irq_lock) {
+ if (rt722->disable_irq) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK1,
+ SDW_SCP_SDCA_INTMASK_SDCA_0);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK2,
+ SDW_SCP_SDCA_INTMASK_SDCA_8);
+ rt722->disable_irq = false;
+ }
}
- mutex_unlock(&rt722->disable_irq_lock);
}
ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
@@ -561,7 +564,13 @@ static int rt722_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(rt722->regmap, false);
- regcache_sync(rt722->regmap);
+ ret = regcache_sync(rt722->regmap);
+ if (ret) {
+ regcache_cache_only(rt722->regmap, true);
+ regcache_mark_dirty(rt722->regmap);
+ return ret;
+ }
+
return 0;
}
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
index 6b509eb65d77..4cbe9e909585 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -6,6 +6,7 @@
//
//
+#include <linux/cleanup.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dmi.h>
@@ -294,7 +295,7 @@ io_error:
static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
{
- mutex_lock(&rt722->calibrate_mutex);
+ guard(mutex)(&rt722->calibrate_mutex);
if (rt722->hs_jack) {
/* set SCP_SDCA_IntMask1[0]=1 */
sdw_write_no_pm(rt722->slave, SDW_SCP_SDCA_INTMASK1,
@@ -317,7 +318,6 @@ static void rt722_sdca_jack_init(struct rt722_sdca_priv *rt722)
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
RT722_GE_RELATED_CTL2, 0x4000, 0x4000);
}
- mutex_unlock(&rt722->calibrate_mutex);
}
static int rt722_sdca_set_jack_detect(struct snd_soc_component *component,
@@ -352,8 +352,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
static const char func_tag[] = "FUNC";
static const char xu_tag[] = "XU";
const char *dmi_vendor, *dmi_product, *dmi_sku;
- char *cae_filename;
- const struct firmware *cae_fw = NULL;
unsigned int cae_st_spk, cae_st_hp, cae_st_mic;
unsigned int func, value;
unsigned int combined_val;
@@ -385,7 +383,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
space = strchr(dmi_sku, ' ');
s_len = space ? space - dmi_sku : strlen(dmi_sku);
- cae_filename = kasprintf(GFP_KERNEL,
+ char *cae_filename __free(kfree) =
+ kasprintf(GFP_KERNEL,
"realtek/rt722/rt722_RAE_%.*s_%.*s_%.*s.dat",
v_len, dmi_vendor,
p_len, dmi_product,
@@ -399,8 +398,8 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
regmap_write(rt722->regmap, RT722_MIC_CAE_PARAM39, 0x5f);
usleep_range(50000, 60000);
+ const struct firmware *cae_fw __free(firmware) = NULL;
request_firmware(&cae_fw, cae_filename, dev);
- kfree(cae_filename);
if (!cae_fw) {
dev_err(dev, "%s: Failed to load CAE firmware\n", __func__);
return -ENOENT;
@@ -555,7 +554,6 @@ static int rt722_cae_load(struct rt722_sdca_priv *rt722)
regcache_cache_bypass(rt722->regmap, false);
rt722->cae_update_done = 1;
dev_dbg(dev, "%s: CAE FW update done.\n", __func__);
- release_firmware(cae_fw);
return 0;
verify_abort:
@@ -565,7 +563,6 @@ verify_abort:
out_release:
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
RT722_MISC_CTRL1, 0x8000, 0x0000);
- release_firmware(cae_fw);
dev_err(dev, "%s: CAE FW update aborted (ret=%d).\n", __func__, ret);
return ret;
}
@@ -1906,6 +1903,9 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
rt722_sdca_amp_preset(rt722);
rt722_sdca_jack_preset(rt722);
+ if (rt722->hs_jack && (!rt722->first_hw_init))
+ rt722_sdca_jack_init(rt722);
+
if (rt722->first_hw_init) {
regcache_cache_bypass(rt722->regmap, false);
regcache_mark_dirty(rt722->regmap);
diff --git a/sound/soc/codecs/rt766-sdca-sdw.c b/sound/soc/codecs/rt766-sdca-sdw.c
new file mode 100644
index 000000000000..5d60c3bcc6cd
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca-sdw.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt766-sdca-sdw.c -- rt766 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2026 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include "rt766-sdca.h"
+#include "rt766-sdca-sdw.h"
+
+#define RT766_PROBE_TIMEOUT 5000
+
+static bool rt766_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4:
+ case RT766_VERSION_ID ... RT766_BOND_LATCH_ID:
+ case 0xc344 ... 0xc345:
+ case 0xc900:
+ case 0xc920:
+ case 0xd540 ... 0xd542:
+ case 0xf01e:
+ case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1:
+ case 0x310100:
+ case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END:
+ case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END:
+ case RT766_MUTE_REG(UAJ, USER_FU41, 1):
+ case RT766_MUTE_REG(UAJ, USER_FU41, 2):
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 2):
+ case RT766_MUTE_REG(UAJ, USER_FU36, 1):
+ case RT766_MUTE_REG(UAJ, USER_FU36, 2):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 2):
+ case RT766_PDE_REQ_REG(UAJ, PDE47):
+ case RT766_PDE_REQ_REG(UAJ, PDE34):
+ case RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_FUNC_STATUS_REG(UAJ): /* 0x40480000 */
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE47): /* 0x40481400 */
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE34): /* 0x40481480 */
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1):
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2):
+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE):
+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE): /* 0x40600490 */
+ case RT766_PDE_REQ_REG(MIC, PDE11):
+ case RT766_MUTE_REG(MIC, USER_FU113, 1):
+ case RT766_MUTE_REG(MIC, USER_FU113, 2):
+ case RT766_MUTE_REG(MIC, USER_FU113, 3):
+ case RT766_MUTE_REG(MIC, USER_FU113, 4):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 1):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 2):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 3):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 4):
+ case RT766_FUNC_STATUS_REG(MIC): /* 0x40880000 */
+ case RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_PDE_ACTUAL_REG(MIC, PDE11): /* 0x40881500 */
+ case RT766_FUNC_STATUS_REG(HID): /* 0x40c80000 */
+ /* 0x40c80080 - 0x40c80098 */
+ case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ...
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH):
+ case RT766_MUTE_REG(AMP, USER_FU21, 1):
+ case RT766_MUTE_REG(AMP, USER_FU21, 2):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 1):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 2):
+ case RT766_PDE_REQ_REG(AMP, PDE23):
+ case RT766_FUNC_STATUS_REG(AMP): /* 0x41080000 */
+ case RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER):
+ case RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX):
+ case RT766_PDE_ACTUAL_REG(AMP, PDE23): /* 0x41081980 */
+ case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool rt766_sdca_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INTMASK4:
+ case RT766_VERSION_ID ... RT766_BOND_LATCH_ID:
+ case 0xc344 ... 0xc345:
+ case 0xc900:
+ case 0xc920:
+ case 0xd540 ... 0xd542:
+ case 0xf01e:
+ case RT766_HP_POWER_STATE ... RT766_HP_FSM_CTL2_1:
+ case 0x310100:
+ case RT766_MCU_PATCH_ADDR1_START ... RT766_MCU_PATCH_ADDR1_END:
+ case RT766_MCU_PATCH_ADDR2_START ... RT766_MCU_PATCH_ADDR2_END:
+ case RT766_FUNC_STATUS_REG(UAJ):
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE47):
+ case RT766_PDE_ACTUAL_REG(UAJ, PDE34):
+ case RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE):
+ case RT766_FUNC_STATUS_REG(MIC):
+ case RT766_PDE_ACTUAL_REG(MIC, PDE11):
+ case RT766_FUNC_STATUS_REG(HID):
+ case RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER) ...
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH):
+ case RT766_FUNC_STATUS_REG(AMP):
+ case RT766_PDE_ACTUAL_REG(AMP, PDE23):
+ case RT766_BUF_ADDR_HID1 ... RT766_BUF_ADDR_HID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int rt766_sdca_mbq_size(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU41, 2):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 1):
+ case RT766_VOLUME_REG(UAJ, USER_FU36, 2):
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1):
+ case RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 1):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 2):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 3):
+ case RT766_VOLUME_REG(MIC, USER_FU113, 4):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 1):
+ case RT766_VOLUME_REG(AMP, USER_FU21, 2):
+ return 2;
+ default:
+ return 1;
+ }
+}
+
+static const struct regmap_sdw_mbq_cfg rt766_sdca_mbq_cfg = {
+ .mbq_size = rt766_sdca_mbq_size,
+};
+
+static const struct regmap_config rt766_sdca_regmap = {
+ .reg_bits = 32,
+ .val_bits = 16,
+ .readable_reg = rt766_sdca_readable_register,
+ .volatile_reg = rt766_sdca_volatile_register,
+ .reg_defaults = rt766_sdca_defaults,
+ .num_reg_defaults = ARRAY_SIZE(rt766_sdca_defaults),
+ .max_register = SDW_SDCA_MAX_REGISTER,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int rt766_sdca_update_status(struct sdw_slave *slave,
+ enum sdw_slave_status status)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(&slave->dev);
+
+ if (status == SDW_SLAVE_UNATTACHED)
+ rt766->hw_init = false;
+
+ if (status == SDW_SLAVE_ATTACHED) {
+ if (rt766->hs_jack) {
+ /*
+ * Due to the SCP_SDCA_INTMASK will be cleared by any reset, and then
+ * if the device attached again, we will need to set the setting back.
+ * It could avoid losing the jack detection interrupt.
+ * This also could sync with the cache value as the rt766_sdca_jack_init set.
+ */
+ sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK3,
+ SDW_SCP_SDCA_INTMASK_SDCA_16);
+ sdw_write_no_pm(rt766->slave, SDW_SCP_SDCA_INTMASK4,
+ SDW_SCP_SDCA_INTMASK_SDCA_24);
+ }
+ }
+
+ /*
+ * Perform initialization only if slave status is present and
+ * hw_init flag is false
+ */
+ if (rt766->hw_init || status != SDW_SLAVE_ATTACHED)
+ return 0;
+
+ /* perform I/O transfers required for Slave initialization */
+ return rt766_sdca_io_init(&slave->dev, slave);
+}
+
+static int rt766_sdca_read_prop(struct sdw_slave *slave)
+{
+ struct sdw_slave_prop *prop = &slave->prop;
+ int ret;
+
+ ret = sdw_slave_read_prop(slave);
+ if (ret < 0)
+ return ret;
+
+ prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
+ prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
+ /*
+ * SDCA interrupts are routed through SoundWire domain IRQ.
+ */
+ prop->use_domain_irq = true;
+
+ return 0;
+}
+
+static const struct sdw_slave_ops rt766_sdca_slave_ops = {
+ .read_prop = rt766_sdca_read_prop,
+ .update_status = rt766_sdca_update_status,
+};
+
+static int rt766_sdca_sdw_probe(struct sdw_slave *slave,
+ const struct sdw_device_id *id)
+{
+ struct regmap *regmap;
+
+ /* Regmap Initialization */
+ regmap = devm_regmap_init_sdw_mbq_cfg(&slave->dev, slave,
+ &rt766_sdca_regmap, &rt766_sdca_mbq_cfg);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return rt766_sdca_init(&slave->dev, regmap, slave);
+}
+
+static void rt766_sdca_sdw_remove(struct sdw_slave *slave)
+{
+ pm_runtime_disable(&slave->dev);
+}
+
+static const struct sdw_device_id rt766_sdca_id[] = {
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x766, 0x3, 0x1, 0),
+ SDW_SLAVE_ENTRY_EXT(0x025d, 0x767, 0x3, 0x1, 0),
+ {},
+};
+MODULE_DEVICE_TABLE(sdw, rt766_sdca_id);
+
+static int rt766_sdca_dev_suspend(struct device *dev)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+
+ if (!rt766->hw_init)
+ return 0;
+
+ regcache_cache_only(rt766->regmap, true);
+ return 0;
+}
+
+static int rt766_sdca_dev_system_suspend(struct device *dev)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ int ret1, ret2;
+
+ if (!rt766->hw_init)
+ return 0;
+
+ /*
+ * prevent new interrupts from being handled after the
+ * deferred work completes and before the parent disables
+ * interrupts on the link
+ */
+ mutex_lock(&rt766->disable_irq_lock);
+ rt766->disable_irq = true;
+ ret1 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK3,
+ SDW_SCP_SDCA_INTMASK_SDCA_16, 0);
+ ret2 = sdw_update_no_pm(slave, SDW_SCP_SDCA_INTMASK4,
+ SDW_SCP_SDCA_INTMASK_SDCA_24, 0);
+ mutex_unlock(&rt766->disable_irq_lock);
+
+ if (ret1 < 0 || ret2 < 0) {
+ /* log but don't prevent suspend from happening */
+ dev_dbg(&slave->dev, "%s: could not disable SDCA interrupts\n:", __func__);
+ }
+
+ return rt766_sdca_dev_suspend(dev);
+}
+
+static int rt766_sdca_dev_resume(struct device *dev)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+ int ret;
+
+ if (!rt766->first_hw_init)
+ return 0;
+
+ if (!slave->unattach_request) {
+ mutex_lock(&rt766->disable_irq_lock);
+ if (rt766->disable_irq == true) {
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK3, SDW_SCP_SDCA_INTMASK_SDCA_16);
+ sdw_write_no_pm(slave, SDW_SCP_SDCA_INTMASK4, SDW_SCP_SDCA_INTMASK_SDCA_24);
+ rt766->disable_irq = false;
+ }
+ mutex_unlock(&rt766->disable_irq_lock);
+ goto regmap_sync;
+ }
+
+ ret = sdw_slave_wait_for_init(slave, RT766_PROBE_TIMEOUT);
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
+ return ret;
+ }
+
+regmap_sync:
+ regcache_cache_only(rt766->regmap, false);
+ ret = regcache_sync(rt766->regmap);
+ if (ret) {
+ regcache_cache_only(rt766->regmap, true);
+ regcache_mark_dirty(rt766->regmap);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops rt766_sdca_pm = {
+ SYSTEM_SLEEP_PM_OPS(rt766_sdca_dev_system_suspend, rt766_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt766_sdca_dev_suspend, rt766_sdca_dev_resume, NULL)
+};
+
+static struct sdw_driver rt766_sdca_sdw_driver = {
+ .driver = {
+ .name = "rt766-sdca",
+ .pm = pm_ptr(&rt766_sdca_pm),
+ },
+ .probe = rt766_sdca_sdw_probe,
+ .remove = rt766_sdca_sdw_remove,
+ .ops = &rt766_sdca_slave_ops,
+ .id_table = rt766_sdca_id,
+};
+module_sdw_driver(rt766_sdca_sdw_driver);
+
+MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt766-sdca-sdw.h b/sound/soc/codecs/rt766-sdca-sdw.h
new file mode 100644
index 000000000000..3e923a1ea2f8
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca-sdw.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt766-sdca-sdw.h -- RT766 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2026 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT766_SDW_H__
+#define __RT766_SDW_H__
+
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+
+static const struct reg_default rt766_sdca_defaults[] = {
+ /* 0x40400289 - 0x4040028a */
+ { RT766_MUTE_REG(UAJ, USER_FU41, 1), 0x01 },
+ { RT766_MUTE_REG(UAJ, USER_FU41, 2), 0x01 },
+ /* 0x40400291 - 0x40400292 */
+ { RT766_VOLUME_REG(UAJ, USER_FU41, 1), 0x0000 },
+ { RT766_VOLUME_REG(UAJ, USER_FU41, 2), 0x0000 },
+ /* 0x40400789 - 0x4040078a */
+ { RT766_MUTE_REG(UAJ, USER_FU36, 1), 0x01 },
+ { RT766_MUTE_REG(UAJ, USER_FU36, 2), 0x01 },
+ /* 0x40400791 - 0x40400792 */
+ { RT766_VOLUME_REG(UAJ, USER_FU36, 1), 0x0000 },
+ { RT766_VOLUME_REG(UAJ, USER_FU36, 2), 0x0000 },
+ { RT766_PDE_REQ_REG(UAJ, PDE47), 0x03 }, /* 0x40401408 */
+ { RT766_PDE_REQ_REG(UAJ, PDE34), 0x03 }, /* 0x40401488 */
+ { RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480080 */
+ { RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40480880 */
+ /* 0x40600259 - 0x4060025a */
+ { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1), 0xfe00 },
+ { RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2), 0xfe00 },
+ { RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE), 0x00 }, /* 0x40600488 */
+
+ { RT766_PDE_REQ_REG(MIC, PDE11), 0x03 }, /* 0x40801508 */
+ /* 0x40801809 - 0x4080180c */
+ { RT766_MUTE_REG(MIC, USER_FU113, 1), 0x01 },
+ { RT766_MUTE_REG(MIC, USER_FU113, 2), 0x01 },
+ { RT766_MUTE_REG(MIC, USER_FU113, 3), 0x01 },
+ { RT766_MUTE_REG(MIC, USER_FU113, 4), 0x01 },
+ /* 0x40801811 - 0x40801814 */
+ { RT766_VOLUME_REG(MIC, USER_FU113, 1), 0x0000 },
+ { RT766_VOLUME_REG(MIC, USER_FU113, 2), 0x0000 },
+ { RT766_VOLUME_REG(MIC, USER_FU113, 3), 0x0000 },
+ { RT766_VOLUME_REG(MIC, USER_FU113, 4), 0x0000 },
+ { RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x40880900 */
+
+ /* 0x41000189 - 0x4100018a */
+ { RT766_MUTE_REG(AMP, USER_FU21, 1), 0x01 },
+ { RT766_MUTE_REG(AMP, USER_FU21, 2), 0x01 },
+ /* 0x41000191 - 0x41000192 */
+ { RT766_VOLUME_REG(AMP, USER_FU21, 1), 0x0000 },
+ { RT766_VOLUME_REG(AMP, USER_FU21, 2), 0x0000 },
+ { RT766_PDE_REQ_REG(AMP, PDE23), 0x03 }, /* 0x41001988 */
+ { RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0x00 }, /* 0x41080200 */
+ { RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX), 0x09 }, /* 0x41081080 */
+
+};
+
+#endif /* __RT766_SDW_H__ */
diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c
new file mode 100644
index 000000000000..64d763b96a06
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca.c
@@ -0,0 +1,1378 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// rt766-sdca.c -- rt766 SDCA ALSA SoC audio driver
+//
+// Copyright(c) 2026 Realtek Semiconductor Corp.
+//
+//
+
+#include <linux/bitops.h>
+#include <sound/core.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_asoc.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_hid.h>
+#include <sound/sdca_regmap.h>
+#include <sound/sdca_interrupts.h>
+#include <linux/slab.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "rt766-sdca.h"
+#include "rt-sdw-common.h"
+
+static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt)
+{
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+ unsigned char *buf = NULL;
+ unsigned int offset, owner, length;
+ unsigned int det_mode, idx, val;
+ int ret;
+
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE),
+ &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ /* get current UMP message owner */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER),
+ &owner);
+ if (ret < 0)
+ goto io_error;
+
+ /* if owner is device then there is no button event from device */
+ if (owner == 1)
+ return 0;
+
+ if (det_mode) {
+ /* read UMP message length */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH),
+ &length);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ /* read UMP message offset */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET),
+ &offset);
+ if (ret < 0)
+ goto _end_btn_det_;
+
+ buf = devm_kzalloc(&rt766->slave->dev, length, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&rt766->slave->dev, "%s: alloc buf failed\n", __func__);
+ goto _end_btn_det_;
+ }
+
+ for (idx = 0; idx < length; idx++) {
+ ret = regmap_read(rt766->regmap,
+ RT766_BUF_ADDR_HID1 + offset + idx, &val);
+ if (ret < 0)
+ goto _end_btn_det_;
+ buf[idx] = val & 0xff;
+ }
+
+ if (rt766->hid)
+ hid_input_report(rt766->hid, HID_INPUT_REPORT,
+ buf, length, 1);
+ }
+
+_end_btn_det_:
+ if (buf)
+ devm_kfree(&rt766->slave->dev, buf);
+
+ /* Host is owner, so set back to device */
+ if (owner == 0) {
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(HID, HID101, SDCA_CTL_HIDE_HIDTX_CURRENTOWNER), 0x01);
+ }
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static irqreturn_t rt766_sdca_irq_btn_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+
+ if (!rt766->hs_jack)
+ return IRQ_HANDLED;
+
+ if (!rt766->component->card || !rt766->component->card->instantiated)
+ return IRQ_HANDLED;
+
+ mutex_lock(&rt766->disable_irq_lock);
+ if (!rt766->disable_irq)
+ rt766_sdca_btn_detect(interrupt);
+ mutex_unlock(&rt766->disable_irq_lock);
+ return IRQ_HANDLED;
+}
+
+static int rt766_sdca_headset_detect(struct rt766_sdca_priv *rt766)
+{
+ unsigned int det_mode;
+ int ret;
+
+ /* get detected_mode */
+ ret = regmap_read(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_DETECTED_MODE),
+ &det_mode);
+ if (ret < 0)
+ goto io_error;
+
+ switch (det_mode) {
+ case 0x00:
+ rt766->jack_type = 0;
+ break;
+ case 0x03:
+ rt766->jack_type = SND_JACK_HEADPHONE;
+ break;
+ case 0x05:
+ rt766->jack_type = SND_JACK_HEADSET;
+ break;
+ }
+
+ /* write selected_mode */
+ if (det_mode) {
+ ret = regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, GE49, SDCA_CTL_GE_SELECTED_MODE),
+ det_mode);
+ if (ret < 0)
+ goto io_error;
+ }
+
+ dev_dbg(&rt766->slave->dev,
+ "%s, detected_mode=0x%x\n", __func__, det_mode);
+
+ return 0;
+
+io_error:
+ pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
+ return ret;
+}
+
+static irqreturn_t rt766_sdca_irq_jd_handler(int irq, void *data)
+{
+ struct sdca_interrupt *interrupt = data;
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+
+ if (!rt766->hs_jack)
+ return IRQ_HANDLED;
+
+ if (!rt766->component->card || !rt766->component->card->instantiated)
+ return IRQ_HANDLED;
+
+ mutex_lock(&rt766->disable_irq_lock);
+ if (!rt766->disable_irq)
+ rt766_sdca_headset_detect(rt766);
+ mutex_unlock(&rt766->disable_irq_lock);
+
+ dev_dbg(&rt766->slave->dev,
+ "in %s, jack_type=%d\n", __func__, rt766->jack_type);
+
+ snd_soc_jack_report(rt766->hs_jack, rt766->jack_type, SND_JACK_HEADSET);
+ return IRQ_HANDLED;
+}
+
+static void rt766_sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
+{
+ struct rt766_sdca_priv *rt766 = interrupt->priv;
+
+ hid_destroy_device(rt766->hid);
+}
+
+static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766,
+ struct sdca_function_data *function,
+ struct snd_soc_component *component,
+ struct sdca_interrupt_info *info,
+ bool enabled)
+{
+ struct device *dev = &rt766->slave->dev;
+ struct sdca_interrupt *interrupt;
+ struct sdca_control *control;
+ struct sdca_entity *entity;
+ irq_handler_t handler;
+ int i, j, irq, ret;
+
+ for (i = 0; i < function->num_entities; i++) {
+ entity = &function->entities[i];
+
+ for (j = 0; j < entity->num_controls; j++) {
+ control = &entity->controls[j];
+ irq = control->interrupt_position;
+
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ handler = rt766_sdca_irq_jd_handler;
+ break;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ handler = rt766_sdca_irq_btn_handler;
+ break;
+ default:
+ continue;
+ }
+
+ interrupt = &info->irqs[irq];
+
+ if (enabled) {
+ ret = sdca_irq_data_populate(dev, rt766->regmap, component,
+ function, entity, control,
+ interrupt);
+ if (ret)
+ return ret;
+
+ if (handler == rt766_sdca_irq_btn_handler) {
+ ret = sdca_add_hid_device(interrupt);
+ if (ret)
+ return ret;
+
+ interrupt->free_priv = rt766_sdca_destroy_hid_device;
+ rt766->hid = interrupt->priv;
+ }
+
+ interrupt->priv = rt766;
+ ret = sdca_irq_request(dev, info, irq, interrupt->name,
+ handler, interrupt);
+ if (ret) {
+ dev_err(dev, "failed to request irq %s: %d\n",
+ interrupt->name, ret);
+ sdca_irq_cleanup_late(dev, function, info);
+ return ret;
+ }
+ dev_dbg(dev, "Requesting IRQ %d InterruptName=%s\n", irq, interrupt->name);
+ } else {
+ sdca_irq_cleanup_late(dev, function, info);
+ dev_dbg(dev, "Freeing IRQ %d\n", irq);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int rt766_sdca_set_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *hs_jack, void *data)
+{
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ if (!rt766->uaj_func_data) {
+ dev_err(&rt766->slave->dev, "The SDCA UAJ function is not supported.\n");
+ return -EINVAL;
+ }
+
+ rt766->hs_jack = hs_jack;
+
+ if (!rt766->first_hw_init)
+ return 0;
+
+ ret = pm_runtime_resume_and_get(component->dev);
+ if (ret < 0) {
+ if (ret != -EACCES) {
+ dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* pm_runtime not enabled yet */
+ dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
+ return 0;
+ }
+
+ /* disable interrupts if hs_jack is not set */
+ if (!rt766->hs_jack) {
+ if (rt766->uaj_func_data)
+ rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data,
+ rt766->component, rt766->irq_info, false);
+
+ if (rt766->hid_func_data)
+ rt766_sdca_irq_ctl(rt766, rt766->hid_func_data,
+ rt766->component, rt766->irq_info, false);
+ }
+
+ pm_runtime_put_autosuspend(component->dev);
+
+ return 0;
+}
+
+static int rt766_sdca_set_fu_ctl(struct rt766_sdca_priv *rt766, int func_num, int fu_num)
+{
+ unsigned int fu01_reg, fu02_reg;
+ unsigned int ch_01, ch_02;
+ unsigned int ch_mute;
+ unsigned int fu_reg;
+ int err, i;
+
+ switch (fu_num) {
+ case RT766_SDCA_ENT_USER_FU41:
+ ch_01 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt766->fu41_dapm_mute || rt766->fu41_mixer_r_mute) ? 0x01 : 0x00;
+ break;
+ case RT766_SDCA_ENT_USER_FU36:
+ ch_01 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt766->fu36_dapm_mute || rt766->fu36_mixer_r_mute) ? 0x01 : 0x00;
+ break;
+ case RT766_SDCA_ENT_USER_FU21:
+ ch_01 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt766->fu21_dapm_mute || rt766->fu21_mixer_r_mute) ? 0x01 : 0x00;
+ break;
+ case RT766_SDCA_ENT_USER_FU113:
+ for (i = 0; i < ARRAY_SIZE(rt766->fu113_mixer_mute); i++) {
+ ch_mute = (rt766->fu113_dapm_mute || rt766->fu113_mixer_mute[i]) ? 0x01 : 0x00;
+ fu_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1) + i;
+ err = regmap_write(rt766->regmap, fu_reg, ch_mute);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+ }
+
+ fu01_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 1);
+ fu02_reg = SDW_SDCA_CTL(func_num, fu_num, SDCA_CTL_FU_MUTE, 2);
+ err = regmap_write(rt766->regmap, fu01_reg, ch_01);
+ if (err < 0)
+ return err;
+ err = regmap_write(rt766->regmap, fu02_reg, ch_02);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt766_sdca_fu41_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt766->fu41_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt766->fu41_mixer_r_mute;
+ return 0;
+}
+
+static int rt766_sdca_fu41_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt766->fu41_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt766->fu41_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt766->fu41_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt766->fu41_mixer_r_mute = !ucontrol->value.integer.value[1];
+
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+static int rt766_sdca_fu36_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt766->fu36_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt766->fu36_mixer_r_mute;
+ return 0;
+}
+
+static int rt766_sdca_fu36_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt766->fu36_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt766->fu36_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt766->fu36_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt766->fu36_mixer_r_mute = !ucontrol->value.integer.value[1];
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+static int rt766_sdca_fu21_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt766->fu21_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt766->fu21_mixer_r_mute;
+ return 0;
+}
+
+static int rt766_sdca_fu21_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt766->fu21_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt766->fu21_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt766->fu21_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt766->fu21_mixer_r_mute = !ucontrol->value.integer.value[1];
+
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
+static int rt766_sdca_fu113_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu113_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu113_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ const unsigned int interval_offset = 0xc0;
+ unsigned int regvalue, ctl, i;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt766->regmap, p->reg_base + i, &regvalue);
+ ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+
+ ucontrol->value.integer.value[i] = ctl;
+ }
+
+ return 0;
+}
+
+static int rt766_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ const unsigned int interval_offset = 0xc0;
+ unsigned int gain_val[4];
+ unsigned int i, changed = 0;
+ unsigned int regvalue[4];
+ int err;
+
+ /* check all channels */
+ for (i = 0; i < p->count; i++) {
+ regmap_read(rt766->regmap, p->reg_base + i, &regvalue[i]);
+
+ gain_val[i] = ucontrol->value.integer.value[i];
+ if (gain_val[i] > p->max)
+ gain_val[i] = p->max;
+
+ gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+ gain_val[i] &= 0xffff;
+
+ if (regvalue[i] != gain_val[i])
+ changed = 1;
+ }
+
+ if (!changed)
+ return 0;
+
+ for (i = 0; i < p->count; i++) {
+ err = regmap_write(rt766->regmap, p->reg_base + i, gain_val[i]);
+ if (err < 0)
+ dev_err(&rt766->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+ }
+
+ return changed;
+}
+
+static int rt766_sdca_dmic_fu113_capture_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ unsigned int i;
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.integer.value[i] = !rt766->fu113_mixer_mute[i];
+ return 0;
+}
+
+static int rt766_sdca_dmic_fu113_capture_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ int err, changed = 0, i;
+
+ for (i = 0; i < 4; i++) {
+ if (rt766->fu113_mixer_mute[i] != !ucontrol->value.integer.value[i])
+ changed = 1;
+ rt766->fu113_mixer_mute[i] = !ucontrol->value.integer.value[i];
+ }
+
+ err = rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_USER_FU113);
+ if (err < 0)
+ return err;
+ return changed;
+}
+
+static int rt766_sdca_fu41_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu41_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu41_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU41);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_pde_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event, int func_num, int pde_num, const char *pde_ent)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct sdca_function_data *func_data;
+ unsigned char ps0 = 0x0, ps3 = 0x3;
+ const struct sdca_entity *entity;
+ unsigned int pde_req_reg;
+ int from_ps, to_ps;
+ int ret;
+
+ pde_req_reg = SDW_SDCA_CTL(func_num, pde_num, SDCA_CTL_PDE_REQUESTED_PS, 0);
+
+ switch (func_num) {
+ case RT766_FUNC_NUM_UAJ:
+ func_data = rt766->uaj_func_data;
+ break;
+ case RT766_FUNC_NUM_AMP:
+ func_data = rt766->sa_func_data;
+ break;
+ case RT766_FUNC_NUM_MIC:
+ func_data = rt766->sm_func_data;
+ break;
+ default:
+ dev_err(component->dev, "%s: unsupported func_num %d\n",
+ __func__, func_num);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ regmap_write(rt766->regmap, pde_req_reg, ps0);
+ from_ps = ps3;
+ to_ps = ps0;
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ regmap_write(rt766->regmap, pde_req_reg, ps3);
+ from_ps = ps0;
+ to_ps = ps3;
+ break;
+ }
+
+ entity = sdca_find_entity_by_label(func_data, pde_ent);
+ if (!entity) {
+ dev_err(component->dev, "%s: failed to find entity %s\n",
+ __func__, pde_ent);
+ return -EINVAL;
+ }
+
+ ret = sdca_asoc_pde_poll_actual_ps(rt766->regmap,
+ func_num,
+ pde_num,
+ from_ps, to_ps,
+ entity->pde.max_delay,
+ entity->pde.num_max_delay);
+ if (ret)
+ dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n",
+ __func__, from_ps, to_ps, ret);
+
+ return ret;
+}
+
+static int rt766_sdca_pde47_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE47, "PDE 47");
+}
+
+static int rt766_sdca_fu36_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu36_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu36_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_USER_FU36);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_pde34_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_UAJ, RT766_SDCA_ENT_PDE34, "PDE 34");
+}
+
+static int rt766_sdca_fu21_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ rt766->fu21_dapm_mute = false;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ rt766->fu21_dapm_mute = true;
+ rt766_sdca_set_fu_ctl(rt766, RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_USER_FU21);
+ break;
+ }
+ return 0;
+}
+
+static int rt766_sdca_pde23_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_AMP, RT766_SDCA_ENT_PDE23, "PDE 23");
+}
+
+static int rt766_sdca_pde11_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ return rt766_sdca_pde_event(w, kcontrol, event,
+ RT766_FUNC_NUM_MIC, RT766_SDCA_ENT_PDE11, "PDE 11");
+}
+
+static int rt766_dmic_fu_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rt_sdca_dmic_kctrl_priv *p =
+ (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+ if (p->max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = p->count;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = p->max;
+ return 0;
+}
+
+static const char * const rt766_rx_data_ch_select[] = {
+ "L,R",
+ "R,L",
+ "L,L",
+ "R,R",
+ "L,L+R",
+ "R,L+R",
+ "L+R,L",
+ "L+R,R",
+ "L+R,L+R",
+};
+
+static SOC_ENUM_SINGLE_DECL(rt766_rx_data_ch_enum,
+ RT766_SDCA_CTL(AMP, PPU21, SDCA_CTL_PPU_POSTURENUMBER), 0,
+ rt766_rx_data_ch_select);
+
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -9525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, -200, 200, 0);
+
+#define RT766_P75DB_STEP 0xC0 /* 0.75 dB in Q7.8 format */
+#define RT766_2DB_STEP 0x200 /* 2 dB in Q7.8 format */
+#define RT766_HP_VOL_MIN (-127) /* -95.25 dB / 0.75 dB step */
+#define RT766_HS_VOL_MIN (-23) /* -17.25 dB / 0.75 dB step */
+#define RT766_HS_BOOST_VOL_MIN (-1) /* -2 dB / 2 dB step */
+#define RT766_SPK_VOL_MIN (-87) /* -65.25 dB / 0.75 dB step */
+#define RT766_P_VOL_MAX 0 /* 0 dB / 0.75 dB step */
+#define RT766_HS_VOL_MAX 40 /* 30 dB / 0.75 dB step */
+#define RT766_HS_BOOST_VOL_MAX 20 /* 40 dB / 2 dB step */
+
+static const struct snd_kcontrol_new rt766_sdca_controls[] = {
+ SOC_DOUBLE_EXT("FU41 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt766_sdca_fu41_playback_get, rt766_sdca_fu41_playback_put),
+ SDCA_DOUBLE_Q78_TLV("FU41 Playback Volume",
+ RT766_VOLUME_REG(UAJ, USER_FU41, 1),
+ RT766_VOLUME_REG(UAJ, USER_FU41, 2),
+ RT766_HP_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, hp_vol_tlv),
+ SOC_DOUBLE_EXT("FU36 Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt766_sdca_fu36_capture_get, rt766_sdca_fu36_capture_put),
+ SDCA_DOUBLE_Q78_TLV("FU36 Capture Volume",
+ RT766_VOLUME_REG(UAJ, USER_FU36, 1),
+ RT766_VOLUME_REG(UAJ, USER_FU36, 2),
+ RT766_HS_VOL_MIN, RT766_HS_VOL_MAX, RT766_P75DB_STEP, mic_vol_tlv),
+ SDCA_DOUBLE_Q78_TLV("FU33 Boost Volume",
+ RT766_GAIN_REG(UAJ, PLATFORM_FU33, 1),
+ RT766_GAIN_REG(UAJ, PLATFORM_FU33, 2),
+ RT766_HS_BOOST_VOL_MIN, RT766_HS_BOOST_VOL_MAX, RT766_2DB_STEP, boost_vol_tlv),
+
+ SOC_DOUBLE_EXT("FU21 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt766_sdca_fu21_playback_get, rt766_sdca_fu21_playback_put),
+ SDCA_DOUBLE_Q78_TLV("FU21 Playback Volume",
+ RT766_VOLUME_REG(AMP, USER_FU21, 1),
+ RT766_VOLUME_REG(AMP, USER_FU21, 2),
+ RT766_SPK_VOL_MIN, RT766_P_VOL_MAX, RT766_P75DB_STEP, spk_vol_tlv),
+ SOC_ENUM("RX Channel Select", rt766_rx_data_ch_enum),
+
+ RT_SDCA_FU_CTRL("FU113 Capture Switch",
+ RT766_MUTE_REG(MIC, USER_FU113, 1), 1, 1, 4, rt766_dmic_fu_info,
+ rt766_sdca_dmic_fu113_capture_get, rt766_sdca_dmic_fu113_capture_put),
+ RT_SDCA_EXT_TLV("FU113 Capture Volume",
+ RT766_VOLUME_REG(MIC, USER_FU113, 1),
+ rt766_sdca_dmic_set_gain_get, rt766_sdca_dmic_set_gain_put,
+ 4, 0x3f, mic_vol_tlv, rt766_dmic_fu_info),
+};
+
+static const struct snd_soc_dapm_widget rt766_sdca_dapm_widgets[] = {
+ /* UAJ */
+ SND_SOC_DAPM_OUTPUT("HP"),
+ SND_SOC_DAPM_INPUT("MIC2"),
+ SND_SOC_DAPM_SUPPLY("PDE 47", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde47_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 34", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde34_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("FU 41", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu41_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 36", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu36_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DP12TX", "DP12 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ /* AMP */
+ SND_SOC_DAPM_OUTPUT("SPOL"),
+ SND_SOC_DAPM_OUTPUT("SPOR"),
+ SND_SOC_DAPM_DAC_E("FU 21", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu21_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde23_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
+
+ /* DMIC */
+ SND_SOC_DAPM_INPUT("DMIC1"),
+ SND_SOC_DAPM_INPUT("DMIC2"),
+ SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+ rt766_sdca_pde11_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("FU 113", NULL, SND_SOC_NOPM, 0, 0,
+ rt766_sdca_fu113_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt766_sdca_audio_map[] = {
+ { "FU 41", NULL, "DP3RX" },
+ { "DP12TX", NULL, "FU 36" },
+ { "FU 36", NULL, "PDE 34" },
+ { "FU 36", NULL, "MIC2" },
+ { "HP", NULL, "PDE 47" },
+ { "HP", NULL, "FU 41" },
+
+ { "FU 21", NULL, "DP1RX" },
+ { "FU 21", NULL, "PDE 23" },
+ { "SPOL", NULL, "FU 21" },
+ { "SPOR", NULL, "FU 21" },
+
+ {"DP8TX", NULL, "FU 113"},
+ {"FU 113", NULL, "PDE 11"},
+ {"FU 113", NULL, "DMIC1"},
+ {"FU 113", NULL, "DMIC2"},
+};
+
+static int rt766_sdca_probe(struct snd_soc_component *component)
+{
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct device *dev = &rt766->slave->dev;
+ int ret;
+
+ rt766->component = component;
+
+ ret = pm_runtime_resume(component->dev);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ if (rt766->uaj_func_data) {
+ dev_dbg(dev, "%s : irq %d\n", __func__, rt766->slave->irq);
+
+ rt766->irq_info = devm_sdca_irq_allocate(dev, rt766->regmap, rt766->slave->irq);
+ if (IS_ERR(rt766->irq_info))
+ return PTR_ERR(rt766->irq_info);
+
+ ret = rt766_sdca_irq_ctl(rt766, rt766->uaj_func_data,
+ component, rt766->irq_info, true);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request UAJ SDCA IRQ: %d\n", ret);
+ return ret;
+ }
+
+ if (rt766->hid_func_data) {
+ ret = rt766_sdca_irq_ctl(rt766, rt766->hid_func_data,
+ component, rt766->irq_info, true);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request HID SDCA IRQ: %d\n", ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void rt766_sdca_remove(struct snd_soc_component *component)
+{
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+
+ sdca_irq_cleanup_late(component->dev, rt766->uaj_func_data, rt766->irq_info);
+ sdca_irq_cleanup_late(component->dev, rt766->hid_func_data, rt766->irq_info);
+}
+
+static const struct snd_soc_component_driver soc_sdca_dev_rt766 = {
+ .probe = rt766_sdca_probe,
+ .remove = rt766_sdca_remove,
+ .controls = rt766_sdca_controls,
+ .num_controls = ARRAY_SIZE(rt766_sdca_controls),
+ .dapm_widgets = rt766_sdca_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(rt766_sdca_dapm_widgets),
+ .dapm_routes = rt766_sdca_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(rt766_sdca_audio_map),
+ .set_jack = rt766_sdca_set_jack_detect,
+ .endianness = 1,
+};
+
+static int rt766_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
+ int direction)
+{
+ snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
+
+ return 0;
+}
+
+static void rt766_sdca_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+}
+
+static int rt766_sdca_pcm_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 rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_config stream_config;
+ struct sdw_port_config port_config;
+ enum sdw_data_direction direction;
+ struct sdw_stream_runtime *sdw_stream;
+ unsigned int sampling_rate;
+ int retval, port;
+
+ dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
+ sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!sdw_stream)
+ return -EINVAL;
+
+ if (!rt766->slave)
+ return -EINVAL;
+
+ /* SoundWire specific configuration */
+ snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
+
+ /* SoundWire specific configuration */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ direction = SDW_DATA_DIR_RX;
+ if (dai->id == RT766_AIF1)
+ port = 3;
+ else if (dai->id == RT766_AIF2)
+ port = 1;
+ else
+ return -EINVAL;
+ } else {
+ direction = SDW_DATA_DIR_TX;
+ if (dai->id == RT766_AIF1)
+ port = 12;
+ else if (dai->id == RT766_AIF3)
+ port = 8;
+ else
+ return -EINVAL;
+ }
+
+ port_config.num = port;
+ retval = sdw_stream_add_slave(rt766->slave, &stream_config,
+ &port_config, 1, sdw_stream);
+ if (retval) {
+ dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
+ return retval;
+ }
+
+ if (params_channels(params) > 16) {
+ dev_err(component->dev, "%s: Unsupported channels %d\n",
+ __func__, params_channels(params));
+ return -EINVAL;
+ }
+
+ /* sampling rate configuration */
+ switch (params_rate(params)) {
+ case 44100:
+ sampling_rate = RT766_SDCA_RATE_44100HZ;
+ break;
+ case 48000:
+ sampling_rate = RT766_SDCA_RATE_48000HZ;
+ break;
+ case 96000:
+ sampling_rate = RT766_SDCA_RATE_96000HZ;
+ break;
+ case 192000:
+ sampling_rate = RT766_SDCA_RATE_192000HZ;
+ break;
+ default:
+ dev_err(component->dev, "%s: Rate %d is not supported\n",
+ __func__, params_rate(params));
+ return -EINVAL;
+ }
+
+ /* set sampling frequency */
+ switch (dai->id) {
+ case RT766_AIF1:
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, CS41, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(UAJ, CS36, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ break;
+ case RT766_AIF2:
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(AMP, CS21, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ break;
+ case RT766_AIF3:
+ regmap_write(rt766->regmap,
+ RT766_SDCA_CTL(MIC, CS113, SDCA_CTL_CS_SAMPLERATEINDEX),
+ sampling_rate);
+ break;
+ default:
+ dev_err(component->dev, "%s: Wrong DAI id\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt766_sdca_pcm_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_component *component = dai->component;
+ struct rt766_sdca_priv *rt766 = snd_soc_component_get_drvdata(component);
+ struct sdw_stream_runtime *sdw_stream =
+ snd_soc_dai_get_dma_data(dai, substream);
+
+ if (!rt766->slave)
+ return -EINVAL;
+
+ sdw_stream_remove_slave(rt766->slave, sdw_stream);
+ return 0;
+}
+
+#define RT766_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
+ SNDRV_PCM_RATE_192000)
+#define RT766_DAC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+#define RT766_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops rt766_sdca_ops = {
+ .hw_params = rt766_sdca_pcm_hw_params,
+ .hw_free = rt766_sdca_pcm_hw_free,
+ .set_stream = rt766_sdca_set_sdw_stream,
+ .shutdown = rt766_sdca_shutdown,
+};
+
+static struct snd_soc_dai_driver rt766_sdca_dai[] = {
+ {
+ .name = "rt766-sdca-aif1",
+ .id = RT766_AIF1,
+ .playback = {
+ .stream_name = "DP3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_DAC_FORMATS,
+ },
+ .capture = {
+ .stream_name = "DP12 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_ADC_FORMATS,
+ },
+ .ops = &rt766_sdca_ops,
+ .symmetric_rate = 1,
+ },
+ {
+ .name = "rt766-sdca-aif2",
+ .id = RT766_AIF2,
+ .playback = {
+ .stream_name = "DP1 Playback",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_DAC_FORMATS,
+ },
+ .ops = &rt766_sdca_ops,
+ },
+ {
+ .name = "rt766-sdca-aif3",
+ .id = RT766_AIF3,
+ .capture = {
+ .stream_name = "DP8 Capture",
+ .channels_min = 1,
+ .channels_max = 4,
+ .rates = RT766_STEREO_RATES,
+ .formats = RT766_ADC_FORMATS,
+ },
+ .ops = &rt766_sdca_ops,
+ }
+};
+
+static unsigned int rt766_find_dt_rates(struct device *dev, struct sdca_function_data *function,
+ const char *label)
+{
+ struct snd_soc_pcm_stream stream;
+ struct sdca_entity *entity;
+ int i, ret;
+
+ for (i = 0; i < function->num_entities; i++) {
+ entity = &function->entities[i];
+
+ if (strcmp(entity->label, label))
+ continue;
+
+ /* Can't check earlier as only terminals have an iot member. */
+ if (!entity->iot.is_dataport)
+ continue;
+
+ ret = sdca_asoc_populate_rate_format(dev, function, entity, &stream);
+ if (ret < 0) {
+ dev_dbg(dev, "%s: failed to parse rates for entity %s\n",
+ __func__, entity->label);
+ return 0;
+ }
+
+ dev_dbg(dev, "%s: %s supports rates 0x%08x\n", __func__, entity->label, stream.rates);
+ }
+
+ return stream.rates;
+}
+
+int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave)
+{
+ struct sdca_function_data *func_data_ptr;
+ struct snd_soc_dai_driver *dai_drv;
+ struct rt766_sdca_priv *rt766;
+ unsigned int rates;
+ int ret;
+ int i;
+
+ rt766 = devm_kzalloc(dev, sizeof(*rt766), GFP_KERNEL);
+ if (!rt766)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, rt766);
+ rt766->slave = slave;
+ rt766->regmap = regmap;
+
+ regcache_cache_only(rt766->regmap, true);
+
+ ret = devm_mutex_init(dev, &rt766->disable_irq_lock);
+ if (ret < 0) {
+ dev_err(dev, "Failed to initialize mutex\n");
+ return ret;
+ }
+
+ /*
+ * Mark hw_init to false
+ * HW init will be performed when device reports present
+ */
+ rt766->hw_init = false;
+ rt766->first_hw_init = false;
+ rt766->fu41_dapm_mute = true;
+ rt766->fu41_mixer_l_mute = rt766->fu41_mixer_r_mute = false;
+ rt766->fu36_dapm_mute = true;
+ rt766->fu36_mixer_l_mute = rt766->fu36_mixer_r_mute = true;
+ rt766->fu21_dapm_mute = true;
+ rt766->fu21_mixer_l_mute = rt766->fu21_mixer_r_mute = false;
+ rt766->fu113_dapm_mute = true;
+ rt766->fu113_mixer_mute[0] = rt766->fu113_mixer_mute[1] =
+ rt766->fu113_mixer_mute[2] = rt766->fu113_mixer_mute[3] = true;
+
+ dai_drv = devm_kzalloc(dev, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai), GFP_KERNEL);
+ if (!dai_drv) {
+ dev_err(dev, "Failed to allocate memory for DAI driver\n");
+ ret = -ENOMEM;
+ goto _sdw_init_err_;
+ }
+ memcpy(dai_drv, rt766_sdca_dai, sizeof(struct snd_soc_dai_driver) * ARRAY_SIZE(rt766_sdca_dai));
+
+ /* get SDCA function data */
+ dev_dbg(dev, "SDCA functions found: %d", slave->sdca_data.num_functions);
+ for (i = 0; i < slave->sdca_data.num_functions; i++) {
+ func_data_ptr = devm_kzalloc(dev, sizeof(*func_data_ptr), GFP_KERNEL);
+ if (!func_data_ptr) {
+ dev_err(dev, "Failed to allocate memory for function data\n");
+ ret = -ENOMEM;
+ goto _free_dai_drv_;
+ }
+
+ func_data_ptr->desc = &slave->sdca_data.function[i];
+ ret = sdca_parse_function(dev, func_data_ptr);
+ if (ret) {
+ devm_kfree(dev, func_data_ptr);
+ goto _free_dai_drv_;
+ }
+ dev_dbg(dev, "Function type=%d, num_entities=%d",
+ slave->sdca_data.function[i].type, func_data_ptr->num_entities);
+
+ switch (slave->sdca_data.function[i].type) {
+ case SDCA_FUNCTION_TYPE_UAJ:
+ rt766->uaj_func_data = func_data_ptr;
+ /*
+ * Some machines may only support a subset of the sample rates supported by the codec.
+ * Therefore, we need to parse the supported sample rates from the DisCo table and
+ * configure them in the DAI. If the DisCo table does not provide sample rate information,
+ * we will fall back to the default supported rates defined in the codec driver.
+ */
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 41");
+ if (rates)
+ dai_drv[RT766_DAI_UAJ].playback.rates = rates;
+
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 36");
+ if (rates)
+ dai_drv[RT766_DAI_UAJ].capture.rates = rates;
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ rt766->sa_func_data = func_data_ptr;
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "IT 21");
+ if (rates)
+ dai_drv[RT766_DAI_AMP].playback.rates = rates;
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ rt766->sm_func_data = func_data_ptr;
+ rates = rt766_find_dt_rates(dev, func_data_ptr, "OT 113");
+ if (rates)
+ dai_drv[RT766_DAI_MIC].capture.rates = rates;
+ break;
+ case SDCA_FUNCTION_TYPE_HID:
+ rt766->hid_func_data = func_data_ptr;
+ break;
+ default:
+ dev_dbg(dev, "Unexpected SDCA function type found: %d",
+ slave->sdca_data.function[i].type);
+ }
+ }
+
+ ret = devm_snd_soc_register_component(dev,
+ &soc_sdca_dev_rt766, dai_drv, ARRAY_SIZE(rt766_sdca_dai));
+ if (ret < 0)
+ goto _free_dai_drv_;
+
+ /* set autosuspend parameters */
+ pm_runtime_set_autosuspend_delay(dev, 3000);
+ pm_runtime_use_autosuspend(dev);
+
+ /* make sure the device does not suspend immediately */
+ pm_runtime_mark_last_busy(dev);
+
+ pm_runtime_enable(dev);
+ dev_dbg(dev, "%s\n", __func__);
+ return 0;
+
+_free_dai_drv_:
+ if (dai_drv)
+ devm_kfree(dev, dai_drv);
+
+_sdw_init_err_:
+ return ret;
+}
+
+static int rt766_func_initialize(struct rt766_sdca_priv *rt766, struct sdca_function_data *func_data)
+{
+ struct device *dev = &rt766->slave->dev;
+ unsigned int func_status_reg;
+ unsigned int func_status;
+ int ret;
+
+ switch (func_data->desc->type) {
+ case SDCA_FUNCTION_TYPE_UAJ:
+ func_status_reg = RT766_FUNC_STATUS_REG(UAJ);
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_AMP:
+ func_status_reg = RT766_FUNC_STATUS_REG(AMP);
+ break;
+ case SDCA_FUNCTION_TYPE_SMART_MIC:
+ func_status_reg = RT766_FUNC_STATUS_REG(MIC);
+ break;
+ case SDCA_FUNCTION_TYPE_HID:
+ func_status_reg = RT766_FUNC_STATUS_REG(HID);
+ break;
+ default:
+ dev_dbg(dev, "Unexpected SDCA function type found: %d",
+ func_data->desc->type);
+ return -EINVAL;
+ }
+
+ regmap_read(rt766->regmap, func_status_reg, &func_status);
+ dev_dbg(dev, "%s, %s func_status=0x%x\n", __func__, func_data->desc->name, func_status);
+
+ if ((func_status & SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION) || (!rt766->first_hw_init)) {
+ ret = sdca_regmap_write_init(dev, rt766->regmap, func_data);
+ if (ret) {
+ dev_err(dev, "%s initialization table update failed\n", func_data->desc->name);
+ goto _func_init_err_;
+ }
+
+ regmap_write(rt766->regmap, func_status_reg,
+ SDCA_CTL_ENTITY_0_FUNCTION_NEEDS_INITIALIZATION);
+ }
+
+ return 0;
+
+_func_init_err_:
+ dev_err(dev, "%s: %s init writes failed, err=%d", __func__, func_data->desc->name, ret);
+ return ret;
+}
+
+int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct rt766_sdca_priv *rt766 = dev_get_drvdata(dev);
+ unsigned int val;
+
+ rt766->disable_irq = false;
+
+ if (rt766->hw_init)
+ return 0;
+
+ regcache_cache_only(rt766->regmap, false);
+ if (rt766->first_hw_init) {
+ regcache_cache_bypass(rt766->regmap, true);
+ } else {
+ /*
+ * PM runtime status is marked as 'active' only when a Slave reports as Attached
+ */
+
+ /* update count of parent 'active' children */
+ pm_runtime_set_active(&slave->dev);
+ }
+
+ pm_runtime_get_noresume(&slave->dev);
+
+ regmap_read(rt766->regmap, RT766_BOND_LATCH_ID, &val);
+ dev_dbg(&slave->dev, "%s bond ID=0x%x (%s)\n", __func__, val, (val == 0x1) ? "RT767" : "RT766");
+
+ /* check function status and initialize if needed */
+ if (rt766->uaj_func_data)
+ rt766_func_initialize(rt766, rt766->uaj_func_data);
+ if (rt766->sa_func_data)
+ rt766_func_initialize(rt766, rt766->sa_func_data);
+ if (rt766->sm_func_data)
+ rt766_func_initialize(rt766, rt766->sm_func_data);
+ if (rt766->hid_func_data)
+ rt766_func_initialize(rt766, rt766->hid_func_data);
+
+ if (rt766->first_hw_init) {
+ regcache_cache_bypass(rt766->regmap, false);
+ regcache_mark_dirty(rt766->regmap);
+ } else {
+ rt766->first_hw_init = true;
+ }
+
+ /* Mark Slave initialization complete */
+ rt766->hw_init = true;
+
+ dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
+
+ pm_runtime_put_autosuspend(&slave->dev);
+
+ return 0;
+}
+
+MODULE_DESCRIPTION("ASoC RT766 SDCA SDW driver");
+MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt766-sdca.h b/sound/soc/codecs/rt766-sdca.h
new file mode 100644
index 000000000000..de4064007eb9
--- /dev/null
+++ b/sound/soc/codecs/rt766-sdca.h
@@ -0,0 +1,140 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * rt766-sdca.h -- RT766 SDCA ALSA SoC audio driver header
+ *
+ * Copyright(c) 2026 Realtek Semiconductor Corp.
+ */
+
+#ifndef __RT766_H__
+#define __RT766_H__
+
+#include <linux/hid.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_type.h>
+#include <sound/soc.h>
+#include <linux/workqueue.h>
+
+struct rt766_sdca_priv {
+ struct regmap *regmap;
+ struct snd_soc_component *component;
+ struct sdw_slave *slave;
+ bool hw_init;
+ bool first_hw_init;
+ struct snd_soc_jack *hs_jack;
+ struct mutex disable_irq_lock; /* SDCA irq lock protection */
+ bool disable_irq;
+ int jack_type;
+ bool fu41_dapm_mute;
+ bool fu41_mixer_l_mute;
+ bool fu41_mixer_r_mute;
+ bool fu113_dapm_mute;
+ bool fu113_mixer_mute[4];
+ bool fu21_dapm_mute;
+ bool fu21_mixer_l_mute;
+ bool fu21_mixer_r_mute;
+ bool fu36_dapm_mute;
+ bool fu36_mixer_l_mute;
+ bool fu36_mixer_r_mute;
+ struct sdca_function_data *uaj_func_data;
+ struct sdca_function_data *sm_func_data;
+ struct sdca_function_data *sa_func_data;
+ struct sdca_function_data *hid_func_data;
+ struct sdca_interrupt_info *irq_info;
+ struct hid_device *hid;
+};
+
+/* vendor registers */
+#define RT766_VERSION_ID 0xc404
+#define RT766_DEV_ID1 0xc405
+#define RT766_DEV_ID0 0xc406
+#define RT766_BOND_LATCH_ID 0xc407
+
+#define RT766_HP_POWER_STATE 0x1000004
+#define RT766_HP_FSM_CTL2_1 0x100000d
+
+/* MCU Patch address */
+#define RT766_MCU_PATCH_ADDR1_START 0x10010000
+#define RT766_MCU_PATCH_ADDR1_END 0x10011fff
+#define RT766_MCU_PATCH_ADDR2_START 0x10020000
+#define RT766_MCU_PATCH_ADDR2_END 0x10023fff
+
+/* Buffer address for HID */
+#define RT766_BUF_ADDR_HID1 0x44030000
+#define RT766_BUF_ADDR_HID2 0x44030020
+
+/* SDCA (Channel) */
+#define RT766_CH_1 0x01
+#define RT766_CH_2 0x02
+#define RT766_CH_3 0x03
+#define RT766_CH_4 0x04
+
+/* RT766 SDCA Control - function number */
+#define RT766_FUNC_NUM_UAJ 0x01
+#define RT766_FUNC_NUM_MIC 0x02
+#define RT766_FUNC_NUM_HID 0x03
+#define RT766_FUNC_NUM_AMP 0x04
+
+/* RT766 SDCA entity */
+#define RT766_SDCA_ENT_0 0x00
+#define RT766_SDCA_ENT_HID101 0x01
+#define RT766_SDCA_ENT_GE49 0x49
+#define RT766_SDCA_ENT_USER_FU41 0x05
+#define RT766_SDCA_ENT_USER_FU36 0x0f
+#define RT766_SDCA_ENT_USER_FU21 0x03
+#define RT766_SDCA_ENT_USER_FU113 0x30
+#define RT766_SDCA_ENT_PDE23 0x33
+#define RT766_SDCA_ENT_PDE47 0x28
+#define RT766_SDCA_ENT_PDE11 0x2a
+#define RT766_SDCA_ENT_PDE34 0x29
+#define RT766_SDCA_ENT_CS41 0x01
+#define RT766_SDCA_ENT_CS36 0x11
+#define RT766_SDCA_ENT_CS113 0x12
+#define RT766_SDCA_ENT_CS21 0x21
+#define RT766_SDCA_ENT_PLATFORM_FU33 0x44
+#define RT766_SDCA_ENT_PPU21 0x04
+
+/* sample frequency index */
+#define RT766_SDCA_RATE_44100HZ 0x08
+#define RT766_SDCA_RATE_48000HZ 0x09
+#define RT766_SDCA_RATE_96000HZ 0x0b
+#define RT766_SDCA_RATE_192000HZ 0x0d
+
+/* SDCA Register macros */
+#define RT766_MUTE_REG(func, fu, ch) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_MUTE, RT766_CH_##ch)
+
+#define RT766_VOLUME_REG(func, fu, ch) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_CHANNEL_VOLUME, RT766_CH_##ch)
+
+#define RT766_GAIN_REG(func, fu, ch) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##fu, SDCA_CTL_FU_GAIN, RT766_CH_##ch)
+
+#define RT766_PDE_REQ_REG(func, pde) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_REQUESTED_PS, 0)
+
+#define RT766_PDE_ACTUAL_REG(func, pde) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##pde, SDCA_CTL_PDE_ACTUAL_PS, 0)
+
+#define RT766_FUNC_STATUS_REG(func) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_0, SDCA_CTL_ENTITY_0_FUNCTION_STATUS, 0)
+
+#define RT766_SDCA_CTL(func, ent, ctl) \
+ SDW_SDCA_CTL(RT766_FUNC_NUM_##func, RT766_SDCA_ENT_##ent, ctl, 0)
+
+enum {
+ RT766_AIF1,
+ RT766_AIF2,
+ RT766_AIF3,
+};
+
+enum {
+ RT766_DAI_UAJ,
+ RT766_DAI_AMP,
+ RT766_DAI_MIC,
+};
+
+int rt766_sdca_io_init(struct device *dev, struct sdw_slave *slave);
+int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave);
+#endif /* __RT766_H__ */
diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
index 97f56af25577..e51cd4a31894 100644
--- a/sound/soc/codecs/rt9120.c
+++ b/sound/soc/codecs/rt9120.c
@@ -606,12 +606,19 @@ static int rt9120_runtime_suspend(struct device *dev)
static int rt9120_runtime_resume(struct device *dev)
{
struct rt9120_data *data = dev_get_drvdata(dev);
+ int ret;
if (data->pwdnn_gpio) {
gpiod_set_value(data->pwdnn_gpio, 1);
msleep(RT9120_CHIPON_WAITMS);
regcache_cache_only(data->regmap, false);
- regcache_sync(data->regmap);
+ ret = regcache_sync(data->regmap);
+ if (ret) {
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+ gpiod_set_value(data->pwdnn_gpio, 0);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 59642673b4cb..35df1a8c4c8c 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -56,8 +56,8 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
{ SGTL5000_CHIP_PLL_CTRL, 0x5000 },
{ SGTL5000_CHIP_CLK_TOP_CTRL, 0x0000 },
{ SGTL5000_CHIP_ANA_STATUS, 0x0000 },
- { SGTL5000_CHIP_SHORT_CTRL, 0x0000 },
{ SGTL5000_CHIP_ANA_TEST2, 0x0000 },
+ { SGTL5000_CHIP_SHORT_CTRL, 0x0000 },
{ SGTL5000_DAP_CTRL, 0x0000 },
{ SGTL5000_DAP_PEQ, 0x0000 },
{ SGTL5000_DAP_BASS_ENHANCE, 0x0040 },
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index 2e08fde3989c..4ecbbac93258 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -5,6 +5,7 @@
* Copyright 2009-2014 Analog Devices Inc.
*/
+#include <linux/cleanup.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
@@ -135,7 +136,7 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
uint8_t *data;
int ret = 0;
- mutex_lock(&sigmadsp->lock);
+ guard(mutex)(&sigmadsp->lock);
data = ucontrol->value.bytes.data;
@@ -148,8 +149,6 @@ static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
ctrl->cached = true;
}
- mutex_unlock(&sigmadsp->lock);
-
return ret;
}
@@ -160,7 +159,7 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
int ret = 0;
- mutex_lock(&sigmadsp->lock);
+ guard(mutex)(&sigmadsp->lock);
if (!ctrl->cached) {
ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache,
@@ -174,8 +173,6 @@ static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
ctrl->num_bytes);
}
- mutex_unlock(&sigmadsp->lock);
-
return ret;
}
@@ -487,7 +484,7 @@ static void devm_sigmadsp_release(struct device *dev, void *res)
static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
{
const struct sigma_firmware_header *ssfw_head;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
u32 crc;
@@ -495,7 +492,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
ret = request_firmware(&fw, name, sigmadsp->dev);
if (ret) {
pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
- goto done;
+ return ret;
}
/* then verify the header */
@@ -509,13 +506,13 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
*/
if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
- goto done;
+ return -EINVAL;
}
ssfw_head = (void *)fw->data;
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
- goto done;
+ return -EINVAL;
}
crc = crc32(0, fw->data + sizeof(*ssfw_head),
@@ -524,7 +521,7 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
if (crc != le32_to_cpu(ssfw_head->crc)) {
dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
le32_to_cpu(ssfw_head->crc), crc);
- goto done;
+ return -EINVAL;
}
switch (ssfw_head->version) {
@@ -545,9 +542,6 @@ static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
if (ret)
sigmadsp_firmware_release(sigmadsp);
-done:
- release_firmware(fw);
-
return ret;
}
@@ -677,10 +671,10 @@ static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
return;
changed = snd_ctl_activate_id(card, &ctrl->kcontrol->id, active);
if (active && changed > 0) {
- mutex_lock(&sigmadsp->lock);
- if (ctrl->cached)
- sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
- mutex_unlock(&sigmadsp->lock);
+ scoped_guard(mutex, &sigmadsp->lock) {
+ if (ctrl->cached)
+ sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
+ }
}
}
diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c
index 7fce60de5e5f..15758eb13f8c 100644
--- a/sound/soc/codecs/sma1303.c
+++ b/sound/soc/codecs/sma1303.c
@@ -1777,6 +1777,8 @@ static void sma1303_i2c_remove(struct i2c_client *client)
struct sma1303_priv *sma1303 =
(struct sma1303_priv *) i2c_get_clientdata(client);
+ if (sma1303->attr_grp)
+ sysfs_remove_group(sma1303->kobj, sma1303->attr_grp);
cancel_delayed_work_sync(&sma1303->check_fault_work);
}
diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
index c52fe95b30c6..adb369a29b9d 100644
--- a/sound/soc/codecs/sma1307.c
+++ b/sound/soc/codecs/sma1307.c
@@ -1690,7 +1690,7 @@ static void sma1307_check_fault_worker(struct work_struct *work)
static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *file)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int size, offset, num_mode;
int ret;
@@ -1703,22 +1703,18 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
return;
} else if ((fw->size) < SMA1307_SETTING_HEADER_SIZE) {
dev_err(sma1307->dev, "%s: Invalid file\n", __func__);
- release_firmware(fw);
sma1307->set.status = false;
return;
}
int *data __free(kfree) = kzalloc(fw->size, GFP_KERNEL);
if (!data) {
- release_firmware(fw);
sma1307->set.status = false;
return;
}
size = fw->size >> 2;
memcpy(data, fw->data, fw->size);
- release_firmware(fw);
-
/* HEADER */
sma1307->set.header_size = SMA1307_SETTING_HEADER_SIZE;
sma1307->set.checksum = data[sma1307->set.header_size - 2];
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 652c6e3a9e63..d6de739212f9 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
@@ -269,9 +270,9 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
unsigned int cfud, val;
- int i, ret = 0;
+ int i;
- mutex_lock(&sta32x->coeff_lock);
+ guard(mutex)(&sta32x->coeff_lock);
/* preserve reserved bits in STA32X_CFUD */
regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
@@ -283,24 +284,20 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
- if (numcoef == 1) {
+ if (numcoef == 1)
regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
- } else if (numcoef == 5) {
+ else if (numcoef == 5)
regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
- } else {
- ret = -EINVAL;
- goto exit_unlock;
- }
+ else
+ return -EINVAL;
+
for (i = 0; i < 3 * numcoef; i++) {
regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
ucontrol->value.bytes.data[i] = val;
}
-exit_unlock:
- mutex_unlock(&sta32x->coeff_lock);
-
- return ret;
+ return 0;
}
static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index 99c7f7ac807b..2ba35076732b 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -16,6 +16,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -306,9 +307,9 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
int numcoef = kcontrol->private_value >> 16;
int index = kcontrol->private_value & 0xffff;
unsigned int cfud, val;
- int i, ret = 0;
+ int i;
- mutex_lock(&sta350->coeff_lock);
+ guard(mutex)(&sta350->coeff_lock);
/* preserve reserved bits in STA350_CFUD */
regmap_read(sta350->regmap, STA350_CFUD, &cfud);
@@ -320,24 +321,19 @@ static int sta350_coefficient_get(struct snd_kcontrol *kcontrol,
regmap_write(sta350->regmap, STA350_CFUD, cfud);
regmap_write(sta350->regmap, STA350_CFADDR2, index);
- if (numcoef == 1) {
+ if (numcoef == 1)
regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x04);
- } else if (numcoef == 5) {
+ else if (numcoef == 5)
regmap_write(sta350->regmap, STA350_CFUD, cfud | 0x08);
- } else {
- ret = -EINVAL;
- goto exit_unlock;
- }
+ else
+ return -EINVAL;
for (i = 0; i < 3 * numcoef; i++) {
regmap_read(sta350->regmap, STA350_B1CF1 + i, &val);
ucontrol->value.bytes.data[i] = val;
}
-exit_unlock:
- mutex_unlock(&sta350->coeff_lock);
-
- return ret;
+ return 0;
}
static int sta350_coefficient_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c
index 4ab15be69f3a..b7eaf4795d8b 100644
--- a/sound/soc/codecs/sti-sas.c
+++ b/sound/soc/codecs/sti-sas.c
@@ -44,8 +44,8 @@ enum {
};
static const struct reg_default stih407_sas_reg_defaults[] = {
- { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
+ { STIH407_AUDIO_DAC_CTRL, 0x000000000 },
};
struct sti_dac_audio {
diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c
index ace06f5ab58c..c062065a807d 100644
--- a/sound/soc/codecs/tac5xx2-sdw.c
+++ b/sound/soc/codecs/tac5xx2-sdw.c
@@ -88,6 +88,9 @@
#define TAC_FW_FILE_HDR 20
#define TAC_MAX_FW_CHUNKS 512
+#define TAC_UAJ_PREP_CONNECTED 0xff
+#define TAC_UAJ_PREP_DISCONNECTED 0xdf
+
struct tac_fw_hdr {
u32 size;
u32 version_offset;
@@ -138,6 +141,7 @@ struct tac5xx2_prv {
bool hw_init;
bool first_hw_init_done;
u32 part_id;
+ u32 rev_id;
struct snd_soc_jack *hs_jack;
int jack_type;
/* Custom fw binary. UMP File Download is not used. */
@@ -261,7 +265,6 @@ static const struct reg_default tac_reg_default[] = {
{TAC_REG_SDW(0, 0, 0x78), 0x0},
{TAC_REG_SDW(0, 0, 0x7b), 0x0},
{TAC_REG_SDW(0, 0, 0x7c), 0xd0},
- {TAC_REG_SDW(0, 0, 0x7d), 0x0},
{TAC_REG_SDW(0, 0, 0x7e), 0x0},
{TAC_REG_SDW(0, 1, 0x1), 0x0},
{TAC_REG_SDW(0, 1, 0x2), 0x0},
@@ -507,18 +510,6 @@ static const struct regmap_config tac_regmap = {
.use_single_write = true,
};
-/* Check if device has DSP algo that needs status monitoring */
-static bool tac_has_dsp_algo(struct tac5xx2_prv *tac_dev)
-{
- switch (tac_dev->part_id) {
- case 0x5682:
- case 0x2883:
- return true;
- default:
- return false;
- }
-}
-
/* Check if device has UAJ (Universal Audio Jack) support */
static bool tac_has_uaj_support(struct tac5xx2_prv *tac_dev)
{
@@ -800,7 +791,7 @@ static int tac_sdw_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, pde_entity,
+ ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity,
SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0);
if (ret)
dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> PS0, err=%d\n",
@@ -847,7 +838,7 @@ static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
return ret;
}
- ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id,
+ ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id,
pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3,
NULL, 0);
if (ret)
@@ -942,6 +933,7 @@ end_btn_det:
static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
{
int val, ret;
+ u8 jack_prep;
ret = regmap_read(tac_dev->regmap,
SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35,
@@ -951,6 +943,8 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
return ret;
}
+ jack_prep = TAC_UAJ_PREP_CONNECTED;
+
switch (val) {
case 4:
tac_dev->jack_type = SND_JACK_MICROPHONE;
@@ -964,6 +958,7 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
case 0:
default:
tac_dev->jack_type = 0;
+ jack_prep = TAC_UAJ_PREP_DISCONNECTED;
break;
}
@@ -973,26 +968,44 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
if (ret)
dev_err(tac_dev->dev, "Failed to update the jack type to device");
+ /*
+ * When uaj is uplugged and booted, we end up with the channel prepare
+ * timeout error for the uaj ports. This writes allows the channel prepare
+ * to succeed when the uaj is not plugged in.
+ */
+ if (tac_dev->rev_id >= 0x30) {
+ ret = regmap_write(tac_dev->regmap, TAC_REG_SDW(0, 3, 127), jack_prep);
+ if (ret)
+ dev_warn(tac_dev->dev, "Failed to write jack_prep register: %d\n", ret);
+ }
+
return 0;
}
static int tac5xx2_jack_init(struct tac5xx2_prv *tac_dev)
{
+ u32 jd_int_mask, hid_int_mask;
int ret = 0;
+ if (tac_dev->rev_id >= 0x30) {
+ jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_12;
+ hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_17;
+ } else {
+ jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_11;
+ hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_16;
+ }
+
if (!tac_dev->hs_jack)
goto disable_interrupts;
- ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2,
- SDW_SCP_SDCA_INTMASK_SDCA_11);
+ ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, jd_int_mask);
if (ret) {
dev_err(tac_dev->dev,
"Failed to register jack detection interrupt: %d\n", ret);
goto disable_interrupts;
}
- ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3,
- SDW_SCP_SDCA_INTMASK_SDCA_16);
+ ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, hid_int_mask);
if (ret) {
dev_err(tac_dev->dev,
"Failed to register for button detect interrupt: %d\n", ret);
@@ -1051,6 +1064,7 @@ static int tac_interrupt_callback(struct sdw_slave *slave,
unsigned int sdca_int2, sdca_int3, jack_report_mask = 0;
struct tac5xx2_prv *tac_dev = dev_get_drvdata(&slave->dev);
struct device *dev = &slave->dev;
+ u32 headset_detect_chk, hid_detect_chk;
int btn_type = 0;
int ret = 0;
@@ -1081,14 +1095,22 @@ static int tac_interrupt_callback(struct sdw_slave *slave,
dev_dbg(dev, "SDCA_INT2: 0x%02x, SDCA_INT3: 0x%02x\n",
sdca_int2, sdca_int3);
- if (sdca_int2 & SDW_SCP_SDCA_INT_SDCA_11) {
+ if (tac_dev->rev_id >= 0x30) {
+ headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_12;
+ hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_17;
+ } else {
+ headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_11;
+ hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_16;
+ }
+
+ if (sdca_int2 & headset_detect_chk) {
ret = tac5xx2_sdca_headset_detect(tac_dev);
if (ret < 0)
goto clear;
jack_report_mask |= SND_JACK_HEADSET;
}
- if (sdca_int3 & SDW_SCP_SDCA_INT_SDCA_16) {
+ if (sdca_int3 & hid_detect_chk) {
btn_type = tac5xx2_sdca_button_detect(tac_dev);
if (btn_type < 0)
btn_type = 0;
@@ -1695,6 +1717,15 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first)
goto io_init_err;
}
+ if (!tac_dev->rev_id) {
+ ret = regmap_read(tac_dev->regmap, TAC_REV_ID, &tac_dev->rev_id);
+ if (ret) {
+ dev_err(tac_dev->dev, "failed to rev id, err=%d\n", ret);
+ goto io_init_err;
+ }
+ dev_dbg(tac_dev->dev, "detected rev_id 0x%x", tac_dev->rev_id);
+ }
+
if (tac_dev->fw_files && tac_dev->fw_file_cnt > 0) {
ret = tac_download_fw_to_hw(tac_dev);
if (ret) {
@@ -1940,7 +1971,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
"failed to allocate %s function data",
func_name);
function_data->desc = &peripheral->sdca_data.function[i];
- ret = sdca_parse_function(dev, peripheral, function_data);
+ ret = sdca_parse_function(dev, function_data);
if (!ret)
*func_ptr = function_data;
else
@@ -1959,6 +1990,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
tac_dev->hw_init = false;
tac_dev->first_hw_init_done = false;
tac_dev->part_id = id->part_id;
+ tac_dev->rev_id = 0x0;
dev_set_drvdata(dev, tac_dev);
regmap = devm_regmap_init_sdw_mbq_cfg(&peripheral->dev, peripheral,
@@ -1972,17 +2004,13 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
tac_dev->jack_type = 0;
init_completion(&tac_dev->fw_caching_complete);
- if (tac_has_dsp_algo(tac_dev)) {
- tac_generate_fw_name(peripheral, tac_dev->fw_binaryname,
- sizeof(tac_dev->fw_binaryname));
+ tac_generate_fw_name(peripheral, tac_dev->fw_binaryname,
+ sizeof(tac_dev->fw_binaryname));
- ret = tac_load_and_cache_firmware_async(tac_dev);
- if (ret) {
- complete_all(&tac_dev->fw_caching_complete);
- dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret);
- }
- } else {
+ ret = tac_load_and_cache_firmware_async(tac_dev);
+ if (ret) {
complete_all(&tac_dev->fw_caching_complete);
+ dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret);
}
ret = tac_init(tac_dev);
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 1a7650b9b2a7..be2c9a0fa529 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -31,25 +31,25 @@
static const struct reg_default tas2552_reg_defs[] = {
{TAS2552_CFG_1, 0x22},
+ {TAS2552_CFG_2, 0xef},
{TAS2552_CFG_3, 0x80},
{TAS2552_DOUT, 0x00},
- {TAS2552_OUTPUT_DATA, 0xc0},
- {TAS2552_PDM_CFG, 0x01},
- {TAS2552_PGA_GAIN, 0x00},
- {TAS2552_BOOST_APT_CTRL, 0x0f},
- {TAS2552_RESERVED_0D, 0xbe},
- {TAS2552_LIMIT_RATE_HYS, 0x08},
- {TAS2552_CFG_2, 0xef},
{TAS2552_SER_CTRL_1, 0x00},
{TAS2552_SER_CTRL_2, 0x00},
+ {TAS2552_OUTPUT_DATA, 0xc0},
{TAS2552_PLL_CTRL_1, 0x10},
{TAS2552_PLL_CTRL_2, 0x00},
{TAS2552_PLL_CTRL_3, 0x00},
{TAS2552_BTIP, 0x8f},
{TAS2552_BTS_CTRL, 0x80},
+ {TAS2552_RESERVED_0D, 0xbe},
+ {TAS2552_LIMIT_RATE_HYS, 0x08},
{TAS2552_LIMIT_RELEASE, 0x04},
{TAS2552_LIMIT_INT_COUNT, 0x00},
+ {TAS2552_PDM_CFG, 0x01},
+ {TAS2552_PGA_GAIN, 0x00},
{TAS2552_EDGE_RATE_CTRL, 0x40},
+ {TAS2552_BOOST_APT_CTRL, 0x0f},
{TAS2552_VBAT_DATA, 0x00},
};
@@ -495,13 +495,21 @@ static int tas2552_runtime_suspend(struct device *dev)
static int tas2552_runtime_resume(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
+ int ret;
gpiod_set_value_cansleep(tas2552->enable_gpio, 1);
tas2552_sw_shutdown(tas2552, 0);
regcache_cache_only(tas2552->regmap, false);
- regcache_sync(tas2552->regmap);
+ ret = regcache_sync(tas2552->regmap);
+ if (ret) {
+ regcache_cache_only(tas2552->regmap, true);
+ regcache_mark_dirty(tas2552->regmap);
+ tas2552_sw_shutdown(tas2552, 1);
+ gpiod_set_value_cansleep(tas2552->enable_gpio, 0);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index b11b998aa32a..f9c65c9f6d0a 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -897,13 +897,13 @@ static const struct reg_default tas2764_reg_defaults[] = {
{ TAS2764_PAGE, 0x00 },
{ TAS2764_SW_RST, 0x00 },
{ TAS2764_PWR_CTRL, 0x1a },
- { TAS2764_DVC, 0x00 },
{ TAS2764_CHNL_0, 0x28 },
{ TAS2764_TDM_CFG0, 0x09 },
{ TAS2764_TDM_CFG1, 0x02 },
{ TAS2764_TDM_CFG2, 0x0a },
{ TAS2764_TDM_CFG3, 0x10 },
{ TAS2764_TDM_CFG5, 0x42 },
+ { TAS2764_DVC, 0x00 },
{ TAS2764_INT_CLK_CFG, 0x19 },
};
diff --git a/sound/soc/codecs/tas2780.c b/sound/soc/codecs/tas2780.c
index 1ec1c076204f..f1fce4305fa1 100644
--- a/sound/soc/codecs/tas2780.c
+++ b/sound/soc/codecs/tas2780.c
@@ -527,13 +527,13 @@ static const struct reg_default tas2780_reg_defaults[] = {
{ TAS2780_PAGE, 0x00 },
{ TAS2780_SW_RST, 0x00 },
{ TAS2780_PWR_CTRL, 0x1a },
- { TAS2780_DVC, 0x00 },
{ TAS2780_CHNL_0, 0x00 },
{ TAS2780_TDM_CFG0, 0x09 },
{ TAS2780_TDM_CFG1, 0x02 },
{ TAS2780_TDM_CFG2, 0x0a },
{ TAS2780_TDM_CFG3, 0x10 },
{ TAS2780_TDM_CFG5, 0x42 },
+ { TAS2780_DVC, 0x00 },
};
static const struct regmap_range_cfg tas2780_regmap_ranges[] = {
diff --git a/sound/soc/codecs/tas2781-comlib-i2c.c b/sound/soc/codecs/tas2781-comlib-i2c.c
index e24d56a14cfd..79b5f5b04c74 100644
--- a/sound/soc/codecs/tas2781-comlib-i2c.c
+++ b/sound/soc/codecs/tas2781-comlib-i2c.c
@@ -6,6 +6,7 @@
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -342,7 +343,7 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
/* Codec Lock Hold to ensure that codec_probe and firmware parsing and
* loading do not simultaneously execute.
*/
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
if (tas_priv->name_prefix)
scnprintf(tas_priv->rca_binaryname, 64, "%s-%sRCA%d.bin",
@@ -360,8 +361,6 @@ int tascodec_init(struct tasdevice_priv *tas_priv, void *codec,
dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
ret);
- /* Codec Lock Release*/
- mutex_unlock(&tas_priv->codec_lock);
return ret;
}
EXPORT_SYMBOL_GPL(tascodec_init);
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index dcbeb9618195..2b9efccf1a0b 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -1849,16 +1849,26 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
}
}
if (ret == -EAGAIN) {
- if (block->nr_retry > 0)
+ if (block->nr_retry > 0) {
+ /* Give the hardware time to stabilize before
+ * next block re-transmission attempt.
+ */
+ usleep_range(2000, 2500);
continue;
+ }
} else if (ret < 0) /*err in current device, skip it*/
break;
if (block->is_pchksum_present) {
ret = tasdev_block_chksum(tas_priv, block, chn);
if (ret == -EAGAIN) {
- if (block->nr_retry > 0)
+ if (block->nr_retry > 0) {
+ /* Give the bus time to recover after
+ * a checksum mismatch error.
+ */
+ usleep_range(2000, 2500);
continue;
+ }
} else if (ret < 0) /*err in current device, skip it*/
break;
}
@@ -2243,7 +2253,7 @@ int tas2781_load_calibration(void *context, char *file_name,
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
struct tasdevice *tasdev = &(tas_priv->tasdevice[i]);
- const struct firmware *fw_entry = NULL;
+ const struct firmware *fw_entry __free(firmware) = NULL;
struct tasdevice_fw *tas_fmw;
struct firmware fmw;
int offset = 0;
@@ -2253,60 +2263,50 @@ int tas2781_load_calibration(void *context, char *file_name,
if (ret) {
dev_err(tas_priv->dev, "%s: Request firmware %s failed\n",
__func__, file_name);
- goto out;
+ return ret;
}
if (!fw_entry->size) {
dev_err(tas_priv->dev, "%s: file read error: size = %lu\n",
__func__, (unsigned long)fw_entry->size);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
fmw.size = fw_entry->size;
fmw.data = fw_entry->data;
tas_fmw = tasdev->cali_data_fmw = kzalloc_obj(struct tasdevice_fw);
- if (!tasdev->cali_data_fmw) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!tasdev->cali_data_fmw)
+ return -ENOMEM;
+
tas_fmw->dev = tas_priv->dev;
offset = fw_parse_header(tas_priv, tas_fmw, &fmw, offset);
if (offset == -EINVAL) {
dev_err(tas_priv->dev, "fw_parse_header EXIT!\n");
- ret = offset;
- goto out;
+ return -EINVAL;
}
offset = fw_parse_variable_hdr_cal(tas_priv, tas_fmw, &fmw, offset);
if (offset == -EINVAL) {
dev_err(tas_priv->dev,
"%s: fw_parse_variable_header_cal EXIT!\n", __func__);
- ret = offset;
- goto out;
+ return -EINVAL;
}
offset = fw_parse_program_data(tas_priv, tas_fmw, &fmw, offset);
if (offset < 0) {
dev_err(tas_priv->dev, "fw_parse_program_data EXIT!\n");
- ret = offset;
- goto out;
+ return offset;
}
offset = fw_parse_configuration_data(tas_priv, tas_fmw, &fmw, offset);
if (offset < 0) {
dev_err(tas_priv->dev, "fw_parse_configuration_data EXIT!\n");
- ret = offset;
- goto out;
+ return offset;
}
offset = fw_parse_calibration_data(tas_priv, tas_fmw, &fmw, offset);
if (offset < 0) {
dev_err(tas_priv->dev, "fw_parse_calibration_data EXIT!\n");
- ret = offset;
- goto out;
+ return offset;
}
-out:
- release_firmware(fw_entry);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(tas2781_load_calibration, "SND_SOC_TAS2781_FMWLIB");
@@ -2399,7 +2399,7 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
int tasdevice_dsp_parser(void *context)
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *)context;
- const struct firmware *fw_entry;
+ const struct firmware *fw_entry __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw_entry, tas_priv->coef_binaryname,
@@ -2407,15 +2407,10 @@ int tasdevice_dsp_parser(void *context)
if (ret) {
dev_err(tas_priv->dev, "%s: load %s error\n", __func__,
tas_priv->coef_binaryname);
- goto out;
+ return ret;
}
- ret = tasdevice_dspfw_ready(fw_entry, tas_priv);
- release_firmware(fw_entry);
- fw_entry = NULL;
-
-out:
- return ret;
+ return tasdevice_dspfw_ready(fw_entry, tas_priv);
}
EXPORT_SYMBOL_NS_GPL(tasdevice_dsp_parser, "SND_SOC_TAS2781_FMWLIB");
@@ -2797,11 +2792,12 @@ out:
}
EXPORT_SYMBOL_NS_GPL(tasdevice_prmg_load, "SND_SOC_TAS2781_FMWLIB");
-void tasdevice_tuning_switch(void *context, int state)
+void tasdevice_tuning_switch(void *context, int state, bool is_cap)
{
struct tasdevice_priv *tas_priv = (struct tasdevice_priv *) context;
struct tasdevice_fw *tas_fmw = tas_priv->fmw;
- int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+ int profile_cfg_id = is_cap ? tas_priv->rcabin.capture_profile_id :
+ tas_priv->rcabin.profile_cfg_id;
/*
* Only RCA-based Playback can still work with no dsp program running
@@ -2818,7 +2814,6 @@ void tasdevice_tuning_switch(void *context, int state)
if (state == 0) {
if (tas_fmw && tas_priv->cur_prog < tas_fmw->nr_programs) {
/* dsp mode or tuning mode */
- profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
tasdevice_select_tuningprm_cfg(tas_priv,
tas_priv->cur_prog, tas_priv->cur_conf,
profile_cfg_id);
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 95d875c44b91..6f349f88f194 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -13,6 +13,7 @@
// Author: Kevin Lu <kevin-lu@ti.com>
//
+#include <linux/cleanup.h>
#include <linux/crc8.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
@@ -617,6 +618,7 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
struct tasdevice_priv *priv = snd_soc_component_get_drvdata(comp);
+ int i;
guard(mutex)(&priv->codec_lock);
if (priv->chip_id == TAS2563)
@@ -624,6 +626,14 @@ static int tasdev_calib_stop_put(struct snd_kcontrol *kcontrol,
else
tas2781_calib_stop_put(priv);
+ /*
+ * Set reloading-firmware flag after calibration, the flag will work
+ * during next playback, then set to the program id after reloading
+ * firmware.
+ */
+ for (i = 0; i < priv->ndev; i++)
+ priv->tasdevice[i].cur_prog = -1;
+
return 1;
}
@@ -843,12 +853,12 @@ static int tasdevice_digital_gain_get(
unsigned char data[4];
int ret;
- mutex_lock(&tas_dev->codec_lock);
+ guard(mutex)(&tas_dev->codec_lock);
/* Read the primary device */
ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
if (ret) {
dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
- goto out;
+ return ret;
}
target = get_unaligned_be32(&data[0]);
@@ -868,8 +878,7 @@ static int tasdevice_digital_gain_get(
/* find out the member same as or closer to the current volume */
ucontrol->value.integer.value[0] =
abs(target - ar_l) <= abs(target - ar_r) ? l : r;
-out:
- mutex_unlock(&tas_dev->codec_lock);
+
return 0;
}
@@ -882,29 +891,26 @@ static int tasdevice_digital_gain_put(
struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
struct tasdevice_priv *tas_dev = snd_soc_component_get_drvdata(codec);
int vol = ucontrol->value.integer.value[0];
- int status = 0, max = mc->max, rc = 1;
+ int status = 0, max = mc->max;
int i, ret;
unsigned int reg = mc->reg;
unsigned int volrd, volwr;
unsigned char data[4];
vol = clamp(vol, 0, max);
- mutex_lock(&tas_dev->codec_lock);
+ guard(mutex)(&tas_dev->codec_lock);
/* Read the primary device */
ret = tasdevice_dev_bulk_read(tas_dev, 0, reg, data, 4);
if (ret) {
dev_err(tas_dev->dev, "%s, get AMP vol error\n", __func__);
- rc = -1;
- goto out;
+ return -1;
}
volrd = get_unaligned_be32(&data[0]);
volwr = get_unaligned_be32(tas_dev->dvc_tlv_table[vol]);
- if (volrd == volwr) {
- rc = 0;
- goto out;
- }
+ if (volrd == volwr)
+ return 0;
for (i = 0; i < tas_dev->ndev; i++) {
ret = tasdevice_dev_bulk_write(tas_dev, i, reg,
@@ -918,10 +924,9 @@ static int tasdevice_digital_gain_put(
}
if (status)
- rc = -1;
-out:
- mutex_unlock(&tas_dev->codec_lock);
- return rc;
+ return -1;
+
+ return 1;
}
static const struct snd_kcontrol_new tasdevice_cali_controls[] = {
@@ -995,6 +1000,57 @@ static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
return ret;
}
+/**
+ * tasdevice_set_capture_profile_id - Set runtime capture profile index via
+ * ALSA control
+ * @kcontrol: ALSA kcontrol handle that triggers this operation
+ * @ucontrol: User space control value carrying the new profile index
+ *
+ * This mixer control handler validates the user-provided capture profile ID
+ * against the maximum valid index parsed from the loaded DSP firmware,
+ * then updates the runtime stored capture profile ID only if the new value
+ * differs from the current active one. It will immediately return -EINVAL
+ * if the submitted profile ID falls outside the valid range, including the
+ * edge case that no valid configuration blocks are detected in firmware.
+ *
+ * No actual DSP register write is performed in this handler. The updated
+ * profile ID will be applied to the hardware when the next ALSA capture
+ * stream starts up. Caller does not need to take extra codec lock here,
+ * as the ALSA control core already guarantees serialized execution.
+ *
+ * Return: 1 if profile ID value was changed, 0 if no modification needed,
+ * -EINVAL if the input profile ID is out of valid range
+ */
+static int tasdevice_set_capture_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int user_prof_id = ucontrol->value.integer.value[0];
+ unsigned int max_valid_id;
+ int ret = 0;
+
+ /*
+ * Align valid range with the bound defined in
+ * tasdevice_info_profile()
+ */
+ max_valid_id = tas_priv->rcabin.ncfgs - 1;
+
+ /*
+ * Reject invalid input including zero total configuration edge
+ * case
+ */
+ if (tas_priv->rcabin.ncfgs == 0 || user_prof_id > max_valid_id)
+ return -EINVAL;
+
+ if (tas_priv->rcabin.capture_profile_id != user_prof_id) {
+ tas_priv->rcabin.capture_profile_id = user_prof_id;
+ ret = 1;
+ }
+
+ return ret;
+}
+
static int tasdevice_info_active_num(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1075,6 +1131,41 @@ static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
return 0;
}
+/**
+ * tasdevice_get_capture_profile_id - Report current active capture profile
+ * ID to user space
+ * @kcontrol: ALSA kcontrol structure passed from ALSA core
+ * @ucontrol: User-space control element value buffer to write the result back
+ *
+ * This function ensures the returned profile ID is always clamped inside the
+ * valid range advertised by the info callback, preventing accidental invalid
+ * values from being exposed to applications even if internal driver state is
+ * temporarily inconsistent.
+ *
+ * Returns 0 on successful fill of the control value, no error conditions
+ * are defined for this getter callback.
+ */
+static int tasdevice_get_capture_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_kcontrol_chip(kcontrol);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ unsigned int max_valid_id, current_prof_id;
+
+ max_valid_id = tas_priv->rcabin.ncfgs > 0 ?
+ (tas_priv->rcabin.ncfgs - 1U) : 0;
+
+ /*
+ * Cast current profile id to unsigned to match type with max_valid_id,
+ * avoid signedness mismatch;
+ */
+ current_prof_id = (unsigned int)tas_priv->rcabin.capture_profile_id;
+ /* Prevent underflow when there are no loaded capture profiles. */
+ ucontrol->value.integer.value[0] = min(current_prof_id, max_valid_id);
+
+ return 0;
+}
+
static int tasdevice_get_chip_id(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1117,6 +1208,41 @@ static int tasdevice_create_control(struct tasdevice_priv *tas_priv)
ret = snd_soc_add_component_controls(tas_priv->codec,
prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+ mix_index = 0;
+ switch (tas_priv->chip_id) {
+ case TAS2563:
+ case TAS2568:
+ case TAS2570:
+ case TAS2572:
+ case TAS2573:
+ case TAS2574:
+ case TAS2781:
+ prof_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
+ sizeof(prof_ctrls[0]), GFP_KERNEL);
+ if (!prof_ctrls) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Create a mixer item for selecting the capture profile */
+ name = devm_kstrdup(tas_priv->dev, "Speaker Capture Profile Id",
+ GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ prof_ctrls[mix_index].name = name;
+ prof_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ prof_ctrls[mix_index].info = tasdevice_info_profile;
+ prof_ctrls[mix_index].get = tasdevice_get_capture_profile_id;
+ prof_ctrls[mix_index].put = tasdevice_set_capture_profile_id;
+ mix_index++;
+
+ ret = snd_soc_add_component_controls(tas_priv->codec,
+ prof_ctrls, nr_controls < mix_index ? nr_controls : mix_index);
+ break;
+ }
+
out:
return ret;
}
@@ -1330,6 +1456,43 @@ static void alpa_cali_update(struct bulk_reg_val *p,
p->val_len = 4;
}
+static int create_tas2781_cali_start_ktrl(struct tasdevice_priv
+ *priv, struct snd_kcontrol_new *cali_ctrl)
+{
+ struct soc_bytes_ext *ext_cali_start;
+ char *cali_start_name;
+
+ ext_cali_start = devm_kzalloc(priv->dev,
+ sizeof(*ext_cali_start), GFP_KERNEL);
+ if (!ext_cali_start)
+ return -ENOMEM;
+
+ cali_start_name = devm_kstrdup(priv->dev,
+ "Calibration Start", GFP_KERNEL);
+ if (!cali_start_name)
+ return -ENOMEM;
+ /*
+ * package structure for tas2781 ftc start:
+ * Pkg len (1 byte)
+ * Reg id (1 byte, constant 'r')
+ * book, page, register for pilot threshold, pilot tone
+ * and sine gain (12 bytes)
+ * for (i = 0; i < Device-Sum; i++) {
+ * Device #i index_info (1 byte)
+ * Sine gain for Device #i (8 bytes)
+ * }
+ */
+ ext_cali_start->max = 14 + priv->ndev * 9;
+ cali_ctrl->name = cali_start_name;
+ cali_ctrl->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ cali_ctrl->info = snd_soc_bytes_info_ext;
+ cali_ctrl->put = tas2781_calib_start_put;
+ cali_ctrl->get = tasdev_nop_get;
+ cali_ctrl->private_value = (unsigned long)ext_cali_start;
+
+ return 0;
+}
+
static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
{
struct calidata *cali_data = &priv->cali_data;
@@ -1448,37 +1611,11 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
*/
cali_data->data[0] = 0xff;
if (priv->chip_id == TAS2781) {
- struct soc_bytes_ext *ext_cali_start;
- char *cali_start_name;
-
- ext_cali_start = devm_kzalloc(priv->dev,
- sizeof(*ext_cali_start), GFP_KERNEL);
- if (!ext_cali_start)
- return -ENOMEM;
-
- cali_start_name = devm_kstrdup(priv->dev,
- "Calibration Start", GFP_KERNEL);
- if (!cali_start_name)
- return -ENOMEM;
- /*
- * package structure for tas2781 ftc start:
- * Pkg len (1 byte)
- * Reg id (1 byte, constant 'r')
- * book, page, register for pilot threshold, pilot tone
- * and sine gain (12 bytes)
- * for (i = 0; i < Device-Sum; i++) {
- * Device #i index_info (1 byte)
- * Sine gain for Device #i (8 bytes)
- * }
- */
- ext_cali_start->max = 14 + priv->ndev * 9;
- cali_ctrls[i].name = cali_start_name;
- cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
- cali_ctrls[i].info = snd_soc_bytes_info_ext;
- cali_ctrls[i].put = tas2781_calib_start_put;
- cali_ctrls[i].get = tasdev_nop_get;
- cali_ctrls[i].private_value = (unsigned long)ext_cali_start;
+ rc = create_tas2781_cali_start_ktrl(priv, &cali_ctrls[i]);
+ if (rc != 0)
+ return rc;
i++;
+
}
return snd_soc_add_component_controls(priv->codec, cali_ctrls,
@@ -1765,13 +1902,25 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
int state = 0;
- /* Codec Lock Hold */
- mutex_lock(&tas_priv->codec_lock);
+ guard(mutex)(&tas_priv->codec_lock);
if (event == SND_SOC_DAPM_PRE_PMD)
state = 1;
- tasdevice_tuning_switch(tas_priv, state);
- /* Codec Lock Release*/
- mutex_unlock(&tas_priv->codec_lock);
+ tasdevice_tuning_switch(tas_priv, state, false);
+
+ return 0;
+}
+
+static int tasdevice_capture_dapm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
+ struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(codec);
+ int state = 0;
+
+ guard(mutex)(&tas_priv->codec_lock);
+ if (event == SND_SOC_DAPM_PRE_PMD)
+ state = 1;
+ tasdevice_tuning_switch(tas_priv, state, true);
return 0;
}
@@ -1779,7 +1928,7 @@ static int tasdevice_dapm_event(struct snd_soc_dapm_widget *w,
static const struct snd_soc_dapm_widget tasdevice_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("ASI", "ASI Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT_E("ASI OUT", "ASI Capture", 0, SND_SOC_NOPM,
- 0, 0, tasdevice_dapm_event,
+ 0, 0, tasdevice_capture_dapm_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SPK("SPK", tasdevice_dapm_event),
SND_SOC_DAPM_OUTPUT("OUT"),
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 3d0b116544cc..caf8fe1bf4db 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -12,6 +12,7 @@
// Author: Baojun Xu <baojun.xu@ti.com>
// Author: Kevin Lu <kevin-lu@ti.com>
+#include <linux/cleanup.h>
#include <linux/unaligned.h>
#include <linux/crc32.h>
#include <linux/efi.h>
@@ -106,7 +107,6 @@ struct tas2783_prv {
static const struct reg_default tas2783_reg_default[] = {
{TAS2783_AMP_LEVEL, 0x28},
- {TASDEV_REG_SDW(0, 0, 0x03), 0x28},
{TASDEV_REG_SDW(0, 0, 0x04), 0x21},
{TASDEV_REG_SDW(0, 0, 0x05), 0x41},
{TASDEV_REG_SDW(0, 0, 0x06), 0x00},
@@ -142,6 +142,7 @@ static const struct reg_default tas2783_reg_default[] = {
{TASDEV_REG_SDW(0, 0, 0x41), 0x14},
{TASDEV_REG_SDW(0, 0, 0x5c), 0x19},
{TASDEV_REG_SDW(0, 0, 0x5d), 0x80},
+ {TASDEV_REG_SDW(0, 0, 0x60), 0x21},
{TASDEV_REG_SDW(0, 0, 0x63), 0x48},
{TASDEV_REG_SDW(0, 0, 0x65), 0x08},
{TASDEV_REG_SDW(0, 0, 0x66), 0xb2},
@@ -157,7 +158,6 @@ static const struct reg_default tas2783_reg_default[] = {
{TASDEV_REG_SDW(0, 0, 0x73), 0x08},
{TASDEV_REG_SDW(0, 0, 0x75), 0xe0},
{TASDEV_REG_SDW(0, 0, 0x7a), 0x60},
- {TASDEV_REG_SDW(0, 0, 0x60), 0x21},
{TASDEV_REG_SDW(0, 1, 0x02), 0x00},
{TASDEV_REG_SDW(0, 1, 0x17), 0xc0},
{TASDEV_REG_SDW(0, 1, 0x19), 0x60},
@@ -176,63 +176,44 @@ static const struct reg_default tas2783_reg_default[] = {
{TASDEV_REG_SDW(0, 0xfd, 0x39), 0x00},
{TASDEV_REG_SDW(0, 0xfd, 0x3e), 0x00},
{TASDEV_REG_SDW(0, 0xfd, 0x45), 0x00},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU21, 0x02, 1), 0x9c00},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 0), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x0b, 1), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x01, 1), 0x1},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x0b, 1), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x04, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x04, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x04, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 1), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 2), 0x0},
@@ -242,19 +223,60 @@ static const struct reg_default tas2783_reg_default[] = {
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 6), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x01, 7), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MU26, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT23, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 1), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x01, 2), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 1), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x0b, 2), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x02, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x05, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x01, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x04, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x05, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x08, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS24, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS28, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT29, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_IT28, 0x11, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT24, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT25, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT28, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x04, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x08, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x11, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 1), 0x0},
@@ -264,6 +286,14 @@ static const struct reg_default tas2783_reg_default[] = {
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 5), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 6), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 7), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_FU127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_CS127, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU21, 0x12, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x10, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x11, 0), 0x0},
+ {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_MFPU26, 0x12, 0), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 8), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 9), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xa), 0x0},
@@ -272,36 +302,6 @@ static const struct reg_default tas2783_reg_default[] = {
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xd), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xe), 0x0},
{SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_OT127, 0x12, 0xf), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x1, 0), 0x3},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23, 0x10, 0), 0x3},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU21, 0x13, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PPU26, 0x13, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x05, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x10, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x11, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_SAPU29, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_TG23, 0x10, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x01, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x06, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x07, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x08, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x09, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x0a, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x10, 0), 0x1},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x12, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x13, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x14, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x15, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_XU22, 0x16, 0), 0x0},
- {SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_UDMPU23, 0x10, 0), 0x0},
};
static const struct reg_sequence tas2783_init_seq[] = {
@@ -495,6 +495,56 @@ static bool tas2783_readable_register(struct device *dev, unsigned int reg)
return tas2783_sdca_mbq_size(dev, reg) > 0;
}
+static bool tas2783_writeable_register(struct device *dev, unsigned int reg)
+{
+ /*
+ * The Latency Control of every Entity, together with the Power Domain
+ * actual state and the protection status, is read-only. They are
+ * listed in tas2783_reg_default[] with a placeholder value, so without
+ * this a regcache_sync() would try to write them back and the
+ * peripheral would reject the transaction, aborting the sync.
+ */
+ switch (reg) {
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU21, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU23, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU26, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x07, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_XU22, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS24, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS21, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS25, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS26, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS28, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PDE23, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_UDMPU23, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x05, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_SAPU29, 0x11, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU21, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_PPU26, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT21, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT29, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT26, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_IT28, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT24, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT23, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT25, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT28, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MU26, 0x06, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_OT127, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_FU127, 0x10, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_CS127, 0x02, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU21, 0x04, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x08, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_SMART_AMP, TAS2783_SDCA_ENT_MFPU26, 0x04, 0):
+ return false;
+
+ default:
+ return tas2783_sdca_mbq_size(dev, reg) > 0;
+ }
+}
+
static bool tas2783_volatile_register(struct device *dev, u32 reg)
{
switch (reg) {
@@ -516,6 +566,7 @@ static const struct regmap_config tas_regmap = {
.reg_bits = 32,
.val_bits = 8,
.readable_reg = tas2783_readable_register,
+ .writeable_reg = tas2783_writeable_register,
.volatile_reg = tas2783_volatile_register,
.reg_defaults = tas2783_reg_default,
.num_reg_defaults = ARRAY_SIZE(tas2783_reg_default),
@@ -693,12 +744,12 @@ static s32 tas2783_update_calibdata(struct tas2783_prv *tas_dev)
return 0;
}
- mutex_lock(&tas_dev->calib_lock);
- ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data,
- tas_dev->cali_data.read_sz);
- if (!ret)
- tas2783_set_calib_params_to_device(tas_dev, tmp_val);
- mutex_unlock(&tas_dev->calib_lock);
+ scoped_guard(mutex, &tas_dev->calib_lock) {
+ ret = tas2783_validate_calibdata(tas_dev, tas_dev->cali_data.data,
+ tas_dev->cali_data.read_sz);
+ if (!ret)
+ tas2783_set_calib_params_to_device(tas_dev, tmp_val);
+ }
return ret;
}
@@ -927,22 +978,23 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
dev_err(tas_dev->dev,
"clear latch failed, err=%d", ret);
- mutex_lock(&tas_dev->pde_lock);
- /*
- * Sometimes, there is error returned during power on.
- * So added retry logic to ensure power on so that
- * port prepare succeeds
- */
- do {
- ret = regmap_write(tas_dev->regmap,
- SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
- TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
- TAS2783_SDCA_POW_STATE_ON);
- if (!ret)
- break;
- usleep_range(2000, 2200);
- } while (retry--);
- mutex_unlock(&tas_dev->pde_lock);
+ scoped_guard(mutex, &tas_dev->pde_lock) {
+ /*
+ * Sometimes, there is error returned during power on.
+ * So added retry logic to ensure power on so that
+ * port prepare succeeds
+ */
+ do {
+ ret = regmap_write(tas_dev->regmap,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
+ TAS2783_SDCA_POW_STATE_ON);
+ if (!ret)
+ break;
+ usleep_range(2000, 2200);
+ } while (retry--);
+ }
+
if (ret)
return ret;
@@ -966,7 +1018,6 @@ static s32 tas_sdw_hw_params(struct snd_pcm_substream *substream,
static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- s32 ret;
struct snd_soc_component *component = dai->component;
struct tas2783_prv *tas_dev =
snd_soc_component_get_drvdata(component);
@@ -975,14 +1026,11 @@ static s32 tas_sdw_pcm_hw_free(struct snd_pcm_substream *substream,
sdw_stream_remove_slave(tas_dev->sdw_peripheral, sdw_stream);
- mutex_lock(&tas_dev->pde_lock);
- ret = regmap_write(tas_dev->regmap,
- SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
- TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
- TAS2783_SDCA_POW_STATE_OFF);
- mutex_unlock(&tas_dev->pde_lock);
-
- return ret;
+ guard(mutex)(&tas_dev->pde_lock);
+ return regmap_write(tas_dev->regmap,
+ SDW_SDCA_CTL(1, TAS2783_SDCA_ENT_PDE23,
+ TAS2783_SDCA_CTL_REQ_POW_STATE, 0),
+ TAS2783_SDCA_POW_STATE_OFF);
}
static const struct snd_soc_dai_ops tas_dai_ops = {
@@ -1099,7 +1147,13 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
}
regcache_cache_only(tas_dev->regmap, false);
- regcache_sync(tas_dev->regmap);
+ ret = regcache_sync(tas_dev->regmap);
+ if (ret) {
+ regcache_cache_only(tas_dev->regmap, true);
+ regcache_mark_dirty(tas_dev->regmap);
+ return ret;
+ }
+
return 0;
}
@@ -1225,9 +1279,23 @@ static s32 tas_update_status(struct sdw_slave *slave,
if (tas_dev->hw_init || tas_dev->status != SDW_SLAVE_ATTACHED)
return 0;
- /* updated the cache data to device */
regcache_cache_only(tas_dev->regmap, false);
- regcache_sync(tas_dev->regmap);
+
+ /*
+ * The device is attaching uninitialized: either this is the first
+ * attach, or it lost power (and with it all register and DSP state)
+ * while the controller was power-gated during system suspend. The
+ * cache still holds the pre-suspend values, and tas_io_init() below
+ * resets the device via TAS2783_SW_RESET anyway, so syncing it back
+ * is both useless and harmful: later read-modify-write updates would
+ * compare against stale data and skip the hardware write.
+ *
+ * Drop the cache instead, so that subsequent accesses see the real
+ * hardware state. Syncing after the reset is not an option either:
+ * the cache accepts registers for which tas2783_sdca_mbq_size()
+ * returns 0, and writing those back fails with -EINVAL.
+ */
+ regcache_drop_region(tas_dev->regmap, 0, UINT_MAX);
/* perform I/O transfers required for Slave initialization */
return tas_io_init(&slave->dev, slave);
@@ -1330,7 +1398,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
function_data->desc = &peripheral->sdca_data.function[i];
/* Parse the function */
- ret = sdca_parse_function(dev, peripheral, function_data);
+ ret = sdca_parse_function(dev, function_data);
if (!ret)
tas_dev->sa_func_data = function_data;
else
diff --git a/sound/soc/codecs/tas5805m.c b/sound/soc/codecs/tas5805m.c
index bcc8cab8d667..d32796a6fa75 100644
--- a/sound/soc/codecs/tas5805m.c
+++ b/sound/soc/codecs/tas5805m.c
@@ -12,6 +12,7 @@
//
// It has been simplified a little and reworked for the 5.x ALSA SoC API.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -230,10 +231,9 @@ static int tas5805m_vol_get(struct snd_kcontrol *kcontrol,
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
ucontrol->value.integer.value[0] = tas5805m->vol[0];
ucontrol->value.integer.value[1] = tas5805m->vol[1];
- mutex_unlock(&tas5805m->lock);
return 0;
}
@@ -249,13 +249,12 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
- int ret = 0;
if (!(volume_is_valid(ucontrol->value.integer.value[0]) &&
volume_is_valid(ucontrol->value.integer.value[1])))
return -EINVAL;
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
if (tas5805m->vol[0] != ucontrol->value.integer.value[0] ||
tas5805m->vol[1] != ucontrol->value.integer.value[1]) {
tas5805m->vol[0] = ucontrol->value.integer.value[0];
@@ -265,11 +264,10 @@ static int tas5805m_vol_put(struct snd_kcontrol *kcontrol,
tas5805m->is_powered);
if (tas5805m->is_powered)
tas5805m_refresh(tas5805m);
- ret = 1;
+ return 1;
}
- mutex_unlock(&tas5805m->lock);
- return ret;
+ return 0;
}
static const struct snd_kcontrol_new tas5805m_snd_controls[] = {
@@ -332,7 +330,7 @@ static void do_work(struct work_struct *work)
dev_dbg(&tas5805m->i2c->dev, "DSP startup\n");
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
/* We mustn't issue any I2C transactions until the I2S
* clock is stable. Furthermore, we must allow a 5ms
* delay after the first set of register writes to
@@ -345,7 +343,6 @@ static void do_work(struct work_struct *work)
tas5805m->is_powered = true;
tas5805m_refresh(tas5805m);
- mutex_unlock(&tas5805m->lock);
}
static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
@@ -362,7 +359,7 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
dev_dbg(component->dev, "DSP shutdown\n");
cancel_work_sync(&tas5805m->work);
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
if (tas5805m->is_powered) {
tas5805m->is_powered = false;
@@ -379,7 +376,6 @@ static int tas5805m_dac_event(struct snd_soc_dapm_widget *w,
regmap_write(rm, REG_DEVICE_CTRL_2, DCTRL2_MODE_HIZ);
}
- mutex_unlock(&tas5805m->lock);
}
return 0;
@@ -414,14 +410,13 @@ static int tas5805m_mute(struct snd_soc_dai *dai, int mute, int direction)
struct tas5805m_priv *tas5805m =
snd_soc_component_get_drvdata(component);
- mutex_lock(&tas5805m->lock);
+ guard(mutex)(&tas5805m->lock);
dev_dbg(component->dev, "set mute=%d (is_powered=%d)\n",
mute, tas5805m->is_powered);
tas5805m->is_muted = mute;
if (tas5805m->is_powered)
tas5805m_refresh(tas5805m);
- mutex_unlock(&tas5805m->lock);
return 0;
}
@@ -462,7 +457,6 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
struct tas5805m_priv *tas5805m;
char filename[128];
const char *config_name;
- const struct firmware *fw;
int ret;
regmap = devm_regmap_init_i2c(i2c, &tas5805m_regmap);
@@ -507,24 +501,20 @@ static int tas5805m_i2c_probe(struct i2c_client *i2c)
snprintf(filename, sizeof(filename), "tas5805m_dsp_%s.bin",
config_name);
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, filename, dev);
if (ret)
return ret;
if ((fw->size < 2) || (fw->size & 1)) {
dev_err(dev, "firmware is invalid\n");
- release_firmware(fw);
return -EINVAL;
}
tas5805m->dsp_cfg_len = fw->size;
tas5805m->dsp_cfg_data = devm_kmemdup(dev, fw->data, fw->size, GFP_KERNEL);
- if (!tas5805m->dsp_cfg_data) {
- release_firmware(fw);
+ if (!tas5805m->dsp_cfg_data)
return -ENOMEM;
- }
-
- release_firmware(fw);
/* Do the first part of the power-on here, while we can expect
* the I2S interface to be quiet. We must raise PDN# and then
diff --git a/sound/soc/codecs/tas675x.c b/sound/soc/codecs/tas675x.c
index 82526362de7b..404706b62156 100644
--- a/sound/soc/codecs/tas675x.c
+++ b/sound/soc/codecs/tas675x.c
@@ -1924,15 +1924,6 @@ static const struct reg_default tas675x_reg_defaults[] = {
{ TAS675X_PWM_PHASE_M_CTRL_CH2_REG, 0x00 },
{ TAS675X_PWM_PHASE_M_CTRL_CH3_REG, 0x00 },
{ TAS675X_PWM_PHASE_M_CTRL_CH4_REG, 0x00 },
- { TAS675X_DC_LDG_CTRL_REG, 0x00 },
- { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 },
- { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 },
- { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 },
- { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 },
- { TAS675X_AC_LDG_CTRL_REG, 0x10 },
- { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 },
- { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 },
- { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 },
{ TAS675X_REPORT_ROUTING_1_REG, 0x00 },
{ TAS675X_OTSD_RECOVERY_EN_REG, 0x00 },
{ TAS675X_REPORT_ROUTING_2_REG, 0xA2 },
@@ -1943,6 +1934,15 @@ static const struct reg_default tas675x_reg_defaults[] = {
{ TAS675X_GPIO1_OUTPUT_SEL_REG, 0x00 },
{ TAS675X_GPIO2_OUTPUT_SEL_REG, 0x00 },
{ TAS675X_GPIO_CTRL_REG, TAS675X_GPIO_CTRL_RSTVAL },
+ { TAS675X_DC_LDG_CTRL_REG, 0x00 },
+ { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 },
+ { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 },
+ { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 },
+ { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 },
+ { TAS675X_AC_LDG_CTRL_REG, 0x10 },
+ { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 },
+ { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 },
+ { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 },
{ TAS675X_OTW_CTRL_CH1_CH2_REG, 0x11 },
{ TAS675X_OTW_CTRL_CH3_CH4_REG, 0x11 },
};
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index e5dfb3d752a3..84e954311c1b 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -320,8 +320,14 @@ static int aic26_probe(struct snd_soc_component *component)
return 0;
}
+static void aic26_remove(struct snd_soc_component *component)
+{
+ device_remove_file(component->dev, &dev_attr_keyclick);
+}
+
static const struct snd_soc_component_driver aic26_soc_component_dev = {
.probe = aic26_probe,
+ .remove = aic26_remove,
.controls = aic26_snd_controls,
.num_controls = ARRAY_SIZE(aic26_snd_controls),
.dapm_widgets = tlv320aic26_dapm_widgets,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 1d2e0ea6d4fe..43bcbc5449e1 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1720,18 +1720,14 @@ static int tlv320dac3100_fw_load(struct aic31xx_priv *aic31xx,
static int tlv320dac3100_load_coeffs(struct aic31xx_priv *aic31xx,
const char *fw_name)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw, fw_name, aic31xx->dev);
if (ret)
return ret;
- ret = tlv320dac3100_fw_load(aic31xx, fw->data, fw->size);
-
- release_firmware(fw);
-
- return ret;
+ return tlv320dac3100_fw_load(aic31xx, fw->data, fw->size);
}
static int aic31xx_i2c_probe(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index 5c0a76a4a106..deed61650e09 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+// SPDX-License-Identifier: GPL-2.0
+/*
* Clock Tree for the Texas Instruments TLV320AIC32x4
*
* Copyright 2019 Annaliese McDermond
@@ -9,6 +9,7 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
+#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/device.h>
@@ -57,7 +58,7 @@ static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
- AIC32X4_PLLEN, 0);
+ AIC32X4_PLLEN, 0);
}
static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
@@ -75,7 +76,7 @@ static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
}
static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
- struct clk_aic32x4_pll_muldiv *settings)
+ struct clk_aic32x4_pll_muldiv *settings)
{
/* Change to use regmap_bulk_read? */
unsigned int val;
@@ -106,19 +107,19 @@ static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
}
static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
- struct clk_aic32x4_pll_muldiv *settings)
+ struct clk_aic32x4_pll_muldiv *settings)
{
int ret;
/* Change to use regmap_bulk_write for some if not all? */
ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
- AIC32X4_PLL_R_MASK, settings->r);
+ AIC32X4_PLL_R_MASK, settings->r);
if (ret < 0)
return ret;
ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
- AIC32X4_PLL_P_MASK,
- settings->p << AIC32X4_PLL_P_SHIFT);
+ AIC32X4_PLL_P_MASK,
+ settings->p << AIC32X4_PLL_P_SHIFT);
if (ret < 0)
return ret;
@@ -136,23 +137,21 @@ static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
return 0;
}
-static unsigned long clk_aic32x4_pll_calc_rate(
- struct clk_aic32x4_pll_muldiv *settings,
- unsigned long parent_rate)
+static unsigned long clk_aic32x4_pll_calc_rate(struct clk_aic32x4_pll_muldiv *settings,
+ unsigned long parent_rate)
{
u64 rate;
/*
* We scale j by 10000 to account for the decimal part of P and divide
* it back out later.
*/
- rate = (u64) parent_rate * settings->r *
- ((settings->j * 10000) + settings->d);
+ rate = (u64)parent_rate * settings->r * ((settings->j * 10000) + settings->d);
- return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
+ return (unsigned long)DIV_ROUND_UP_ULL(rate, settings->p * 10000);
}
static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
- unsigned long rate, unsigned long parent_rate)
+ unsigned long rate, unsigned long parent_rate)
{
u64 multiplier;
@@ -165,14 +164,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
* of the multiplier. This is because we can't do floating point
* math in the kernel.
*/
- multiplier = (u64) rate * settings->p * 10000;
+ multiplier = (u64)rate * settings->p * 10000;
do_div(multiplier, parent_rate);
/*
* J can't be over 64, so R can scale this.
* R can't be greater than 4.
*/
- settings->r = ((u32) multiplier / 640000) + 1;
+ settings->r = ((u32)multiplier / 640000) + 1;
if (settings->r > 4)
return -1;
do_div(multiplier, settings->r);
@@ -184,14 +183,14 @@ static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
return -1;
/* Figure out the integer part, J, and the fractional part, D. */
- settings->j = (u32) multiplier / 10000;
- settings->d = (u32) multiplier % 10000;
+ settings->j = (u32)multiplier / 10000;
+ settings->d = (u32)multiplier % 10000;
return 0;
}
static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+ unsigned long parent_rate)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
struct clk_aic32x4_pll_muldiv settings;
@@ -220,8 +219,8 @@ static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw,
}
static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
- unsigned long rate,
- unsigned long parent_rate)
+ unsigned long rate,
+ unsigned long parent_rate)
{
struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
struct clk_aic32x4_pll_muldiv settings;
@@ -236,7 +235,7 @@ static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
return ret;
/* 10ms is the delay to wait before the clocks are stable */
- msleep(10);
+ usleep_range(10000, 20000);
return 0;
}
@@ -261,7 +260,6 @@ static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
}
-
static const struct clk_ops aic32x4_pll_ops = {
.prepare = clk_aic32x4_pll_prepare,
.unprepare = clk_aic32x4_pll_unprepare,
@@ -311,11 +309,11 @@ static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
regmap_update_bits(div->regmap, div->reg,
- AIC32X4_DIVEN, 0);
+ AIC32X4_DIVEN, 0);
}
static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
+ unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
u8 divisor;
@@ -342,7 +340,7 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
}
static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+ unsigned long parent_rate)
{
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
unsigned int val;
@@ -399,7 +397,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
{
.name = "pll",
.parent_names =
- (const char* []) { "mclk", "bclk", "gpio", "din" },
+ (const char *[]) { "mclk", "bclk", "gpio", "din" },
.num_parents = 4,
.ops = &aic32x4_pll_ops,
.reg = 0,
@@ -414,28 +412,28 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
},
{
.name = "ndac",
- .parent_names = (const char * []) { "codec_clkin" },
+ .parent_names = (const char *[]) { "codec_clkin" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_NDAC,
},
{
.name = "mdac",
- .parent_names = (const char * []) { "ndac" },
+ .parent_names = (const char *[]) { "ndac" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_MDAC,
},
{
.name = "nadc",
- .parent_names = (const char * []) { "codec_clkin" },
+ .parent_names = (const char *[]) { "codec_clkin" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_NADC,
},
{
.name = "madc",
- .parent_names = (const char * []) { "nadc" },
+ .parent_names = (const char *[]) { "nadc" },
.num_parents = 1,
.ops = &aic32x4_div_ops,
.reg = AIC32X4_MADC,
@@ -451,7 +449,7 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
};
static struct clk *aic32x4_register_clk(struct device *dev,
- struct aic32x4_clkdesc *desc)
+ struct aic32x4_clkdesc *desc)
{
struct clk_init_data init;
struct clk_aic32x4 *priv;
@@ -464,8 +462,8 @@ static struct clk *aic32x4_register_clk(struct device *dev,
init.flags = 0;
priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
- if (priv == NULL)
- return (struct clk *) -ENOMEM;
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
priv->dev = dev;
priv->hw.init = &init;
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c
index 449353d5f088..cbbb8ff3ee38 100644
--- a/sound/soc/codecs/tlv320aic32x4-i2c.c
+++ b/sound/soc/codecs/tlv320aic32x4-i2c.c
@@ -1,11 +1,10 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+// SPDX-License-Identifier: GPL-2.0
+/*
* Copyright 2011-2019 NW Digital Radio
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
*/
#include <linux/i2c.h>
@@ -16,17 +15,23 @@
#include "tlv320aic32x4.h"
+static const struct regmap_config aic32x4_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AIC32X4_REFPOWERUP,
+ .ranges = aic32x4_regmap_pages,
+ .num_ranges = 1,
+};
+
static int aic32x4_i2c_probe(struct i2c_client *i2c)
{
struct regmap *regmap;
- struct regmap_config config;
enum aic32x4_type type;
- config = aic32x4_regmap_config;
- config.reg_bits = 8;
- config.val_bits = 8;
+ regmap = devm_regmap_init_i2c(i2c, &aic32x4_i2c_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- regmap = devm_regmap_init_i2c(i2c, &config);
type = (uintptr_t)i2c_get_match_data(i2c);
return aic32x4_probe(&i2c->dev, regmap, type);
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c
index 92246243ff94..cb615b2e4f02 100644
--- a/sound/soc/codecs/tlv320aic32x4-spi.c
+++ b/sound/soc/codecs/tlv320aic32x4-spi.c
@@ -1,11 +1,10 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
+// SPDX-License-Identifier: GPL-2.0
+/*
* Copyright 2011-2019 NW Digital Radio
*
* Author: Annaliese McDermond <nh6z@nh6z.net>
*
* Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27.
- *
*/
#include <linux/spi/spi.h>
@@ -16,19 +15,25 @@
#include "tlv320aic32x4.h"
+static const struct regmap_config aic32x4_spi_regmap_config = {
+ .reg_bits = 7,
+ .pad_bits = 1,
+ .val_bits = 8,
+ .read_flag_mask = 0x01,
+ .max_register = AIC32X4_REFPOWERUP,
+ .ranges = aic32x4_regmap_pages,
+ .num_ranges = 1,
+};
+
static int aic32x4_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
- struct regmap_config config;
enum aic32x4_type type;
- config = aic32x4_regmap_config;
- config.reg_bits = 7;
- config.pad_bits = 1;
- config.val_bits = 8;
- config.read_flag_mask = 0x01;
+ regmap = devm_regmap_init_spi(spi, &aic32x4_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
- regmap = devm_regmap_init_spi(spi, &config);
type = (uintptr_t)spi_get_device_match_data(spi);
return aic32x4_probe(&spi->dev, regmap, type);
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index d85094557215..9e0e4aa2b09c 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * linux/sound/soc/codecs/tlv320aic32x4.c
- *
* Copyright 2011 Vista Silicon S.L.
*
* Author: Javier Martin <javier.martin@vista-silicon.com>
@@ -28,7 +26,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
-#include <sound/tlv320aic32x4.h>
#include "tlv320aic32x4.h"
@@ -45,7 +42,8 @@ struct aic32x4_priv {
struct regulator *supply_dv;
struct regulator *supply_av;
- struct aic32x4_setup_data *setup;
+ unsigned int gpio_func[5];
+
struct device *dev;
enum aic32x4_type type;
@@ -75,7 +73,7 @@ static int aic32x4_reset_adc(struct snd_soc_dapm_widget *w,
};
static int mic_bias_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+ struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
@@ -83,25 +81,23 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
/* Change Mic Bias Registor */
snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
- AIC32x4_MICBIAS_MASK,
- AIC32X4_MICBIAS_LDOIN |
- AIC32X4_MICBIAS_2075V);
- printk(KERN_DEBUG "%s: Mic Bias will be turned ON\n", __func__);
+ AIC32x4_MICBIAS_MASK,
+ AIC32X4_MICBIAS_LDOIN |
+ AIC32X4_MICBIAS_2075V);
+ dev_dbg(component->dev, "Mic Bias will be turned ON\n");
break;
case SND_SOC_DAPM_PRE_PMD:
snd_soc_component_update_bits(component, AIC32X4_MICBIAS,
- AIC32x4_MICBIAS_MASK, 0);
- printk(KERN_DEBUG "%s: Mic Bias will be turned OFF\n",
- __func__);
+ AIC32x4_MICBIAS_MASK, 0);
+ dev_dbg(component->dev, "Mic Bias will be turned OFF\n");
break;
}
return 0;
}
-
static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -114,7 +110,7 @@ static int aic32x4_get_mfp1_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -123,8 +119,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
val = snd_soc_component_read(component, AIC32X4_DOUTCTL);
gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
- printk(KERN_ERR "%s: MFP2 is not configure as a GPIO output\n",
- __func__);
+ dev_err(component->dev, "MFP2 is not configure as a GPIO output\n");
return -EINVAL;
}
@@ -142,7 +137,7 @@ static int aic32x4_set_mfp2_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -155,7 +150,7 @@ static int aic32x4_get_mfp3_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -164,8 +159,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
val = snd_soc_component_read(component, AIC32X4_MISOCTL);
gpio_check = (val & AIC32X4_MFP_GPIO_ENABLED);
if (gpio_check != AIC32X4_MFP_GPIO_ENABLED) {
- printk(KERN_ERR "%s: MFP4 is not configure as a GPIO output\n",
- __func__);
+ dev_err(component->dev, "MFP4 is not configure as a GPIO output\n");
return -EINVAL;
}
@@ -183,7 +177,7 @@ static int aic32x4_set_mfp4_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -195,7 +189,7 @@ static int aic32x4_get_mfp5_gpio(struct snd_kcontrol *kcontrol,
};
static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+ struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
u8 val;
@@ -204,8 +198,7 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
val = snd_soc_component_read(component, AIC32X4_GPIOCTL);
gpio_check = (val & AIC32X4_MFP5_GPIO_OUTPUT);
if (gpio_check != AIC32X4_MFP5_GPIO_OUTPUT) {
- printk(KERN_ERR "%s: MFP5 is not configure as a GPIO output\n",
- __func__);
+ dev_err(component->dev, "MFP5 is not configure as a GPIO output\n");
return -EINVAL;
}
@@ -222,25 +215,31 @@ static int aic32x4_set_mfp5_gpio(struct snd_kcontrol *kcontrol,
return 0;
};
-static const struct snd_kcontrol_new aic32x4_mfp1[] = {
- SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp2[] = {
- SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp3[] = {
- SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp4[] = {
- SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
-};
-
-static const struct snd_kcontrol_new aic32x4_mfp5[] = {
- SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
- aic32x4_set_mfp5_gpio),
+static const struct {
+ unsigned int reg;
+ struct snd_kcontrol_new ctrl;
+} aic32x4_mfp_cfg[] = {
+ {
+ .reg = AIC32X4_DINCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP1 GPIO", 0, aic32x4_get_mfp1_gpio, NULL),
+ },
+ {
+ .reg = AIC32X4_DOUTCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP2 GPIO", 0, NULL, aic32x4_set_mfp2_gpio),
+ },
+ {
+ .reg = AIC32X4_SCLKCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP3 GPIO", 0, aic32x4_get_mfp3_gpio, NULL),
+ },
+ {
+ .reg = AIC32X4_MISOCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP4 GPIO", 0, NULL, aic32x4_set_mfp4_gpio),
+ },
+ {
+ .reg = AIC32X4_GPIOCTL,
+ .ctrl = SOC_SINGLE_BOOL_EXT("MFP5 GPIO", 0, aic32x4_get_mfp5_gpio,
+ aic32x4_set_mfp5_gpio),
+ },
};
/* 0dB min, 0.5dB steps */
@@ -270,53 +269,42 @@ static SOC_ENUM_SINGLE_DECL(r_ptm_enum, AIC32X4_RPLAYBACK, 2, ptm_text);
static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
- AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
+ AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
SOC_ENUM("DAC Left Playback PowerTune Switch", l_ptm_enum),
SOC_ENUM("DAC Right Playback PowerTune Switch", r_ptm_enum),
SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN,
- AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0,
- tlv_driver_gain),
+ AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain),
SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN,
- AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0,
- tlv_driver_gain),
+ AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, tlv_driver_gain),
SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
- AIC32X4_HPRGAIN, 6, 0x01, 1),
+ AIC32X4_HPRGAIN, 6, 0x01, 1),
SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN,
- AIC32X4_LORGAIN, 6, 0x01, 1),
+ AIC32X4_LORGAIN, 6, 0x01, 1),
SOC_ENUM("LO Playback Common Mode Switch", lo_cm_enum),
SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL,
- AIC32X4_RMICPGAVOL, 7, 0x01, 1),
+ AIC32X4_RMICPGAVOL, 7, 0x01, 1),
SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0),
SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL,
- AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
+ AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol),
SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL,
- AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
+ AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0),
SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0),
- SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1,
- 4, 0x07, 0),
- SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1,
- 0, 0x03, 0),
- SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2,
- 6, 0x03, 0),
- SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2,
- 1, 0x1F, 0),
- SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3,
- 0, 0x7F, 0),
- SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4,
- 3, 0x1F, 0),
- SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5,
- 3, 0x1F, 0),
- SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6,
- 0, 0x1F, 0),
- SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7,
- 0, 0x0F, 0),
+ SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, 4, 0x07, 0),
+ SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, 0, 0x03, 0),
+ SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, 6, 0x03, 0),
+ SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, 1, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, 0, 0x7F, 0),
+ SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, 3, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, 0, 0x1F, 0),
+ SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, 0, 0x0F, 0),
};
static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
@@ -354,21 +342,27 @@ static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_te
static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum),
};
+
static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum),
};
+
static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum),
};
+
static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum),
};
+
static const struct snd_kcontrol_new cml_to_lmixer_controls[] = {
SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum),
};
+
static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum),
};
+
static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = {
SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum),
};
@@ -385,21 +379,27 @@ static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_te
static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum),
};
+
static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum),
};
+
static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum),
};
+
static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum),
};
+
static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = {
SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum),
};
+
static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum),
};
+
static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = {
SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum),
};
@@ -428,38 +428,38 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0),
SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in1r_to_rmixer_controls),
+ in1r_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in2r_to_rmixer_controls),
+ in2r_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in3r_to_rmixer_controls),
+ in3r_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in2l_to_rmixer_controls),
+ in2l_to_rmixer_controls),
SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- cmr_to_rmixer_controls),
+ cmr_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in1l_to_rmixer_controls),
+ in1l_to_rmixer_controls),
SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in3l_to_rmixer_controls),
+ in3l_to_rmixer_controls),
SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0),
SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in1l_to_lmixer_controls),
+ in1l_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in2l_to_lmixer_controls),
+ in2l_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in3l_to_lmixer_controls),
+ in3l_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0,
- in1r_to_lmixer_controls),
+ in1r_to_lmixer_controls),
SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- cml_to_lmixer_controls),
+ cml_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in2r_to_lmixer_controls),
+ in2r_to_lmixer_controls),
SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0,
- in3r_to_lmixer_controls),
+ in3r_to_lmixer_controls),
SND_SOC_DAPM_SUPPLY("Mic Bias", AIC32X4_MICBIAS, 6, 0, mic_bias_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_POST("ADC Reset", aic32x4_reset_adc),
@@ -575,7 +575,7 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
{"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"},
};
-static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
+const struct regmap_range_cfg aic32x4_regmap_pages[] = {
{
.selector_reg = 0,
.selector_mask = 0xff,
@@ -585,13 +585,7 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = {
.range_max = AIC32X4_REFPOWERUP,
},
};
-
-const struct regmap_config aic32x4_regmap_config = {
- .max_register = AIC32X4_REFPOWERUP,
- .ranges = aic32x4_regmap_pages,
- .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages),
-};
-EXPORT_SYMBOL(aic32x4_regmap_config);
+EXPORT_SYMBOL_GPL(aic32x4_regmap_pages);
static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
@@ -624,7 +618,7 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
- printk(KERN_ERR "aic32x4: invalid clock provider\n");
+ dev_err(component->dev, "invalid clock provider\n");
return -EINVAL;
}
@@ -651,19 +645,20 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
AIC32X4_IFACE1_DATATYPE_SHIFT);
break;
default:
- printk(KERN_ERR "aic32x4: invalid DAI interface format\n");
+ dev_err(component->dev, "invalid DAI interface format\n");
return -EINVAL;
}
aic32x4->fmt = fmt;
snd_soc_component_update_bits(component, AIC32X4_IFACE1,
- AIC32X4_IFACE1_DATATYPE_MASK |
- AIC32X4_IFACE1_MASTER_MASK, iface_reg_1);
+ AIC32X4_IFACE1_DATATYPE_MASK |
+ AIC32X4_IFACE1_MASTER_MASK,
+ iface_reg_1);
snd_soc_component_update_bits(component, AIC32X4_IFACE2,
- AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
+ AIC32X4_DATA_OFFSET_MASK, iface_reg_2);
snd_soc_component_update_bits(component, AIC32X4_IFACE3,
- AIC32X4_BCLKINV_MASK, iface_reg_3);
+ AIC32X4_BCLKINV_MASK, iface_reg_3);
return 0;
}
@@ -676,14 +671,13 @@ static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
{
snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
- snd_soc_component_write(component, AIC32X4_DOSRLSB,
- (dosr & 0xff));
+ snd_soc_component_write(component, AIC32X4_DOSRLSB, dosr & 0xff);
return 0;
}
static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
- u8 r_block, u8 p_block)
+ u8 r_block, u8 p_block)
{
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
@@ -703,6 +697,45 @@ static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
return 0;
}
+static int aic32x4_configure_rate(struct snd_soc_component *component,
+ unsigned int rate, u8 *aosr, u8 *adc_rc,
+ u8 *dac_rc, u8 *dosr_inc)
+{
+ struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+ u8 prb_rx, prb_tx;
+
+ if (rate <= 48000) {
+ *aosr = 128;
+ *adc_rc = 6;
+ *dac_rc = 8;
+ *dosr_inc = 8;
+ prb_rx = 1;
+ prb_tx = 1;
+ } else if (rate <= 96000) {
+ *aosr = 64;
+ *adc_rc = 6;
+ *dac_rc = 8;
+ *dosr_inc = 4;
+ prb_rx = 1;
+ prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 9;
+ } else if (rate == 192000) {
+ *aosr = 32;
+ *adc_rc = 3;
+ *dac_rc = 4;
+ *dosr_inc = 2;
+ prb_rx = 13;
+ prb_tx = (aic32x4->type == AIC32X4_TYPE_TAS2505) ? 1 : 19;
+ } else {
+ dev_err(component->dev, "Sampling rate %u not supported\n", rate);
+ return -EINVAL;
+ }
+
+ if (aic32x4->type == AIC32X4_TYPE_TAS2505)
+ prb_rx = 0;
+
+ return aic32x4_set_processing_blocks(component, prb_rx, prb_tx);
+}
+
static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned int sample_rate, unsigned int channels,
unsigned int bit_depth)
@@ -717,7 +750,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
unsigned long adc_clock_rate, dac_clock_rate;
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "pll" },
{ .id = "nadc" },
{ .id = "madc" },
@@ -729,37 +762,11 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
if (ret)
return ret;
- if (sample_rate <= 48000) {
- aosr = 128;
- adc_resource_class = 6;
- dac_resource_class = 8;
- dosr_increment = 8;
- if (aic32x4->type == AIC32X4_TYPE_TAS2505)
- aic32x4_set_processing_blocks(component, 0, 1);
- else
- aic32x4_set_processing_blocks(component, 1, 1);
- } else if (sample_rate <= 96000) {
- aosr = 64;
- adc_resource_class = 6;
- dac_resource_class = 8;
- dosr_increment = 4;
- if (aic32x4->type == AIC32X4_TYPE_TAS2505)
- aic32x4_set_processing_blocks(component, 0, 1);
- else
- aic32x4_set_processing_blocks(component, 1, 9);
- } else if (sample_rate == 192000) {
- aosr = 32;
- adc_resource_class = 3;
- dac_resource_class = 4;
- dosr_increment = 2;
- if (aic32x4->type == AIC32X4_TYPE_TAS2505)
- aic32x4_set_processing_blocks(component, 0, 1);
- else
- aic32x4_set_processing_blocks(component, 13, 19);
- } else {
- dev_err(component->dev, "Sampling rate not supported\n");
- return -EINVAL;
- }
+ ret = aic32x4_configure_rate(component, sample_rate, &aosr,
+ &adc_resource_class, &dac_resource_class,
+ &dosr_increment);
+ if (ret)
+ return ret;
/* PCM over I2S is always 2-channel */
if ((aic32x4->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S)
@@ -781,50 +788,39 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
(min_mdac * dosr * sample_rate);
for (mdac = min_mdac; mdac <= 128; ++mdac) {
for (ndac = max_ndac; ndac > 0; --ndac) {
- dac_clock_rate = ndac * mdac * dosr *
- sample_rate;
- if (dac_clock_rate == adc_clock_rate) {
- if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
- continue;
-
- clk_set_rate(clocks[0].clk,
- dac_clock_rate);
-
- clk_set_rate(clocks[1].clk,
- sample_rate * aosr *
- madc);
- clk_set_rate(clocks[2].clk,
- sample_rate * aosr);
- aic32x4_set_aosr(component,
- aosr);
-
- clk_set_rate(clocks[3].clk,
- sample_rate * dosr *
- mdac);
- clk_set_rate(clocks[4].clk,
- sample_rate * dosr);
- aic32x4_set_dosr(component,
- dosr);
-
- clk_set_rate(clocks[5].clk,
- sample_rate * channels *
- bit_depth);
-
- return 0;
- }
+ dac_clock_rate = ndac * mdac * dosr * sample_rate;
+ if (dac_clock_rate != adc_clock_rate)
+ continue;
+
+ if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
+ continue;
+
+ clk_set_rate(clocks[0].clk, dac_clock_rate);
+
+ clk_set_rate(clocks[1].clk, sample_rate * aosr * madc);
+ clk_set_rate(clocks[2].clk, sample_rate * aosr);
+ aic32x4_set_aosr(component, aosr);
+
+ clk_set_rate(clocks[3].clk, sample_rate * dosr * mdac);
+ clk_set_rate(clocks[4].clk, sample_rate * dosr);
+ aic32x4_set_dosr(component, dosr);
+
+ clk_set_rate(clocks[5].clk,
+ sample_rate * channels * bit_depth);
+
+ return 0;
}
}
}
}
- dev_err(component->dev,
- "Could not set clocks to support sample rate.\n");
+ dev_err(component->dev, "Could not set clocks to support sample rate.\n");
return -EINVAL;
}
static int aic32x4_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
@@ -837,24 +833,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
switch (params_physical_width(params)) {
case 16:
- iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_16BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 20:
- iface1_reg |= (AIC32X4_WORD_LEN_20BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 24:
- iface1_reg |= (AIC32X4_WORD_LEN_24BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
case 32:
- iface1_reg |= (AIC32X4_WORD_LEN_32BITS <<
- AIC32X4_IFACE1_DATALEN_SHIFT);
+ iface1_reg |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_IFACE1_DATALEN_SHIFT);
break;
}
snd_soc_component_update_bits(component, AIC32X4_IFACE1,
- AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
+ AIC32X4_IFACE1_DATALEN_MASK, iface1_reg);
if (params_channels(params) == 1) {
dacsetup_reg = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
@@ -865,7 +857,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
dacsetup_reg = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
}
snd_soc_component_update_bits(component, AIC32X4_DACSETUP,
- AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
+ AIC32X4_DAC_CHAN_MASK, dacsetup_reg);
return 0;
}
@@ -875,7 +867,7 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute, int direction)
struct snd_soc_component *component = dai->component;
snd_soc_component_update_bits(component, AIC32X4_DACMUTE,
- AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
+ AIC32X4_MUTEON, mute ? AIC32X4_MUTEON : 0);
return 0;
}
@@ -886,7 +878,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "madc" },
{ .id = "mdac" },
{ .id = "bdiv" },
@@ -955,44 +947,14 @@ static void aic32x4_setup_gpios(struct snd_soc_component *component)
struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
/* setup GPIO functions */
- /* MFP1 */
- if (aic32x4->setup->gpio_func[0] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_DINCTL,
- aic32x4->setup->gpio_func[0]);
- snd_soc_add_component_controls(component, aic32x4_mfp1,
- ARRAY_SIZE(aic32x4_mfp1));
- }
-
- /* MFP2 */
- if (aic32x4->setup->gpio_func[1] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_DOUTCTL,
- aic32x4->setup->gpio_func[1]);
- snd_soc_add_component_controls(component, aic32x4_mfp2,
- ARRAY_SIZE(aic32x4_mfp2));
- }
-
- /* MFP3 */
- if (aic32x4->setup->gpio_func[2] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_SCLKCTL,
- aic32x4->setup->gpio_func[2]);
- snd_soc_add_component_controls(component, aic32x4_mfp3,
- ARRAY_SIZE(aic32x4_mfp3));
- }
-
- /* MFP4 */
- if (aic32x4->setup->gpio_func[3] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_MISOCTL,
- aic32x4->setup->gpio_func[3]);
- snd_soc_add_component_controls(component, aic32x4_mfp4,
- ARRAY_SIZE(aic32x4_mfp4));
- }
-
- /* MFP5 */
- if (aic32x4->setup->gpio_func[4] != AIC32X4_MFPX_DEFAULT_VALUE) {
- snd_soc_component_write(component, AIC32X4_GPIOCTL,
- aic32x4->setup->gpio_func[4]);
- snd_soc_add_component_controls(component, aic32x4_mfp5,
- ARRAY_SIZE(aic32x4_mfp5));
+ BUILD_BUG_ON(ARRAY_SIZE(aic32x4->gpio_func) != ARRAY_SIZE(aic32x4_mfp_cfg));
+ for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++) {
+ if (aic32x4->gpio_func[i] == AIC32X4_MFPX_DEFAULT_VALUE)
+ continue;
+
+ snd_soc_component_write(component, aic32x4_mfp_cfg[i].reg,
+ aic32x4->gpio_func[i]);
+ snd_soc_add_component_controls(component, &aic32x4_mfp_cfg[i].ctrl, 1);
}
}
@@ -1002,7 +964,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
u32 tmp_reg;
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
@@ -1013,8 +975,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- if (aic32x4->setup)
- aic32x4_setup_gpios(component);
+ aic32x4_setup_gpios(component);
clk_set_parent(clocks[0].clk, clocks[1].clk);
clk_set_parent(clocks[2].clk, clocks[3].clk);
@@ -1022,7 +983,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
/* Power platform configuration */
if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
snd_soc_component_write(component, AIC32X4_MICBIAS,
- AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
+ AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
}
if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
@@ -1041,16 +1002,16 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
/* Mic PGA routing */
if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
snd_soc_component_write(component, AIC32X4_LMICPGANIN,
- AIC32X4_LMICPGANIN_IN2R_10K);
+ AIC32X4_LMICPGANIN_IN2R_10K);
else
snd_soc_component_write(component, AIC32X4_LMICPGANIN,
- AIC32X4_LMICPGANIN_CM1L_10K);
+ AIC32X4_LMICPGANIN_CM1L_10K);
if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
snd_soc_component_write(component, AIC32X4_RMICPGANIN,
- AIC32X4_RMICPGANIN_IN1L_10K);
+ AIC32X4_RMICPGANIN_IN1L_10K);
else
snd_soc_component_write(component, AIC32X4_RMICPGANIN,
- AIC32X4_RMICPGANIN_CM1R_10K);
+ AIC32X4_RMICPGANIN_CM1R_10K);
/*
* Workaround: for an unknown reason, the ADC needs to be powered up
@@ -1058,8 +1019,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
* a HW BUG or some kind of behavior not documented in the datasheet.
*/
tmp_reg = snd_soc_component_read(component, AIC32X4_ADCSETUP);
- snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg |
- AIC32X4_LADC_EN | AIC32X4_RADC_EN);
+ snd_soc_component_write(component, AIC32X4_ADCSETUP,
+ tmp_reg | AIC32X4_LADC_EN | AIC32X4_RADC_EN);
snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
/*
@@ -1102,13 +1063,13 @@ static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum),
SOC_SINGLE_TLV("HP Driver Gain Volume",
- AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
+ AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1),
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
- TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
+ TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
SOC_SINGLE_TLV("Speaker Amplifier Playback Volume",
- TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
+ TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
};
@@ -1144,11 +1105,12 @@ static const struct snd_soc_dapm_route aic32x4_tas2505_dapm_routes[] = {
static struct snd_soc_dai_driver aic32x4_tas2505_dai = {
.name = "tas2505-hifi",
.playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = AIC32X4_FORMATS,},
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = AIC32X4_FORMATS,
+ },
.ops = &aic32x4_ops,
.symmetric_rate = 1,
};
@@ -1159,7 +1121,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
u32 tmp_reg;
int ret;
- static struct clk_bulk_data clocks[] = {
+ struct clk_bulk_data clocks[] = {
{ .id = "codec_clkin" },
{ .id = "pll" },
{ .id = "bdiv" },
@@ -1170,8 +1132,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
if (ret)
return ret;
- if (aic32x4->setup)
- aic32x4_setup_gpios(component);
+ aic32x4_setup_gpios(component);
clk_set_parent(clocks[0].clk, clocks[1].clk);
clk_set_parent(clocks[2].clk, clocks[3].clk);
@@ -1192,7 +1153,7 @@ static int aic32x4_tas2505_component_probe(struct snd_soc_component *component)
snd_soc_component_write(component, AIC32X4_CMMODE, tmp_reg);
/*
- * Enable the fast charging feature and ensure the needed 40ms ellapsed
+ * Enable the fast charging feature and ensure the needed 40ms elapsed
* before using the analog circuits.
*/
snd_soc_component_write(component, TAS2505_REFPOWERUP,
@@ -1218,17 +1179,10 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4_tas2505 =
.endianness = 1,
};
-static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
- struct device_node *np)
+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, struct device_node *np)
{
- struct aic32x4_setup_data *aic32x4_setup;
int ret;
- aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
- GFP_KERNEL);
- if (!aic32x4_setup)
- return -ENOMEM;
-
ret = of_property_match_string(np, "clock-names", "mclk");
if (ret < 0)
return -EINVAL;
@@ -1245,9 +1199,11 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
gpiod_set_consumer_name(aic32x4->rstn_gpio, "tlv320aic32x4_rstn");
}
- if (of_property_read_u32_array(np, "aic32x4-gpio-func",
- aic32x4_setup->gpio_func, 5) >= 0)
- aic32x4->setup = aic32x4_setup;
+ for (int i = 0; i < ARRAY_SIZE(aic32x4->gpio_func); i++)
+ aic32x4->gpio_func[i] = AIC32X4_MFPX_DEFAULT_VALUE;
+ of_property_read_u32_array(np, "aic32x4-gpio-func",
+ aic32x4->gpio_func, ARRAY_SIZE(aic32x4->gpio_func));
+
return 0;
}
@@ -1266,7 +1222,7 @@ static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4)
}
static int aic32x4_setup_regulators(struct device *dev,
- struct aic32x4_priv *aic32x4)
+ struct aic32x4_priv *aic32x4)
{
int ret = 0;
@@ -1356,12 +1312,8 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap,
struct device_node *np = dev->of_node;
int ret;
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv),
- GFP_KERNEL);
- if (aic32x4 == NULL)
+ aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), GFP_KERNEL);
+ if (!aic32x4)
return -ENOMEM;
aic32x4->dev = dev;
@@ -1405,11 +1357,13 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap,
switch (aic32x4->type) {
case AIC32X4_TYPE_TAS2505:
ret = devm_snd_soc_register_component(dev,
- &soc_component_dev_aic32x4_tas2505, &aic32x4_tas2505_dai, 1);
+ &soc_component_dev_aic32x4_tas2505,
+ &aic32x4_tas2505_dai, 1);
break;
default:
ret = devm_snd_soc_register_component(dev,
- &soc_component_dev_aic32x4, &aic32x4_dai, 1);
+ &soc_component_dev_aic32x4,
+ &aic32x4_dai, 1);
}
if (ret) {
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index f68a846ef61d..cfab6f8ce5ac 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -3,7 +3,6 @@
* tlv320aic32x4.h
*/
-
#ifndef _TLV320AIC32X4_H
#define _TLV320AIC32X4_H
@@ -16,7 +15,7 @@ enum aic32x4_type {
AIC32X4_TYPE_TAS2505,
};
-extern const struct regmap_config aic32x4_regmap_config;
+extern const struct regmap_range_cfg aic32x4_regmap_pages[];
int aic32x4_probe(struct device *dev, struct regmap *regmap,
enum aic32x4_type type);
void aic32x4_remove(struct device *dev);
@@ -24,7 +23,7 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
/* tlv320aic32x4 register space (in decimal to match datasheet) */
-#define AIC32X4_REG(page, reg) ((page * 128) + reg)
+#define AIC32X4_REG(page, reg) (((page) * 128) + (reg))
#define AIC32X4_PSEL AIC32X4_REG(0, 0)
@@ -234,4 +233,31 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
#define AIC32X4_MAX_CODEC_CLKIN_FREQ 110000000
#define AIC32X4_MAX_PLL_CLKIN 20000000
+#define AIC32X4_PWR_MICBIAS_2075_LDOIN 0x00000001
+#define AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE 0x00000002
+#define AIC32X4_PWR_AIC32X4_LDO_ENABLE 0x00000004
+#define AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36 0x00000008
+#define AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED 0x00000010
+
+#define AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K 0x00000001
+#define AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K 0x00000002
+
+/* GPIO API */
+#define AIC32X4_MFPX_DEFAULT_VALUE 0xff
+
+#define AIC32X4_MFP1_DIN_DISABLED 0
+#define AIC32X4_MFP1_DIN_ENABLED 0x2
+#define AIC32X4_MFP1_GPIO_IN 0x4
+
+#define AIC32X4_MFP2_GPIO_OUT_LOW 0x0
+#define AIC32X4_MFP2_GPIO_OUT_HIGH 0x1
+
+#define AIC32X4_MFP_GPIO_ENABLED 0x4
+
+#define AIC32X4_MFP5_GPIO_DISABLED 0x0
+#define AIC32X4_MFP5_GPIO_INPUT 0x8
+#define AIC32X4_MFP5_GPIO_OUTPUT 0xc
+#define AIC32X4_MFP5_GPIO_OUT_LOW 0x0
+#define AIC32X4_MFP5_GPIO_OUT_HIGH 0x1
+
#endif /* _TLV320AIC32X4_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 223c49dfc450..9bd2ddd8dacd 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -7,6 +7,7 @@
* Copyright: (C) 2009 Nokia Corporation
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -236,13 +237,10 @@ static int dac33_write_locked(struct snd_soc_component *component, unsigned int
unsigned int value)
{
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
- int ret;
- mutex_lock(&dac33->mutex);
- ret = dac33_write(component, reg, value);
- mutex_unlock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
- return ret;
+ return dac33_write(component, reg, value);
}
#define DAC33_I2C_ADDR_AUTOINC 0x80
@@ -365,13 +363,13 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
int ret = 0;
- mutex_lock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
/* Safety check */
if (unlikely(power == dac33->chip_power)) {
dev_dbg(component->dev, "Trying to set the same power state: %s\n",
power ? "ON" : "OFF");
- goto exit;
+ return ret;
}
if (power) {
@@ -380,7 +378,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to enable supplies: %d\n", ret);
- goto exit;
+ return ret;
}
if (dac33->reset_gpiod) {
@@ -388,7 +386,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret < 0) {
dev_err(&dac33->i2c->dev,
"Failed to set reset GPIO: %d\n", ret);
- goto exit;
+ return ret;
}
}
@@ -400,7 +398,7 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret < 0) {
dev_err(&dac33->i2c->dev,
"Failed to set reset GPIO: %d\n", ret);
- goto exit;
+ return ret;
}
}
@@ -409,14 +407,12 @@ static int dac33_hard_power(struct snd_soc_component *component, int power)
if (ret != 0) {
dev_err(component->dev,
"Failed to disable supplies: %d\n", ret);
- goto exit;
+ return ret;
}
dac33->chip_power = 0;
}
-exit:
- mutex_unlock(&dac33->mutex);
return ret;
}
@@ -659,7 +655,6 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
{
struct snd_soc_component *component = dac33->component;
unsigned int delay;
- unsigned long flags;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@@ -667,10 +662,10 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
DAC33_THRREG(dac33->nsample));
/* Take the timestamps */
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp2 = ktime_to_us(ktime_get());
- dac33->t_stamp1 = dac33->t_stamp2;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ dac33->t_stamp2 = ktime_to_us(ktime_get());
+ dac33->t_stamp1 = dac33->t_stamp2;
+ }
dac33_write16(component, DAC33_PREFILL_MSB,
DAC33_THRREG(dac33->alarm_threshold));
@@ -682,11 +677,11 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
break;
case DAC33_FIFO_MODE7:
/* Take the timestamp */
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp1 = ktime_to_us(ktime_get());
- /* Move back the timestamp with drain time */
- dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ dac33->t_stamp1 = ktime_to_us(ktime_get());
+ /* Move back the timestamp with drain time */
+ dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
+ }
dac33_write16(component, DAC33_PREFILL_MSB,
DAC33_THRREG(DAC33_MODE7_MARGIN));
@@ -704,14 +699,12 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
{
struct snd_soc_component *component = dac33->component;
- unsigned long flags;
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
/* Take the timestamp */
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp2 = ktime_to_us(ktime_get());
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock)
+ dac33->t_stamp2 = ktime_to_us(ktime_get());
dac33_write16(component, DAC33_NSAMPLE_MSB,
DAC33_THRREG(dac33->nsample));
@@ -735,7 +728,7 @@ static void dac33_work(struct work_struct *work)
dac33 = container_of(work, struct tlv320dac33_priv, work);
component = dac33->component;
- mutex_lock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
switch (dac33->state) {
case DAC33_PREFILL:
dac33->state = DAC33_PLAYBACK;
@@ -757,18 +750,15 @@ static void dac33_work(struct work_struct *work)
dac33_write(component, DAC33_FIFO_CTRL_A, reg);
break;
}
- mutex_unlock(&dac33->mutex);
}
static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
{
struct snd_soc_component *component = dev;
struct tlv320dac33_priv *dac33 = snd_soc_component_get_drvdata(component);
- unsigned long flags;
- spin_lock_irqsave(&dac33->lock, flags);
- dac33->t_stamp1 = ktime_to_us(ktime_get());
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock)
+ dac33->t_stamp1 = ktime_to_us(ktime_get());
/* Do not schedule the workqueue in Mode7 */
if (dac33->fifo_mode != DAC33_FIFO_MODE7)
@@ -902,14 +892,13 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
return -EINVAL;
}
- mutex_lock(&dac33->mutex);
+ guard(mutex)(&dac33->mutex);
if (!dac33->chip_power) {
/*
* Chip is not powered yet.
* Do the init in the dac33_set_bias_level later.
*/
- mutex_unlock(&dac33->mutex);
return 0;
}
@@ -1053,8 +1042,6 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream,
break;
}
- mutex_unlock(&dac33->mutex);
-
return 0;
}
@@ -1156,21 +1143,20 @@ static snd_pcm_sframes_t dac33_dai_delay(
unsigned int time_delta, uthr;
int samples_out, samples_in, samples;
snd_pcm_sframes_t delay = 0;
- unsigned long flags;
switch (dac33->fifo_mode) {
case DAC33_FIFO_BYPASS:
break;
case DAC33_FIFO_MODE1:
- spin_lock_irqsave(&dac33->lock, flags);
- t0 = dac33->t_stamp1;
- t1 = dac33->t_stamp2;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ t0 = dac33->t_stamp1;
+ t1 = dac33->t_stamp2;
+ }
t_now = ktime_to_us(ktime_get());
/* We have not started to fill the FIFO yet, delay is 0 */
if (!t1)
- goto out;
+ return 0;
if (t0 > t1) {
/*
@@ -1230,23 +1216,22 @@ static snd_pcm_sframes_t dac33_dai_delay(
}
break;
case DAC33_FIFO_MODE7:
- spin_lock_irqsave(&dac33->lock, flags);
- t0 = dac33->t_stamp1;
- uthr = dac33->uthr;
- spin_unlock_irqrestore(&dac33->lock, flags);
+ scoped_guard(spinlock_irqsave, &dac33->lock) {
+ t0 = dac33->t_stamp1;
+ uthr = dac33->uthr;
+ }
t_now = ktime_to_us(ktime_get());
/* We have not started to fill the FIFO yet, delay is 0 */
if (!t0)
- goto out;
+ return 0;
if (t_now <= t0) {
/*
* Either the timestamps are messed or equal. Report
* maximum delay
*/
- delay = uthr;
- goto out;
+ return uthr;
}
time_delta = t_now - t0;
@@ -1287,7 +1272,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
dac33->fifo_mode);
break;
}
-out:
+
return delay;
}
diff --git a/sound/soc/codecs/tscs42xx.c b/sound/soc/codecs/tscs42xx.c
index dba581857920..02082ef790b4 100644
--- a/sound/soc/codecs/tscs42xx.c
+++ b/sound/soc/codecs/tscs42xx.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
@@ -210,25 +211,21 @@ static int power_up_audio_plls(struct snd_soc_component *component)
return ret;
}
- mutex_lock(&tscs42xx->pll_lock);
+ guard(mutex)(&tscs42xx->pll_lock);
ret = snd_soc_component_update_bits(component, R_PLLCTL1C, mask, val);
if (ret < 0) {
dev_err(component->dev, "Failed to turn PLL on (%d)\n", ret);
- goto exit;
+ return ret;
}
if (!plls_locked(component)) {
dev_err(component->dev, "Failed to lock plls\n");
ret = -ENOMSG;
- goto exit;
+ return ret;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->pll_lock);
-
- return ret;
+ return 0;
}
static int power_down_audio_plls(struct snd_soc_component *component)
@@ -236,28 +233,24 @@ static int power_down_audio_plls(struct snd_soc_component *component)
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
int ret;
- mutex_lock(&tscs42xx->pll_lock);
+ guard(mutex)(&tscs42xx->pll_lock);
ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
RM_PLLCTL1C_PDB_PLL1,
RV_PLLCTL1C_PDB_PLL1_DISABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
- goto exit;
+ return ret;
}
ret = snd_soc_component_update_bits(component, R_PLLCTL1C,
RM_PLLCTL1C_PDB_PLL2,
RV_PLLCTL1C_PDB_PLL2_DISABLE);
if (ret < 0) {
dev_err(component->dev, "Failed to turn PLL off (%d)\n", ret);
- goto exit;
+ return ret;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->pll_lock);
-
- return ret;
+ return 0;
}
static int coeff_ram_get(struct snd_kcontrol *kcontrol,
@@ -269,13 +262,11 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
(struct coeff_ram_ctl *)kcontrol->private_value;
struct soc_bytes_ext *params = &ctl->bytes_ext;
- mutex_lock(&tscs42xx->coeff_ram_lock);
+ guard(mutex)(&tscs42xx->coeff_ram_lock);
memcpy(ucontrol->value.bytes.data,
&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE], params->max);
- mutex_unlock(&tscs42xx->coeff_ram_lock);
-
return 0;
}
@@ -290,14 +281,14 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
unsigned int coeff_cnt = params->max / COEFF_SIZE;
int ret;
- mutex_lock(&tscs42xx->coeff_ram_lock);
+ guard(mutex)(&tscs42xx->coeff_ram_lock);
tscs42xx->coeff_ram_synced = false;
memcpy(&tscs42xx->coeff_ram[ctl->addr * COEFF_SIZE],
ucontrol->value.bytes.data, params->max);
- mutex_lock(&tscs42xx->pll_lock);
+ guard(mutex)(&tscs42xx->pll_lock);
if (plls_locked(component)) {
ret = write_coeff_ram(component, tscs42xx->coeff_ram,
@@ -305,18 +296,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
if (ret < 0) {
dev_err(component->dev,
"Failed to flush coeff ram cache (%d)\n", ret);
- goto exit;
+ return ret;
}
tscs42xx->coeff_ram_synced = true;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->pll_lock);
-
- mutex_unlock(&tscs42xx->coeff_ram_lock);
-
- return ret;
+ return 0;
}
/* Input L Capture Route */
@@ -385,21 +370,17 @@ static int dac_event(struct snd_soc_dapm_widget *w,
struct tscs42xx *tscs42xx = snd_soc_component_get_drvdata(component);
int ret;
- mutex_lock(&tscs42xx->coeff_ram_lock);
+ guard(mutex)(&tscs42xx->coeff_ram_lock);
if (!tscs42xx->coeff_ram_synced) {
ret = write_coeff_ram(component, tscs42xx->coeff_ram, 0x00,
COEFF_RAM_COEFF_COUNT);
if (ret < 0)
- goto exit;
+ return ret;
tscs42xx->coeff_ram_synced = true;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs42xx->coeff_ram_lock);
-
- return ret;
+ return 0;
}
static const struct snd_soc_dapm_widget tscs42xx_dapm_widgets[] = {
@@ -926,12 +907,10 @@ static int setup_sample_rate(struct snd_soc_component *component,
return ret;
}
- mutex_lock(&tscs42xx->audio_params_lock);
+ guard(mutex)(&tscs42xx->audio_params_lock);
tscs42xx->samplerate = rate;
- mutex_unlock(&tscs42xx->audio_params_lock);
-
return 0;
}
@@ -1253,12 +1232,10 @@ static int tscs42xx_set_dai_bclk_ratio(struct snd_soc_dai *codec_dai,
return ret;
}
- mutex_lock(&tscs42xx->audio_params_lock);
+ guard(mutex)(&tscs42xx->audio_params_lock);
tscs42xx->bclk_ratio = ratio;
- mutex_unlock(&tscs42xx->audio_params_lock);
-
return 0;
}
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index aad394937ce6..b70c9d931e1e 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -4,6 +4,7 @@
// Author: Steven Eckhoff <steven.eckhoff.opensource@gmail.com>
#include <linux/kernel.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/regmap.h>
@@ -329,12 +330,10 @@ static int coeff_ram_get(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- mutex_lock(coeff_ram_lock);
-
- memcpy(ucontrol->value.bytes.data,
- &coeff_ram[ctl->addr * COEFF_SIZE], params->max);
-
- mutex_unlock(coeff_ram_lock);
+ scoped_guard(mutex, coeff_ram_lock) {
+ memcpy(ucontrol->value.bytes.data,
+ &coeff_ram[ctl->addr * COEFF_SIZE], params->max);
+ }
return 0;
}
@@ -428,15 +427,15 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
- mutex_lock(coeff_ram_lock);
+ guard(mutex)(coeff_ram_lock);
*coeff_ram_synced = false;
memcpy(&coeff_ram[ctl->addr * COEFF_SIZE],
ucontrol->value.bytes.data, params->max);
- mutex_lock(&tscs454->pll1.lock);
- mutex_lock(&tscs454->pll2.lock);
+ guard(mutex)(&tscs454->pll1.lock);
+ guard(mutex)(&tscs454->pll2.lock);
val = snd_soc_component_read(component, R_PLLSTAT);
if (val) { /* PLLs locked */
@@ -446,18 +445,12 @@ static int coeff_ram_put(struct snd_kcontrol *kcontrol,
if (ret < 0) {
dev_err(component->dev,
"Failed to flush coeff ram cache (%d)\n", ret);
- goto exit;
+ return ret;
}
*coeff_ram_synced = true;
}
- ret = 0;
-exit:
- mutex_unlock(&tscs454->pll2.lock);
- mutex_unlock(&tscs454->pll1.lock);
- mutex_unlock(coeff_ram_lock);
-
- return ret;
+ return 0;
}
static inline int coeff_ram_sync(struct snd_soc_component *component,
@@ -465,41 +458,35 @@ static inline int coeff_ram_sync(struct snd_soc_component *component,
{
int ret;
- mutex_lock(&tscs454->dac_ram.lock);
- if (!tscs454->dac_ram.synced) {
- ret = write_coeff_ram(component, tscs454->dac_ram.cache,
- R_DACCRS, R_DACCRADD, R_DACCRWDL,
- 0x00, COEFF_RAM_COEFF_COUNT);
- if (ret < 0) {
- mutex_unlock(&tscs454->dac_ram.lock);
- return ret;
+ scoped_guard(mutex, &tscs454->dac_ram.lock) {
+ if (!tscs454->dac_ram.synced) {
+ ret = write_coeff_ram(component, tscs454->dac_ram.cache,
+ R_DACCRS, R_DACCRADD, R_DACCRWDL,
+ 0x00, COEFF_RAM_COEFF_COUNT);
+ if (ret < 0)
+ return ret;
}
}
- mutex_unlock(&tscs454->dac_ram.lock);
- mutex_lock(&tscs454->spk_ram.lock);
- if (!tscs454->spk_ram.synced) {
- ret = write_coeff_ram(component, tscs454->spk_ram.cache,
- R_SPKCRS, R_SPKCRADD, R_SPKCRWDL,
- 0x00, COEFF_RAM_COEFF_COUNT);
- if (ret < 0) {
- mutex_unlock(&tscs454->spk_ram.lock);
- return ret;
+ scoped_guard(mutex, &tscs454->spk_ram.lock) {
+ if (!tscs454->spk_ram.synced) {
+ ret = write_coeff_ram(component, tscs454->spk_ram.cache,
+ R_SPKCRS, R_SPKCRADD, R_SPKCRWDL,
+ 0x00, COEFF_RAM_COEFF_COUNT);
+ if (ret < 0)
+ return ret;
}
}
- mutex_unlock(&tscs454->spk_ram.lock);
- mutex_lock(&tscs454->sub_ram.lock);
- if (!tscs454->sub_ram.synced) {
- ret = write_coeff_ram(component, tscs454->sub_ram.cache,
- R_SUBCRS, R_SUBCRADD, R_SUBCRWDL,
- 0x00, COEFF_RAM_COEFF_COUNT);
- if (ret < 0) {
- mutex_unlock(&tscs454->sub_ram.lock);
- return ret;
+ scoped_guard(mutex, &tscs454->sub_ram.lock) {
+ if (!tscs454->sub_ram.synced) {
+ ret = write_coeff_ram(component, tscs454->sub_ram.cache,
+ R_SUBCRS, R_SUBCRADD, R_SUBCRWDL,
+ 0x00, COEFF_RAM_COEFF_COUNT);
+ if (ret < 0)
+ return ret;
}
}
- mutex_unlock(&tscs454->sub_ram.lock);
return 0;
}
@@ -658,16 +645,14 @@ static int set_sysclk(struct snd_soc_component *component)
static inline void reserve_pll(struct pll *pll)
{
- mutex_lock(&pll->lock);
+ guard(mutex)(&pll->lock);
pll->users++;
- mutex_unlock(&pll->lock);
}
static inline void free_pll(struct pll *pll)
{
- mutex_lock(&pll->lock);
+ guard(mutex)(&pll->lock);
pll->users--;
- mutex_unlock(&pll->lock);
}
static int pll_connected(struct snd_soc_dapm_widget *source,
@@ -679,15 +664,13 @@ static int pll_connected(struct snd_soc_dapm_widget *source,
int users;
if (strstr(source->name, "PLL 1")) {
- mutex_lock(&tscs454->pll1.lock);
- users = tscs454->pll1.users;
- mutex_unlock(&tscs454->pll1.lock);
+ scoped_guard(mutex, &tscs454->pll1.lock)
+ users = tscs454->pll1.users;
dev_dbg(component->dev, "%s(): PLL 1 users = %d\n", __func__,
users);
} else {
- mutex_lock(&tscs454->pll2.lock);
- users = tscs454->pll2.users;
- mutex_unlock(&tscs454->pll2.lock);
+ scoped_guard(mutex, &tscs454->pll2.lock)
+ users = tscs454->pll2.users;
dev_dbg(component->dev, "%s(): PLL 2 users = %d\n", __func__,
users);
}
@@ -806,7 +789,7 @@ static inline int aif_free(struct snd_soc_component *component,
{
struct tscs454 *tscs454 = snd_soc_component_get_drvdata(component);
- mutex_lock(&tscs454->aifs_status_lock);
+ guard(mutex)(&tscs454->aifs_status_lock);
dev_dbg(component->dev, "%s(): aif %d\n", __func__, aif->id);
@@ -829,8 +812,6 @@ static inline int aif_free(struct snd_soc_component *component,
free_pll(tscs454->internal_rate.pll);
}
- mutex_unlock(&tscs454->aifs_status_lock);
-
return 0;
}
@@ -3174,7 +3155,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream,
unsigned int val;
int ret;
- mutex_lock(&tscs454->aifs_status_lock);
+ guard(mutex)(&tscs454->aifs_status_lock);
dev_dbg(component->dev, "%s(): aif %d fs = %u\n", __func__,
aif->id, fs);
@@ -3207,14 +3188,14 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream,
ret = set_aif_fs(component, aif->id, fs);
if (ret < 0) {
dev_err(component->dev, "Failed to set aif fs (%d)\n", ret);
- goto exit;
+ return ret;
}
ret = set_aif_sample_format(component, params_format(params), aif->id);
if (ret < 0) {
dev_err(component->dev,
"Failed to set aif sample format (%d)\n", ret);
- goto exit;
+ return ret;
}
set_aif_status_active(&tscs454->aifs_status, aif->id,
@@ -3223,11 +3204,7 @@ static int tscs454_hw_params(struct snd_pcm_substream *substream,
dev_dbg(component->dev, "Set aif %d active. Streams status is 0x%x\n",
aif->id, tscs454->aifs_status.streams);
- ret = 0;
-exit:
- mutex_unlock(&tscs454->aifs_status_lock);
-
- return ret;
+ return 0;
}
static int tscs454_hw_free(struct snd_pcm_substream *substream,
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index e10c51092a35..650836f9615f 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
@@ -273,7 +274,7 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component,
struct twl6040_data *priv = snd_soc_component_get_drvdata(component);
int status;
- mutex_lock(&priv->mutex);
+ guard(mutex)(&priv->mutex);
/* Sync status */
status = twl6040_read(component, TWL6040_REG_STATUS);
@@ -281,8 +282,6 @@ static void twl6040_hs_jack_report(struct snd_soc_component *component,
snd_soc_jack_report(jack, report, report);
else
snd_soc_jack_report(jack, 0, report);
-
- mutex_unlock(&priv->mutex);
}
void twl6040_hs_jack_detect(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
index 12f5757f4210..4e2d6240a869 100644
--- a/sound/soc/codecs/uda1342.c
+++ b/sound/soc/codecs/uda1342.c
@@ -308,9 +308,16 @@ static int uda1342_suspend(struct device *dev)
static int uda1342_resume(struct device *dev)
{
struct uda1342_priv *uda1342 = dev_get_drvdata(dev);
+ int ret;
+ regcache_cache_only(uda1342->regmap, false);
regcache_mark_dirty(uda1342->regmap);
- regcache_sync(uda1342->regmap);
+ ret = regcache_sync(uda1342->regmap);
+ if (ret) {
+ regcache_cache_only(uda1342->regmap, true);
+ regcache_mark_dirty(uda1342->regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index e3ca5ca6de3d..40de279a9750 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -5010,9 +5010,9 @@ static int wcd9335_power_on_reset(struct wcd9335_codec *wcd)
*/
usleep_range(600, 650);
- gpiod_set_value(wcd->reset_gpio, 1);
+ gpiod_set_value_cansleep(wcd->reset_gpio, 1);
msleep(20);
- gpiod_set_value(wcd->reset_gpio, 0);
+ gpiod_set_value_cansleep(wcd->reset_gpio, 0);
msleep(20);
return 0;
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index bc41a1466c70..caca5cc25100 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -1265,13 +1265,10 @@ static int wcd934x_set_sido_input_src(struct wcd934x_codec *wcd, int sido_src)
static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd)
{
- mutex_lock(&wcd->sysclk_mutex);
-
- if (++wcd->sysclk_users != 1) {
- mutex_unlock(&wcd->sysclk_mutex);
- return 0;
+ scoped_guard(mutex, &wcd->sysclk_mutex) {
+ if (++wcd->sysclk_users != 1)
+ return 0;
}
- mutex_unlock(&wcd->sysclk_mutex);
regmap_update_bits(wcd->regmap, WCD934X_ANA_BIAS,
WCD934X_ANA_BIAS_EN_MASK,
@@ -1328,12 +1325,10 @@ static int wcd934x_enable_ana_bias_and_sysclk(struct wcd934x_codec *wcd)
static int wcd934x_disable_ana_bias_and_syclk(struct wcd934x_codec *wcd)
{
- mutex_lock(&wcd->sysclk_mutex);
- if (--wcd->sysclk_users != 0) {
- mutex_unlock(&wcd->sysclk_mutex);
- return 0;
+ scoped_guard(mutex, &wcd->sysclk_mutex) {
+ if (--wcd->sysclk_users != 0)
+ return 0;
}
- mutex_unlock(&wcd->sysclk_mutex);
regmap_update_bits(wcd->regmap, WCD934X_CLK_SYS_MCLK_PRG,
WCD934X_EXT_CLK_BUF_EN_MASK |
@@ -2384,7 +2379,7 @@ static int wcd934x_micbias_control(struct snd_soc_component *component,
__func__, micb_num);
return -EINVAL;
}
- mutex_lock(&wcd934x->micb_lock);
+ guard(mutex)(&wcd934x->micb_lock);
switch (req) {
case MICB_PULLUP_ENABLE:
@@ -2446,8 +2441,6 @@ static int wcd934x_micbias_control(struct snd_soc_component *component,
break;
}
- mutex_unlock(&wcd934x->micb_lock);
-
return 0;
}
@@ -2488,7 +2481,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd934x_codec *wcd934x = snd_soc_component_get_drvdata(component);
- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en;
switch (micb_num) {
case MIC_BIAS_1:
@@ -2506,7 +2499,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd934x->micb_lock);
+ guard(mutex)(&wcd934x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
* voltage, then just return. Otherwise, adjust voltage as
@@ -2521,15 +2514,11 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD934X_MICB_VAL_MASK);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = -EINVAL;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return -EINVAL;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
if (micb_en == WCD934X_MICB_ENABLE)
snd_soc_component_write_field(component, micb_reg,
@@ -2550,9 +2539,8 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
*/
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd934x->micb_lock);
- return ret;
+
+ return 0;
}
static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
@@ -5899,10 +5887,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
}
static const struct platform_device_id wcd934x_driver_id[] = {
- {
- .name = "wcd934x-codec",
- },
- {},
+ { .name = "wcd934x-codec" },
+ { }
};
MODULE_DEVICE_TABLE(platform, wcd934x_driver_id);
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
index 7a18bed7f347..1ad75c226060 100644
--- a/sound/soc/codecs/wcd937x-sdw.c
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -1084,10 +1084,16 @@ static int wcd937x_sdw_runtime_suspend(struct device *dev)
static int wcd937x_sdw_runtime_resume(struct device *dev)
{
struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index e0169e783ee9..0dd05604f5b8 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -2,6 +2,7 @@
// Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
#include <linux/component.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
@@ -1056,7 +1057,7 @@ static int wcd937x_micbias_control(struct snd_soc_component *component,
return -EINVAL;
}
- mutex_lock(&wcd937x->micb_lock);
+ guard(mutex)(&wcd937x->micb_lock);
switch (req) {
case MICB_PULLUP_ENABLE:
wcd937x->pullup_ref[micb_index]++;
@@ -1136,7 +1137,6 @@ static int wcd937x_micbias_control(struct snd_soc_component *component,
}
break;
}
- mutex_unlock(&wcd937x->micb_lock);
return 0;
}
@@ -1460,7 +1460,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en;
switch (micb_num) {
case MIC_BIAS_1:
@@ -1475,7 +1475,7 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd937x->micb_lock);
+ guard(mutex)(&wcd937x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
* voltage, then just return. Otherwise, adjust voltage as
@@ -1490,15 +1490,11 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD937X_MICB_VOUT_MASK);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = -EINVAL;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return -EINVAL;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
if (micb_en == WCD937X_MICB_ENABLE)
snd_soc_component_write_field(component, micb_reg,
@@ -1519,9 +1515,8 @@ static int wcd937x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
*/
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd937x->micb_lock);
- return ret;
+
+ return 0;
}
static int wcd937x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index 0f0cc0ac3056..e5ad368418a2 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -1245,10 +1245,16 @@ static int wcd938x_sdw_runtime_suspend(struct device *dev)
static int wcd938x_sdw_runtime_resume(struct device *dev)
{
struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
pm_runtime_mark_last_busy(dev);
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index c69e18667a85..9a9ea37ecab3 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
@@ -1976,7 +1977,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
int req_volt, int micb_num)
{
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
- int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en, ret = 0;
+ int cur_vout_ctl, req_vout_ctl, micb_reg, micb_en;
switch (micb_num) {
case MIC_BIAS_1:
@@ -1994,7 +1995,7 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd938x->micb_lock);
+ guard(mutex)(&wcd938x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
* voltage, then just return. Otherwise, adjust voltage as
@@ -2009,15 +2010,11 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD938X_MICB_VOUT_MASK);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = -EINVAL;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return -EINVAL;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
if (micb_en == WCD938X_MICB_ENABLE)
snd_soc_component_write_field(component, micb_reg,
@@ -2038,9 +2035,8 @@ static int wcd938x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
*/
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd938x->micb_lock);
- return ret;
+
+ return 0;
}
static int wcd938x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
index 95f4be287e79..69b9b08118f0 100644
--- a/sound/soc/codecs/wcd939x-sdw.c
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -1431,10 +1431,16 @@ static int wcd939x_sdw_runtime_suspend(struct device *dev)
static int wcd939x_sdw_runtime_resume(struct device *dev)
{
struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
+ int ret;
if (wcd->regmap) {
regcache_cache_only(wcd->regmap, false);
- regcache_sync(wcd->regmap);
+ ret = regcache_sync(wcd->regmap);
+ if (ret) {
+ regcache_cache_only(wcd->regmap, true);
+ regcache_mark_dirty(wcd->regmap);
+ return ret;
+ }
}
return 0;
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index 010d12466722..26fe0b6313cd 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
@@ -1923,7 +1924,6 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component);
unsigned int micb_reg, cur_vout_ctl, micb_en;
int req_vout_ctl;
- int ret = 0;
switch (micb_num) {
case MIC_BIAS_1:
@@ -1941,7 +1941,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
default:
return -EINVAL;
}
- mutex_lock(&wcd939x->micb_lock);
+ guard(mutex)(&wcd939x->micb_lock);
/*
* If requested micbias voltage is same as current micbias
@@ -1957,15 +1957,11 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
WCD939X_MICB_VOUT_CTL);
req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
- if (req_vout_ctl < 0) {
- ret = req_vout_ctl;
- goto exit;
- }
+ if (req_vout_ctl < 0)
+ return req_vout_ctl;
- if (cur_vout_ctl == req_vout_ctl) {
- ret = 0;
- goto exit;
- }
+ if (cur_vout_ctl == req_vout_ctl)
+ return 0;
dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n",
__func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl),
@@ -1990,9 +1986,7 @@ static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
usleep_range(2000, 2100);
}
-exit:
- mutex_unlock(&wcd939x->micb_lock);
- return ret;
+ return 0;
}
static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component,
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index 2a8c61a72c17..c44abffe9b56 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -9,6 +9,7 @@
* Scott Ling <sl@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
@@ -148,13 +149,11 @@ static const char *wm0010_state_to_str(enum wm0010_state state)
static void wm0010_halt(struct snd_soc_component *component)
{
struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
- unsigned long flags;
enum wm0010_state state;
/* Fetch the wm0010 state */
- spin_lock_irqsave(&wm0010->irq_lock, flags);
- state = wm0010->state;
- spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock)
+ state = wm0010->state;
switch (state) {
case WM0010_POWER_OFF:
@@ -173,9 +172,8 @@ static void wm0010_halt(struct snd_soc_component *component)
break;
}
- spin_lock_irqsave(&wm0010->irq_lock, flags);
- wm0010->state = WM0010_POWER_OFF;
- spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock)
+ wm0010->state = WM0010_POWER_OFF;
}
struct wm0010_boot_xfer {
@@ -190,11 +188,9 @@ struct wm0010_boot_xfer {
static void wm0010_mark_boot_failure(struct wm0010_priv *wm0010)
{
enum wm0010_state state;
- unsigned long flags;
- spin_lock_irqsave(&wm0010->irq_lock, flags);
- state = wm0010->state;
- spin_unlock_irqrestore(&wm0010->irq_lock, flags);
+ scoped_guard(spinlock_irqsave, &wm0010->irq_lock)
+ state = wm0010->state;
dev_err(wm0010->dev, "Failed to transition from `%s' state to `%s' state\n",
wm0010_state_to_str(state), wm0010_state_to_str(state + 1));
@@ -337,7 +333,6 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
struct wm0010_boot_xfer *xfer;
int ret;
DECLARE_COMPLETION_ONSTACK(done);
- const struct firmware *fw;
const struct dfw_binrec *rec;
const struct dfw_inforec *inforec;
u64 *img;
@@ -346,6 +341,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
INIT_LIST_HEAD(&xfer_list);
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, name, component->dev);
if (ret != 0) {
dev_err(component->dev, "Failed to request application(%s): %d\n",
@@ -364,16 +360,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
/* First record should be INFO */
if (rec->command != DFW_CMD_INFO) {
dev_err(component->dev, "First record not INFO\r\n");
- ret = -EINVAL;
- goto abort;
+ return -EINVAL;
}
if (inforec->info_version != INFO_VERSION) {
dev_err(component->dev,
"Unsupported version (%02d) of INFO record\r\n",
inforec->info_version);
- ret = -EINVAL;
- goto abort;
+ return -EINVAL;
}
dev_dbg(component->dev, "Version v%02d INFO record found\r\n",
@@ -382,8 +376,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
/* Check it's a DSP file */
if (dsp != DEVICE_ID_WM0010) {
dev_err(component->dev, "Not a WM0010 firmware file.\r\n");
- ret = -EINVAL;
- goto abort;
+ return -EINVAL;
}
/* Skip the info record as we don't need to send it */
@@ -408,14 +401,14 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
out = kzalloc(len, GFP_KERNEL | GFP_DMA);
if (!out) {
ret = -ENOMEM;
- goto abort1;
+ goto abort;
}
xfer->t.rx_buf = out;
img = kzalloc(len, GFP_KERNEL | GFP_DMA);
if (!img) {
ret = -ENOMEM;
- goto abort1;
+ goto abort;
}
xfer->t.tx_buf = img;
@@ -453,13 +446,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
ret = spi_async(spi, &xfer->m);
if (ret != 0) {
dev_err(component->dev, "Write failed: %d\n", ret);
- goto abort1;
+ goto abort;
}
if (wm0010->boot_failed) {
dev_dbg(component->dev, "Boot fail!\n");
ret = -EINVAL;
- goto abort1;
+ goto abort;
}
}
@@ -467,7 +460,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_component *comp
ret = 0;
-abort1:
+abort:
while (!list_empty(&xfer_list)) {
xfer = list_first_entry(&xfer_list, struct wm0010_boot_xfer,
list);
@@ -477,8 +470,6 @@ abort1:
kfree(xfer);
}
-abort:
- release_firmware(fw);
return ret;
}
@@ -486,14 +477,12 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
{
struct spi_device *spi = to_spi_device(component->dev);
struct wm0010_priv *wm0010 = snd_soc_component_get_drvdata(component);
- const struct firmware *fw;
struct spi_message m;
struct spi_transfer t;
- u32 *img;
- u8 *out;
int i;
int ret = 0;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, "wm0010_stage2.bin", component->dev);
if (ret != 0) {
dev_err(component->dev, "Failed to request stage2 loader: %d\n",
@@ -504,17 +493,15 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
dev_dbg(component->dev, "Downloading %zu byte stage 2 loader\n", fw->size);
/* Copy to local buffer first as vmalloc causes problems for dma */
- img = kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA);
- if (!img) {
- ret = -ENOMEM;
- goto abort2;
- }
+ u32 *img __free(kfree) =
+ kmemdup(&fw->data[0], fw->size, GFP_KERNEL | GFP_DMA);
+ if (!img)
+ return -ENOMEM;
- out = kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
- if (!out) {
- ret = -ENOMEM;
- goto abort1;
- }
+ u8 *out __free(kfree) =
+ kzalloc(fw->size, GFP_KERNEL | GFP_DMA);
+ if (!out)
+ return -ENOMEM;
spi_message_init(&m);
memset(&t, 0, sizeof(t));
@@ -531,7 +518,7 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
ret = spi_sync(spi, &m);
if (ret != 0) {
dev_err(component->dev, "Initial download failed: %d\n", ret);
- goto abort;
+ return ret;
}
/* Look for errors from the boot ROM */
@@ -540,18 +527,11 @@ static int wm0010_stage2_load(struct snd_soc_component *component)
dev_err(component->dev, "Boot ROM error: %x in %d\n",
out[i], i);
wm0010_mark_boot_failure(wm0010);
- ret = -EBUSY;
- goto abort;
+ return -EBUSY;
}
}
-abort:
- kfree(out);
-abort1:
- kfree(img);
-abort2:
- release_firmware(fw);
- return ret;
+ return 0;
}
static int wm0010_boot(struct snd_soc_component *component)
@@ -734,9 +714,8 @@ static int wm0010_set_bias_level(struct snd_soc_component *component,
break;
case SND_SOC_BIAS_STANDBY:
if (snd_soc_dapm_get_bias_level(dapm) == SND_SOC_BIAS_PREPARE) {
- mutex_lock(&wm0010->lock);
- wm0010_halt(component);
- mutex_unlock(&wm0010->lock);
+ scoped_guard(mutex, &wm0010->lock)
+ wm0010_halt(component);
}
break;
case SND_SOC_BIAS_OFF:
@@ -832,9 +811,8 @@ static irqreturn_t wm0010_irq(int irq, void *data)
case WM0010_OUT_OF_RESET:
case WM0010_BOOTROM:
case WM0010_STAGE2:
- spin_lock(&wm0010->irq_lock);
- complete(&wm0010->boot_completion);
- spin_unlock(&wm0010->irq_lock);
+ scoped_guard(spinlock, &wm0010->irq_lock)
+ complete(&wm0010->boot_completion);
return IRQ_HANDLED;
default:
return IRQ_NONE;
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 9b68ee69324b..41c8cfb346c6 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/firmware.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
@@ -612,20 +613,15 @@ static int wm2000_anc_mode_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
unsigned int anc_active = ucontrol->value.integer.value[0];
- int ret;
if (anc_active > 1)
return -EINVAL;
- mutex_lock(&wm2000->lock);
+ guard(mutex)(&wm2000->lock);
wm2000->anc_active = anc_active;
- ret = wm2000_anc_set_mode(wm2000);
-
- mutex_unlock(&wm2000->lock);
-
- return ret;
+ return wm2000_anc_set_mode(wm2000);
}
static int wm2000_speaker_get(struct snd_kcontrol *kcontrol,
@@ -645,20 +641,15 @@ static int wm2000_speaker_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
unsigned int val = ucontrol->value.integer.value[0];
- int ret;
if (val > 1)
return -EINVAL;
- mutex_lock(&wm2000->lock);
+ guard(mutex)(&wm2000->lock);
wm2000->spk_ena = val;
- ret = wm2000_anc_set_mode(wm2000);
-
- mutex_unlock(&wm2000->lock);
-
- return ret;
+ return wm2000_anc_set_mode(wm2000);
}
static const struct snd_kcontrol_new wm2000_controls[] = {
@@ -676,9 +667,8 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
struct wm2000_priv *wm2000 = dev_get_drvdata(component->dev);
- int ret;
- mutex_lock(&wm2000->lock);
+ guard(mutex)(&wm2000->lock);
if (SND_SOC_DAPM_EVENT_ON(event))
wm2000->anc_eng_ena = 1;
@@ -686,11 +676,7 @@ static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_OFF(event))
wm2000->anc_eng_ena = 0;
- ret = wm2000_anc_set_mode(wm2000);
-
- mutex_unlock(&wm2000->lock);
-
- return ret;
+ return wm2000_anc_set_mode(wm2000);
}
static const struct snd_soc_dapm_widget wm2000_dapm_widgets[] = {
@@ -810,7 +796,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c)
struct wm2000_priv *wm2000;
struct wm2000_platform_data *pdata;
const char *filename;
- const struct firmware *fw = NULL;
+ const struct firmware *fw __free(firmware) = NULL;
int ret, i;
unsigned int reg;
u16 id;
@@ -828,7 +814,7 @@ static int wm2000_i2c_probe(struct i2c_client *i2c)
ret = PTR_ERR(wm2000->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
- goto out;
+ return ret;
}
for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
@@ -922,9 +908,6 @@ static int wm2000_i2c_probe(struct i2c_client *i2c)
err_supplies:
regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
-
-out:
- release_firmware(fw);
return ret;
}
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index ba8ce2e6e615..bc78b553b6cb 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -2461,7 +2461,15 @@ static int wm2200_runtime_resume(struct device *dev)
}
regcache_cache_only(wm2200->regmap, false);
- regcache_sync(wm2200->regmap);
+ ret = regcache_sync(wm2200->regmap);
+ if (ret) {
+ regcache_cache_only(wm2200->regmap, true);
+ regcache_mark_dirty(wm2200->regmap);
+ gpiod_set_value_cansleep(wm2200->ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm2200->core_supplies),
+ wm2200->core_supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index bd94fa53c362..2fe937a93026 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -2659,7 +2659,15 @@ static int wm5100_runtime_resume(struct device *dev)
}
regcache_cache_only(wm5100->regmap, false);
- regcache_sync(wm5100->regmap);
+ ret = regcache_sync(wm5100->regmap);
+ if (ret) {
+ regcache_cache_only(wm5100->regmap, true);
+ regcache_mark_dirty(wm5100->regmap);
+ gpiod_set_value_cansleep(wm5100->ldo_ena, 0);
+ regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
+ wm5100->core_supplies);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index b4d4137c05b4..74b775b95bfd 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -667,10 +668,9 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
put_unaligned_be16(arizona->dac_comp_coeff,
ucontrol->value.bytes.data);
- mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -681,16 +681,14 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
- int ret = 0;
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
if (arizona->dac_comp_coeff != dac_comp_coeff) {
arizona->dac_comp_coeff = dac_comp_coeff;
- ret = 1;
+ return 1;
}
- mutex_unlock(&arizona->dac_comp_lock);
- return ret;
+ return 0;
}
static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
@@ -699,9 +697,8 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
- mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -712,19 +709,17 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct arizona *arizona = dev_get_drvdata(component->dev->parent);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- int ret = 0;
if (ucontrol->value.integer.value[0] > mc->max)
return -EINVAL;
- mutex_lock(&arizona->dac_comp_lock);
+ guard(mutex)(&arizona->dac_comp_lock);
if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) {
arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
- ret = 1;
+ return 1;
}
- mutex_unlock(&arizona->dac_comp_lock);
- return ret;
+ return 0;
}
static const char * const wm5102_osr_text[] = {
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index a2f0e2f5c407..ce87280d590d 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -10,6 +10,7 @@
* Based on wm8753.c by Liam Girdwood
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -110,22 +111,20 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
- int ret = 0;
if (deemph > 1)
return -EINVAL;
- mutex_lock(&wm8731->lock);
+ guard(mutex)(&wm8731->lock);
if (wm8731->deemph != deemph) {
wm8731->deemph = deemph;
wm8731_set_deemph(component);
- ret = 1;
+ return 1;
}
- mutex_unlock(&wm8731->lock);
- return ret;
+ return 0;
}
static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 320d7737699d..156e1e24a388 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/gpio/driver.h>
@@ -458,22 +459,20 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8903_priv *wm8903 = snd_soc_component_get_drvdata(component);
unsigned int deemph = ucontrol->value.integer.value[0];
- int ret = 0;
if (deemph > 1)
return -EINVAL;
- mutex_lock(&wm8903->lock);
+ guard(mutex)(&wm8903->lock);
if (wm8903->deemph != deemph) {
wm8903->deemph = deemph;
wm8903_set_deemph(component);
- ret = 1;
+ return 1;
}
- mutex_unlock(&wm8903->lock);
- return ret;
+ return 0;
}
/* ALSA can only do steps of .01dB */
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index e631ec072249..229252363188 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -333,7 +333,7 @@ static const struct snd_soc_dapm_route wm8940_dapm_routes[] = {
{"ADC", NULL, "Boost Mixer"},
};
-#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0);
+#define wm8940_reset(c) snd_soc_component_write(c, WM8940_SOFTRESET, 0)
static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 8ff0882732e7..f75a6dc9d2bb 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -864,9 +865,8 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (fw && (wm8958_dsp2_fw(component, "ENH_EQ", fw, true) == 0)) {
- mutex_lock(&wm8994->fw_lock);
+ guard(mutex)(&wm8994->fw_lock);
wm8994->enh_eq = fw;
- mutex_unlock(&wm8994->fw_lock);
}
}
@@ -876,9 +876,8 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (fw && (wm8958_dsp2_fw(component, "MBC+VSS", fw, true) == 0)) {
- mutex_lock(&wm8994->fw_lock);
+ guard(mutex)(&wm8994->fw_lock);
wm8994->mbc_vss = fw;
- mutex_unlock(&wm8994->fw_lock);
}
}
@@ -888,9 +887,8 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
if (fw && (wm8958_dsp2_fw(component, "MBC", fw, true) == 0)) {
- mutex_lock(&wm8994->fw_lock);
+ guard(mutex)(&wm8994->fw_lock);
wm8994->mbc = fw;
- mutex_unlock(&wm8994->fw_lock);
}
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index de18b1f85a32..8a9598161b35 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm.h>
@@ -1564,11 +1565,10 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct wm8962_priv *wm8962 = snd_soc_component_get_drvdata(component);
int old = wm8962->dsp2_ena;
- int ret = 0;
int dsp2_running = snd_soc_component_read(component, WM8962_DSP2_POWER_MANAGEMENT) &
WM8962_DSP2_ENA;
- mutex_lock(&wm8962->dsp2_ena_lock);
+ guard(mutex)(&wm8962->dsp2_ena_lock);
if (ucontrol->value.integer.value[0])
wm8962->dsp2_ena |= 1 << shift;
@@ -1576,9 +1576,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
wm8962->dsp2_ena &= ~(1 << shift);
if (wm8962->dsp2_ena == old)
- goto out;
-
- ret = 1;
+ return 0;
if (dsp2_running) {
if (wm8962->dsp2_ena)
@@ -1587,10 +1585,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
wm8962_dsp2_stop(component);
}
-out:
- mutex_unlock(&wm8962->dsp2_ena_lock);
-
- return ret;
+ return 1;
}
/* The VU bits for the headphones are in a different register to the mute
@@ -3937,7 +3932,9 @@ static int wm8962_runtime_resume(struct device *dev)
WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
0);
- regcache_sync(wm8962->regmap);
+ ret = regcache_sync(wm8962->regmap);
+ if (ret)
+ goto cache_sync_err;
regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
@@ -3955,6 +3952,11 @@ static int wm8962_runtime_resume(struct device *dev)
return 0;
+cache_sync_err:
+ regcache_cache_only(wm8962->regmap, true);
+ regcache_mark_dirty(wm8962->regmap);
+ regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies),
+ wm8962->supplies);
disable_clock:
clk_disable_unprepare(wm8962->pdata.mclk);
return ret;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 1d64c7c42ed1..8bf58a6a8af7 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -7,6 +7,7 @@
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*/
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -766,7 +767,7 @@ static void active_reference(struct snd_soc_component *component)
{
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
wm8994->active_refcount++;
@@ -775,8 +776,6 @@ static void active_reference(struct snd_soc_component *component)
/* If we're using jack detection go into audio mode */
wm1811_jackdet_set_mode(component, WM1811_JACKDET_MODE_AUDIO);
-
- mutex_unlock(&wm8994->accdet_lock);
}
static void active_dereference(struct snd_soc_component *component)
@@ -784,7 +783,7 @@ static void active_dereference(struct snd_soc_component *component)
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
u16 mode;
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
wm8994->active_refcount--;
@@ -800,8 +799,6 @@ static void active_dereference(struct snd_soc_component *component)
wm1811_jackdet_set_mode(component, mode);
}
-
- mutex_unlock(&wm8994->accdet_lock);
}
static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -3704,7 +3701,7 @@ static void wm8958_open_circuit_work(struct work_struct *work)
open_circuit_work.work);
struct device *dev = wm8994->wm8994->dev;
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
wm1811_micd_stop(wm8994->hubs.component);
@@ -3718,8 +3715,6 @@ static void wm8958_open_circuit_work(struct work_struct *work)
snd_soc_jack_report(wm8994->micdet[0].jack, 0,
wm8994->btn_mask |
SND_JACK_HEADSET);
-
- mutex_unlock(&wm8994->accdet_lock);
}
static void wm8958_mic_id(void *data, u16 status)
@@ -3777,7 +3772,7 @@ static void wm1811_mic_work(struct work_struct *work)
struct snd_soc_component *component = wm8994->hubs.component;
struct snd_soc_dapm_context *dapm = snd_soc_component_to_dapm(component);
- pm_runtime_get_sync(component->dev);
+ guard(pm_runtime_active)(component->dev);
/* If required for an external cap force MICBIAS on */
if (control->pdata.jd_ext_cap) {
@@ -3785,7 +3780,7 @@ static void wm1811_mic_work(struct work_struct *work)
snd_soc_dapm_sync(dapm);
}
- mutex_lock(&wm8994->accdet_lock);
+ guard(mutex)(&wm8994->accdet_lock);
dev_dbg(component->dev, "Starting mic detection\n");
@@ -3803,10 +3798,6 @@ static void wm1811_mic_work(struct work_struct *work)
snd_soc_component_update_bits(component, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, WM8958_MICD_ENA);
}
-
- mutex_unlock(&wm8994->accdet_lock);
-
- pm_runtime_put(component->dev);
}
static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
@@ -4026,15 +4017,10 @@ static void wm8958_mic_work(struct work_struct *work)
mic_complete_work.work);
struct snd_soc_component *component = wm8994->hubs.component;
- pm_runtime_get_sync(component->dev);
-
- mutex_lock(&wm8994->accdet_lock);
+ guard(pm_runtime_active)(component->dev);
+ guard(mutex)(&wm8994->accdet_lock);
wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status);
-
- mutex_unlock(&wm8994->accdet_lock);
-
- pm_runtime_put(component->dev);
}
static irqreturn_t wm8958_mic_irq(int irq, void *data)
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index 83cd42fa0c28..3105b2e0556f 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -6,6 +6,7 @@
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*/
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mfd/wm97xx.h>
@@ -229,7 +230,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
shift = mc->shift & 0xff;
mask = 1 << shift;
- mutex_lock(&wm9712->lock);
+ guard(mutex)(&wm9712->lock);
old = wm9712->hp_mixer[mixer];
if (ucontrol->value.integer.value[0])
wm9712->hp_mixer[mixer] |= mask;
@@ -251,8 +252,6 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
&update);
}
- mutex_unlock(&wm9712->lock);
-
return change;
}
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index b3bbecf074ee..3ba7ca3c1770 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -11,6 +11,7 @@
* o Support for DAPM
*/
+#include <linux/cleanup.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mfd/wm97xx.h>
@@ -238,7 +239,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
shift = mc->shift & 0xff;
mask = (1 << shift);
- mutex_lock(&wm9713->lock);
+ guard(mutex)(&wm9713->lock);
old = wm9713->hp_mixer[mixer];
if (ucontrol->value.integer.value[0])
wm9713->hp_mixer[mixer] |= mask;
@@ -260,8 +261,6 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
&update);
}
- mutex_unlock(&wm9713->lock);
-
return change;
}
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index baa75e7ff53b..90c24c4b318e 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -348,7 +348,6 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct wm_adsp *dsp = snd_soc_component_get_drvdata(component);
- int ret = 1;
if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw)
return 0;
@@ -356,16 +355,14 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW)
return -EINVAL;
- mutex_lock(&dsp[e->shift_l].cs_dsp.pwr_lock);
+ guard(mutex)(&dsp[e->shift_l].cs_dsp.pwr_lock);
if (dsp[e->shift_l].cs_dsp.booted || !list_empty(&dsp[e->shift_l].compr_list))
- ret = -EBUSY;
+ return -EBUSY;
else
dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0];
- mutex_unlock(&dsp[e->shift_l].cs_dsp.pwr_lock);
-
- return ret;
+ return 1;
}
EXPORT_SYMBOL_GPL(wm_adsp_fw_put);
@@ -450,15 +447,13 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl,
if (val == 0)
return 0; /* 0 means no event */
- mutex_lock(&cs_ctl->dsp->pwr_lock);
+ guard(mutex)(&cs_ctl->dsp->pwr_lock);
if (cs_ctl->enabled)
ret = cs_dsp_coeff_write_acked_control(cs_ctl, val);
else
ret = -EPERM;
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
-
if (ret < 0)
return ret;
@@ -486,15 +481,13 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl;
int ret = 0;
- mutex_lock(&cs_ctl->dsp->pwr_lock);
+ guard(mutex)(&cs_ctl->dsp->pwr_lock);
ret = cs_dsp_coeff_read_ctrl(cs_ctl, 0, cs_ctl->cache, size);
if (!ret && copy_to_user(bytes, cs_ctl->cache, size))
ret = -EFAULT;
- mutex_unlock(&cs_ctl->dsp->pwr_lock);
-
return ret;
}
@@ -694,10 +687,9 @@ int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type,
struct cs_dsp_coeff_ctl *cs_ctl;
int ret;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
cs_ctl = cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg);
ret = cs_dsp_coeff_write_ctrl(cs_ctl, 0, buf, len);
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
if (ret < 0)
return ret;
@@ -709,14 +701,10 @@ EXPORT_SYMBOL_GPL(wm_adsp_write_ctl);
int wm_adsp_read_ctl(struct wm_adsp *dsp, const char *name, int type,
unsigned int alg, void *buf, size_t len)
{
- int ret;
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
- mutex_lock(&dsp->cs_dsp.pwr_lock);
- ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
+ return cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(&dsp->cs_dsp, name, type, alg),
0, buf, len);
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
- return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_read_ctl);
@@ -1270,38 +1258,32 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
{
struct wm_adsp_compr *compr, *tmp;
struct snd_soc_pcm_runtime *rtd = stream->private_data;
- int ret = 0;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
if (wm_adsp_fw[dsp->fw].num_caps == 0) {
adsp_err(dsp, "%s: Firmware does not support compressed API\n",
snd_soc_rtd_to_codec(rtd, 0)->name);
- ret = -ENXIO;
- goto out;
+ return -ENXIO;
}
if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) {
adsp_err(dsp, "%s: Firmware does not support stream direction\n",
snd_soc_rtd_to_codec(rtd, 0)->name);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
list_for_each_entry(tmp, &dsp->compr_list, list) {
if (!strcmp(tmp->name, snd_soc_rtd_to_codec(rtd, 0)->name)) {
adsp_err(dsp, "%s: Only a single stream supported per dai\n",
snd_soc_rtd_to_codec(rtd, 0)->name);
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
}
compr = kzalloc_obj(*compr);
- if (!compr) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!compr)
+ return -ENOMEM;
compr->dsp = dsp;
compr->stream = stream;
@@ -1311,10 +1293,7 @@ int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream)
stream->runtime->private_data = compr;
-out:
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_open);
@@ -1324,7 +1303,7 @@ int wm_adsp_compr_free(struct snd_soc_component *component,
struct wm_adsp_compr *compr = stream->runtime->private_data;
struct wm_adsp *dsp = compr->dsp;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
wm_adsp_compr_detach(compr);
list_del(&compr->list);
@@ -1332,8 +1311,6 @@ int wm_adsp_compr_free(struct snd_soc_component *component,
kfree(compr->raw_buf);
kfree(compr);
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_free);
@@ -1741,7 +1718,7 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component,
compr_dbg(compr, "Trigger: %d\n", cmd);
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -1777,8 +1754,6 @@ int wm_adsp_compr_trigger(struct snd_soc_component *component,
break;
}
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger);
@@ -1907,21 +1882,20 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component,
compr_dbg(compr, "Pointer request\n");
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
buf = compr->buf;
if (dsp->fatal_error || !buf || buf->error) {
snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN);
- ret = -EIO;
- goto out;
+ return -EIO;
}
if (buf->avail < wm_adsp_compr_frag_words(compr)) {
ret = wm_adsp_buffer_update_avail(buf);
if (ret < 0) {
compr_err(compr, "Error reading avail: %d\n", ret);
- goto out;
+ return ret;
}
/*
@@ -1934,14 +1908,14 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component,
if (buf->error)
snd_compr_stop_error(stream,
SNDRV_PCM_STATE_XRUN);
- goto out;
+ return ret;
}
ret = wm_adsp_buffer_reenable_irq(buf);
if (ret < 0) {
compr_err(compr, "Failed to re-enable buffer IRQ: %d\n",
ret);
- goto out;
+ return ret;
}
}
}
@@ -1950,9 +1924,6 @@ int wm_adsp_compr_pointer(struct snd_soc_component *component,
tstamp->copied_total += buf->avail * CS_DSP_DATA_WORD_SIZE;
tstamp->sampling_rate = compr->sample_rate;
-out:
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer);
@@ -2063,15 +2034,13 @@ int wm_adsp_compr_copy(struct snd_soc_component *component,
struct wm_adsp *dsp = compr->dsp;
int ret;
- mutex_lock(&dsp->cs_dsp.pwr_lock);
+ guard(mutex)(&dsp->cs_dsp.pwr_lock);
if (stream->direction == SND_COMPRESS_CAPTURE)
ret = wm_adsp_compr_read(compr, buf, count);
else
ret = -ENOTSUPP;
- mutex_unlock(&dsp->cs_dsp.pwr_lock);
-
return ret;
}
EXPORT_SYMBOL_GPL(wm_adsp_compr_copy);
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 5174614c3e83..47ac3e4985a5 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -1178,7 +1178,13 @@ static int wsa881x_runtime_resume(struct device *dev)
}
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ gpiod_direction_output(wsa881x->sd_n, 1);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index 468d2b38a22a..442cf9f3eaac 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -4,6 +4,7 @@
*/
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/hwmon.h>
@@ -1237,9 +1238,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- mutex_lock(&wsa883x->sp_lock);
- wsa883x->pa_on = true;
- mutex_unlock(&wsa883x->sp_lock);
+ scoped_guard(mutex, &wsa883x->sp_lock)
+ wsa883x->pa_on = true;
switch (wsa883x->dev_mode) {
case RECEIVER:
@@ -1290,9 +1290,8 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w,
WSA883X_GLOBAL_PA_EN_MASK, 0);
snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL,
WSA883X_PDM_EN_MASK, 0);
- mutex_lock(&wsa883x->sp_lock);
- wsa883x->pa_on = false;
- mutex_unlock(&wsa883x->sp_lock);
+ scoped_guard(mutex, &wsa883x->sp_lock)
+ wsa883x->pa_on = false;
break;
}
return 0;
@@ -1696,9 +1695,15 @@ static int wsa883x_runtime_suspend(struct device *dev)
static int wsa883x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index 6c6b497657d0..a367c94bfb4d 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -1701,9 +1701,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- mutex_lock(&wsa884x->sp_lock);
- wsa884x->pa_on = true;
- mutex_unlock(&wsa884x->sp_lock);
+ scoped_guard(mutex, &wsa884x->sp_lock)
+ wsa884x->pa_on = true;
wsa884x_spkr_post_pmu(component, wsa884x);
@@ -1717,9 +1716,8 @@ static int wsa884x_spkr_event(struct snd_soc_dapm_widget *w,
WSA884X_PDM_WD_CTL_PDM_WD_EN_MASK,
0x0);
- mutex_lock(&wsa884x->sp_lock);
- wsa884x->pa_on = false;
- mutex_unlock(&wsa884x->sp_lock);
+ scoped_guard(mutex, &wsa884x->sp_lock)
+ wsa884x->pa_on = false;
break;
}
@@ -2147,9 +2145,15 @@ static int wsa884x_runtime_suspend(struct device *dev)
static int wsa884x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
+ int ret;
regcache_cache_only(regmap, false);
- regcache_sync(regmap);
+ ret = regcache_sync(regmap);
+ if (ret) {
+ regcache_cache_only(regmap, true);
+ regcache_mark_dirty(regmap);
+ return ret;
+ }
return 0;
}
diff --git a/sound/soc/codecs/wsa885x.c b/sound/soc/codecs/wsa885x.c
new file mode 100644
index 000000000000..1faa8541a872
--- /dev/null
+++ b/sound/soc/codecs/wsa885x.c
@@ -0,0 +1,1533 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+/* WSA885X codec driver */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+
+/* Control Registers - Audio Processing */
+#define WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S 0x0000
+#define WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK 0x0004
+#define WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX 0x0140
+#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID 0x0208
+#define WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX 0x0240
+#define WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER 0x0340
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0 0x4405
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1 0x4406
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB 0x4409
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB 0x6409
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB 0x440a
+#define WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB 0x640a
+#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS 0x0a04
+#define WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS 0x0a40
+#define WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE 0x0b10
+#define WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX 0x0e40
+
+/* Analog Top Registers - Power and Clock Control */
+#define WSA885X_ANA_TOP_PON_CKSK_CTL_0 0x800d
+#define WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG 0x8024
+#define WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG 0x8025
+#define WSA885X_ANA_TOP_BG_TVP_OVRD_CTL 0x8034
+
+/* Analog PLL Registers */
+#define WSA885X_ANA_PLL_DIV_CTL_0 0x8090
+#define WSA885X_ANA_PLL_DIV_CTL_1 0x8091
+#define WSA885X_ANA_TOP_PLL_VCO_CTL 0x8092
+#define WSA885X_ANA_TOP_PLL_LOOPFILT_0 0x8093
+#define WSA885X_ANA_TOP_PLL_OVRD_CTL 0x8098
+#define WSA885X_ANA_TOP_PLL_STATUS_0 0x809a
+#define WSA885X_ANA_TOP_PLL_STATUS_1 0x809b
+
+/* Analog Boost Control Registers */
+#define WSA885X_ANA_TOP_BOOST_STB_CTRL2 0x805b
+#define WSA885X_ANA_TOP_BOOST_STB_CTRL3 0x805c
+#define WSA885X_ANA_TOP_BOOST_BYP_CTRL2 0x805e
+#define WSA885X_ANA_TOP_BOOST_BYP_CTRL3 0x805f
+#define WSA885X_ANA_TOP_BOOST_MISC 0x8063
+#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2 0x8065
+#define WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4 0x8067
+
+/* Analog IV Sense ADC Registers */
+#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2 0x80ca
+#define WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3 0x80cb
+#define WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL 0x80cc
+#define WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2 0x80d0
+
+/* Analog Speaker Power Stage Registers */
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3 0x8108
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3 0x810b
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3 0x810e
+#define WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3 0x8111
+#define WSA885X_ANA_TOP_SPK_TOP_SPARE3 0x813c
+#define WSA885X_SPK_TOP_LF_CH1_CTRL11 0x811c
+#define WSA885X_SPK_TOP_LF_CH1_TUNE1 0x811d
+#define WSA885X_SPK_TOP_LF_CH2_TUNE1 0x8129
+#define WSA885X_SPK_TOP_LF_CH1_CTRL9 0x811a
+#define WSA885X_SPK_TOP_LF_CH2_CTRL9 0x8126
+#define WSA885X_SPK_TOP_LF_CH2_CTRL11 0x8128
+#define WSA885X_SPK_TOP_COMMON_CTRL2 0x8102
+#define WSA885X_SPK_TOP_COMMON_TUNE1 0x8103
+#define WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1 0x80ba
+#define WSA885X_DIG_CTRL0_TOP_CLK_CFG 0x8418
+#define WSA885X_DIG_CTRL0_SDCA_COMMIT 0x8419
+#define WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE 0x841a
+#define WSA885X_DIG_CTRL0_SYS_CLK_SEL 0x841b
+#define WSA885X_DIG_CTRL0_CDC_CLK_CTL 0x841c
+#define WSA885X_DIG_CTRL0_PA_FSM_CTL 0x8420
+#define WSA885X_DIG_CTRL0_POWER_FSM_CTL0 0x8423
+#define WSA885X_DIG_CTRL0_POWER_FSM_CTL1 0x8424
+#define WSA885X_DIG_CTRL0_PA0_FSM_CTL1 0x842b
+#define WSA885X_DIG_CTRL0_PA1_FSM_CTL1 0x8435
+#define WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL 0x8458
+#define WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL 0x8470
+#define WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1 0x84b4
+#define WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1 0x84b7
+#define WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1 0x84A0
+#define WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1 0x84A4
+
+/* Digital Control 1 Registers - I2S/TDM Interface */
+#define WSA885X_DIG_CTRL1_I2S_CTL0 0x85A0
+#define WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX 0x85A2
+#define WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX 0x85A3
+#define WSA885X_DIG_CTRL1_I2S_TDM_CTL0 0x85A7
+#define WSA885X_DIG_CTRL1_I2S_TDM_CTL1 0x85A9
+#define WSA885X_DIG_CTRL1_I2S_TDM_CH_RX 0x85AA
+#define WSA885X_DIG_CTRL1_I2S_TDM_CH_TX 0x85AB
+#define WSA885X_DIG_CTRL1_I2S_RESET_CTL 0x85AE
+
+/* CDC RX Path Registers - Audio Data Path */
+#define WSA885X_CDC_RX0_RX_PATH_CFG0 0x8601
+#define WSA885X_CDC_RX0_RX_PATH_CFG1 0x8602
+#define WSA885X_CDC_RX0_RX_PATH_CTL 0x8606
+#define WSA885X_RX0_RX_PATH_DSMDEM_CTL 0x8613
+#define WSA885X_CDC_RX1_RX_PATH_CFG0 0x8621
+#define WSA885X_CDC_RX1_RX_PATH_CFG1 0x8622
+#define WSA885X_CDC_RX1_RX_PATH_CTL 0x8626
+#define WSA885X_RX1_RX_PATH_DSMDEM_CTL 0x8633
+
+/* CDC Compander Registers - Dynamic Range Control */
+#define WSA885X_CDC_COMPANDER0_CTL0 0x8640
+#define WSA885X_CDC_COMPANDER0_CTL7 0x8647
+#define WSA885X_CDC_COMPANDER1_CTL0 0x8660
+#define WSA885X_CDC_COMPANDER1_CTL7 0x8667
+
+/* CDC Speaker Protection Registers - IV Sense */
+#define WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL 0x86A1
+#define WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL 0x86B1
+#define WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL 0x86A9
+#define WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL 0x86B9
+
+/* CDC Class-H Registers - Headroom Control */
+#define WSA885X_CDC_CLSH_V1P8_BP_CTL1 0x86CD
+#define WSA885X_CDC_CLSH_V1P8_BP_CTL0 0x86CC
+#define WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0 0x86C7
+#define WSA885X_CDC_CLSH_CLSH_V_HD_PA 0x86C3
+#define WSA885X_CDC_CLSH_V1P8_BP_CTL2 0x86CE
+
+/* Driver Constants */
+#define WSA885X_CLK_RATE_FIXED 73728000
+#define WSA885X_NUM_REGS 0x03
+
+/* Interrupt Registers */
+#define WSA885X_INTR_STATUS0 0x8584
+#define WSA885X_INTR_MASK0 0x8581
+#define WSA885X_INTR_CLEAR0 0x8587
+
+/* Power and PA FSM Control Registers */
+#define WSA885X_PA0_FSM_CTL0 0x842A
+#define WSA885X_PA1_FSM_CTL0 0x8434
+
+/* Digital Control GPIO and Interrupt Registers */
+#define WSA885X_DIG_CTRL1_PIN_CT 0x8510
+#define WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL 0x8518
+#define WSA885X_DIG_CTRL1_INTR_MODE 0x8580
+
+#define WSA885X_I2S_CTL0_PCM_RATE_MASK GENMASK(4, 1)
+#define WSA885X_I2S_CTL0_ENABLE_MASK BIT(0)
+#define WSA885X_I2S_CTL0_PCM_RATE(v) \
+ FIELD_PREP(WSA885X_I2S_CTL0_PCM_RATE_MASK, (v))
+#define WSA885X_I2S_CTL0_PCM_RATE_8KHZ 0x0
+#define WSA885X_I2S_CTL0_PCM_RATE_16KHZ 0x1
+#define WSA885X_I2S_CTL0_PCM_RATE_32KHZ 0x2
+#define WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ 0x3
+#define WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ 0x4
+#define WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ 0x5
+#define WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ 0x6
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK GENMASK(2, 0)
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK GENMASK(6, 4)
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT0(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK, (v))
+#define WSA885X_I2S_CFG0_TDM_TX_SLOT1(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK, (v))
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK GENMASK(2, 0)
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK GENMASK(6, 4)
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT2(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK, (v))
+#define WSA885X_I2S_CFG1_TDM_TX_SLOT3(v) \
+ FIELD_PREP_CONST(WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK, (v))
+#define WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK BIT(0)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK GENMASK(3, 2)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2 \
+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 0)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4 \
+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 1)
+#define WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8 \
+ FIELD_PREP_CONST(WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK, 3)
+#define WSA885X_I2S_TDM_CH_TX_CH0_EN BIT(0)
+#define WSA885X_I2S_TDM_CH_TX_CH1_EN BIT(1)
+#define WSA885X_I2S_TDM_CH_TX_CH2_EN BIT(2)
+#define WSA885X_I2S_TDM_CH_TX_CH3_EN BIT(3)
+#define WSA885X_I2S_TDM_CH_RX_CH0_EN BIT(0)
+#define WSA885X_I2S_TDM_CH_RX_CH3_EN BIT(3)
+#define WSA885X_I2S_RESET_CTL_RESET_MASK BIT(0)
+#define WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK BIT(2)
+#define WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK BIT(3)
+#define WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK BIT(2)
+
+#define WSA885X_I2S_TX_SLOT_ISENSE0 0x1
+#define WSA885X_I2S_TX_SLOT_ISENSE1 0x2
+#define WSA885X_I2S_TX_SLOT_CUR_SENSE0 0x5
+#define WSA885X_I2S_TX_SLOT_CUR_SENSE1 0x6
+
+/* RX Sample Rate Index Values - Audio Playback Path */
+#define WSA885X_RX_RATE_8000HZ 0x00
+#define WSA885X_RX_RATE_16000HZ 0x01
+#define WSA885X_RX_RATE_32000HZ 0x02
+#define WSA885X_RX_RATE_44100HZ 0x03
+#define WSA885X_RX_RATE_48000HZ 0x04
+#define WSA885X_RX_RATE_96000HZ 0x05
+#define WSA885X_RX_RATE_192000HZ 0x06
+#define WSA885X_RX_RATE_384000HZ 0x07
+
+/* VI Sample Rate Index Values - Voltage/Current Sensing Path */
+#define WSA885X_VI_RATE_8000HZ 0x00
+#define WSA885X_VI_RATE_16000HZ 0x01
+#define WSA885X_VI_RATE_44100HZ 0x02
+#define WSA885X_VI_RATE_48000HZ 0x03
+#define WSA885X_VI_RATE_96000HZ 0x04
+#define WSA885X_VI_RATE_22050HZ 0x05
+#define WSA885X_VI_RATE_24000HZ 0x06
+#define WSA885X_VI_RATE_192000HZ 0x07
+#define WSA885X_VI_RATE_384000HZ 0x08
+
+/* Channel Configuration Masks */
+#define WSA885X_CHANNEL_STEREO 0x03
+#define WSA885X_CHANNEL_MONO_LEFT 0x01
+#define WSA885X_CHANNEL_MONO_RIGHT 0x02
+
+#define WSA885X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define WSA885X_PLL_LOCK_BIT BIT(0)
+
+#define WSA885X_FU21_VOL_STEPS 124
+#define WSA885X_USAGE_MODE_MAX 8
+static const DECLARE_TLV_DB_SCALE(wsa885x_fu21_digital_gain, -8400, 100, 0);
+
+static bool wsa885x_is_valid_rx_slot_mask(u32 mask)
+{
+ return mask == WSA885X_CHANNEL_MONO_LEFT ||
+ mask == WSA885X_CHANNEL_MONO_RIGHT ||
+ mask == WSA885X_CHANNEL_STEREO;
+}
+
+static const char *const wsa885x_supply_name[] = {
+ "vdd-1p8",
+ "vdd-io",
+};
+
+enum {
+ WSA885X_BATT_1S = 1,
+ WSA885X_BATT_2S,
+};
+
+enum {
+ WSA885X_IRQ_INT_SAF2WAR = 0,
+ WSA885X_IRQ_INT_WAR2SAF,
+ WSA885X_IRQ_INT_DISABLE,
+ WSA885X_IRQ_INT_PA0_OCP,
+ WSA885X_IRQ_INT_PA1_OCP,
+ WSA885X_IRQ_INT_CLIP0,
+ WSA885X_IRQ_INT_CLIP1,
+ WSA885X_IRQ_INT_CLK_WD,
+ WSA885X_IRQ_INT_INTR_GPIO1_PIN,
+ WSA885X_IRQ_INT_INTR_GPIO2_PIN,
+ WSA885X_IRQ_INT_UVLO,
+ WSA885X_IRQ_INT_BOP,
+ WSA885X_IRQ_INT_PA0_FSM_ERR,
+ WSA885X_IRQ_INT_PA1_FSM_ERR,
+ WSA885X_IRQ_INT_MAIN_FSM_ERR,
+ WSA885X_IRQ_INT_PCM_DATA0_WD,
+ WSA885X_IRQ_INT_PCM_DATA1_WD,
+ WSA885X_IRQ_INT_PCM_DATA0_DC,
+ WSA885X_IRQ_INT_PCM_DATA1_DC,
+ WSA885X_IRQ_INT_PLL_UNLOCKED,
+ WSA885X_IRQ_INT_PROT_MODE_CHANGE,
+ WSA885X_IRQ_INT_PB_CLOCK_VALID,
+ WSA885X_IRQ_INT_SENSE_CLOCK_VALID,
+ WSA885X_IRQ_MAX,
+};
+
+struct wsa885x_priv {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct device *dev;
+ struct snd_soc_component *component;
+ struct gpio_desc *sd_n;
+ struct reset_control *sd_reset;
+ u32 usage_mode;
+ u32 rx_slot_mask;
+ u32 batt_conf;
+ int stereo_vol_db;
+ struct mutex state_lock; /* protects mutable control state */
+};
+
+struct wsa885x_reg_update {
+ unsigned int reg;
+ unsigned int mask;
+ unsigned int val;
+};
+
+static const struct regmap_range_cfg wsa885x_regmap_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = 0x88ff,
+ .selector_reg = 0x0,
+ .selector_mask = 0xFF,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+static const struct reg_default wsa885x_codec_reg_defaults[] = {
+ {WSA885X_SMP_AMP_CTRL_STEREO_STEREO_SMP_AMP_CTRL_I2S, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX, 0x04},
+ {WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB, 0xac},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB, 0xac},
+ {WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00},
+ {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03},
+ {WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS, 0x03},
+ {WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX, 0x03},
+ {WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x00},
+ {WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x19},
+ {WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x22},
+ {WSA885X_ANA_PLL_DIV_CTL_0, 0x0c},
+ {WSA885X_ANA_PLL_DIV_CTL_1, 0x50},
+ {WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00},
+ {WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xb4},
+ {WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00},
+ {WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00},
+ {WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x03},
+ {WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x3c},
+ {WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc5},
+ {WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x13},
+ {WSA885X_ANA_TOP_BOOST_MISC, 0x79},
+ {WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x00},
+ {WSA885X_SPK_TOP_COMMON_CTRL2, 0x08},
+ {WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x09},
+ {WSA885X_SPK_TOP_LF_CH1_TUNE1, 0x00},
+ {WSA885X_SPK_TOP_LF_CH2_TUNE1, 0x00},
+ {WSA885X_SPK_TOP_LF_CH1_CTRL9, 0x00},
+ {WSA885X_SPK_TOP_LF_CH2_CTRL9, 0x00},
+ {WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x09},
+ {WSA885X_SPK_TOP_COMMON_TUNE1, 0x03},
+ {WSA885X_IVSENSE_VSNS_ISNS_CTL_CH1, 0x00},
+ {WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0e},
+ {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x40},
+ {WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0xff},
+ {WSA885X_ANA_TOP_PLL_STATUS_0, 0x00},
+ {WSA885X_ANA_TOP_PLL_STATUS_1, 0x00},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x84},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x02},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x00},
+ {WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0xe0},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa4},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0xc9},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa4},
+ {WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0xc9},
+ {WSA885X_DIG_CTRL0_TOP_CLK_CFG, 0x00},
+ {WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x00},
+ {WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00},
+ {WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00},
+ {WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00},
+ {WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05},
+ {WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x00},
+ {WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x45},
+ {WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x45},
+ {WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x7f},
+ {WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00},
+ {WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01},
+ {WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01},
+ {WSA885X_DIG_CTRL1_I2S_CTL0, 0x06},
+ {WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CTL0, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x05},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CH_TX, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00},
+ {WSA885X_DIG_CTRL1_I2S_TDM_CH_RX, WSA885X_I2S_TDM_CH_RX_CH3_EN},
+ {WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89},
+ {WSA885X_CDC_RX0_RX_PATH_CFG1, 0x64},
+ {WSA885X_CDC_RX0_RX_PATH_CTL, 0x24},
+ {WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01},
+ {WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89},
+ {WSA885X_CDC_RX1_RX_PATH_CFG1, 0x64},
+ {WSA885X_CDC_RX1_RX_PATH_CTL, 0x04},
+ {WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01},
+ {WSA885X_CDC_COMPANDER0_CTL0, 0x01},
+ {WSA885X_CDC_COMPANDER0_CTL7, 0x2a},
+ {WSA885X_CDC_COMPANDER1_CTL0, 0x01},
+ {WSA885X_CDC_COMPANDER1_CTL7, 0x2a},
+ {WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14},
+ {WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50},
+ {WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c},
+ {WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d},
+ {WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03},
+ {WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05},
+};
+
+static void wsa885x_multi_update_bits(struct regmap *regmap,
+ const struct wsa885x_reg_update *updates,
+ size_t num_updates)
+{
+ size_t i;
+
+ for (i = 0; i < num_updates; i++)
+ regmap_update_bits(regmap, updates[i].reg,
+ updates[i].mask, updates[i].val);
+}
+
+static void wsa885x_toggle_irq_bit(struct wsa885x_priv *wsa885x,
+ unsigned int reg, unsigned int mask)
+{
+ regmap_update_bits(wsa885x->regmap, reg, mask, 0);
+ regmap_update_bits(wsa885x->regmap, reg, mask, mask);
+}
+
+static void wsa885x_pulse_irq_bit(struct wsa885x_priv *wsa885x,
+ unsigned int reg, unsigned int mask)
+{
+ regmap_update_bits(wsa885x->regmap, reg, mask, 0);
+ regmap_update_bits(wsa885x->regmap, reg, mask, mask);
+ regmap_update_bits(wsa885x->regmap, reg, mask, 0);
+}
+
+static int wsa885x_tdm_ctl0_slot_num_val(int slots, unsigned int *slot_num_val)
+{
+ if (!slot_num_val)
+ return -EINVAL;
+
+ switch (slots) {
+ case 2:
+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_2;
+ return 0;
+ case 4:
+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_4;
+ return 0;
+ case 8:
+ *slot_num_val = WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_8;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int wsa885x_reg_update_sequence(struct regmap *regmap, int slots)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x15 },
+ { WSA885X_DIG_CTRL1_I2S_TDM_CTL1, 0x11 },
+ };
+ unsigned int slot_num_val;
+ int ret;
+
+ if (!regmap)
+ return -EINVAL;
+
+ ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val);
+ if (ret)
+ return ret;
+
+ regmap_multi_reg_write(regmap, regs, ARRAY_SIZE(regs));
+
+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0,
+ WSA885X_I2S_TDM_CTL0_NUM_CHANNELS_MASK,
+ slot_num_val);
+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CTL0,
+ WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK,
+ WSA885X_I2S_TDM_CTL0_I2S_TDM_EN_MASK);
+ regmap_write(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH0_EN);
+ regmap_update_bits(regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH1_EN,
+ WSA885X_I2S_TDM_CH_TX_CH1_EN);
+
+ return 0;
+}
+
+static int wsa885x_wait_for_pll_lock(struct wsa885x_priv *wsa885x)
+{
+ unsigned int status = 0;
+ int cnt = 0, ret = 0;
+
+ do {
+ usleep_range(1000, 1100);
+ ret = regmap_read(wsa885x->regmap, WSA885X_ANA_TOP_PLL_STATUS_0, &status);
+ if (ret) {
+ dev_err(wsa885x->dev, "PLL status read failed: %d\n", ret);
+ return ret;
+ }
+
+ if (status & WSA885X_PLL_LOCK_BIT)
+ return 0;
+ } while (++cnt < 20);
+
+ dev_warn(wsa885x->dev, "PLL lock timeout after 20ms, status=0x%x\n", status);
+ return -ETIMEDOUT;
+}
+
+static int wsa885x_2s_conf(struct wsa885x_priv *wsa885x)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_SPK_TOP_COMMON_TUNE1, 0x26 },
+ { WSA885X_SPK_TOP_LF_CH1_CTRL11, 0x0d },
+ { WSA885X_SPK_TOP_LF_CH2_CTRL11, 0x0d },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x71 },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0xAA },
+ };
+
+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+}
+
+static const struct reg_sequence wsa885x_reg_init[] = {
+ { WSA885X_CDC_RX0_RX_PATH_CTL, 0x24 },
+ { WSA885X_CDC_RX1_RX_PATH_CTL, 0x24 },
+ { WSA885X_RX0_RX_PATH_DSMDEM_CTL, 0x01 },
+ { WSA885X_RX1_RX_PATH_DSMDEM_CTL, 0x01 },
+ { WSA885X_CDC_COMPANDER0_CTL0, 0x01 },
+ { WSA885X_CDC_COMPANDER1_CTL0, 0x01 },
+ { WSA885X_CDC_VSENSE0_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_CDC_VSENSE1_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_CDC_ISENSE0_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_CDC_ISENSE1_SPKR_PROT_PATH_CTL, 0x14 },
+ { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x0f },
+ { WSA885X_DIG_CTRL0_CDC_CLK_CTL, 0x4f },
+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x02 },
+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x00 },
+ { WSA885X_DIG_CTRL0_CDC_RXTX_FSCNT_CTL, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_CMT_GRP_MASK, 0x01 },
+ { WSA885X_CDC_RX0_RX_PATH_CFG1, 0x60 },
+ { WSA885X_CDC_RX1_RX_PATH_CFG1, 0x60 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_CTRL3, 0xa5 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_CTRL3, 0xa5 },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL2, 0x85 },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0c },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_MODE_CTL3, 0x0e },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_REF_CTL, 0x0c },
+ { WSA885X_DIG_CTRL0_GAIN_RAMP0_CTL1, 0x01 },
+ { WSA885X_DIG_CTRL0_GAIN_RAMP1_CTL1, 0x01 },
+ { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x88 },
+ { WSA885X_CDC_RX0_RX_PATH_CFG0, 0x89 },
+ { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x88 },
+ { WSA885X_CDC_RX1_RX_PATH_CFG0, 0x89 },
+ { WSA885X_ANA_TOP_BOOST_STB_CTRL2, 0x82 },
+ { WSA885X_ANA_TOP_BOOST_STB_CTRL3, 0x34 },
+ { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL2, 0x41 },
+ { WSA885X_ANA_TOP_BOOST_PWRSTAGE_CTRL4, 0x7f },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL1, 0x50 },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL0, 0x6c },
+ { WSA885X_CDC_CLSH_CLSH_SIG_DP_CTL0, 0x0d },
+ { WSA885X_CDC_CLSH_CLSH_V_HD_PA, 0x03 },
+ { WSA885X_DIG_CTRL0_POWER_FSM_CTL0, 0x05 },
+ { WSA885X_ANA_TOP_PON_CKSK_CTL_0, 0x20 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH1_TUNE3, 0x45 },
+ { WSA885X_ANA_TOP_SPK_TOP_PWRSTG_CH2_TUNE3, 0x45 },
+ { WSA885X_CDC_CLSH_V1P8_BP_CTL2, 0x05 },
+ { WSA885X_ANA_TOP_BG_TVP_UVLO1_PROG, 0x35 },
+ { WSA885X_ANA_TOP_BG_TVP_UVLO2_PROG, 0x21 },
+ { WSA885X_ANA_TOP_BOOST_BYP_CTRL2, 0xc7 },
+ { WSA885X_ANA_TOP_BOOST_BYP_CTRL3, 0x11 },
+ { WSA885X_ANA_TOP_IVSENSE_ADC_CDAC_CAL_CTL2, 0x80 },
+ { WSA885X_ANA_TOP_SPK_TOP_SPARE3, 0x08 },
+ { WSA885X_DIG_CTRL0_PA0_FSM_CTL1, 0x47 },
+ { WSA885X_DIG_CTRL0_PA1_FSM_CTL1, 0x47 },
+ { WSA885X_CDC_COMPANDER0_CTL7, 0x34 },
+ { WSA885X_CDC_COMPANDER1_CTL7, 0x34 },
+ { WSA885X_DIG_CTRL0_VBAT_THRM_FLT_CTL, 0x79 },
+};
+
+static int wsa885x_hw_init(struct wsa885x_priv *wsa885x)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_DIG_CTRL1_SPMI_PAD_GPIO2_CTL, 0x2e },
+ { WSA885X_DIG_CTRL1_INTR_MODE, 0x01 },
+ { WSA885X_DIG_CTRL1_PIN_CT, 0x04 },
+ };
+ int ret;
+
+ ret = regmap_multi_reg_write(wsa885x->regmap, wsa885x_reg_init,
+ ARRAY_SIZE(wsa885x_reg_init));
+ if (ret)
+ return ret;
+
+ if (wsa885x->batt_conf == WSA885X_BATT_2S) {
+ ret = wsa885x_2s_conf(wsa885x);
+ if (ret)
+ return ret;
+ }
+
+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+}
+
+static int wsa885x_unmask_interrupts(struct wsa885x_priv *wsa885x)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_INTR_MASK0, 0x00 },
+ { WSA885X_INTR_MASK0 + 1, 0x00 },
+ { WSA885X_INTR_MASK0 + 2, 0xf8 },
+ };
+
+ return regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+}
+
+static int wsa885x_wait_for_pde_state(struct wsa885x_priv *wsa885x, int ps)
+{
+ unsigned int act_ps = 0, clock_valid = 0;
+ int rc = 0, cnt = 0;
+
+ if (ps < 0 || ps > 3)
+ return -EINVAL;
+
+ do {
+ usleep_range(1000, 1500);
+ rc = regmap_read(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS,
+ &act_ps);
+ if (rc) {
+ dev_err(wsa885x->dev, "PDE state read failed: %d\n", rc);
+ return rc;
+ }
+ if (act_ps == ps)
+ return 0;
+ } while (++cnt < 5);
+
+ if (regmap_read(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID,
+ &clock_valid))
+ dev_err(wsa885x->dev,
+ "PDE power state %d request failed, actual_ps %d, clock_valid read failed\n",
+ ps, act_ps);
+ else
+ dev_err(wsa885x->dev,
+ "PDE power state %d request failed, actual_ps %d, clock_valid:%d\n",
+ ps, act_ps, clock_valid);
+
+ return -ETIMEDOUT;
+}
+
+static void wsa885x_program_stereo_volume(struct wsa885x_priv *wsa885x,
+ int stereo_vol_db, bool commit)
+{
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_MSB,
+ (u8)(s8)stereo_vol_db);
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00);
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_MSB,
+ (u8)(s8)stereo_vol_db);
+ regmap_write(wsa885x->regmap,
+ WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00);
+
+ if (commit)
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01);
+}
+
+static int wsa885x_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wsa885x_priv *wsa885x;
+ u8 pcm_rate, cs21_sample_rate_idx, cs24_sample_rate_idx;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ switch (params_rate(params)) {
+ case 8000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_8KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_8000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_8000HZ;
+ break;
+ case 16000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_16KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_16000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_16000HZ;
+ break;
+ case 32000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_32KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_32000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ;
+ break;
+ case 44100:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_44100HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_44100HZ;
+ break;
+ case 48000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_48_OR_44KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_48000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_48000HZ;
+ break;
+ case 88200:
+ case 96000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_96_OR_88KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_96000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_96000HZ;
+ break;
+ case 176400:
+ case 192000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_192_OR_176KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_192000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_192000HZ;
+ break;
+ case 352800:
+ case 384000:
+ pcm_rate = WSA885X_I2S_CTL0_PCM_RATE_384_OR_352KHZ;
+ cs21_sample_rate_idx = WSA885X_RX_RATE_384000HZ;
+ cs24_sample_rate_idx = WSA885X_VI_RATE_384000HZ;
+ break;
+ default:
+ dev_err(wsa885x->dev, "sampling rate %d is not supported\n", params_rate(params));
+ return -EINVAL;
+ }
+
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0,
+ WSA885X_I2S_CTL0_PCM_RATE_MASK |
+ WSA885X_I2S_CTL0_ENABLE_MASK,
+ WSA885X_I2S_CTL0_PCM_RATE(pcm_rate) |
+ WSA885X_I2S_CTL0_ENABLE_MASK);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL, 0x00);
+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS21_SAMPLERATEINDEX,
+ cs21_sample_rate_idx);
+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_CS24_SAMPLERATEINDEX,
+ cs24_sample_rate_idx);
+
+ mutex_lock(&wsa885x->state_lock);
+ wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false);
+ mutex_unlock(&wsa885x->state_lock);
+
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01);
+
+ return 0;
+}
+
+static int wsa885x_codec_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_slot_mask,
+ unsigned int rx_slot_mask, int slots,
+ int slot_width)
+{
+ static const struct wsa885x_reg_update stereo_updates[] = {
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) },
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_ISENSE1) },
+ { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT2_MASK,
+ WSA885X_I2S_CFG1_TDM_TX_SLOT2(WSA885X_I2S_TX_SLOT_CUR_SENSE0) },
+ { WSA885X_DIG_CTRL1_I2S_CFG1_TDM_TX, WSA885X_I2S_CFG1_TDM_TX_SLOT3_MASK,
+ WSA885X_I2S_CFG1_TDM_TX_SLOT3(WSA885X_I2S_TX_SLOT_CUR_SENSE1) },
+ };
+ static const struct wsa885x_reg_update mono_left_updates[] = {
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE0) },
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE0) },
+ };
+ static const struct wsa885x_reg_update mono_right_updates[] = {
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT0_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT0(WSA885X_I2S_TX_SLOT_ISENSE1) },
+ { WSA885X_DIG_CTRL1_I2S_CFG0_TDM_TX, WSA885X_I2S_CFG0_TDM_TX_SLOT1_MASK,
+ WSA885X_I2S_CFG0_TDM_TX_SLOT1(WSA885X_I2S_TX_SLOT_CUR_SENSE1) },
+ };
+ struct wsa885x_priv *wsa885x;
+ unsigned int slot_num_val;
+ u32 mask;
+ int ret;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ ret = wsa885x_tdm_ctl0_slot_num_val(slots, &slot_num_val);
+ if (ret) {
+ dev_err(wsa885x->dev, "%s: unsupported slot count %d\n",
+ __func__, slots);
+ return ret;
+ }
+
+ if (rx_slot_mask && !wsa885x_is_valid_rx_slot_mask(rx_slot_mask)) {
+ dev_err(wsa885x->dev,
+ "%s: unsupported rx_slot_mask 0x%x\n",
+ __func__, rx_slot_mask);
+ return -EINVAL;
+ }
+
+ mutex_lock(&wsa885x->state_lock);
+ if (rx_slot_mask)
+ wsa885x->rx_slot_mask = rx_slot_mask;
+ else if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask))
+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO;
+ mask = wsa885x->rx_slot_mask;
+
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL,
+ WSA885X_I2S_RESET_CTL_RESET_MASK,
+ WSA885X_I2S_RESET_CTL_RESET_MASK);
+
+ if (mask == WSA885X_CHANNEL_STEREO) {
+ wsa885x_multi_update_bits(wsa885x->regmap, stereo_updates,
+ ARRAY_SIZE(stereo_updates));
+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots);
+ if (ret)
+ goto exit_unlock;
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH2_EN,
+ WSA885X_I2S_TDM_CH_TX_CH2_EN);
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_TX,
+ WSA885X_I2S_TDM_CH_TX_CH3_EN,
+ WSA885X_I2S_TDM_CH_TX_CH3_EN);
+ } else if (mask == WSA885X_CHANNEL_MONO_LEFT) {
+ wsa885x_multi_update_bits(wsa885x->regmap, mono_left_updates,
+ ARRAY_SIZE(mono_left_updates));
+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots);
+ if (ret)
+ goto exit_unlock;
+ } else if (mask == WSA885X_CHANNEL_MONO_RIGHT) {
+ wsa885x_multi_update_bits(wsa885x->regmap, mono_right_updates,
+ ARRAY_SIZE(mono_right_updates));
+ ret = wsa885x_reg_update_sequence(wsa885x->regmap, slots);
+ if (ret)
+ goto exit_unlock;
+ }
+
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_CTL0,
+ WSA885X_I2S_CTL0_ENABLE_MASK,
+ WSA885X_I2S_CTL0_ENABLE_MASK);
+ regmap_update_bits(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_RESET_CTL,
+ WSA885X_I2S_RESET_CTL_RESET_MASK, 0);
+
+ ret = 0;
+
+exit_unlock:
+ mutex_unlock(&wsa885x->state_lock);
+
+ return ret;
+}
+
+static int wsa885x_codec_set_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ static const struct reg_sequence pll_prep[] = {
+ { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x03 },
+ { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x04 },
+ { WSA885X_ANA_TOP_PLL_LOOPFILT_0, 0xB4 },
+ { WSA885X_ANA_TOP_PLL_VCO_CTL, 0x00 },
+ { WSA885X_ANA_TOP_PLL_OVRD_CTL, 0x00 },
+ };
+ static const struct reg_sequence pll_cleanup[] = {
+ { WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x00 },
+ { WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00 },
+ { WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00 },
+ };
+ struct wsa885x_priv *wsa885x;
+ u32 pll_div;
+ int ret = 0;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ if (!freq)
+ return -EINVAL;
+ if (WSA885X_CLK_RATE_FIXED % freq)
+ return -EINVAL;
+ pll_div = WSA885X_CLK_RATE_FIXED / freq;
+ if (pll_div > 0xff)
+ return -EINVAL;
+
+ regmap_multi_reg_write(wsa885x->regmap, pll_prep, ARRAY_SIZE(pll_prep));
+ regmap_write(wsa885x->regmap, WSA885X_ANA_PLL_DIV_CTL_0, pll_div);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_CLK_SOURCE_ENABLE, 0x02);
+
+ ret = wsa885x_wait_for_pll_lock(wsa885x);
+ if (ret) {
+ dev_err(wsa885x->dev, "PLL lock failed, aborting sysclk configuration\n");
+ regmap_multi_reg_write(wsa885x->regmap, pll_cleanup,
+ ARRAY_SIZE(pll_cleanup));
+ return ret;
+ }
+
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_SYS_CLK_SEL, 0x00);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_POWER_FSM_CTL1, 0x01);
+ regmap_write(wsa885x->regmap, WSA885X_ANA_TOP_BG_TVP_OVRD_CTL, 0x00);
+
+ return 0;
+}
+
+static int wsa885x_codec_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ static const struct reg_sequence mute_regs[] = {
+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x03 },
+ };
+ static const struct reg_sequence mute_commit_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x01 },
+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 },
+ };
+ static const struct reg_sequence unmute_prep_head_regs[] = {
+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
+ };
+ static const struct reg_sequence unmute_prep_tail_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_IT21_CLUSERINDEX, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_PPU21_POSTURENUMBER, 0x01 },
+ };
+ static const struct reg_sequence unmute_volume_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X0_LSB, 0x00 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_CH_VOL_CH2X1_LSB, 0x00 },
+ };
+ static const struct reg_sequence unmute_commit_regs[] = {
+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_PDE23_REQ_PS, 0x00 },
+ };
+ static const struct reg_sequence unmute_finish_regs[] = {
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X0, 0x00 },
+ { WSA885X_SMP_AMP_CTRL_STEREO_FU21_MUTE_CH2X1, 0x00 },
+ { WSA885X_DIG_CTRL0_SDCA_COMMIT, 0x01 },
+ };
+ struct wsa885x_priv *wsa885x;
+ int ret = 0, ps0 = 0, ps3 = 3;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ mutex_lock(&wsa885x->state_lock);
+
+ if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) {
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ if (!wsa885x_is_valid_rx_slot_mask(wsa885x->rx_slot_mask))
+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO;
+
+ if (mute) {
+ regmap_multi_reg_write(wsa885x->regmap, mute_regs,
+ ARRAY_SIZE(mute_regs));
+ ret = wsa885x_wait_for_pde_state(wsa885x, ps3);
+ if (ret) {
+ dev_err(wsa885x->dev,
+ "PS3 transition failed: %d\n", ret);
+ } else {
+ regmap_multi_reg_write(wsa885x->regmap, mute_commit_regs,
+ ARRAY_SIZE(mute_commit_regs));
+ }
+ } else {
+ regmap_multi_reg_write(wsa885x->regmap, unmute_prep_head_regs,
+ ARRAY_SIZE(unmute_prep_head_regs));
+ regmap_write(wsa885x->regmap, WSA885X_SMP_AMP_CTRL_STEREO_OT23_USAGE,
+ wsa885x->usage_mode);
+ regmap_multi_reg_write(wsa885x->regmap, unmute_prep_tail_regs,
+ ARRAY_SIZE(unmute_prep_tail_regs));
+ wsa885x_program_stereo_volume(wsa885x, wsa885x->stereo_vol_db, false);
+ regmap_multi_reg_write(wsa885x->regmap, unmute_volume_regs,
+ ARRAY_SIZE(unmute_volume_regs));
+ regmap_multi_reg_write(wsa885x->regmap, unmute_commit_regs,
+ ARRAY_SIZE(unmute_commit_regs));
+ ret = wsa885x_wait_for_pde_state(wsa885x, ps0);
+ if (ret)
+ goto exit_unlock;
+
+ if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_STEREO) {
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX,
+ WSA885X_I2S_TDM_CH_RX_CH0_EN |
+ WSA885X_I2S_TDM_CH_RX_CH3_EN);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x03);
+ } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_LEFT) {
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX,
+ WSA885X_I2S_TDM_CH_RX_CH3_EN);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x01);
+ } else if (wsa885x->rx_slot_mask == WSA885X_CHANNEL_MONO_RIGHT) {
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL1_I2S_TDM_CH_RX,
+ WSA885X_I2S_TDM_CH_RX_CH0_EN);
+ regmap_write(wsa885x->regmap, WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x02);
+ }
+
+ regmap_multi_reg_write(wsa885x->regmap, unmute_finish_regs,
+ ARRAY_SIZE(unmute_finish_regs));
+ }
+
+exit_unlock:
+ mutex_unlock(&wsa885x->state_lock);
+
+ return ret;
+}
+
+static int wsa885x_codec_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ static const struct reg_sequence regs[] = {
+ { WSA885X_DIG_CTRL0_PA_FSM_CTL, 0x00 },
+ };
+ struct wsa885x_priv *wsa885x;
+
+ wsa885x = snd_soc_component_get_drvdata(dai->component);
+
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ mutex_lock(&wsa885x->state_lock);
+ regmap_multi_reg_write(wsa885x->regmap, regs, ARRAY_SIZE(regs));
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops wsa885x_dai_ops = {
+ .hw_params = wsa885x_codec_hw_params,
+ .set_tdm_slot = wsa885x_codec_set_tdm_slot,
+ .set_sysclk = wsa885x_codec_set_sysclk,
+ .mute_stream = wsa885x_codec_mute_stream,
+ .hw_free = wsa885x_codec_hw_free,
+};
+
+static struct snd_soc_dai_driver wsa885x_dai[] = {
+ {
+ .name = "wsa885x_dai_drv",
+ .playback = {
+ .stream_name = "WSA885X TDM Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = WSA885X_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &wsa885x_dai_ops,
+ },
+};
+
+static void wsa885x_reset_assert(void *data)
+{
+ struct wsa885x_priv *wsa885x = data;
+
+ if (wsa885x->sd_reset)
+ reset_control_assert(wsa885x->sd_reset);
+ else
+ gpiod_direction_output(wsa885x->sd_n, 1);
+}
+
+static void wsa885x_reset_deassert(struct wsa885x_priv *wsa885x)
+{
+ if (wsa885x->sd_reset)
+ reset_control_deassert(wsa885x->sd_reset);
+ else
+ gpiod_direction_output(wsa885x->sd_n, 0);
+}
+
+static int wsa885x_get_reset(struct device *dev, struct wsa885x_priv *wsa885x)
+{
+ wsa885x->sd_reset = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(wsa885x->sd_reset))
+ return dev_err_probe(dev, PTR_ERR(wsa885x->sd_reset),
+ "Failed to get reset\n");
+ else if (wsa885x->sd_reset)
+ return 0;
+
+ wsa885x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(wsa885x->sd_n))
+ return dev_err_probe(dev, PTR_ERR(wsa885x->sd_n),
+ "Shutdown Control GPIO not found\n");
+
+ return 0;
+}
+
+static bool wsa885x_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WSA885X_ANA_TOP_PLL_STATUS_0:
+ case WSA885X_ANA_TOP_PLL_STATUS_1:
+ case WSA885X_DIG_CTRL0_SDCA_COMMIT:
+ case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS:
+ case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID:
+ case WSA885X_INTR_STATUS0:
+ case WSA885X_INTR_STATUS0 + 1:
+ case WSA885X_INTR_STATUS0 + 2:
+ case WSA885X_INTR_CLEAR0:
+ case WSA885X_INTR_CLEAR0 + 1:
+ case WSA885X_INTR_CLEAR0 + 2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wsa885x_readable_register(struct device *dev, unsigned int reg)
+{
+ if (reg == WSA885X_INTR_CLEAR0 ||
+ reg == WSA885X_INTR_CLEAR0 + 1 ||
+ reg == WSA885X_INTR_CLEAR0 + 2)
+ return false;
+ return reg <= 0x88ff;
+}
+
+static bool wsa885x_writeable_register(struct device *dev, unsigned int reg)
+{
+ if (reg > 0x88ff)
+ return false;
+
+ switch (reg) {
+ case WSA885X_ANA_TOP_PLL_STATUS_0:
+ case WSA885X_ANA_TOP_PLL_STATUS_1:
+ case WSA885X_INTR_STATUS0:
+ case WSA885X_INTR_STATUS0 + 1:
+ case WSA885X_INTR_STATUS0 + 2:
+ case WSA885X_SMP_AMP_CTRL_STEREO_PDE23_ACT_PS:
+ case WSA885X_SMP_AMP_CTRL_STEREO_CS21_CLOCK_VALID:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config wsa885x_regmap_cfg = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x88FF,
+ .ranges = wsa885x_regmap_ranges,
+ .num_ranges = ARRAY_SIZE(wsa885x_regmap_ranges),
+ .reg_defaults = wsa885x_codec_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wsa885x_codec_reg_defaults),
+ .volatile_reg = wsa885x_volatile_register,
+ .writeable_reg = wsa885x_writeable_register,
+ .readable_reg = wsa885x_readable_register,
+ .cache_type = REGCACHE_MAPLE,
+ .use_single_read = true,
+ .use_single_write = true,
+};
+
+static int wsa885x_component_probe(struct snd_soc_component *component)
+{
+ struct wsa885x_priv *wsa885x =
+ snd_soc_component_get_drvdata(component);
+ int ret;
+
+ wsa885x->component = component;
+ snd_soc_component_init_regmap(component, wsa885x->regmap);
+
+ ret = wsa885x_hw_init(wsa885x);
+ if (ret)
+ return ret;
+
+ return wsa885x_unmask_interrupts(wsa885x);
+}
+
+static int wsa885x_stereo_gain_offset_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ int val;
+
+ mutex_lock(&wsa885x->state_lock);
+ val = wsa885x->stereo_vol_db + 84;
+ mutex_unlock(&wsa885x->state_lock);
+ if (val < 0 || val > WSA885X_FU21_VOL_STEPS)
+ return -ERANGE;
+
+ ucontrol->value.integer.value[0] = val;
+ return 0;
+}
+
+static int wsa885x_stereo_gain_offset_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ long val;
+ int stereo_vol_db;
+
+ val = ucontrol->value.integer.value[0];
+
+ if (val < 0 || val > WSA885X_FU21_VOL_STEPS) {
+ dev_err(component->dev, "%s: Invalid range, Val: %ld\n", __func__, val);
+ return -EINVAL;
+ }
+
+ stereo_vol_db = (int)val - 84;
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->stereo_vol_db == stereo_vol_db) {
+ mutex_unlock(&wsa885x->state_lock);
+ return 0;
+ }
+
+ wsa885x_program_stereo_volume(wsa885x, stereo_vol_db, true);
+ wsa885x->stereo_vol_db = stereo_vol_db;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 1;
+}
+
+static int wsa885x_usage_modes_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->usage_mode > WSA885X_USAGE_MODE_MAX) {
+ mutex_unlock(&wsa885x->state_lock);
+ return -ERANGE;
+ }
+
+ ucontrol->value.integer.value[0] = wsa885x->usage_mode;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 0;
+}
+
+static int wsa885x_usage_modes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ u32 val = ucontrol->value.integer.value[0];
+
+ if (val > WSA885X_USAGE_MODE_MAX)
+ return -EINVAL;
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->usage_mode == val) {
+ mutex_unlock(&wsa885x->state_lock);
+ return 0;
+ }
+
+ wsa885x->usage_mode = val;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 1;
+}
+
+static int wsa885x_rx_slot_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ u32 mask;
+
+ mutex_lock(&wsa885x->state_lock);
+ mask = wsa885x->rx_slot_mask;
+ mutex_unlock(&wsa885x->state_lock);
+ if (!wsa885x_is_valid_rx_slot_mask(mask))
+ return -ERANGE;
+
+ ucontrol->value.integer.value[0] = mask;
+
+ return 0;
+}
+
+static int wsa885x_rx_slot_mask_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct wsa885x_priv *wsa885x = snd_soc_component_get_drvdata(component);
+ u32 mask = ucontrol->value.integer.value[0];
+
+ if (!wsa885x_is_valid_rx_slot_mask(mask))
+ return -EINVAL;
+
+ mutex_lock(&wsa885x->state_lock);
+ if (wsa885x->rx_slot_mask == mask) {
+ mutex_unlock(&wsa885x->state_lock);
+ return 0;
+ }
+
+ wsa885x->rx_slot_mask = mask;
+ mutex_unlock(&wsa885x->state_lock);
+
+ return 1;
+}
+
+static const struct snd_kcontrol_new wsa885x_snd_controls[] = {
+ SOC_SINGLE_EXT("Usage Mode", SND_SOC_NOPM, 0, WSA885X_USAGE_MODE_MAX, 0,
+ wsa885x_usage_modes_get,
+ wsa885x_usage_modes_put),
+
+ SOC_SINGLE_EXT_TLV("Speaker Volume", SND_SOC_NOPM,
+ 0, WSA885X_FU21_VOL_STEPS, 0,
+ wsa885x_stereo_gain_offset_get,
+ wsa885x_stereo_gain_offset_put,
+ wsa885x_fu21_digital_gain),
+
+ SOC_SINGLE_EXT("Rx Slot Mask", SND_SOC_NOPM, 0, 3, 0,
+ wsa885x_rx_slot_mask_get,
+ wsa885x_rx_slot_mask_put),
+};
+
+static const struct snd_soc_component_driver wsa885x_component = {
+ .name = "wsa885x",
+ .probe = wsa885x_component_probe,
+ .controls = wsa885x_snd_controls,
+ .num_controls = ARRAY_SIZE(wsa885x_snd_controls),
+};
+
+static irqreturn_t wsa885x_handle_irq(int irq_idx, void *data)
+{
+ struct wsa885x_priv *wsa885x = data;
+
+ if (irq_idx < 0 || irq_idx >= WSA885X_IRQ_MAX)
+ return IRQ_NONE;
+
+ switch (irq_idx) {
+ case WSA885X_IRQ_INT_SAF2WAR:
+ case WSA885X_IRQ_INT_WAR2SAF:
+ case WSA885X_IRQ_INT_DISABLE:
+ case WSA885X_IRQ_INT_INTR_GPIO1_PIN:
+ case WSA885X_IRQ_INT_INTR_GPIO2_PIN:
+ case WSA885X_IRQ_INT_PA0_OCP:
+ case WSA885X_IRQ_INT_PA1_OCP:
+ case WSA885X_IRQ_INT_CLIP0:
+ case WSA885X_IRQ_INT_CLIP1:
+ case WSA885X_IRQ_INT_CLK_WD:
+ case WSA885X_IRQ_INT_BOP:
+ case WSA885X_IRQ_INT_UVLO:
+ case WSA885X_IRQ_INT_PCM_DATA0_DC:
+ case WSA885X_IRQ_INT_PCM_DATA1_DC:
+ case WSA885X_IRQ_INT_PLL_UNLOCKED:
+ case WSA885X_IRQ_INT_PROT_MODE_CHANGE:
+ case WSA885X_IRQ_INT_PB_CLOCK_VALID:
+ case WSA885X_IRQ_INT_SENSE_CLOCK_VALID:
+ break;
+ case WSA885X_IRQ_INT_PCM_DATA0_WD:
+ case WSA885X_IRQ_INT_PCM_DATA1_WD:
+ if (irq_idx == WSA885X_IRQ_INT_PCM_DATA0_WD)
+ wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD0_CTL1,
+ WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK);
+ else
+ wsa885x_toggle_irq_bit(wsa885x, WSA885X_DIG_CTRL0_PCM_DATA_WD1_CTL1,
+ WSA885X_PCM_DATA_WD_CTL1_PCM_DATA_WD_EN_MASK);
+ break;
+ case WSA885X_IRQ_INT_PA0_FSM_ERR:
+ case WSA885X_IRQ_INT_PA1_FSM_ERR:
+ case WSA885X_IRQ_INT_MAIN_FSM_ERR:
+ if (irq_idx == WSA885X_IRQ_INT_MAIN_FSM_ERR) {
+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_DIG_CTRL0_POWER_FSM_CTL0,
+ WSA885X_POWER_FSM_CTL0_CLEAR_ERROR_MASK);
+ } else if (irq_idx == WSA885X_IRQ_INT_PA0_FSM_ERR) {
+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA0_FSM_CTL0,
+ WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK);
+ } else if (irq_idx == WSA885X_IRQ_INT_PA1_FSM_ERR) {
+ wsa885x_pulse_irq_bit(wsa885x, WSA885X_PA1_FSM_CTL0,
+ WSA885X_PA_FSM_CTL0_CLEAR_ERROR_MASK);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wsa885x_interrupt_handler(int irq, void *data)
+{
+ static const unsigned int status_reg[WSA885X_NUM_REGS] = {
+ WSA885X_INTR_STATUS0,
+ WSA885X_INTR_STATUS0 + 1,
+ WSA885X_INTR_STATUS0 + 2,
+ };
+ static const unsigned int clear_reg[WSA885X_NUM_REGS] = {
+ WSA885X_INTR_CLEAR0,
+ WSA885X_INTR_CLEAR0 + 1,
+ WSA885X_INTR_CLEAR0 + 2,
+ };
+ unsigned int status[WSA885X_NUM_REGS] = { 0 };
+ struct wsa885x_priv *wsa885x = data;
+ irqreturn_t handled = IRQ_NONE;
+ irqreturn_t irq_ret;
+ int i, bit, ret, irq_num;
+
+ for (i = 0; i < WSA885X_NUM_REGS; i++) {
+ ret = regmap_read(wsa885x->regmap, status_reg[i], &status[i]);
+ if (ret) {
+ dev_err(wsa885x->dev,
+ "Failed to read status_reg[%d] (0x%x): %d\n",
+ i, status_reg[i], ret);
+ status[i] = 0;
+ continue;
+ }
+ }
+
+ for (i = 0; i < WSA885X_NUM_REGS; i++) {
+ for (bit = 0; bit < 8; bit++) {
+ if (status[i] & BIT(bit)) {
+ irq_num = i * 8 + bit;
+ regmap_write(wsa885x->regmap, clear_reg[i], BIT(bit));
+ regmap_write(wsa885x->regmap, clear_reg[i], 0);
+ if (irq_num >= WSA885X_IRQ_MAX) {
+ dev_warn_ratelimited(wsa885x->dev,
+ "Unexpected IRQ bit %d (reg %d)\n",
+ bit, i);
+ handled = IRQ_HANDLED;
+ continue;
+ }
+ irq_ret = wsa885x_handle_irq(irq_num, wsa885x);
+ if (irq_ret == IRQ_HANDLED)
+ handled = IRQ_HANDLED;
+ }
+ }
+ }
+ return handled;
+}
+
+static int wsa885x_register_irq(struct wsa885x_priv *wsa885x)
+{
+ if (!wsa885x->client->irq)
+ return dev_err_probe(wsa885x->dev, -EINVAL,
+ "IRQ is not configured\n");
+
+ return devm_request_threaded_irq(wsa885x->dev, wsa885x->client->irq, NULL,
+ wsa885x_interrupt_handler,
+ IRQF_ONESHOT,
+ dev_name(wsa885x->dev), wsa885x);
+}
+
+static int wsa885x_probe(struct i2c_client *client)
+{
+ struct wsa885x_priv *wsa885x;
+ const struct snd_soc_component_driver *component_driver = &wsa885x_component;
+ const char *battery_config;
+ unsigned int i;
+ int ret;
+ struct device *dev = &client->dev;
+
+ wsa885x = devm_kzalloc(dev, sizeof(*wsa885x), GFP_KERNEL);
+ if (!wsa885x)
+ return -ENOMEM;
+
+ wsa885x->client = client;
+ wsa885x->dev = dev;
+ wsa885x->stereo_vol_db = -84;
+ wsa885x->rx_slot_mask = WSA885X_CHANNEL_STEREO;
+ mutex_init(&wsa885x->state_lock);
+ wsa885x->regmap = devm_regmap_init_i2c(client, &wsa885x_regmap_cfg);
+
+ if (IS_ERR(wsa885x->regmap))
+ return PTR_ERR(wsa885x->regmap);
+
+ ret = device_property_read_string(dev, "qcom,battery-config",
+ &battery_config);
+ if (ret) {
+ wsa885x->batt_conf = WSA885X_BATT_1S;
+ } else if (!strcmp(battery_config, "1s")) {
+ wsa885x->batt_conf = WSA885X_BATT_1S;
+ } else if (!strcmp(battery_config, "2s")) {
+ wsa885x->batt_conf = WSA885X_BATT_2S;
+ } else {
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid battery config %s (expected 1s or 2s)\n",
+ battery_config);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(wsa885x_supply_name); i++) {
+ ret = devm_regulator_get_enable(dev, wsa885x_supply_name[i]);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable regulator %s\n",
+ wsa885x_supply_name[i]);
+ }
+
+ ret = wsa885x_get_reset(dev, wsa885x);
+ if (ret)
+ return ret;
+
+ wsa885x_reset_deassert(wsa885x);
+ usleep_range(5000, 5500);
+
+ ret = devm_add_action_or_reset(dev, wsa885x_reset_assert, wsa885x);
+ if (ret)
+ return dev_err_probe(dev, ret, "devm_add_action_or_reset failed\n");
+
+ i2c_set_clientdata(client, wsa885x);
+
+ ret = wsa885x_register_irq(wsa885x);
+ if (ret)
+ return dev_err_probe(dev, ret, "wsa885x irq registration failed\n");
+
+ ret = devm_snd_soc_register_component(dev, component_driver,
+ wsa885x_dai,
+ ARRAY_SIZE(wsa885x_dai));
+ if (ret)
+ return dev_err_probe(dev, ret, "Codec component registration failed\n");
+
+ return 0;
+}
+
+static const struct of_device_id wsa885x_dt_match[] = {
+ {
+ .compatible = "qcom,wsa8855",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, wsa885x_dt_match);
+
+static const struct i2c_device_id wsa885x_id[] = {
+ {
+ .name = "wsa885x",
+ .driver_data = 0,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, wsa885x_id);
+
+static struct i2c_driver wsa885x_driver = {
+ .driver = {
+ .name = "wsa885x",
+ .of_match_table = wsa885x_dt_match,
+ },
+ .probe = wsa885x_probe,
+ .id_table = wsa885x_id,
+};
+
+module_i2c_driver(wsa885x_driver);
+
+MODULE_DESCRIPTION("ASoC WSA885X Stereo Smart PA Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c
index 7de4014e626d..894b8eb42e39 100644
--- a/sound/soc/codecs/zl38060.c
+++ b/sound/soc/codecs/zl38060.c
@@ -162,7 +162,7 @@ static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data)
static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
{
const struct ihex_binrec *rec;
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
u32 addr;
u16 len;
int err;
@@ -180,7 +180,7 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
return err;
err = zl38_fw_enter_boot_mode(regmap);
if (err)
- goto out;
+ return err;
rec = (const struct ihex_binrec *)fw->data;
while (rec) {
addr = be32_to_cpu(rec->addr);
@@ -195,15 +195,12 @@ static int zl38_load_firmware(struct device *dev, struct regmap *regmap)
err = -EINVAL;
}
if (err)
- goto out;
+ return err;
/* next ! */
rec = ihex_next_binrec(rec);
}
- err = zl38_fw_go(regmap);
-out:
- release_firmware(fw);
- return err;
+ return zl38_fw_go(regmap);
}
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 74dfd39fd604..2e9fb79b1cd8 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -955,7 +955,9 @@ static int dw_i2s_probe(struct platform_device *pdev)
}
irq = platform_get_irq_optional(pdev, 0);
- if (irq >= 0) {
+ if (irq == -EPROBE_DEFER)
+ return irq;
+ if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0,
pdev->name, dev);
if (ret < 0) {
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 709543308fe9..310ee4c282a1 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -69,7 +69,6 @@ static const struct snd_pcm_hw_constraint_list cs42888_channel_constraints = {
/**
* struct codec_priv - CODEC private data
- * @mclk: Main clock of the CODEC
* @mclk_freq: Clock rate of MCLK
* @free_freq: Clock rate of MCLK for hw_free()
* @mclk_id: MCLK (or main clock) id for set_sysclk()
@@ -80,7 +79,6 @@ static const struct snd_pcm_hw_constraint_list cs42888_channel_constraints = {
* to stay within PLL frequency limits
*/
struct codec_priv {
- struct clk *mclk;
unsigned long mclk_freq;
unsigned long free_freq;
u32 mclk_id;
@@ -109,12 +107,58 @@ struct cpu_priv {
u32 slot_num;
};
+struct fsl_asoc_card_priv;
+
+/*
+ * struct fsl_asoc_card_pdata - per-compatible static card description
+ * @sysclk_dir: initial CPU SYSCLK direction override (0 = leave default IN)
+ * @sysclk_ratio: SYSCLK ratio on sample rate (0 = not used)
+ * @slot_width: TDM slot width (0 = not TDM)
+ * @codec_dai_name: name of the codec DAI
+ * @codec_mclk_id: MCLK id passed to set_sysclk() for the codec
+ * @codec_fll_id: FLL id; only valid when has_pll is true
+ * @codec_pll_id: PLL id; only valid when has_pll is true
+ * @codec_pll_ratio_s24: PLL output ratio for S24_LE
+ * @has_pll: codec uses PLL/FLL; codec_fll_id and codec_pll_id are valid
+ * @dai_fmt: DAI format flags
+ * @playback_only: restrict card to playback direction
+ * @capture_only: restrict card to capture direction
+ * @dapm_routes: DAPM route table override
+ * @num_dapm_routes: number of entries in dapm_routes
+ * @exclude_format: PCM format bitmask excluded (for SAI + WM8960/WM8962)
+ * @codec_init: codec-specific init run after mclk_freq is populated
+ * @probe_init: optional DT-driven init run at end of probe() (e.g. SPDIF codec discovery)
+ */
+struct fsl_asoc_card_pdata {
+ u32 sysclk_dir[2];
+ u32 sysclk_ratio[2];
+ u32 slot_width;
+ const char *codec_dai_name;
+ u32 codec_mclk_id;
+ int codec_fll_id;
+ int codec_pll_id;
+ int codec_pll_ratio_s24;
+ bool has_pll;
+ bool playback_only;
+ bool capture_only;
+ u32 dai_fmt;
+ const struct snd_soc_dapm_route *dapm_routes;
+ int num_dapm_routes;
+ u64 exclude_format;
+ int (*codec_init)(struct fsl_asoc_card_priv *priv);
+ int (*probe_init)(struct device_node *codec_np[],
+ struct device_node *cpu_np,
+ const char *codec_dai_name[],
+ struct fsl_asoc_card_priv *priv);
+};
+
/**
* struct fsl_asoc_card_priv - Freescale Generic ASOC card private data
* @dai_link: DAI link structure including normal one and DPCM link
* @hp_jack: Headphone Jack structure
* @mic_jack: Microphone Jack structure
* @pdev: platform device pointer
+ * @pdata: pointer to the per-compatible card platform data
* @codec_priv: CODEC private data
* @cpu_priv: CPU private data
* @card: ASoC card structure
@@ -135,6 +179,7 @@ struct fsl_asoc_card_priv {
struct simple_util_jack hp_jack;
struct simple_util_jack mic_jack;
struct platform_device *pdev;
+ const struct fsl_asoc_card_pdata *pdata;
struct codec_priv codec_priv[2];
struct cpu_priv cpu_priv;
struct snd_soc_card card;
@@ -609,6 +654,192 @@ static int fsl_asoc_card_spdif_init(struct device_node *codec_np[],
return 0;
}
+static int fsl_asoc_card_cs42888_codec_init(struct fsl_asoc_card_priv *priv)
+{
+ unsigned long mclk_freq = priv->codec_priv[0].mclk_freq;
+
+ /*
+ * Set CPU sysclk frequency from codec MCLK only if not already
+ * set by the CPU DAI init (e.g. ESAI extal clock takes precedence).
+ */
+ if (!priv->cpu_priv.sysclk_freq[TX])
+ priv->cpu_priv.sysclk_freq[TX] = mclk_freq;
+ if (!priv->cpu_priv.sysclk_freq[RX])
+ priv->cpu_priv.sysclk_freq[RX] = mclk_freq;
+
+ priv->constraint_channels = &cs42888_channel_constraints;
+ if (mclk_freq % 12288000 == 0)
+ priv->constraint_rates = &cs42888_rate_48k_constraints;
+ else if (mclk_freq % 11289600 == 0)
+ priv->constraint_rates = &cs42888_rate_44k_constraints;
+ else
+ dev_warn(&priv->pdev->dev,
+ "Unknown MCLK frequency %lu, no rate constraints\n",
+ mclk_freq);
+
+ return 0;
+}
+
+static int fsl_asoc_card_wm8958_codec_init(struct fsl_asoc_card_priv *priv)
+{
+ priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq;
+ return 0;
+}
+
+static const struct fsl_asoc_card_pdata fsl_asoc_cs42888_pdata = {
+ .codec_dai_name = "cs42888",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC,
+ .sysclk_dir = { SND_SOC_CLOCK_OUT, SND_SOC_CLOCK_OUT },
+ .slot_width = 32,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+ .codec_init = fsl_asoc_card_cs42888_codec_init,
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_cs427x_pdata = {
+ .codec_dai_name = "cs4271-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .codec_mclk_id = CS427x_SYSCLK_MCLK,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_sgtl5000_pdata = {
+ .codec_dai_name = "sgtl5000",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .codec_mclk_id = SGTL5000_SYSCLK,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_tlv320aic32x4_pdata = {
+ .codec_dai_name = "tlv320aic32x4-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_tlv320aic31xx_pdata = {
+ .codec_dai_name = "tlv320dac31xx-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC,
+ .sysclk_dir = { SND_SOC_CLOCK_OUT, SND_SOC_CLOCK_OUT },
+ .playback_only = true,
+ .dapm_routes = audio_map_tx,
+ .num_dapm_routes = ARRAY_SIZE(audio_map_tx),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_wm8962_pdata = {
+ .codec_dai_name = "wm8962",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .codec_mclk_id = WM8962_SYSCLK_MCLK,
+ .has_pll = true,
+ .codec_fll_id = WM8962_SYSCLK_FLL,
+ .codec_pll_id = WM8962_FLL,
+ /*
+ * WM8962 has same BCLK generation limitations as WM8960.
+ * See WM8960 section for detailed explanation.
+ */
+ .exclude_format = SNDRV_PCM_FMTBIT_S20_3LE,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_wm8960_pdata = {
+ .codec_dai_name = "wm8960-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .has_pll = true,
+ .codec_fll_id = WM8960_SYSCLK_AUTO,
+ .codec_pll_id = WM8960_SYSCLK_AUTO,
+ /*
+ * WM8960 in master mode cannot generate exact 1.92 MHz BCLK
+ * required for S20_3LE (48kHz x 2ch x 20bit). Closest available
+ * is 2.048 MHz (SYSCLK/6), which causes right channel corruption.
+ *
+ * In SAI master mode, SAI derive BCLK from MCLK using integer
+ * dividers only. S20_3LE requires non-integer divider ratios
+ * with standard MCLK frequencies. For example, 48kHz stereo
+ * needs 1.920 MHz BCLK, which requires a divider of 6.4 from
+ * 12.288 MHz MCLK (not an integer).
+ */
+ .exclude_format = SNDRV_PCM_FMTBIT_S20_3LE,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_ac97_pdata = {
+ .codec_dai_name = "ac97-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_AC97,
+ .dapm_routes = audio_map_ac97,
+ .num_dapm_routes = ARRAY_SIZE(audio_map_ac97),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_mqs_pdata = {
+ .codec_dai_name = "fsl-mqs-dai",
+ .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBC_CFC |
+ SND_SOC_DAIFMT_NB_NF,
+ .playback_only = true,
+ .dapm_routes = audio_map_tx,
+ .num_dapm_routes = ARRAY_SIZE(audio_map_tx),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_wm8524_pdata = {
+ .codec_dai_name = "wm8524-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC,
+ /* RX=0, TX=1: set TX (index 1) to CLOCK_OUT, RX stays at default IN */
+ .sysclk_dir = { 0, SND_SOC_CLOCK_OUT },
+ .sysclk_ratio = { 0, 256 },
+ .slot_width = 32,
+ .playback_only = true,
+ .dapm_routes = audio_map_tx,
+ .num_dapm_routes = ARRAY_SIZE(audio_map_tx),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_si476x_pdata = {
+ .codec_dai_name = "si476x-codec",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBC_CFC,
+ .dapm_routes = audio_map_rx,
+ .num_dapm_routes = ARRAY_SIZE(audio_map_rx),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_wm8958_pdata = {
+ .codec_dai_name = "wm8994-aif1",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .codec_mclk_id = WM8994_FLL_SRC_MCLK1,
+ .has_pll = true,
+ .codec_fll_id = WM8994_SYSCLK_FLL1,
+ .codec_pll_id = WM8994_FLL1,
+ .codec_init = fsl_asoc_card_wm8958_codec_init,
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_nau8822_pdata = {
+ .codec_dai_name = "nau8822-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .codec_mclk_id = NAU8822_CLK_MCLK,
+ .has_pll = true,
+ .codec_fll_id = NAU8822_CLK_PLL,
+ .codec_pll_id = NAU8822_CLK_PLL,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_wm8904_pdata = {
+ .codec_dai_name = "wm8904-hifi",
+ .dai_fmt = DAI_FMT_BASE | SND_SOC_DAIFMT_CBP_CFP,
+ .codec_mclk_id = WM8904_FLL_MCLK,
+ .has_pll = true,
+ .codec_fll_id = WM8904_CLK_FLL,
+ .codec_pll_id = WM8904_FLL_MCLK,
+ .codec_pll_ratio_s24 = 192,
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static const struct fsl_asoc_card_pdata fsl_asoc_spdif_pdata = {
+ .codec_dai_name = "spdif",
+ .dai_fmt = DAI_FMT_BASE,
+ .probe_init = fsl_asoc_card_spdif_init,
+};
+
static int hp_jack_event(struct notifier_block *nb, unsigned long event,
void *data)
{
@@ -643,17 +874,173 @@ static struct notifier_block mic_jack_nb = {
.notifier_call = mic_jack_event,
};
-static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
+/*
+ * fsl_asoc_card_init_cpu - configure CPU DAI-specific settings.
+ *
+ * Called from late_probe() when the CPU DAI component is guaranteed bound.
+ */
+static int fsl_asoc_card_init_cpu(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd)
{
struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
- struct snd_soc_pcm_runtime *rtd = list_first_entry(
- &card->rtd_list, struct snd_soc_pcm_runtime, list);
+ struct device_node *np = priv->pdev->dev.of_node;
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ const char *comp_drv_name = cpu_dai->component->driver->name;
+ struct device *dev = card->dev;
+ int ret;
+
+ if (!strcmp(comp_drv_name, "fsl-ssi")) {
+ /* Only SSI needs to configure AUDMUX */
+ ret = fsl_asoc_card_audmux_init(np, priv);
+ if (ret) {
+ dev_err(dev, "failed to init audmux\n");
+ return ret;
+ }
+ } else if (!strcmp(comp_drv_name, "fsl-esai")) {
+ struct clk *esai_clk = clk_get(cpu_dai->dev, "extal");
+
+ if (!IS_ERR(esai_clk)) {
+ priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk);
+ priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk);
+ clk_put(esai_clk);
+ } else {
+ dev_warn(dev, "failed to get ESAI extal clock: %ld\n", PTR_ERR(esai_clk));
+ }
+
+ priv->cpu_priv.sysclk_id[TX] = ESAI_HCKT_EXTAL;
+ priv->cpu_priv.sysclk_id[RX] = ESAI_HCKR_EXTAL;
+ } else if (!strcmp(comp_drv_name, "fsl-sai")) {
+ priv->cpu_priv.sysclk_id[TX] = FSL_SAI_CLK_MAST1;
+ priv->cpu_priv.sysclk_id[RX] = FSL_SAI_CLK_MAST1;
+
+ if (priv->pdata->exclude_format)
+ priv->exclude_format = priv->pdata->exclude_format;
+ }
+
+ return 0;
+}
+
+/*
+ * fsl_asoc_card_init_codecs - read codec MCLK rates and set codec sysclk.
+ *
+ * Called from late_probe() after all components are bound.
+ */
+static int fsl_asoc_card_init_codecs(struct snd_soc_card *card,
+ struct snd_soc_pcm_runtime *rtd)
+{
+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+ const struct fsl_asoc_card_pdata *pdata = priv->pdata;
struct snd_soc_dai *codec_dai;
struct codec_priv *codec_priv;
struct device *dev = card->dev;
int codec_idx;
int ret;
+ /* Read MCLK rate from each bound codec component */
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ struct clk *codec_clk = clk_get(codec_dai->component->dev, NULL);
+
+ codec_priv = &priv->codec_priv[codec_idx];
+ if (!IS_ERR(codec_clk)) {
+ codec_priv->mclk_freq = clk_get_rate(codec_clk);
+ clk_put(codec_clk);
+ }
+ }
+
+ if (pdata->codec_init) {
+ ret = pdata->codec_init(priv);
+ if (ret)
+ return ret;
+ }
+
+ for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
+ codec_priv = &priv->codec_priv[codec_idx];
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
+ codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(dev, "failed to set sysclk in %s\n", __func__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void fsl_asoc_card_free_jack(struct snd_soc_card *card)
+{
+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+
+ if (priv->hp_jack.gpio.desc) {
+ snd_soc_jack_notifier_unregister(&priv->hp_jack.jack, &hp_jack_nb);
+ snd_soc_jack_free_gpios(&priv->hp_jack.jack, 1, &priv->hp_jack.gpio);
+ priv->hp_jack.gpio.desc = NULL;
+ }
+
+ if (priv->mic_jack.gpio.desc) {
+ snd_soc_jack_notifier_unregister(&priv->mic_jack.jack, &mic_jack_nb);
+ snd_soc_jack_free_gpios(&priv->mic_jack.jack, 1, &priv->mic_jack.gpio);
+ priv->mic_jack.gpio.desc = NULL;
+ }
+}
+
+/*
+ * fsl_asoc_card_init_jack - register optional headphone and mic jacks.
+ *
+ * Called from late_probe() once per card bind cycle.
+ */
+static int fsl_asoc_card_init_jack(struct snd_soc_card *card)
+{
+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+ struct device_node *np = priv->pdev->dev.of_node;
+ int ret;
+
+ /*
+ * Properties "hp-det-gpios" and "mic-det-gpios" are optional.
+ * simple_util_init_jack() checks for the GPIO property and
+ * does nothing if it is absent.
+ */
+ if (of_property_present(np, "hp-det-gpios") ||
+ of_property_present(np, "hp-det-gpio") /* deprecated */) {
+ ret = simple_util_init_jack(card, &priv->hp_jack,
+ 1, NULL, "Headphone Jack");
+ if (ret)
+ return ret;
+
+ snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb);
+ }
+
+ if (of_property_present(np, "mic-det-gpios") ||
+ of_property_present(np, "mic-det-gpio") /* deprecated */) {
+ ret = simple_util_init_jack(card, &priv->mic_jack,
+ 0, NULL, "Mic Jack");
+ if (ret)
+ return ret;
+
+ snd_soc_jack_notifier_register(&priv->mic_jack.jack, &mic_jack_nb);
+ }
+
+ return 0;
+}
+
+static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
+{
+ struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
+ struct snd_soc_pcm_runtime *rtd;
+ int ret;
+
+ /* Use the first rtd which carries the CPU+codec DAIs */
+ rtd = list_first_entry(&card->rtd_list,
+ struct snd_soc_pcm_runtime, list);
+
+ ret = fsl_asoc_card_init_jack(card);
+ if (ret)
+ goto jack_fail;
+
+ ret = fsl_asoc_card_init_cpu(card, rtd);
+ if (ret)
+ goto jack_fail;
+
if (fsl_asoc_card_is_ac97(priv)) {
#if IS_ENABLED(CONFIG_SND_AC97_CODEC)
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
@@ -671,19 +1058,20 @@ static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
return 0;
}
- for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
- codec_priv = &priv->codec_priv[codec_idx];
+ ret = fsl_asoc_card_init_codecs(card, rtd);
+ if (ret)
+ goto jack_fail;
- ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
- codec_priv->mclk_freq, SND_SOC_CLOCK_IN);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dev, "failed to set sysclk in %s\n", __func__);
- return ret;
- }
+ return 0;
- if (!IS_ERR_OR_NULL(codec_priv->mclk))
- clk_prepare_enable(codec_priv->mclk);
- }
+jack_fail:
+ fsl_asoc_card_free_jack(card);
+ return ret;
+}
+
+static int fsl_asoc_card_card_remove(struct snd_soc_card *card)
+{
+ fsl_asoc_card_free_jack(card);
return 0;
}
@@ -697,12 +1085,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
struct platform_device *asrc_pdev = NULL;
struct device_node *bitclkprovider = NULL;
struct device_node *frameprovider = NULL;
- struct platform_device *cpu_pdev;
struct fsl_asoc_card_priv *priv;
- struct device *codec_dev[2] = { NULL, NULL };
+ const struct fsl_asoc_card_pdata *pdata;
struct snd_soc_dai_link_component *dlc;
- const char *codec_dai_name[2];
- const char *codec_dev_name[2];
+ const char *codec_dai_name[2] = { NULL, NULL };
u32 asrc_fmt = 0;
int codec_idx;
u32 width;
@@ -714,6 +1100,13 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->pdev = pdev;
+ pdata = of_device_get_match_data(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "unknown Device Tree compatible\n");
+ return -EINVAL;
+ }
+ priv->pdata = pdata;
+
cpu_np = of_parse_phandle(np, "audio-cpu", 0);
/* Give a chance to old DT bindings */
if (!cpu_np)
@@ -726,52 +1119,13 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto fail;
}
- cpu_pdev = of_find_device_by_node(cpu_np);
- if (!cpu_pdev) {
- dev_err(&pdev->dev, "failed to find CPU DAI device\n");
- ret = -EINVAL;
- goto fail;
- }
-
codec_np[0] = of_parse_phandle(np, "audio-codec", 0);
codec_np[1] = of_parse_phandle(np, "audio-codec", 1);
- for (codec_idx = 0; codec_idx < 2; codec_idx++) {
- if (codec_np[codec_idx]) {
- struct platform_device *codec_pdev;
- struct i2c_client *codec_i2c;
-
- codec_i2c = of_find_i2c_device_by_node(codec_np[codec_idx]);
- if (codec_i2c) {
- codec_dev[codec_idx] = &codec_i2c->dev;
- codec_dev_name[codec_idx] = codec_i2c->name;
- }
- if (!codec_dev[codec_idx]) {
- codec_pdev = of_find_device_by_node(codec_np[codec_idx]);
- if (codec_pdev) {
- codec_dev[codec_idx] = &codec_pdev->dev;
- codec_dev_name[codec_idx] = codec_pdev->name;
- }
- }
- }
- }
-
asrc_np = of_parse_phandle(np, "audio-asrc", 0);
if (asrc_np)
asrc_pdev = of_find_device_by_node(asrc_np);
- /* Get the MCLK rate only, and leave it controlled by CODEC drivers */
- for (codec_idx = 0; codec_idx < 2; codec_idx++) {
- if (codec_dev[codec_idx]) {
- struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL);
-
- if (!IS_ERR(codec_clk)) {
- priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk);
- clk_put(codec_clk);
- }
- }
- }
-
/* Default sample rate and format, will be updated in hw_params() */
priv->sample_rate = 44100;
priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
@@ -823,133 +1177,40 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
/* Diversify the card configurations */
- if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) {
- codec_dai_name[0] = "cs42888";
- priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv[0].mclk_freq;
- priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv[0].mclk_freq;
- priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
- priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
- priv->cpu_priv.slot_width = 32;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
- priv->constraint_channels = &cs42888_channel_constraints;
- if (priv->codec_priv[0].mclk_freq % 12288000 == 0)
- priv->constraint_rates = &cs42888_rate_48k_constraints;
- else if (priv->codec_priv[0].mclk_freq % 11289600 == 0)
- priv->constraint_rates = &cs42888_rate_44k_constraints;
- else
- dev_warn(&pdev->dev, "Unknown MCLK frequency %lu, no rate constraints\n",
- priv->codec_priv[0].mclk_freq);
- } else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) {
- codec_dai_name[0] = "cs4271-hifi";
- priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
- codec_dai_name[0] = "sgtl5000";
- priv->codec_priv[0].mclk_id = SGTL5000_SYSCLK;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) {
- codec_dai_name[0] = "tlv320aic32x4-hifi";
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) {
- codec_dai_name[0] = "tlv320dac31xx-hifi";
- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
- priv->dai_link[1].playback_only = 1;
- priv->dai_link[2].playback_only = 1;
- priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
- priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
- priv->card.dapm_routes = audio_map_tx;
- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
- codec_dai_name[0] = "wm8962";
- priv->codec_priv[0].mclk_id = WM8962_SYSCLK_MCLK;
- priv->codec_priv[0].fll_id = WM8962_SYSCLK_FLL;
- priv->codec_priv[0].pll_id = WM8962_FLL;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- /*
- * WM8962 has same BCLK generation limitations as WM8960.
- * See WM8960 section for detailed explanation.
- */
- if (of_node_name_eq(cpu_np, "sai"))
- priv->exclude_format = SNDRV_PCM_FMTBIT_S20_3LE;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8960")) {
- codec_dai_name[0] = "wm8960-hifi";
- priv->codec_priv[0].fll_id = WM8960_SYSCLK_AUTO;
- priv->codec_priv[0].pll_id = WM8960_SYSCLK_AUTO;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- /*
- * WM8960 in master mode cannot generate exact 1.92 MHz BCLK
- * required for S20_3LE (48kHz × 2ch × 20bit). Closest available
- * is 2.048 MHz (SYSCLK/6), which causes right channel corruption.
- *
- * In SAI master mode, SAI derive BCLK from MCLK using integer
- * dividers only. S20_3LE requires non-integer divider ratios
- * with standard MCLK frequencies. For example, 48kHz stereo
- * needs 1.920 MHz BCLK, which requires a divider of 6.4 from
- * 12.288 MHz MCLK (not an integer).
- */
- if (of_node_name_eq(cpu_np, "sai"))
- priv->exclude_format = SNDRV_PCM_FMTBIT_S20_3LE;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-ac97")) {
- codec_dai_name[0] = "ac97-hifi";
- priv->dai_fmt = SND_SOC_DAIFMT_AC97;
- priv->card.dapm_routes = audio_map_ac97;
- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_ac97);
- } else if (of_device_is_compatible(np, "fsl,imx-audio-mqs")) {
- codec_dai_name[0] = "fsl-mqs-dai";
- priv->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
- SND_SOC_DAIFMT_CBC_CFC |
- SND_SOC_DAIFMT_NB_NF;
- priv->dai_link[1].playback_only = 1;
- priv->dai_link[2].playback_only = 1;
- priv->card.dapm_routes = audio_map_tx;
- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8524")) {
- codec_dai_name[0] = "wm8524-hifi";
- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
+ priv->cpu_priv.sysclk_dir[TX] = pdata->sysclk_dir[TX];
+ priv->cpu_priv.sysclk_dir[RX] = pdata->sysclk_dir[RX];
+ priv->cpu_priv.sysclk_ratio[TX] = pdata->sysclk_ratio[TX];
+ priv->cpu_priv.sysclk_ratio[RX] = pdata->sysclk_ratio[RX];
+ priv->cpu_priv.slot_width = pdata->slot_width;
+
+ codec_dai_name[0] = pdata->codec_dai_name;
+ priv->codec_priv[0].mclk_id = pdata->codec_mclk_id;
+ if (pdata->has_pll) {
+ priv->codec_priv[0].fll_id = pdata->codec_fll_id;
+ priv->codec_priv[0].pll_id = pdata->codec_pll_id;
+ }
+ if (pdata->codec_pll_ratio_s24)
+ priv->codec_priv[0].pll_ratio_s24 = pdata->codec_pll_ratio_s24;
+
+ if (pdata->playback_only) {
priv->dai_link[1].playback_only = 1;
priv->dai_link[2].playback_only = 1;
- priv->cpu_priv.slot_width = 32;
- priv->card.dapm_routes = audio_map_tx;
- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_tx);
- priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
- priv->cpu_priv.sysclk_ratio[TX] = 256;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-si476x")) {
- codec_dai_name[0] = "si476x-codec";
- priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
- priv->card.dapm_routes = audio_map_rx;
- priv->card.num_dapm_routes = ARRAY_SIZE(audio_map_rx);
- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8958")) {
- codec_dai_name[0] = "wm8994-aif1";
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- priv->codec_priv[0].mclk_id = WM8994_FLL_SRC_MCLK1;
- priv->codec_priv[0].fll_id = WM8994_SYSCLK_FLL1;
- priv->codec_priv[0].pll_id = WM8994_FLL1;
- priv->codec_priv[0].free_freq = priv->codec_priv[0].mclk_freq;
- priv->card.dapm_routes = NULL;
- priv->card.num_dapm_routes = 0;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-nau8822")) {
- codec_dai_name[0] = "nau8822-hifi";
- priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK;
- priv->codec_priv[0].fll_id = NAU8822_CLK_PLL;
- priv->codec_priv[0].pll_id = NAU8822_CLK_PLL;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- if (codec_dev[0])
- priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL);
- } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) {
- codec_dai_name[0] = "wm8904-hifi";
- priv->codec_priv[0].mclk_id = WM8904_FLL_MCLK;
- priv->codec_priv[0].fll_id = WM8904_CLK_FLL;
- priv->codec_priv[0].pll_id = WM8904_FLL_MCLK;
- priv->codec_priv[0].pll_ratio_s24 = 192;
- priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP;
- } else if (of_device_is_compatible(np, "fsl,imx-audio-spdif")) {
- ret = fsl_asoc_card_spdif_init(codec_np, cpu_np, codec_dai_name, priv);
+ }
+ if (pdata->capture_only) {
+ priv->dai_link[1].capture_only = 1;
+ priv->dai_link[2].capture_only = 1;
+ }
+
+ priv->dai_fmt = pdata->dai_fmt;
+
+ priv->card.dapm_routes = pdata->dapm_routes;
+ priv->card.num_dapm_routes = pdata->num_dapm_routes;
+
+ if (pdata->probe_init) {
+ ret = pdata->probe_init(codec_np, cpu_np,
+ codec_dai_name, priv);
if (ret)
goto asrc_fail;
- } else {
- dev_err(&pdev->dev, "unknown Device Tree compatible\n");
- ret = -EINVAL;
- goto asrc_fail;
}
/*
@@ -995,51 +1256,21 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
of_node_put(bitclkprovider);
of_node_put(frameprovider);
- if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]
- && codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) {
- dev_dbg(&pdev->dev, "failed to find codec device\n");
- ret = -EPROBE_DEFER;
- goto asrc_fail;
- }
-
- /* Common settings for corresponding Freescale CPU DAI driver */
- if (of_node_name_eq(cpu_np, "ssi")) {
- /* Only SSI needs to configure AUDMUX */
- ret = fsl_asoc_card_audmux_init(np, priv);
- if (ret) {
- dev_err(&pdev->dev, "failed to init audmux\n");
- goto asrc_fail;
- }
- } else if (of_node_name_eq(cpu_np, "esai")) {
- struct clk *esai_clk = clk_get(&cpu_pdev->dev, "extal");
-
- if (!IS_ERR(esai_clk)) {
- priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk);
- priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk);
- clk_put(esai_clk);
- } else if (PTR_ERR(esai_clk) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
- goto asrc_fail;
- }
-
- priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
- priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
- } else if (of_node_name_eq(cpu_np, "sai")) {
- priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1;
- priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1;
- }
-
/* Initialize sound card */
priv->card.dev = &pdev->dev;
priv->card.owner = THIS_MODULE;
ret = snd_soc_of_parse_card_name(&priv->card, "model");
if (ret) {
- snprintf(priv->name, sizeof(priv->name), "%s-audio",
- fsl_asoc_card_is_ac97(priv) ? "ac97" : codec_dev_name[0]);
- priv->card.name = priv->name;
+ /*
+ * "model" is required by the DT binding. Enforce it here so
+ * the driver fails with a clear message.
+ */
+ dev_err(&pdev->dev, "Error parsing card name: %d\n", ret);
+ goto asrc_fail;
}
priv->card.dai_link = priv->dai_link;
priv->card.late_probe = fsl_asoc_card_late_probe;
+ priv->card.remove = fsl_asoc_card_card_remove;
priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets;
priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets);
@@ -1118,7 +1349,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt);
- priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ priv->asrc_format = asrc_fmt;
if (ret) {
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
@@ -1146,39 +1377,10 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
goto asrc_fail;
}
- /*
- * Properties "hp-det-gpios" and "mic-det-gpios" are optional, and
- * simple_util_init_jack() uses these properties for creating
- * Headphone Jack and Microphone Jack.
- *
- * The notifier is initialized in snd_soc_card_jack_new(), then
- * snd_soc_jack_notifier_register can be called.
- */
- if (of_property_present(np, "hp-det-gpios") ||
- of_property_present(np, "hp-det-gpio") /* deprecated */) {
- ret = simple_util_init_jack(&priv->card, &priv->hp_jack,
- 1, NULL, "Headphone Jack");
- if (ret)
- goto asrc_fail;
-
- snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb);
- }
-
- if (of_property_present(np, "mic-det-gpios") ||
- of_property_present(np, "mic-det-gpio") /* deprecated */) {
- ret = simple_util_init_jack(&priv->card, &priv->mic_jack,
- 0, NULL, "Mic Jack");
- if (ret)
- goto asrc_fail;
-
- snd_soc_jack_notifier_register(&priv->mic_jack.jack, &mic_jack_nb);
- }
-
asrc_fail:
of_node_put(asrc_np);
of_node_put(codec_np[0]);
of_node_put(codec_np[1]);
- put_device(&cpu_pdev->dev);
fail:
of_node_put(cpu_np);
@@ -1186,21 +1388,21 @@ fail:
}
static const struct of_device_id fsl_asoc_card_dt_ids[] = {
- { .compatible = "fsl,imx-audio-ac97", },
- { .compatible = "fsl,imx-audio-cs42888", },
- { .compatible = "fsl,imx-audio-cs427x", },
- { .compatible = "fsl,imx-audio-tlv320aic32x4", },
- { .compatible = "fsl,imx-audio-tlv320aic31xx", },
- { .compatible = "fsl,imx-audio-sgtl5000", },
- { .compatible = "fsl,imx-audio-wm8962", },
- { .compatible = "fsl,imx-audio-wm8960", },
- { .compatible = "fsl,imx-audio-mqs", },
- { .compatible = "fsl,imx-audio-wm8524", },
- { .compatible = "fsl,imx-audio-si476x", },
- { .compatible = "fsl,imx-audio-wm8958", },
- { .compatible = "fsl,imx-audio-nau8822", },
- { .compatible = "fsl,imx-audio-wm8904", },
- { .compatible = "fsl,imx-audio-spdif", },
+ { .compatible = "fsl,imx-audio-ac97", .data = &fsl_asoc_ac97_pdata },
+ { .compatible = "fsl,imx-audio-cs42888", .data = &fsl_asoc_cs42888_pdata },
+ { .compatible = "fsl,imx-audio-cs427x", .data = &fsl_asoc_cs427x_pdata },
+ { .compatible = "fsl,imx-audio-tlv320aic32x4", .data = &fsl_asoc_tlv320aic32x4_pdata },
+ { .compatible = "fsl,imx-audio-tlv320aic31xx", .data = &fsl_asoc_tlv320aic31xx_pdata },
+ { .compatible = "fsl,imx-audio-sgtl5000", .data = &fsl_asoc_sgtl5000_pdata },
+ { .compatible = "fsl,imx-audio-wm8962", .data = &fsl_asoc_wm8962_pdata },
+ { .compatible = "fsl,imx-audio-wm8960", .data = &fsl_asoc_wm8960_pdata },
+ { .compatible = "fsl,imx-audio-mqs", .data = &fsl_asoc_mqs_pdata },
+ { .compatible = "fsl,imx-audio-wm8524", .data = &fsl_asoc_wm8524_pdata },
+ { .compatible = "fsl,imx-audio-si476x", .data = &fsl_asoc_si476x_pdata },
+ { .compatible = "fsl,imx-audio-wm8958", .data = &fsl_asoc_wm8958_pdata },
+ { .compatible = "fsl,imx-audio-nau8822", .data = &fsl_asoc_nau8822_pdata },
+ { .compatible = "fsl,imx-audio-wm8904", .data = &fsl_asoc_wm8904_pdata },
+ { .compatible = "fsl,imx-audio-spdif", .data = &fsl_asoc_spdif_pdata },
{}
};
MODULE_DEVICE_TABLE(of, fsl_asoc_card_dt_ids);
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index f23c21032287..b24737add001 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -222,10 +222,9 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
enum asrc_pair_index index = ASRC_INVALID_PAIR;
struct fsl_asrc *asrc = pair->asrc;
struct device *dev = &asrc->pdev->dev;
- unsigned long lock_flags;
int i, ret = 0;
- spin_lock_irqsave(&asrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&asrc->lock);
for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) {
if (asrc->pair[i] != NULL)
@@ -250,8 +249,6 @@ static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair)
pair->index = index;
}
- spin_unlock_irqrestore(&asrc->lock, lock_flags);
-
return ret;
}
@@ -265,19 +262,16 @@ static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair)
{
struct fsl_asrc *asrc = pair->asrc;
enum asrc_pair_index index = pair->index;
- unsigned long lock_flags;
/* Make sure the pair is disabled */
regmap_update_bits(asrc->regmap, REG_ASRCTR,
ASRCTR_ASRCEi_MASK(index), 0);
- spin_lock_irqsave(&asrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&asrc->lock);
asrc->channel_avail += pair->channels;
asrc->pair[index] = NULL;
pair->error = 0;
-
- spin_unlock_irqrestore(&asrc->lock, lock_flags);
}
/**
@@ -1358,7 +1352,7 @@ static int fsl_asrc_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
- asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ asrc->asrc_format = asrc_fmt;
if (ret) {
ret = of_property_read_u32(np, "fsl,asrc-width", &width);
if (ret) {
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 7a81366a0ee4..f57e684d1cca 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -444,7 +444,7 @@ struct dma_block {
};
/**
- * fsl_asrc_soc_data: soc specific data
+ * struct fsl_asrc_soc_data - soc specific data
*
* @use_edma: using edma as dma device or not
* @channel_bits: width of ASRCNCR register for each pair
@@ -457,7 +457,7 @@ struct fsl_asrc_soc_data {
};
/**
- * fsl_asrc_pair_priv: ASRC Pair private data
+ * struct fsl_asrc_pair_priv - ASRC Pair private data
*
* @config: configuration profile
*/
@@ -466,7 +466,7 @@ struct fsl_asrc_pair_priv {
};
/**
- * fsl_asrc_priv: ASRC private data
+ * struct fsl_asrc_priv - ASRC private data
*
* @asrck_clk: clock sources to driver ASRC internal logic
* @soc: soc specific data
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 38f2b7c63133..2f662bdf14d0 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -219,7 +219,9 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
*/
component_be = snd_soc_lookup_component_nolocked(dev_be, SND_DMAENGINE_PCM_DRV_NAME);
if (component_be) {
- be_chan = soc_component_to_pcm(component_be)->chan[substream->stream];
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component_be);
+
+ be_chan = pcm->chan[substream->stream];
tmp_chan = be_chan;
}
if (!tmp_chan) {
diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
index 7d39378c0622..4bc40f328f58 100644
--- a/sound/soc/fsl/fsl_asrc_m2m.c
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -367,13 +367,13 @@ static int fsl_asrc_m2m_comp_set_params(struct snd_compr_stream *stream,
if (ret)
return -EINVAL;
- if (pcm_format_to_bits((__force snd_pcm_format_t)params->codec.format) & cap.fmt_in)
- pair->sample_format[IN] = (__force snd_pcm_format_t)params->codec.format;
+ if (pcm_format_to_bits(params->codec.format) & cap.fmt_in)
+ pair->sample_format[IN] = params->codec.format;
else
return -EINVAL;
- if (pcm_format_to_bits((__force snd_pcm_format_t)params->codec.pcm_format) & cap.fmt_out)
- pair->sample_format[OUT] = (__force snd_pcm_format_t)params->codec.pcm_format;
+ if (pcm_format_to_bits(params->codec.pcm_format) & cap.fmt_out)
+ pair->sample_format[OUT] = params->codec.pcm_format;
else
return -EINVAL;
@@ -600,7 +600,7 @@ static int fsl_asrc_m2m_fill_codec_caps(struct fsl_asrc *asrc,
cap.rate_in,
cap.rate_in_count * sizeof(__u32));
codec->descriptor[j].num_sample_rates = cap.rate_in_count;
- codec->descriptor[j].formats = (__force __u32)k;
+ codec->descriptor[j].formats = k;
codec->descriptor[j].pcm_formats = cap.fmt_out;
codec->descriptor[j].src.out_sample_rate_min = cap.rate_out[0];
codec->descriptor[j].src.out_sample_rate_max =
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index f819f33ec46b..d4140e170edf 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -286,7 +286,6 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
struct fsl_audmix *priv = snd_soc_dai_get_drvdata(dai);
- unsigned long lock_flags;
/* Capture stream shall not be handled */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
@@ -296,16 +295,14 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&priv->lock, lock_flags);
- priv->tdms |= BIT(dai->driver->id);
- spin_unlock_irqrestore(&priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &priv->lock)
+ priv->tdms |= BIT(dai->driver->id);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&priv->lock, lock_flags);
- priv->tdms &= ~BIT(dai->driver->id);
- spin_unlock_irqrestore(&priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &priv->lock)
+ priv->tdms &= ~BIT(dai->driver->id);
break;
default:
return -EINVAL;
@@ -457,6 +454,9 @@ static const struct of_device_id fsl_audmix_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_audmix_ids);
+static int fsl_audmix_runtime_resume(struct device *dev);
+static int fsl_audmix_runtime_suspend(struct device *dev);
+
static int fsl_audmix_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -488,13 +488,25 @@ static int fsl_audmix_probe(struct platform_device *pdev)
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
pm_runtime_enable(dev);
+ if (!pm_runtime_enabled(dev)) {
+ ret = fsl_audmix_runtime_resume(dev);
+ if (ret)
+ goto err_disable_pm;
+ }
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err_pm_get_sync;
+
+ /* To enable regmap cache only when runtime PM enabled */
+ pm_runtime_put(dev);
ret = devm_snd_soc_register_component(dev, &fsl_audmix_component,
fsl_audmix_dai,
ARRAY_SIZE(fsl_audmix_dai));
if (ret) {
dev_err(dev, "failed to register ASoC DAI\n");
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
/*
@@ -506,12 +518,15 @@ static int fsl_audmix_probe(struct platform_device *pdev)
if (IS_ERR(priv->pdev)) {
ret = PTR_ERR(priv->pdev);
dev_err(dev, "failed to register platform: %d\n", ret);
- goto err_disable_pm;
+ goto err_pm_get_sync;
}
}
return 0;
+err_pm_get_sync:
+ if (!pm_runtime_status_suspended(dev))
+ fsl_audmix_runtime_suspend(dev);
err_disable_pm:
pm_runtime_disable(dev);
return ret;
@@ -522,6 +537,8 @@ static void fsl_audmix_remove(struct platform_device *pdev)
struct fsl_audmix *priv = dev_get_drvdata(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ fsl_audmix_runtime_suspend(&pdev->dev);
if (priv->pdev)
platform_device_unregister(priv->pdev);
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index b12474880185..b1b341132dd6 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -18,8 +18,6 @@
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
#include <linux/list.h>
#include <linux/slab.h>
@@ -824,9 +822,34 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct device_node *ssi_np;
struct resource res;
+ void __iomem *channel;
const uint32_t *iprop;
+ int irq;
int ret;
+ channel = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(channel))
+ return PTR_ERR(channel);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ dma = devm_kzalloc(&pdev->dev, sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ dma->dai.name = DRV_NAME;
+ dma->dai.open = fsl_dma_open;
+ dma->dai.close = fsl_dma_close;
+ dma->dai.hw_params = fsl_dma_hw_params;
+ dma->dai.hw_free = fsl_dma_hw_free;
+ dma->dai.pointer = fsl_dma_pointer;
+ dma->dai.pcm_new = fsl_dma_new;
+
+ dma->channel = channel;
+ dma->irq = irq;
+
/* Find the SSI node that points to us. */
ssi_np = find_ssi_node(np);
if (!ssi_np) {
@@ -842,55 +865,19 @@ static int fsl_soc_dma_probe(struct platform_device *pdev)
return ret;
}
- dma = kzalloc_obj(*dma);
- if (!dma) {
- of_node_put(ssi_np);
- return -ENOMEM;
- }
-
- dma->dai.name = DRV_NAME;
- dma->dai.open = fsl_dma_open;
- dma->dai.close = fsl_dma_close;
- dma->dai.hw_params = fsl_dma_hw_params;
- dma->dai.hw_free = fsl_dma_hw_free;
- dma->dai.pointer = fsl_dma_pointer;
- dma->dai.pcm_new = fsl_dma_new;
-
/* Store the SSI-specific information that we need */
dma->ssi_stx_phys = res.start + REG_SSI_STX0;
dma->ssi_srx_phys = res.start + REG_SSI_SRX0;
iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL);
+ of_node_put(ssi_np);
if (iprop)
dma->ssi_fifo_depth = be32_to_cpup(iprop);
else
/* Older 8610 DTs didn't have the fifo-depth property */
dma->ssi_fifo_depth = 8;
- of_node_put(ssi_np);
-
- ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "could not register platform\n");
- kfree(dma);
- return ret;
- }
-
- dma->channel = of_iomap(np, 0);
- dma->irq = irq_of_parse_and_map(np, 0);
-
- dev_set_drvdata(&pdev->dev, dma);
-
- return 0;
-}
-
-static void fsl_soc_dma_remove(struct platform_device *pdev)
-{
- struct dma_object *dma = dev_get_drvdata(&pdev->dev);
-
- iounmap(dma->channel);
- irq_dispose_mapping(dma->irq);
- kfree(dma);
+ return devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0);
}
static const struct of_device_id fsl_soc_dma_ids[] = {
@@ -905,7 +892,6 @@ static struct platform_driver fsl_soc_dma_driver = {
.of_match_table = fsl_soc_dma_ids,
},
.probe = fsl_soc_dma_probe,
- .remove = fsl_soc_dma_remove,
};
module_platform_driver(fsl_soc_dma_driver);
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
index f19ae765b656..928d91e5236c 100644
--- a/sound/soc/fsl/fsl_dma.h
+++ b/sound/soc/fsl/fsl_dma.h
@@ -92,7 +92,7 @@ static inline u32 CCSR_DMA_ECLNDAR_ADDR(u64 x)
#define CCSR_DMA_ATR_SNOOP 0x00050000
#define CCSR_DMA_ATR_ESAD_MASK 0x0000000F
-/**
+/*
* List Descriptor for extended chaining mode DMA operations.
*
* The CLSDAR register points to the first (in a linked-list) List
@@ -107,7 +107,7 @@ struct fsl_dma_list_descriptor {
u8 res[8]; /* Reserved */
} __attribute__ ((aligned(32), packed));
-/**
+/*
* Link Descriptor for basic and extended chaining mode DMA operations.
*
* A Link Descriptor points to a single DMA buffer. Each link descriptor
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index 8535ef844ce0..aced16d1228a 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1025,7 +1025,6 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
struct fsl_easrc_ctx_priv *ctx_priv;
struct fsl_asrc_pair *ctx;
struct device *dev;
- unsigned long lock_flags;
int ret;
if (!easrc)
@@ -1053,9 +1052,8 @@ static int fsl_easrc_config_context(struct fsl_asrc *easrc, unsigned int ctx_id)
if (ret)
return ret;
- spin_lock_irqsave(&easrc->lock, lock_flags);
- ret = fsl_easrc_config_slot(easrc, ctx->index);
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &easrc->lock)
+ ret = fsl_easrc_config_slot(easrc, ctx->index);
if (ret)
return ret;
@@ -1301,13 +1299,12 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
enum asrc_pair_index index = ASRC_INVALID_PAIR;
struct fsl_asrc *easrc = ctx->asrc;
struct device *dev;
- unsigned long lock_flags;
int ret = 0;
int i;
dev = &easrc->pdev->dev;
- spin_lock_irqsave(&easrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&easrc->lock);
for (i = ASRC_PAIR_A; i < EASRC_CTX_MAX_NUM; i++) {
if (easrc->pair[i])
@@ -1331,8 +1328,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
easrc->channel_avail -= channels;
}
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
-
return ret;
}
@@ -1343,7 +1338,6 @@ static int fsl_easrc_request_context(int channels, struct fsl_asrc_pair *ctx)
*/
static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
{
- unsigned long lock_flags;
struct fsl_asrc *easrc;
if (!ctx)
@@ -1351,14 +1345,12 @@ static void fsl_easrc_release_context(struct fsl_asrc_pair *ctx)
easrc = ctx->asrc;
- spin_lock_irqsave(&easrc->lock, lock_flags);
+ guard(spinlock_irqsave)(&easrc->lock);
fsl_easrc_release_slot(easrc, ctx->index);
easrc->channel_avail += ctx->channels;
easrc->pair[ctx->index] = NULL;
-
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
}
/*
@@ -1711,12 +1703,12 @@ static const struct reg_default fsl_easrc_reg_defaults[] = {
{REG_EASRC_SFS(2), 0x00000000},
{REG_EASRC_SFS(3), 0x00000000},
{REG_EASRC_RRL(0), 0x00000000},
- {REG_EASRC_RRL(1), 0x00000000},
- {REG_EASRC_RRL(2), 0x00000000},
- {REG_EASRC_RRL(3), 0x00000000},
{REG_EASRC_RRH(0), 0x00000000},
+ {REG_EASRC_RRL(1), 0x00000000},
{REG_EASRC_RRH(1), 0x00000000},
+ {REG_EASRC_RRL(2), 0x00000000},
{REG_EASRC_RRH(2), 0x00000000},
+ {REG_EASRC_RRL(3), 0x00000000},
{REG_EASRC_RRH(3), 0x00000000},
{REG_EASRC_RUC(0), 0x00000000},
{REG_EASRC_RUC(1), 0x00000000},
@@ -2058,7 +2050,7 @@ static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buff
/* right shift 12 bit to make ratio in 32bit space */
val2 = (u64)in_samples << (frac_bits - 12);
val1 = val1 >> 12;
- do_div(val2, val1);
+ val2 = div64_u64(val2, val1);
out_samples = val2;
out_length = out_samples * out_width * channels;
@@ -2227,7 +2219,7 @@ static int fsl_easrc_probe(struct platform_device *pdev)
}
ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt);
- easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ easrc->asrc_format = asrc_fmt;
if (ret) {
dev_err(dev, "failed to asrc format\n");
return ret;
@@ -2292,15 +2284,13 @@ static int fsl_easrc_runtime_suspend(struct device *dev)
{
struct fsl_asrc *easrc = dev_get_drvdata(dev);
struct fsl_easrc_priv *easrc_priv = easrc->private;
- unsigned long lock_flags;
regcache_cache_only(easrc->regmap, true);
clk_disable_unprepare(easrc->mem_clk);
- spin_lock_irqsave(&easrc->lock, lock_flags);
- easrc_priv->firmware_loaded = 0;
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &easrc->lock)
+ easrc_priv->firmware_loaded = 0;
return 0;
}
@@ -2311,7 +2301,6 @@ static int fsl_easrc_runtime_resume(struct device *dev)
struct fsl_easrc_priv *easrc_priv = easrc->private;
struct fsl_easrc_ctx_priv *ctx_priv;
struct fsl_asrc_pair *ctx;
- unsigned long lock_flags;
int ret;
int i;
@@ -2323,13 +2312,11 @@ static int fsl_easrc_runtime_resume(struct device *dev)
regcache_mark_dirty(easrc->regmap);
regcache_sync(easrc->regmap);
- spin_lock_irqsave(&easrc->lock, lock_flags);
- if (easrc_priv->firmware_loaded) {
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
- goto skip_load;
+ scoped_guard(spinlock_irqsave, &easrc->lock) {
+ if (easrc_priv->firmware_loaded)
+ return 0;
+ easrc_priv->firmware_loaded = 1;
}
- easrc_priv->firmware_loaded = 1;
- spin_unlock_irqrestore(&easrc->lock, lock_flags);
ret = fsl_easrc_get_firmware(easrc);
if (ret) {
@@ -2377,9 +2364,7 @@ static int fsl_easrc_runtime_resume(struct device *dev)
goto disable_mem_clk;
}
-skip_load:
return 0;
-
disable_mem_clk:
clk_disable_unprepare(easrc->mem_clk);
return ret;
diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h
index c9f770862662..36569cf8be9a 100644
--- a/sound/soc/fsl/fsl_easrc.h
+++ b/sound/soc/fsl/fsl_easrc.h
@@ -584,7 +584,7 @@ struct fsl_easrc_slot {
};
/**
- * fsl_easrc_ctx_priv: EASRC context private data
+ * struct fsl_easrc_ctx_priv - EASRC context private data
*
* @in_params: input parameter
* @out_params: output parameter
@@ -625,7 +625,7 @@ struct fsl_easrc_ctx_priv {
};
/**
- * fsl_easrc_priv: EASRC private data
+ * struct fsl_easrc_priv - EASRC private data
*
* @slot: slot setting
* @firmware_hdr: the header of firmware
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index cde0b0c6c1ef..4a530a6c33f0 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -709,10 +709,9 @@ static void fsl_esai_hw_reset(struct work_struct *work)
{
struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work);
bool tx = true, rx = false, enabled[2];
- unsigned long lock_flags;
u32 tfcr, rfcr;
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
+ guard(spinlock_irqsave)(&esai_priv->lock);
/* Save the registers */
regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &tfcr);
regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &rfcr);
@@ -750,8 +749,6 @@ static void fsl_esai_hw_reset(struct work_struct *work)
fsl_esai_trigger_start(esai_priv, tx);
if (enabled[rx])
fsl_esai_trigger_start(esai_priv, rx);
-
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
}
static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
@@ -759,7 +756,6 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned long lock_flags;
esai_priv->channels[tx] = substream->runtime->channels;
@@ -767,16 +763,14 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
- fsl_esai_trigger_start(esai_priv, tx);
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &esai_priv->lock)
+ fsl_esai_trigger_start(esai_priv, tx);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- spin_lock_irqsave(&esai_priv->lock, lock_flags);
- fsl_esai_trigger_stop(esai_priv, tx);
- spin_unlock_irqrestore(&esai_priv->lock, lock_flags);
+ scoped_guard(spinlock_irqsave, &esai_priv->lock)
+ fsl_esai_trigger_stop(esai_priv, tx);
break;
default:
return -EINVAL;
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index d0f644573f49..f27934cf49da 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -503,8 +503,8 @@ static int qmc_dai_constraints_interleaved(struct snd_pcm_substream *substream,
return ret;
}
- access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
- 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+ access = 1ULL << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED |
+ 1ULL << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
access);
if (ret) {
@@ -532,8 +532,8 @@ static int qmc_dai_constraints_noninterleaved(struct snd_pcm_substream *substrea
return ret;
}
- access = 1ULL << (__force int)SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
- 1ULL << (__force int)SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
+ access = 1ULL << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED |
+ 1ULL << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
ret = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_ACCESS,
access);
if (ret) {
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 1b9be85b34c2..ad1206ed9882 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -853,17 +853,15 @@ static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
- unsigned long flags;
int ret = -EAGAIN;
- spin_lock_irqsave(&ctrl->ctl_lock, flags);
+ guard(spinlock_irqsave)(&ctrl->ctl_lock);
if (ctrl->ready_buf) {
int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
memcpy(&ucontrol->value.iec958.subcode[0],
&ctrl->subcode[idx], SPDIF_UBITS_SIZE);
ret = 0;
}
- spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
return ret;
}
@@ -885,17 +883,15 @@ static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
- unsigned long flags;
int ret = -EAGAIN;
- spin_lock_irqsave(&ctrl->ctl_lock, flags);
+ guard(spinlock_irqsave)(&ctrl->ctl_lock);
if (ctrl->ready_buf) {
int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
memcpy(&ucontrol->value.bytes.data[0],
&ctrl->qsub[idx], SPDIF_QSUB_SIZE);
ret = 0;
}
- spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
return ret;
}
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index b2e1da1781ae..dc022976c982 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -1218,13 +1218,13 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
if (reg > 0x7f)
return;
- mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock);
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 write clk_prepare_enable failed: %d\n",
ret);
- goto ret_unlock;
+ return;
}
lreg = reg << 12;
@@ -1238,9 +1238,6 @@ static void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
udelay(100);
clk_disable_unprepare(fsl_ac97_data->clk);
-
-ret_unlock:
- mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
}
static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
@@ -1252,12 +1249,12 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
unsigned int lreg;
int ret;
- mutex_lock(&fsl_ac97_data->ac97_reg_lock);
+ guard(mutex)(&fsl_ac97_data->ac97_reg_lock);
ret = clk_prepare_enable(fsl_ac97_data->clk);
if (ret) {
pr_err("ac97 read clk_prepare_enable failed: %d\n", ret);
- goto ret_unlock;
+ return val;
}
lreg = (reg & 0x7f) << 12;
@@ -1272,8 +1269,6 @@ static unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
clk_disable_unprepare(fsl_ac97_data->clk);
-ret_unlock:
- mutex_unlock(&fsl_ac97_data->ac97_reg_lock);
return val;
}
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 6677d3bf36ec..982827204351 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -797,10 +797,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
{
struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned long lock_flags;
int ret = 0;
- spin_lock_irqsave(&xcvr->lock, lock_flags);
+ guard(spinlock_irqsave)(&xcvr->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -812,7 +811,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (tx) {
@@ -824,7 +823,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_ISR_CMDC_TX_EN);
if (ret < 0) {
dev_err(dai->dev, "err updating isr %d\n", ret);
- goto release_lock;
+ return ret;
}
fallthrough;
case FSL_XCVR_MODE_SPDIF:
@@ -833,7 +832,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
if (ret < 0) {
dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
}
@@ -844,14 +843,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
- goto release_lock;
+ return ret;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
if (ret < 0) {
dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
- goto release_lock;
+ return ret;
}
/* clear DPATH RESET */
@@ -860,7 +859,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
@@ -873,14 +872,14 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
if (ret < 0) {
dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
- goto release_lock;
+ return ret;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0);
if (ret < 0) {
dev_err(dai->dev, "Failed to clear IER0: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (tx) {
@@ -891,7 +890,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
if (ret < 0) {
dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
- goto release_lock;
+ return ret;
}
if (xcvr->soc_data->spdif_only)
break;
@@ -905,7 +904,7 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret < 0) {
dev_err(dai->dev,
"Err updating ISR %d\n", ret);
- goto release_lock;
+ return ret;
}
break;
}
@@ -916,18 +915,16 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
break;
}
-release_lock:
- spin_unlock_irqrestore(&xcvr->lock, lock_flags);
return ret;
}
static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
{
struct device *dev = &xcvr->pdev->dev;
- const struct firmware *fw;
int ret = 0, rem, off, out, page = 0, size = FSL_XCVR_REG_OFFSET;
u32 mask, val;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev);
if (ret) {
dev_err(dev, "failed to request firmware.\n");
@@ -939,7 +936,6 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
/* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */
if (rem > 16384) {
dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
- release_firmware(fw);
return -ENOMEM;
}
@@ -950,7 +946,7 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
if (ret < 0) {
dev_err(dev, "FW: failed to set page %d, err=%d\n",
page, ret);
- goto err_firmware;
+ return ret;
}
off = page * size;
@@ -971,11 +967,6 @@ static int fsl_xcvr_load_firmware(struct fsl_xcvr *xcvr)
}
}
-err_firmware:
- release_firmware(fw);
- if (ret < 0)
- return ret;
-
/* configure watermarks */
mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
val = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
@@ -1448,11 +1439,10 @@ static void reset_rx_work(struct work_struct *work)
{
struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst);
struct device *dev = &xcvr->pdev->dev;
- unsigned long lock_flags;
u32 ext_ctrl;
dev_dbg(dev, "reset rx path\n");
- spin_lock_irqsave(&xcvr->lock, lock_flags);
+ guard(spinlock_irqsave)(&xcvr->lock);
regmap_read(xcvr->regmap, FSL_XCVR_EXT_CTRL, &ext_ctrl);
if (!(ext_ctrl & FSL_XCVR_EXT_CTRL_DMA_RD_DIS)) {
@@ -1469,7 +1459,6 @@ static void reset_rx_work(struct work_struct *work)
FSL_XCVR_EXT_CTRL_RX_DPTH_RESET,
0);
}
- spin_unlock_irqrestore(&xcvr->lock, lock_flags);
}
static irqreturn_t irq0_isr(int irq, void *devid)
diff --git a/sound/soc/fsl/imx-audio-rpmsg.c b/sound/soc/fsl/imx-audio-rpmsg.c
index 38aafb8954c7..b55dfbdb4502 100644
--- a/sound/soc/fsl/imx-audio-rpmsg.c
+++ b/sound/soc/fsl/imx-audio-rpmsg.c
@@ -22,7 +22,6 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
struct rpmsg_r_msg *r_msg = (struct rpmsg_r_msg *)data;
struct rpmsg_info *info;
struct rpmsg_msg *msg;
- unsigned long flags;
if (!rpmsg->rpmsg_pdev)
return 0;
@@ -37,21 +36,21 @@ static int imx_audio_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
/* TYPE C is notification from M core */
switch (r_msg->header.cmd) {
case TX_PERIOD_DONE:
- spin_lock_irqsave(&info->lock[TX], flags);
- msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
- msg->r_msg.param.buffer_tail =
- r_msg->param.buffer_tail;
- msg->r_msg.param.buffer_tail %= info->num_period[TX];
- spin_unlock_irqrestore(&info->lock[TX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[TX]) {
+ msg = &info->msg[TX_PERIOD_DONE + MSG_TYPE_A_NUM];
+ msg->r_msg.param.buffer_tail =
+ r_msg->param.buffer_tail;
+ msg->r_msg.param.buffer_tail %= info->num_period[TX];
+ }
info->callback[TX](info->callback_param[TX]);
break;
case RX_PERIOD_DONE:
- spin_lock_irqsave(&info->lock[RX], flags);
- msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
- msg->r_msg.param.buffer_tail =
- r_msg->param.buffer_tail;
- msg->r_msg.param.buffer_tail %= info->num_period[1];
- spin_unlock_irqrestore(&info->lock[RX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[RX]) {
+ msg = &info->msg[RX_PERIOD_DONE + MSG_TYPE_A_NUM];
+ msg->r_msg.param.buffer_tail =
+ r_msg->param.buffer_tail;
+ msg->r_msg.param.buffer_tail %= info->num_period[1];
+ }
info->callback[RX](info->callback_param[RX]);
break;
default:
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
index 43438af1e1c6..e3cb1438e837 100644
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -531,7 +531,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 unsigned int)data->asrc_format);
+ snd_mask_set(mask, data->asrc_format);
return 0;
}
@@ -684,7 +684,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
}
ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt);
- data->asrc_format = (__force snd_pcm_format_t)asrc_fmt;
+ data->asrc_format = asrc_fmt;
if (ret) {
/* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(args.np, "fsl,asrc-width", &width);
diff --git a/sound/soc/fsl/imx-pcm-rpmsg.c b/sound/soc/fsl/imx-pcm-rpmsg.c
index 2a4813c6cda9..7086fb7fc1eb 100644
--- a/sound/soc/fsl/imx-pcm-rpmsg.c
+++ b/sound/soc/fsl/imx-pcm-rpmsg.c
@@ -39,10 +39,9 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
struct rpmsg_device *rpdev = info->rpdev;
int ret = 0;
- mutex_lock(&info->msg_lock);
+ guard(mutex)(&info->msg_lock);
if (!rpdev) {
dev_err(info->dev, "rpmsg channel not ready\n");
- mutex_unlock(&info->msg_lock);
return -EINVAL;
}
@@ -55,15 +54,12 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
sizeof(struct rpmsg_s_msg));
if (ret) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
- mutex_unlock(&info->msg_lock);
return ret;
}
/* No receive msg for TYPE_C command */
- if (msg->s_msg.header.type == MSG_TYPE_C) {
- mutex_unlock(&info->msg_lock);
+ if (msg->s_msg.header.type == MSG_TYPE_C)
return 0;
- }
/* wait response from rpmsg */
ret = wait_for_completion_timeout(&info->cmd_complete,
@@ -71,7 +67,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
if (!ret) {
dev_err(&rpdev->dev, "rpmsg_send cmd %d timeout!\n",
msg->s_msg.header.cmd);
- mutex_unlock(&info->msg_lock);
return -ETIMEDOUT;
}
@@ -100,8 +95,6 @@ static int imx_rpmsg_pcm_send_message(struct rpmsg_msg *msg,
dev_dbg(&rpdev->dev, "cmd:%d, resp %d\n", msg->s_msg.header.cmd,
info->r_msg.param.resp);
- mutex_unlock(&info->msg_lock);
-
return 0;
}
@@ -109,14 +102,13 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
struct rpmsg_msg *msg,
struct rpmsg_info *info)
{
- unsigned long flags;
int ret = 0;
/*
* Queue the work to workqueue.
* If the queue is full, drop the message.
*/
- spin_lock_irqsave(&info->wq_lock, flags);
+ guard(spinlock_irqsave)(&info->wq_lock);
if (info->work_write_index != info->work_read_index) {
int index = info->work_write_index;
@@ -130,7 +122,6 @@ static int imx_rpmsg_insert_workqueue(struct snd_pcm_substream *substream,
info->msg_drop_count[substream->stream]++;
ret = -EPIPE;
}
- spin_unlock_irqrestore(&info->wq_lock, flags);
return ret;
}
@@ -523,7 +514,6 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
snd_pcm_sframes_t avail;
struct timer_list *timer;
struct rpmsg_msg *msg;
- unsigned long flags;
int buffer_tail = 0;
int written_num;
@@ -553,11 +543,11 @@ static int imx_rpmsg_pcm_ack(struct snd_soc_component *component,
msg->s_msg.param.buffer_tail = buffer_tail;
/* The notification message is updated to latest */
- spin_lock_irqsave(&info->lock[substream->stream], flags);
- memcpy(&info->notify[substream->stream], msg,
- sizeof(struct rpmsg_s_msg));
- info->notify_updated[substream->stream] = true;
- spin_unlock_irqrestore(&info->lock[substream->stream], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[substream->stream]) {
+ memcpy(&info->notify[substream->stream], msg,
+ sizeof(struct rpmsg_s_msg));
+ info->notify_updated[substream->stream] = true;
+ }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
avail = snd_pcm_playback_hw_avail(runtime);
@@ -641,7 +631,7 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
bool is_notification = false;
struct rpmsg_info *info;
struct rpmsg_msg msg;
- unsigned long flags;
+ bool updated;
work_of_rpmsg = container_of(work, struct work_of_rpmsg, work);
info = work_of_rpmsg->info;
@@ -652,25 +642,26 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
* enough data in M core side, need to let M core know
* data is updated immediately.
*/
- spin_lock_irqsave(&info->lock[TX], flags);
- if (info->notify_updated[TX]) {
- memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
- info->notify_updated[TX] = false;
- spin_unlock_irqrestore(&info->lock[TX], flags);
- info->send_message(&msg, info);
- } else {
- spin_unlock_irqrestore(&info->lock[TX], flags);
+ scoped_guard(spinlock_irqsave, &info->lock[TX]) {
+ updated = info->notify_updated[TX];
+ if (updated) {
+ memcpy(&msg, &info->notify[TX], sizeof(struct rpmsg_s_msg));
+ info->notify_updated[TX] = false;
+ }
}
-
- spin_lock_irqsave(&info->lock[RX], flags);
- if (info->notify_updated[RX]) {
- memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
- info->notify_updated[RX] = false;
- spin_unlock_irqrestore(&info->lock[RX], flags);
+ if (updated)
info->send_message(&msg, info);
- } else {
- spin_unlock_irqrestore(&info->lock[RX], flags);
+
+ scoped_guard(spinlock_irqsave, &info->lock[RX]) {
+ updated = info->notify_updated[RX];
+ if (updated) {
+ memcpy(&msg, &info->notify[RX], sizeof(struct rpmsg_s_msg));
+ info->notify_updated[RX] = false;
+ }
}
+ if (updated)
+ info->send_message(&msg, info);
+
/* Skip the notification message for it has been processed above */
if (work_of_rpmsg->msg.s_msg.header.type == MSG_TYPE_C &&
@@ -682,10 +673,10 @@ static void imx_rpmsg_pcm_work(struct work_struct *work)
info->send_message(&work_of_rpmsg->msg, info);
/* update read index */
- spin_lock_irqsave(&info->wq_lock, flags);
- info->work_read_index++;
- info->work_read_index %= WORK_MAX_NUM;
- spin_unlock_irqrestore(&info->wq_lock, flags);
+ scoped_guard(spinlock_irqsave, &info->wq_lock) {
+ info->work_read_index++;
+ info->work_read_index %= WORK_MAX_NUM;
+ }
}
static int imx_rpmsg_pcm_probe(struct platform_device *pdev)
@@ -819,9 +810,9 @@ static const struct dev_pm_ops imx_rpmsg_pcm_pm_ops = {
};
static const struct platform_device_id imx_rpmsg_pcm_id_table[] = {
- { .name = "rpmsg-audio-channel" },
- { .name = "rpmsg-micfil-channel" },
- { },
+ { .name = "rpmsg-audio-channel" },
+ { .name = "rpmsg-micfil-channel" },
+ { }
};
MODULE_DEVICE_TABLE(platform, imx_rpmsg_pcm_id_table);
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 56e2cf2f727b..8327fff3e1b5 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -77,18 +77,20 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
{
struct psc_dma_stream *s = _psc_dma_stream;
- spin_lock(&s->psc_dma->lock);
- /* For each finished period, dequeue the completed period buffer
- * and enqueue a new one in it's place. */
- while (bcom_buffer_done(s->bcom_task)) {
- bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+ scoped_guard(spinlock, &s->psc_dma->lock) {
+ /*
+ * For each finished period, dequeue the completed period buffer
+ * and enqueue a new one in its place
+ */
+ while (bcom_buffer_done(s->bcom_task)) {
+ bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
- s->period_current = (s->period_current+1) % s->runtime->periods;
- s->period_count++;
+ s->period_current = (s->period_current+1) % s->runtime->periods;
+ s->period_count++;
- psc_dma_bcom_enqueue_next_buffer(s);
+ psc_dma_bcom_enqueue_next_buffer(s);
+ }
}
- spin_unlock(&s->psc_dma->lock);
/* If the stream is active, then also inform the PCM middle layer
* of the period finished event. */
@@ -116,7 +118,6 @@ static int psc_dma_trigger(struct snd_soc_component *component,
struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
u16 imr;
- unsigned long flags;
int i;
switch (cmd) {
@@ -135,19 +136,18 @@ static int psc_dma_trigger(struct snd_soc_component *component,
/* Fill up the bestcomm bd queue and enable DMA.
* This will begin filling the PSC's fifo.
*/
- spin_lock_irqsave(&psc_dma->lock, flags);
-
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- bcom_gen_bd_rx_reset(s->bcom_task);
- else
- bcom_gen_bd_tx_reset(s->bcom_task);
+ scoped_guard(spinlock_irqsave, &psc_dma->lock) {
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
- for (i = 0; i < runtime->periods; i++)
- if (!bcom_queue_full(s->bcom_task))
- psc_dma_bcom_enqueue_next_buffer(s);
+ for (i = 0; i < runtime->periods; i++)
+ if (!bcom_queue_full(s->bcom_task))
+ psc_dma_bcom_enqueue_next_buffer(s);
- bcom_enable(s->bcom_task);
- spin_unlock_irqrestore(&psc_dma->lock, flags);
+ bcom_enable(s->bcom_task);
+ }
out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
@@ -158,13 +158,13 @@ static int psc_dma_trigger(struct snd_soc_component *component,
substream->pstr->stream, s->period_count);
s->active = 0;
- spin_lock_irqsave(&psc_dma->lock, flags);
- bcom_disable(s->bcom_task);
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- bcom_gen_bd_rx_reset(s->bcom_task);
- else
- bcom_gen_bd_tx_reset(s->bcom_task);
- spin_unlock_irqrestore(&psc_dma->lock, flags);
+ scoped_guard(spinlock_irqsave, &psc_dma->lock) {
+ bcom_disable(s->bcom_task);
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ bcom_gen_bd_rx_reset(s->bcom_task);
+ else
+ bcom_gen_bd_tx_reset(s->bcom_task);
+ }
break;
@@ -314,35 +314,29 @@ int mpc5200_audio_dma_create(struct platform_device *op)
{
phys_addr_t fifo;
struct psc_dma *psc_dma;
- struct resource res;
+ struct resource *res;
int size, irq, rc;
const __be32 *prop;
void __iomem *regs;
- int ret;
+
+ regs = devm_platform_get_and_ioremap_resource(op, 0, &res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
/* Fetch the registers and IRQ of the PSC */
- irq = irq_of_parse_and_map(op->dev.of_node, 0);
- if (of_address_to_resource(op->dev.of_node, 0, &res)) {
- dev_err(&op->dev, "Missing reg property\n");
- return -ENODEV;
- }
- regs = devm_ioremap(&op->dev, res.start, resource_size(&res));
- if (!regs) {
- dev_err(&op->dev, "Could not map registers\n");
- return -ENODEV;
- }
+ irq = platform_get_irq(op, 0);
+ if (irq < 0)
+ return irq;
/* Allocate and initialize the driver private data */
- psc_dma = kzalloc_obj(*psc_dma);
+ psc_dma = devm_kzalloc(&op->dev, sizeof(*psc_dma), GFP_KERNEL);
if (!psc_dma)
return -ENOMEM;
/* Get the PSC ID */
prop = of_get_property(op->dev.of_node, "cell-index", &size);
- if (!prop || size < sizeof *prop) {
- ret = -ENODEV;
- goto out_free;
- }
+ if (!prop || size < sizeof *prop)
+ return -ENODEV;
spin_lock_init(&psc_dma->lock);
mutex_init(&psc_dma->mutex);
@@ -357,7 +351,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
/* Find the address of the fifo data registers and setup the
* DMA tasks */
- fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+ fifo = res->start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
psc_dma->capture.bcom_task =
bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
psc_dma->playback.bcom_task =
@@ -365,8 +359,7 @@ int mpc5200_audio_dma_create(struct platform_device *op)
if (!psc_dma->capture.bcom_task ||
!psc_dma->playback.bcom_task) {
dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
- ret = -ENODEV;
- goto out_free;
+ return -ENODEV;
}
/* Disable all interrupts and reset the PSC */
@@ -399,16 +392,14 @@ int mpc5200_audio_dma_create(struct platform_device *op)
psc_dma->capture.irq =
bcom_get_task_irq(psc_dma->capture.bcom_task);
- rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
+ rc = devm_request_irq(&op->dev, psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
"psc-dma-status", psc_dma);
- rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
+ rc |= devm_request_irq(&op->dev, psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-capture", &psc_dma->capture);
- rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
+ rc |= devm_request_irq(&op->dev, psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-playback", &psc_dma->playback);
- if (rc) {
- ret = -ENODEV;
- goto out_irq;
- }
+ if (rc)
+ return -ENODEV;
/* Save what we've done so it can be found again later */
dev_set_drvdata(&op->dev, psc_dma);
@@ -416,13 +407,6 @@ int mpc5200_audio_dma_create(struct platform_device *op)
/* Tell the ASoC OF helpers about it */
return devm_snd_soc_register_component(&op->dev,
&mpc5200_audio_dma_component, NULL, 0);
-out_irq:
- free_irq(psc_dma->irq, psc_dma);
- free_irq(psc_dma->capture.irq, &psc_dma->capture);
- free_irq(psc_dma->playback.irq, &psc_dma->playback);
-out_free:
- kfree(psc_dma);
- return ret;
}
EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
@@ -435,12 +419,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op)
bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
- /* Release irqs */
- free_irq(psc_dma->irq, psc_dma);
- free_irq(psc_dma->capture.irq, &psc_dma->capture);
- free_irq(psc_dma->playback.irq, &psc_dma->playback);
-
- kfree(psc_dma);
dev_set_drvdata(&op->dev, NULL);
return 0;
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index c21104355aa0..ccd8bda05860 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -30,14 +30,13 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
int status;
unsigned int val;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
/* Wait for command send status zero = ready */
status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
MPC52xx_PSC_SR_CMDSEND), 100, 0);
if (status == 0) {
pr_err("timeout on ac97 bus (rdy)\n");
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
@@ -53,19 +52,16 @@ static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
if (status == 0) {
pr_err("timeout on ac97 read (val) %x\n",
in_be16(&psc_dma->psc_regs->sr_csr.status));
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
/* Get the data */
val = in_be32(&psc_dma->psc_regs->ac97_data);
if (((val >> 24) & 0x7f) != reg) {
pr_err("reg echo error on ac97 read\n");
- mutex_unlock(&psc_dma->mutex);
return -ENODEV;
}
val = (val >> 8) & 0xffff;
- mutex_unlock(&psc_dma->mutex);
return (unsigned short) val;
}
@@ -74,52 +70,46 @@ static void psc_ac97_write(struct snd_ac97 *ac97,
{
int status;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
/* Wait for command status zero = ready */
status = spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
MPC52xx_PSC_SR_CMDSEND), 100, 0);
if (status == 0) {
pr_err("timeout on ac97 bus (write)\n");
- goto out;
+ return;
}
/* Write data */
out_be32(&psc_dma->psc_regs->ac97_cmd,
((reg & 0x7f) << 24) | (val << 8));
-
- out:
- mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
- mutex_lock(&psc_dma->mutex);
+ guard(mutex)(&psc_dma->mutex);
out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
udelay(3);
out_be32(&regs->sicr, psc_dma->sicr);
-
- mutex_unlock(&psc_dma->mutex);
}
static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
{
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
- mutex_lock(&psc_dma->mutex);
- dev_dbg(psc_dma->dev, "cold reset\n");
+ scoped_guard(mutex, &psc_dma->mutex) {
+ dev_dbg(psc_dma->dev, "cold reset\n");
- mpc5200_psc_ac97_gpio_reset(psc_dma->id);
+ mpc5200_psc_ac97_gpio_reset(psc_dma->id);
- /* Notify the PSC that a reset has occurred */
- out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
+ /* Notify the PSC that a reset has occurred */
+ out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
- /* Re-enable RX and TX */
- out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
-
- mutex_unlock(&psc_dma->mutex);
+ /* Re-enable RX and TX */
+ out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+ }
usleep_range(1000, 2000);
psc_ac97_warm_reset(ac97);
@@ -286,7 +276,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
return rc;
}
- rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
+ rc = devm_snd_soc_register_component(&op->dev, &psc_ac97_component,
psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
if (rc != 0) {
dev_err(&op->dev, "Failed to register DAI\n");
@@ -312,8 +302,6 @@ static int psc_ac97_of_probe(struct platform_device *op)
static void psc_ac97_of_remove(struct platform_device *op)
{
mpc5200_audio_dma_destroy(op);
- snd_soc_unregister_component(&op->dev);
- snd_soc_set_ac97_ops(NULL);
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 9ad44eeed6ad..c024a38e3b9c 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -79,9 +79,12 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
* and we don't care about the frequency. Return an error if the direction
* is not SND_SOC_CLOCK_IN.
*
+ * @cpu_dai: DAI runtime data pointer
* @clk_id: reserved, should be zero
* @freq: the frequency of the given clock ID, currently ignored
* @dir: SND_SOC_CLOCK_IN (clock slave) or SND_SOC_CLOCK_OUT (clock master)
+ *
+ * Returns: %0 on success or %-EINVAL on failure.
*/
static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
@@ -101,7 +104,10 @@ static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
* This driver only supports I2S mode. Return an error if the format is
* not SND_SOC_DAIFMT_I2S.
*
+ * @cpu_dai: DAI runtime data pointer
* @format: one of SND_SOC_DAIFMT_xxx
+ *
+ * Returns: %0 on success or %-EINVAL on failure.
*/
static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
{
@@ -119,7 +125,7 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
*/
/**
- * psc_i2s_dai_template: template CPU Digital Audio Interface
+ * var psc_i2s_dai_ops - template CPU Digital Audio Interface
*/
static const struct snd_soc_dai_ops psc_i2s_dai_ops = {
.hw_params = psc_i2s_hw_params,
@@ -166,10 +172,11 @@ static int psc_i2s_of_probe(struct platform_device *op)
if (rc != 0)
return rc;
- rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
+ rc = devm_snd_soc_register_component(&op->dev, &psc_i2s_component,
psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
if (rc != 0) {
pr_err("Failed to register DAI\n");
+ mpc5200_audio_dma_destroy(op);
return rc;
}
@@ -212,7 +219,6 @@ static int psc_i2s_of_probe(struct platform_device *op)
static void psc_i2s_of_remove(struct platform_device *op)
{
mpc5200_audio_dma_destroy(op);
- snd_soc_unregister_component(&op->dev);
}
/* Match table for of_platform binding */
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index db07817a8024..98389f53246c 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -73,6 +73,8 @@ struct machine_data {
char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
+#define card_to_mdata(_card) container_of(_card, struct machine_data, card)
+
/**
* p1022_ds_machine_probe: initialize the board
*
@@ -82,8 +84,7 @@ struct machine_data {
*/
static int p1022_ds_machine_probe(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -122,8 +123,7 @@ static int p1022_ds_machine_probe(struct snd_soc_card *card)
static int p1022_ds_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct machine_data *mdata =
- container_of(rtd->card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(rtd->card);
struct device *dev = rtd->card->dev;
int ret = 0;
@@ -156,8 +156,7 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream)
*/
static int p1022_ds_machine_remove(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -399,8 +398,7 @@ error_put:
static void p1022_ds_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
snd_soc_unregister_card(card);
kfree(mdata);
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index f80d6d04e791..d82fe22ca5c5 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -79,6 +79,8 @@ struct machine_data {
char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
+#define card_to_mdata(_card) container_of(_card, struct machine_data, card)
+
/**
* p1022_rdk_machine_probe - initialize the board
* @card: ASoC card instance
@@ -91,8 +93,7 @@ struct machine_data {
*/
static int p1022_rdk_machine_probe(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -134,8 +135,7 @@ static int p1022_rdk_machine_probe(struct snd_soc_card *card)
static int p1022_rdk_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct machine_data *mdata =
- container_of(rtd->card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(rtd->card);
struct device *dev = rtd->card->dev;
int ret = 0;
@@ -169,8 +169,7 @@ static int p1022_rdk_startup(struct snd_pcm_substream *substream)
*/
static int p1022_rdk_machine_remove(struct snd_soc_card *card)
{
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
struct ccsr_guts __iomem *guts;
guts = ioremap(guts_phys, sizeof(struct ccsr_guts));
@@ -361,8 +360,7 @@ error_put:
static void p1022_rdk_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct machine_data *mdata =
- container_of(card, struct machine_data, card);
+ struct machine_data *mdata = card_to_mdata(card);
snd_soc_unregister_card(card);
kfree(mdata);
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 18ce4ee06350..0a8a6d891d1f 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -579,11 +579,11 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
goto end;
}
- ret = simple_util_parse_widgets(card, NULL);
+ ret = simple_util_parse_widgets(priv, NULL);
if (ret < 0)
goto end;
- ret = simple_util_parse_routing(card, NULL);
+ ret = simple_util_parse_routing(priv, NULL);
if (ret < 0)
goto end;
@@ -594,6 +594,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
if (ret < 0)
goto err;
+ /* Card name should be set after graph_for_each_link() */
ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -603,14 +604,13 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
simple_util_debug_info(priv);
ret = devm_snd_soc_register_card(dev, card);
- if (ret < 0)
- goto err;
-
- return 0;
err:
- simple_util_clean_reference(card);
+ if (ret < 0) {
+ simple_util_clean_reference(priv);
+ return dev_err_probe(dev, ret, "parse error\n");
+ }
end:
- return dev_err_probe(dev, ret, "parse error\n");
+ return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph_parse_of);
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 0202ed0ee78e..9fb3d3df5cf6 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -1303,11 +1303,11 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
struct graph2_custom_hooks *hooks)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
- int ret;
+ int ret = -ENOMEM;
struct link_info *li __free(kfree) = kzalloc_obj(*li);
if (!li)
- return -ENOMEM;
+ goto end;
card->probe = graph_util_card_probe;
card->owner = THIS_MODULE;
@@ -1316,31 +1316,35 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
if ((hooks) && (hooks)->hook_pre) {
ret = (hooks)->hook_pre(priv);
if (ret < 0)
- goto err;
+ goto end;
}
ret = graph_for_each_link(priv, hooks, li, graph_count);
if (!li->link)
ret = -EINVAL;
if (ret < 0)
- goto err;
+ goto end;
ret = simple_util_init_priv(priv, li);
if (ret < 0)
- goto err;
+ goto end;
priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
if (IS_ERR(priv->pa_gpio)) {
ret = PTR_ERR(priv->pa_gpio);
dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
- goto err;
+ goto end;
}
- ret = simple_util_parse_widgets(card, NULL);
+ ret = simple_util_parse_widgets(priv, NULL);
if (ret < 0)
- goto err;
+ goto end;
+
+ ret = simple_util_parse_routing(priv, NULL);
+ if (ret < 0)
+ goto end;
- ret = simple_util_parse_routing(card, NULL);
+ ret = simple_util_parse_aux_devs(priv, NULL);
if (ret < 0)
goto err;
@@ -1349,6 +1353,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
if (ret < 0)
goto err;
+ /* Card name should be set after graph_for_each_link() */
ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -1363,15 +1368,13 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
simple_util_debug_info(priv);
- ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
- if (ret < 0)
- goto err;
-
ret = devm_snd_soc_register_card(dev, card);
err:
- if (ret < 0)
- dev_err_probe(dev, ret, "parse error\n");
-
+ if (ret < 0) {
+ simple_util_clean_reference(priv);
+ return dev_err_probe(dev, ret, "parse error\n");
+ }
+end:
return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph2_parse_of);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index e5cb602fd248..42019daa5e04 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -216,6 +216,27 @@ int simple_util_set_dailink_name(struct simple_util_priv *priv,
}
EXPORT_SYMBOL_GPL(simple_util_set_dailink_name);
+int simple_util_parse_property(struct simple_util_priv *priv,
+ int (*func)(struct snd_soc_card *card, const char *propname),
+ char *prefix, char *property)
+{
+ struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct device_node *node = card->dev->of_node;
+ char prop[128];
+
+ if (!prefix)
+ prefix = "";
+
+ snprintf(prop, sizeof(prop), "%s%s", prefix, property);
+
+ /* no property is not error */
+ if (!of_property_present(node, prop))
+ return 0;
+
+ return func(card, prop);
+}
+EXPORT_SYMBOL_GPL(simple_util_parse_property);
+
int simple_util_parse_card_name(struct simple_util_priv *priv,
char *prefix)
{
@@ -731,11 +752,12 @@ void simple_util_canonicalize_cpu(struct snd_soc_dai_link_component *cpus,
}
EXPORT_SYMBOL_GPL(simple_util_canonicalize_cpu);
-void simple_util_clean_reference(struct snd_soc_card *card)
+void simple_util_clean_reference(struct simple_util_priv *priv)
{
struct snd_soc_dai_link *dai_link;
struct snd_soc_dai_link_component *cpu;
struct snd_soc_dai_link_component *codec;
+ struct snd_soc_card *card = simple_priv_to_card(priv);
int i, j;
for_each_card_prelinks(card, i, dai_link) {
@@ -747,57 +769,6 @@ void simple_util_clean_reference(struct snd_soc_card *card)
}
EXPORT_SYMBOL_GPL(simple_util_clean_reference);
-int simple_util_parse_routing(struct snd_soc_card *card,
- char *prefix)
-{
- struct device_node *node = card->dev->of_node;
- char prop[128];
-
- if (!prefix)
- prefix = "";
-
- snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
-
- if (!of_property_present(node, prop))
- return 0;
-
- return snd_soc_of_parse_audio_routing(card, prop);
-}
-EXPORT_SYMBOL_GPL(simple_util_parse_routing);
-
-int simple_util_parse_widgets(struct snd_soc_card *card,
- char *prefix)
-{
- struct device_node *node = card->dev->of_node;
- char prop[128];
-
- if (!prefix)
- prefix = "";
-
- snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
-
- if (of_property_present(node, prop))
- return snd_soc_of_parse_audio_simple_widgets(card, prop);
-
- /* no widgets is not error */
- return 0;
-}
-EXPORT_SYMBOL_GPL(simple_util_parse_widgets);
-
-int simple_util_parse_pin_switches(struct snd_soc_card *card,
- char *prefix)
-{
- char prop[128];
-
- if (!prefix)
- prefix = "";
-
- snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches");
-
- return snd_soc_of_parse_pin_switches(card, prop);
-}
-EXPORT_SYMBOL_GPL(simple_util_parse_pin_switches);
-
int simple_util_init_jack(struct snd_soc_card *card,
struct simple_util_jack *sjack,
int is_hp, char *prefix,
@@ -854,9 +825,9 @@ int simple_util_init_jack(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(simple_util_init_jack);
-int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix)
+int simple_util_init_aux_jacks(struct snd_soc_card *card, char *prefix)
{
- struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_component *component;
int found_jack_index = 0;
int type = 0;
@@ -1026,8 +997,9 @@ EXPORT_SYMBOL_GPL(simple_util_init_priv);
void simple_util_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct simple_util_priv *priv = snd_soc_card_get_drvdata(card);
- simple_util_clean_reference(card);
+ simple_util_clean_reference(priv);
}
EXPORT_SYMBOL_GPL(simple_util_remove);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index b4957e025211..e7ad7af04714 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -517,44 +517,6 @@ end:
return simple_ret(priv, ret);
}
-static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li)
-{
- struct snd_soc_card *card = simple_priv_to_card(priv);
- int ret;
-
- ret = simple_util_parse_widgets(card, PREFIX);
- if (ret < 0)
- goto end;
-
- ret = simple_util_parse_routing(card, PREFIX);
- if (ret < 0)
- goto end;
-
- ret = simple_util_parse_pin_switches(card, PREFIX);
- if (ret < 0)
- goto end;
-
- /* Single/Muti DAI link(s) & New style of DT node */
- memset(li, 0, sizeof(*li));
- ret = simple_for_each_link(priv, li,
- simple_dai_link_of,
- simple_dai_link_of_dpcm);
- if (ret < 0)
- goto end;
-
- ret = simple_util_parse_card_name(priv, PREFIX);
- if (ret < 0)
- goto end;
-
- ret = simple_populate_aux(priv);
- if (ret < 0)
- goto end;
-
- ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
-end:
- return simple_ret(priv, ret);
-}
-
static int simple_count_noml(struct simple_util_priv *priv,
struct device_node *np,
struct device_node *codec,
@@ -699,28 +661,19 @@ static int simple_soc_probe(struct snd_soc_card *card)
if (ret < 0)
goto end;
- ret = simple_util_init_aux_jacks(priv, PREFIX);
+ ret = simple_util_init_aux_jacks(card, PREFIX);
end:
return simple_ret(priv, ret);
}
-static int simple_probe(struct platform_device *pdev)
+static int simple_parse_of(struct simple_util_priv *priv)
{
- struct simple_util_priv *priv;
- struct device *dev = &pdev->dev;
- struct snd_soc_card *card;
- int ret;
-
- /* Allocate the private data and the DAI link array */
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ struct snd_soc_card *card = simple_priv_to_card(priv);
+ struct device *dev = card->dev;
+ int ret = -EINVAL;
- card = simple_priv_to_card(priv);
- card->owner = THIS_MODULE;
- card->dev = dev;
- card->probe = simple_soc_probe;
- card->driver_name = "simple-card";
+ if (!dev)
+ return simple_ret(priv, ret);
ret = -ENOMEM;
struct link_info *li __free(kfree) = kzalloc_obj(*li);
@@ -739,25 +692,71 @@ static int simple_probe(struct platform_device *pdev)
if (ret < 0)
goto end;
- ret = simple_parse_of(priv, li);
- if (ret < 0) {
- dev_err_probe(dev, ret, "parse error\n");
+ ret = simple_util_parse_widgets(priv, PREFIX);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_routing(priv, PREFIX);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_pin_switches(priv, PREFIX);
+ if (ret < 0)
+ goto end;
+
+ ret = simple_util_parse_aux_devs(priv, PREFIX);
+ if (ret < 0)
goto err;
- }
- snd_soc_card_set_drvdata(card, priv);
+ /* Single/Muti DAI link(s) & New style of DT node */
+ memset(li, 0, sizeof(*li));
+ ret = simple_for_each_link(priv, li,
+ simple_dai_link_of,
+ simple_dai_link_of_dpcm);
+ if (ret < 0)
+ goto err;
- simple_util_debug_info(priv);
+ /* Card name should be set after simple_for_each_link() */
+ ret = simple_util_parse_card_name(priv, PREFIX);
+ if (ret < 0)
+ goto err;
- ret = devm_snd_soc_register_card(dev, card);
+ ret = simple_populate_aux(priv);
if (ret < 0)
goto err;
- return 0;
+ snd_soc_card_set_drvdata(card, priv);
+
+ simple_util_debug_info(priv);
+
+ ret = devm_snd_soc_register_card(dev, card);
err:
- simple_util_clean_reference(card);
+ if (ret < 0) {
+ simple_util_clean_reference(priv);
+ return dev_err_probe(dev, ret, "parse error\n");
+ }
end:
- return dev_err_probe(dev, ret, "parse error\n");
+ return simple_ret(priv, ret);
+}
+
+static int simple_probe(struct platform_device *pdev)
+{
+ struct simple_util_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card;
+
+ /* Allocate the private data and the DAI link array */
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ card = simple_priv_to_card(priv);
+ card->owner = THIS_MODULE;
+ card->dev = dev;
+ card->probe = simple_soc_probe;
+ card->driver_name = "simple-card";
+
+ return simple_parse_of(priv);
}
static const struct of_device_id simple_of_match[] = {
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c
index 3629ceaaac17..82df398237da 100644
--- a/sound/soc/intel/atom/sst-atom-controls.c
+++ b/sound/soc/intel/atom/sst-atom-controls.c
@@ -14,6 +14,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/tlv.h>
@@ -73,14 +74,10 @@ static int sst_fill_and_send_cmd(struct sst_data *drv,
u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
void *cmd_data, u16 len)
{
- int ret;
+ guard(mutex)(&drv->lock);
- mutex_lock(&drv->lock);
- ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
- task_id, pipe_id, cmd_data, len);
- mutex_unlock(&drv->lock);
-
- return ret;
+ return sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+ task_id, pipe_id, cmd_data, len);
}
/*
@@ -167,7 +164,7 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol,
unsigned int val, mux;
u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
val = 1 << ctl_no;
/* search which slot/channel has this bit set - there should be only one */
for (mux = e->max; mux > 0; mux--)
@@ -175,7 +172,6 @@ static int sst_slot_get(struct snd_kcontrol *kcontrol,
break;
ucontrol->value.enumerated.item[0] = mux;
- mutex_unlock(&drv->lock);
dev_dbg(c->dev, "%s - %s map = %#x\n",
is_tx ? "tx channel" : "rx slot",
@@ -235,7 +231,7 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
if (mux > e->max - 1)
return -EINVAL;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
/* first clear all registers of this bit */
for (i = 0; i < e->max; i++)
map[i] &= ~val;
@@ -244,7 +240,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
/* kctl set to 'none' and we reset the bits so send IPC */
ret = sst_check_and_send_slot_map(drv, kcontrol);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -258,7 +253,6 @@ static int sst_slot_put(struct snd_kcontrol *kcontrol,
ret = sst_check_and_send_slot_map(drv, kcontrol);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -354,13 +348,12 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
struct sst_algo_control *bc = (void *)kcontrol->private_value;
dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
switch (bc->type) {
case SST_ALGO_PARAMS:
memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
break;
default:
- mutex_unlock(&drv->lock);
dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
bc->type);
return -EINVAL;
@@ -368,7 +361,6 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
/*if pipe is enabled, need to send the algo params from here*/
if (bc->w && bc->w->power)
ret = sst_send_algo_cmd(drv, bc);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -475,7 +467,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
struct sst_gain_value *gv = mc->gain_val;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
switch (mc->type) {
case SST_GAIN_TLV:
@@ -497,7 +489,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
break;
default:
- mutex_unlock(&drv->lock);
dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n",
mc->type);
return -EINVAL;
@@ -506,7 +497,6 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol,
if (mc->w && mc->w->power)
ret = sst_send_gain_cmd(drv, gv, mc->task_id,
mc->pipe_id | mc->instance_id, mc->module_id, 0);
- mutex_unlock(&drv->lock);
return ret;
}
@@ -521,10 +511,9 @@ static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w,
struct sst_data *drv = snd_soc_component_get_drvdata(c);
struct sst_ids *ids = w->priv;
- mutex_lock(&drv->lock);
+ guard(mutex)(&drv->lock);
sst_find_and_send_pipe_algo(drv, w->name, ids);
sst_set_pipe_gain(ids, drv, 0);
- mutex_unlock(&drv->lock);
return 0;
}
@@ -761,27 +750,29 @@ int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
return ret;
}
- mutex_lock(&drv->lock);
- if (enable)
- timer_usage++;
- else
- timer_usage--;
-
- /*
- * Send the command only if this call is the first enable or last
- * disable
- */
- if ((enable && (timer_usage == 1)) ||
- (!enable && (timer_usage == 0))) {
- ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
- SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
- sizeof(cmd.header) + cmd.header.length);
- if (ret && enable) {
+ scoped_guard(mutex, &drv->lock) {
+ if (enable)
+ timer_usage++;
+ else
timer_usage--;
- enable = false;
+
+ /*
+ * Send the command only if this call is the first enable or last
+ * disable
+ */
+ if ((enable && timer_usage == 1) ||
+ (!enable && timer_usage == 0)) {
+ ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
+ SST_FLAG_BLOCKED,
+ SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) +
+ cmd.header.length);
+ if (ret && enable) {
+ timer_usage--;
+ enable = false;
+ }
}
}
- mutex_unlock(&drv->lock);
if (!enable)
sst->ops->power(sst->dev, false);
diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
index f074af2499c8..a4c8cbfba096 100644
--- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c
@@ -11,6 +11,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cleanup.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -32,7 +33,7 @@ int sst_register_dsp(struct sst_device *dev)
return -EINVAL;
if (!try_module_get(dev->dev->driver->owner))
return -ENODEV;
- mutex_lock(&sst_lock);
+ guard(mutex)(&sst_lock);
if (sst) {
dev_err(dev->dev, "we already have a device %s\n", sst->name);
module_put(dev->dev->driver->owner);
@@ -41,7 +42,7 @@ int sst_register_dsp(struct sst_device *dev)
}
dev_dbg(dev->dev, "registering device %s\n", dev->name);
sst = dev;
- mutex_unlock(&sst_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(sst_register_dsp);
@@ -53,17 +54,15 @@ int sst_unregister_dsp(struct sst_device *dev)
if (dev != sst)
return -EINVAL;
- mutex_lock(&sst_lock);
+ guard(mutex)(&sst_lock);
- if (!sst) {
- mutex_unlock(&sst_lock);
+ if (!sst)
return -EIO;
- }
module_put(sst->dev->driver->owner);
dev_dbg(dev->dev, "unreg %s\n", sst->name);
sst = NULL;
- mutex_unlock(&sst_lock);
+
return 0;
}
EXPORT_SYMBOL_GPL(sst_unregister_dsp);
@@ -103,21 +102,14 @@ static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
void sst_set_stream_status(struct sst_runtime_stream *stream,
int state)
{
- unsigned long flags;
- spin_lock_irqsave(&stream->status_lock, flags);
+ guard(spinlock_irqsave)(&stream->status_lock);
stream->stream_status = state;
- spin_unlock_irqrestore(&stream->status_lock, flags);
}
static inline int sst_get_stream_status(struct sst_runtime_stream *stream)
{
- int state;
- unsigned long flags;
-
- spin_lock_irqsave(&stream->status_lock, flags);
- state = stream->stream_status;
- spin_unlock_irqrestore(&stream->status_lock, flags);
- return state;
+ guard(spinlock_irqsave)(&stream->status_lock);
+ return stream->stream_status;
}
static void sst_fill_alloc_params(struct snd_pcm_substream *substream,
@@ -244,12 +236,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
stream->stream_info.str_id = str_params.stream_id;
- ret_val = stream->ops->open(sst->dev, &str_params);
- if (ret_val <= 0)
- return ret_val;
-
-
- return ret_val;
+ return stream->ops->open(sst->dev, &str_params);
}
static void sst_period_elapsed(void *arg)
@@ -304,7 +291,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
{
int ret_val = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct sst_runtime_stream *stream;
+ struct sst_runtime_stream *stream __free(kfree) = NULL;
stream = kzalloc_obj(*stream);
if (!stream)
@@ -312,15 +299,14 @@ static int sst_media_open(struct snd_pcm_substream *substream,
spin_lock_init(&stream->status_lock);
/* get the sst ops */
- mutex_lock(&sst_lock);
- if (!sst ||
- !try_module_get(sst->dev->driver->owner)) {
- dev_err(dai->dev, "no device available to run\n");
- ret_val = -ENODEV;
- goto out_ops;
+ scoped_guard(mutex, &sst_lock) {
+ if (!sst ||
+ !try_module_get(sst->dev->driver->owner)) {
+ dev_err(dai->dev, "no device available to run\n");
+ return -ENODEV;
+ }
+ stream->ops = sst->ops;
}
- stream->ops = sst->ops;
- mutex_unlock(&sst_lock);
stream->stream_info.str_id = 0;
@@ -330,7 +316,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
ret_val = power_up_sst(stream);
if (ret_val < 0)
- goto out_power_up;
+ return ret_val;
/*
* Make sure the period to be multiple of 1ms to align the
@@ -347,12 +333,14 @@ static int sst_media_open(struct snd_pcm_substream *substream,
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIODS, 2);
- return snd_pcm_hw_constraint_integer(runtime,
- SNDRV_PCM_HW_PARAM_PERIODS);
-out_ops:
- mutex_unlock(&sst_lock);
-out_power_up:
- kfree(stream);
+ ret_val = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+
+ if (ret_val < 0)
+ return ret_val;
+
+ stream = NULL;
+
return ret_val;
}
diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c
index 0d5e71e8a5b5..6c19ab63aa4f 100644
--- a/sound/soc/intel/atom/sst/sst_ipc.c
+++ b/sound/soc/intel/atom/sst/sst_ipc.c
@@ -11,6 +11,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <linux/sched.h>
@@ -180,9 +181,8 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
union interrupt_reg_mrfld isr;
union interrupt_reg_mrfld imr;
union ipc_header_mrfld clear_ipc;
- unsigned long irq_flags;
- spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ guard(spinlock_irqsave)(&sst_drv_ctx->ipc_spin_lock);
imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX);
isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX);
@@ -200,7 +200,6 @@ void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
/* un mask busy interrupt */
imr.part.busy_interrupt = 0;
sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full);
- spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
}
diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c
index 22ae2d22f121..44bb11c69490 100644
--- a/sound/soc/intel/atom/sst/sst_pci.c
+++ b/sound/soc/intel/atom/sst/sst_pci.c
@@ -130,13 +130,15 @@ static int intel_sst_probe(struct pci_dev *pci,
sst_drv_ctx->pci = pci_dev_get(pci);
ret = sst_platform_get_resources(sst_drv_ctx);
if (ret < 0)
- goto do_free_drv_ctx;
+ goto do_put_pci;
pci_set_drvdata(pci, sst_drv_ctx);
sst_configure_runtime_pm(sst_drv_ctx);
return ret;
+do_put_pci:
+ pci_dev_put(sst_drv_ctx->pci);
do_free_drv_ctx:
sst_context_cleanup(sst_drv_ctx);
dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c
index 67b1ab14239f..0b0cfd70efbc 100644
--- a/sound/soc/intel/atom/sst/sst_pvt.c
+++ b/sound/soc/intel/atom/sst/sst_pvt.c
@@ -11,6 +11,7 @@
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
+#include <linux/cleanup.h>
#include <linux/kobject.h>
#include <linux/pci.h>
#include <linux/fs.h>
@@ -64,9 +65,8 @@ u64 sst_shim_read64(void __iomem *addr, int offset)
void sst_set_fw_state_locked(
struct intel_sst_drv *sst_drv_ctx, int sst_state)
{
- mutex_lock(&sst_drv_ctx->sst_lock);
+ guard(mutex)(&sst_drv_ctx->sst_lock);
sst_drv_ctx->sst_state = sst_state;
- mutex_unlock(&sst_drv_ctx->sst_lock);
}
/*
@@ -302,18 +302,17 @@ int sst_assign_pvt_id(struct intel_sst_drv *drv)
{
int local;
- spin_lock(&drv->block_lock);
+ guard(spinlock)(&drv->block_lock);
/* find first zero index from lsb */
local = ffz(drv->pvt_id);
dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local);
if (local >= SST_MAX_BLOCKS){
- spin_unlock(&drv->block_lock);
dev_err(drv->dev, "PVT _ID error: no free id blocks ");
return -EINVAL;
}
/* toggle the index */
change_bit(local, &drv->pvt_id);
- spin_unlock(&drv->block_lock);
+
return local;
}
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index b922eeaba843..cf600e1c986e 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/devcoredump.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
@@ -190,7 +191,7 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev)
{
struct avs_path *path;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
/* Any gateway without buffer allocated in LP area disqualifies D0IX. */
list_for_each_entry(path, &adev->path_list, node) {
struct avs_path_pipeline *ppl;
@@ -210,14 +211,11 @@ static bool avs_apl_lp_streaming(struct avs_dev *adev)
if (cfg->copier.dma_type == INVALID_OBJECT_ID)
continue;
- if (!mod->gtw_attrs.lp_buffer_alloc) {
- spin_unlock(&adev->path_list_lock);
+ if (!mod->gtw_attrs.lp_buffer_alloc)
return false;
- }
}
}
}
- spin_unlock(&adev->path_list_lock);
return true;
}
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index 0f8ddd0e9e5f..b4f9d66d55ad 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -336,14 +336,13 @@ int avs_icl_load_basefw(struct avs_dev *adev, struct firmware *fw);
/* Soc component members */
struct avs_soc_component {
- struct snd_soc_component base;
+ struct snd_soc_component *base;
struct avs_tplg *tplg;
struct list_head node;
};
-#define to_avs_soc_component(comp) \
- container_of(comp, struct avs_soc_component, base)
+#define to_avs_soc_component(comp) snd_soc_component_to_priv(comp)
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 2b17abcbd2bc..b7bdd8a690cf 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -175,7 +175,6 @@ static int avs_create_dai_link(struct device *dev, int ssp_port, int tdm_slot,
if (!dl || !platform)
return -ENOMEM;
- dl->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_port);
dl->name = devm_kasprintf(dev, GFP_KERNEL,
AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot));
dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
@@ -259,10 +258,8 @@ static int avs_da7219_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_da7219_driver_ids[] = {
- {
- .name = "avs_da7219",
- },
- {},
+ { .name = "avs_da7219" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_da7219_driver_ids);
diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c
index bf6f580a5164..8d36bc7ddf16 100644
--- a/sound/soc/intel/avs/boards/dmic.c
+++ b/sound/soc/intel/avs/boards/dmic.c
@@ -104,10 +104,8 @@ static int avs_dmic_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_dmic_driver_ids[] = {
- {
- .name = "avs_dmic",
- },
- {},
+ { .name = "avs_dmic" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_dmic_driver_ids);
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
index 301cfb3cf15b..36c13db3a272 100644
--- a/sound/soc/intel/avs/boards/es8336.c
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -309,10 +309,8 @@ static int avs_es8336_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_es8336_driver_ids[] = {
- {
- .name = "avs_es8336",
- },
- {},
+ { .name = "avs_es8336" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_es8336_driver_ids);
diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c
index aec769e2396c..03cfd91202d3 100644
--- a/sound/soc/intel/avs/boards/hdaudio.c
+++ b/sound/soc/intel/avs/boards/hdaudio.c
@@ -231,10 +231,8 @@ static int avs_hdaudio_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_hdaudio_driver_ids[] = {
- {
- .name = "avs_hdaudio",
- },
- {},
+ { .name = "avs_hdaudio" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids);
diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c
index 9a6b89ffdf14..787d781ba1d9 100644
--- a/sound/soc/intel/avs/boards/i2s_test.c
+++ b/sound/soc/intel/avs/boards/i2s_test.c
@@ -107,10 +107,8 @@ static int avs_i2s_test_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_i2s_test_driver_ids[] = {
- {
- .name = "avs_i2s_test",
- },
- {},
+ { .name = "avs_i2s_test" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_i2s_test_driver_ids);
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
index e9a87804f918..389a50923d3b 100644
--- a/sound/soc/intel/avs/boards/max98357a.c
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -136,10 +136,8 @@ static int avs_max98357a_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_max98357a_driver_ids[] = {
- {
- .name = "avs_max98357a",
- },
- {},
+ { .name = "avs_max98357a" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_max98357a_driver_ids);
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 8b45b643ca29..b8231f71d3d6 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -191,10 +191,8 @@ static int avs_max98373_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_max98373_driver_ids[] = {
- {
- .name = "avs_max98373",
- },
- {},
+ { .name = "avs_max98373" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_max98373_driver_ids);
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
index db073125fa4d..d657e7da1cc0 100644
--- a/sound/soc/intel/avs/boards/max98927.c
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -188,10 +188,8 @@ static int avs_max98927_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_max98927_driver_ids[] = {
- {
- .name = "avs_max98927",
- },
- {},
+ { .name = "avs_max98927" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_max98927_driver_ids);
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index d44edacbfc9a..d7ea08bb27cd 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -293,10 +293,8 @@ static int avs_nau8825_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_nau8825_driver_ids[] = {
- {
- .name = "avs_nau8825",
- },
- {},
+ { .name = "avs_nau8825" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_nau8825_driver_ids);
diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c
index b5bebadbbcb2..9d415fd0499a 100644
--- a/sound/soc/intel/avs/boards/pcm3168a.c
+++ b/sound/soc/intel/avs/boards/pcm3168a.c
@@ -132,10 +132,8 @@ static int avs_pcm3168a_probe(struct platform_device *pdev)
}
static const struct platform_device_id avs_pcm3168a_driver_ids[] = {
- {
- .name = "avs_pcm3168a",
- },
- {},
+ { .name = "avs_pcm3168a" },
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids);
diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c
index 73884f8a535c..4053d14289b9 100644
--- a/sound/soc/intel/avs/boards/probe.c
+++ b/sound/soc/intel/avs/boards/probe.c
@@ -64,7 +64,7 @@ static const struct platform_device_id avs_probe_mb_driver_ids[] = {
{
.name = "avs_probe_mb",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_probe_mb_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index a689f4c80867..289f1230851f 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -261,7 +261,7 @@ static const struct platform_device_id avs_rt274_driver_ids[] = {
{
.name = "avs_rt274",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt274_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index 4c9ac545555a..9364d60cfcc7 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -231,7 +231,7 @@ static const struct platform_device_id avs_rt286_driver_ids[] = {
{
.name = "avs_rt286",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt286_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index 2d7a7748d577..5d3b3cdc9564 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -250,7 +250,7 @@ static const struct platform_device_id avs_rt298_driver_ids[] = {
{
.name = "avs_rt298",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt298_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c
index 22139eaad83a..e448bc9fa5ad 100644
--- a/sound/soc/intel/avs/boards/rt5514.c
+++ b/sound/soc/intel/avs/boards/rt5514.c
@@ -178,7 +178,7 @@ static const struct platform_device_id avs_rt5514_driver_ids[] = {
{
.name = "avs_rt5514",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5514_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5640.c b/sound/soc/intel/avs/boards/rt5640.c
index 2990d32f2301..c4e33d71e82f 100644
--- a/sound/soc/intel/avs/boards/rt5640.c
+++ b/sound/soc/intel/avs/boards/rt5640.c
@@ -252,7 +252,7 @@ static const struct platform_device_id avs_rt5640_driver_ids[] = {
{
.name = "avs_rt5640",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5640_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
index 68fea325376a..aadbd3f2a1b2 100644
--- a/sound/soc/intel/avs/boards/rt5663.c
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -249,7 +249,7 @@ static const struct platform_device_id avs_rt5663_driver_ids[] = {
{
.name = "avs_rt5663",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5663_driver_ids);
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 81863728da1d..d33699cca595 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -325,7 +325,7 @@ static const struct platform_device_id avs_rt5682_driver_ids[] = {
{
.name = "avs_rt5682",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_rt5682_driver_ids);
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index ae0e6e27a8b8..d7c9bff37556 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -180,7 +180,7 @@ static const struct platform_device_id avs_ssm4567_driver_ids[] = {
{
.name = "avs_ssm4567",
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, avs_ssm4567_driver_ids);
diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c
index a8f05de338e0..370069247a7d 100644
--- a/sound/soc/intel/avs/control.c
+++ b/sound/soc/intel/avs/control.c
@@ -27,7 +27,7 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
struct avs_path_pipeline *ppl;
struct avs_path_module *mod;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
list_for_each_entry(path, &adev->path_list, node) {
list_for_each_entry(ppl, &path->ppl_list, node) {
list_for_each_entry(mod, &ppl->mod_list, node) {
@@ -35,14 +35,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) ||
guid_equal(type, &AVS_GAIN_MOD_UUID)) &&
- mod->template->ctl_id == id) {
- spin_unlock(&adev->path_list_lock);
+ mod->template->ctl_id == id)
return mod;
- }
}
}
}
- spin_unlock(&adev->path_list_lock);
return NULL;
}
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 1a53856c2ffb..2afe59646896 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -14,6 +14,7 @@
// foundation of this driver
//
+#include <linux/cleanup.h>
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -273,7 +274,7 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream))
ret = IRQ_HANDLED;
- spin_lock_irq(&bus->reg_lock);
+ guard(spinlock_irq)(&bus->reg_lock);
/* Clear RIRB interrupt. */
status = snd_hdac_chip_readb(bus, RIRBSTS);
if (status & RIRB_INT_MASK) {
@@ -283,7 +284,6 @@ static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus)
ret = IRQ_HANDLED;
}
- spin_unlock_irq(&bus->reg_lock);
return ret;
}
diff --git a/sound/soc/intel/avs/debug.h b/sound/soc/intel/avs/debug.h
index 94fe8729a5c1..c47fc4e8b02b 100644
--- a/sound/soc/intel/avs/debug.h
+++ b/sound/soc/intel/avs/debug.h
@@ -9,6 +9,7 @@
#ifndef __SOUND_SOC_INTEL_AVS_DEBUG_H
#define __SOUND_SOC_INTEL_AVS_DEBUG_H
+#include <linux/cleanup.h>
#include "messages.h"
#include "registers.h"
@@ -26,14 +27,9 @@ struct avs_dev;
static inline int avs_log_buffer_status_locked(struct avs_dev *adev, union avs_notify_msg *msg)
{
- unsigned long flags;
- int ret;
+ guard(spinlock_irqsave)(&adev->trace_lock);
- spin_lock_irqsave(&adev->trace_lock, flags);
- ret = avs_dsp_op(adev, log_buffer_status, msg);
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
- return ret;
+ return avs_dsp_op(adev, log_buffer_status, msg);
}
struct avs_apl_log_buffer_layout {
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 701c247227bf..9ab503da3b75 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
@@ -251,24 +252,22 @@ static int strace_release(struct inode *inode, struct file *file)
union avs_notify_msg msg = AVS_NOTIFICATION(LOG_BUFFER_STATUS);
struct avs_dev *adev = file->private_data;
unsigned long resource_mask;
- unsigned long flags, i;
+ unsigned long i;
u32 num_cores;
resource_mask = adev->logged_resources;
num_cores = adev->hw_cfg.dsp_cores;
- spin_lock_irqsave(&adev->trace_lock, flags);
+ scoped_guard(spinlock_irqsave, &adev->trace_lock) {
+ /* Gather any remaining logs. */
+ for_each_set_bit(i, &resource_mask, num_cores) {
+ msg.log.core = i;
+ avs_dsp_op(adev, log_buffer_status, &msg);
+ }
- /* Gather any remaining logs. */
- for_each_set_bit(i, &resource_mask, num_cores) {
- msg.log.core = i;
- avs_dsp_op(adev, log_buffer_status, &msg);
+ kfifo_free(&adev->trace_fifo);
}
- kfifo_free(&adev->trace_fifo);
-
- spin_unlock_irqrestore(&adev->trace_lock, flags);
-
module_put(adev->dev->driver->owner);
return 0;
}
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index c0feb9edd7f6..39b0de9831da 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/slab.h>
#include <sound/hdaudio_ext.h>
@@ -99,39 +100,39 @@ static void avs_dsp_recovery(struct avs_dev *adev)
unsigned int core_mask;
int ret;
- mutex_lock(&adev->comp_list_mutex);
- /* disconnect all running streams */
- list_for_each_entry(acomp, &adev->comp_list, node) {
- struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_card *card;
+ scoped_guard(mutex, &adev->comp_list_mutex) {
+ /* disconnect all running streams */
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ struct snd_soc_pcm_runtime *rtd;
+ struct snd_soc_card *card;
- card = acomp->base.card;
- if (!card)
- continue;
-
- for_each_card_rtds(card, rtd) {
- struct snd_pcm *pcm;
- int dir;
-
- pcm = rtd->pcm;
- if (!pcm || rtd->dai_link->no_pcm)
+ card = acomp->base->card;
+ if (!card)
continue;
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream;
+ for_each_card_rtds(card, rtd) {
+ struct snd_pcm *pcm;
+ int dir;
- substream = pcm->streams[dir].substream;
- if (!substream || !substream->runtime)
+ pcm = rtd->pcm;
+ if (!pcm || rtd->dai_link->no_pcm)
continue;
- /* No need for _irq() as we are in nonatomic context. */
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
- snd_pcm_stream_unlock(substream);
+ for_each_pcm_streams(dir) {
+ struct snd_pcm_substream *substream;
+
+ substream = pcm->streams[dir].substream;
+ if (!substream || !substream->runtime)
+ continue;
+
+ /* No need for _irq() as we are in nonatomic context. */
+ snd_pcm_stream_lock(substream);
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
+ snd_pcm_stream_unlock(substream);
+ }
}
}
}
- mutex_unlock(&adev->comp_list_mutex);
/* forcibly shutdown all cores */
core_mask = GENMASK(adev->hw_cfg.dsp_cores - 1, 0);
@@ -397,7 +398,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
if (!ipc->ready)
return -EPERM;
- mutex_lock(&ipc->msg_mutex);
+ guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, reply);
@@ -412,7 +413,7 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
/* Same treatment as on exception, just stack_dump=0. */
avs_dsp_exception_caught(adev, &msg);
}
- goto exit;
+ return ret;
}
ret = ipc->rx.rsp.status;
@@ -436,8 +437,6 @@ static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request
memcpy(reply->data, ipc->rx.data, reply->size);
}
-exit:
- mutex_unlock(&ipc->msg_mutex);
return ret;
}
@@ -501,7 +500,7 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
struct avs_ipc *ipc = adev->ipc;
int ret;
- mutex_lock(&ipc->msg_mutex);
+ guard(mutex)(&ipc->msg_mutex);
spin_lock(&ipc->rx_lock);
avs_ipc_msg_init(ipc, NULL);
@@ -522,8 +521,6 @@ static int avs_dsp_do_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *req
dev_err(adev->dev, "%s (0x%08x 0x%08x) failed: %d\n",
name, request->glb.primary, request->glb.ext.val, ret);
- mutex_unlock(&ipc->msg_mutex);
-
return ret;
}
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 353e343b1d28..bebdc79ec88e 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -630,15 +631,15 @@ static int avs_load_firmware(struct avs_dev *adev, bool purge)
if (ret)
goto reenable_gating;
- mutex_lock(&adev->comp_list_mutex);
- list_for_each_entry(acomp, &adev->comp_list, node) {
- struct avs_tplg *tplg = acomp->tplg;
+ scoped_guard(mutex, &adev->comp_list_mutex) {
+ list_for_each_entry(acomp, &adev->comp_list, node) {
+ struct avs_tplg *tplg = acomp->tplg;
- ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
- if (ret < 0)
- break;
+ ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
+ if (ret < 0)
+ break;
+ }
}
- mutex_unlock(&adev->comp_list_mutex);
reenable_gating:
avs_hda_l1sen_enable(adev, true);
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index 2291f9728a54..213d6ecdd7cc 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/acpi.h>
#include <acpi/nhlt.h>
#include <sound/pcm_params.h>
@@ -69,16 +70,13 @@ avs_path_find_path(struct avs_dev *adev, const char *name, u32 template_id)
if (!template)
return NULL;
- spin_lock(&adev->path_list_lock);
+ guard(spinlock)(&adev->path_list_lock);
/* Only one variant of given path template may be instantiated at a time. */
list_for_each_entry(path, &adev->path_list, node) {
- if (path->template->owner == template) {
- spin_unlock(&adev->path_list_lock);
+ if (path->template->owner == template)
return path;
- }
}
- spin_unlock(&adev->path_list_lock);
return NULL;
}
@@ -1305,7 +1303,7 @@ void avs_path_free(struct avs_path *path)
struct avs_path *cpath, *csave;
struct avs_dev *adev = path->owner;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Free all condpaths this path spawned. */
list_for_each_entry_safe(cpath, csave, &path->source_list, source_node)
@@ -1314,8 +1312,6 @@ void avs_path_free(struct avs_path *path)
avs_condpath_free(path->owner, cpath);
avs_path_free_unlocked(path);
-
- mutex_unlock(&adev->path_mutex);
}
struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
@@ -1334,13 +1330,13 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
}
/* Serialize path and its components creation. */
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Satisfy needs of avs_path_find_tplg(). */
- mutex_lock(&adev->comp_list_mutex);
+ guard(mutex)(&adev->comp_list_mutex);
path = avs_path_create_unlocked(adev, dma_id, variant);
if (IS_ERR(path))
- goto exit;
+ return path;
ret = avs_condpaths_walk_all(adev, path);
if (ret) {
@@ -1348,10 +1344,6 @@ struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
path = ERR_PTR(ret);
}
-exit:
- mutex_unlock(&adev->comp_list_mutex);
- mutex_unlock(&adev->path_mutex);
-
return path;
}
@@ -1496,15 +1488,13 @@ static void avs_condpaths_pause(struct avs_dev *adev, struct avs_path *path)
{
struct avs_path *cpath;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* If either source or sink stops, so do the attached conditional paths. */
list_for_each_entry(cpath, &path->source_list, source_node)
avs_condpath_pause(adev, cpath);
list_for_each_entry(cpath, &path->sink_list, sink_node)
avs_condpath_pause(adev, cpath);
-
- mutex_unlock(&adev->path_mutex);
}
int avs_path_pause(struct avs_path *path)
@@ -1560,7 +1550,7 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t
{
struct avs_path *cpath;
- mutex_lock(&adev->path_mutex);
+ guard(mutex)(&adev->path_mutex);
/* Run conditional paths only if source and sink are both running. */
list_for_each_entry(cpath, &path->source_list, source_node)
@@ -1572,8 +1562,6 @@ static void avs_condpaths_run(struct avs_dev *adev, struct avs_path *path, int t
if (cpath->source->state == AVS_PPL_STATE_RUNNING &&
cpath->sink->state == AVS_PPL_STATE_RUNNING)
avs_condpath_run(adev, cpath, trigger);
-
- mutex_unlock(&adev->path_mutex);
}
int avs_path_run(struct avs_path *path, int trigger)
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 797b9c9163b4..2b886fae8209 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -958,7 +958,7 @@ static const struct file_operations topology_name_fops = {
static int avs_component_load_libraries(struct avs_soc_component *acomp)
{
struct avs_tplg *tplg = acomp->tplg;
- struct avs_dev *adev = to_avs_dev(acomp->base.dev);
+ struct avs_dev *adev = to_avs_dev(acomp->base->dev);
int ret;
if (!tplg->num_libs)
@@ -1387,25 +1387,28 @@ int avs_register_component(struct device *dev, const char *name,
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
{
struct avs_soc_component *acomp;
- int ret;
+ const char *comp_name;
acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL);
if (!acomp)
return -ENOMEM;
- acomp->base.name = devm_kstrdup(dev, name, GFP_KERNEL);
- if (!acomp->base.name)
+ acomp->base = snd_soc_component_alloc(dev);
+ if (!acomp->base)
+ return -ENOMEM;
+
+ comp_name = devm_kstrdup(dev, name, GFP_KERNEL);
+ if (!comp_name)
return -ENOMEM;
INIT_LIST_HEAD(&acomp->node);
drv->use_dai_pcm_id = !obsolete_card_names;
- ret = snd_soc_component_initialize(&acomp->base, drv, dev);
- if (ret < 0)
- return ret;
+ snd_soc_component_set_name(acomp->base, comp_name);
+ snd_soc_component_set_priv(acomp->base, acomp);
- return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
+ return snd_soc_register_component(acomp->base, drv, cpu_dais, num_cpu_dais);
}
static struct snd_soc_dai_driver dmic_cpu_dais[] = {
diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c
index 099119ad28b3..2e4063b743ba 100644
--- a/sound/soc/intel/avs/probes.c
+++ b/sound/soc/intel/avs/probes.c
@@ -144,7 +144,7 @@ static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
if (ret < 0)
return ret;
- bps = snd_pcm_format_physical_width((__force snd_pcm_format_t)params->codec.format);
+ bps = snd_pcm_format_physical_width(params->codec.format);
if (bps < 0)
return bps;
format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
@@ -296,19 +296,19 @@ static const struct snd_soc_component_driver avs_probe_component_driver = {
int avs_register_probe_component(struct avs_dev *adev, const char *name)
{
struct snd_soc_component *component;
- int ret;
+ const char *comp_name;
- component = devm_kzalloc(adev->dev, sizeof(*component), GFP_KERNEL);
+ component = snd_soc_component_alloc(adev->dev);
if (!component)
return -ENOMEM;
- component->name = devm_kstrdup(adev->dev, name, GFP_KERNEL);
- if (!component->name)
+ comp_name = devm_kstrdup(adev->dev, name, GFP_KERNEL);
+ if (!comp_name)
return -ENOMEM;
- ret = snd_soc_component_initialize(component, &avs_probe_component_driver, adev->dev);
- if (ret)
- return ret;
+ snd_soc_component_set_name(component, comp_name);
- return snd_soc_add_component(component, probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
+ return snd_soc_register_component(component,
+ &avs_probe_component_driver,
+ probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
}
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 9033f683393c..673ac31f2fea 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -2222,7 +2222,7 @@ struct avs_tplg *avs_tplg_new(struct snd_soc_component *comp)
int avs_load_topology(struct snd_soc_component *comp, const char *filename)
{
- const struct firmware *fw;
+ const struct firmware *fw __free(firmware) = NULL;
int ret;
ret = request_firmware(&fw, filename, comp->dev);
@@ -2235,7 +2235,6 @@ int avs_load_topology(struct snd_soc_component *comp, const char *filename)
if (ret < 0)
dev_err(comp->dev, "load topology \"%s\" failed: %d\n", filename, ret);
- release_firmware(fw);
return ret;
}
diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c
index ee36725ac731..ea14ec173855 100644
--- a/sound/soc/intel/avs/utils.c
+++ b/sound/soc/intel/avs/utils.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/cleanup.h>
#include <linux/firmware.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
@@ -48,13 +49,12 @@ int avs_get_module_entry(struct avs_dev *adev, const guid_t *uuid, struct avs_mo
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_entry_index(adev, uuid);
if (idx >= 0)
memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
- mutex_unlock(&adev->modres_mutex);
return (idx < 0) ? idx : 0;
}
@@ -62,13 +62,12 @@ int avs_get_module_id_entry(struct avs_dev *adev, u32 module_id, struct avs_modu
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx >= 0)
memcpy(entry, &adev->mods_info->entries[idx], sizeof(*entry));
- mutex_unlock(&adev->modres_mutex);
return (idx < 0) ? idx : 0;
}
@@ -86,13 +85,12 @@ bool avs_is_module_ida_empty(struct avs_dev *adev, u32 module_id)
bool ret = false;
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx >= 0)
ret = ida_is_empty(adev->mod_idas[idx]);
- mutex_unlock(&adev->modres_mutex);
return ret;
}
@@ -163,68 +161,57 @@ int avs_module_info_init(struct avs_dev *adev, bool purge)
if (ret)
return AVS_IPC_RET(ret);
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
ret = avs_module_ida_alloc(adev, info, purge);
if (ret < 0) {
dev_err(adev->dev, "initialize module idas failed: %d\n", ret);
- goto exit;
+ return ret;
}
/* Refresh current information with newly received table. */
kfree(adev->mods_info);
adev->mods_info = info;
-exit:
- mutex_unlock(&adev->modres_mutex);
return ret;
}
void avs_module_info_free(struct avs_dev *adev)
{
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
avs_module_ida_destroy(adev);
kfree(adev->mods_info);
adev->mods_info = NULL;
-
- mutex_unlock(&adev->modres_mutex);
}
int avs_module_id_alloc(struct avs_dev *adev, u16 module_id)
{
- int ret, idx, max_id;
+ int idx, max_id;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
if (idx == -ENOENT) {
dev_err(adev->dev, "invalid module id: %d", module_id);
- ret = -EINVAL;
- goto exit;
+ return -EINVAL;
}
max_id = adev->mods_info->entries[idx].instance_max_count - 1;
- ret = ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
-exit:
- mutex_unlock(&adev->modres_mutex);
- return ret;
+
+ return ida_alloc_max(adev->mod_idas[idx], max_id, GFP_KERNEL);
}
void avs_module_id_free(struct avs_dev *adev, u16 module_id, u8 instance_id)
{
int idx;
- mutex_lock(&adev->modres_mutex);
+ guard(mutex)(&adev->modres_mutex);
idx = avs_module_id_entry_index(adev, module_id);
- if (idx == -ENOENT) {
+ if (idx == -ENOENT)
dev_err(adev->dev, "invalid module id: %d", module_id);
- goto exit;
- }
-
- ida_free(adev->mod_idas[idx], instance_id);
-exit:
- mutex_unlock(&adev->modres_mutex);
+ else
+ ida_free(adev->mod_idas[idx], instance_id);
}
/*
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index c527d575d1ed..72fe013fffe8 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -1288,7 +1288,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_dai;
}
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
if (ret < 0)
goto err_end;
@@ -1483,12 +1483,12 @@ static int mc_probe(struct platform_device *pdev)
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
- dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
+ dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
sof_sdw_quirk, quirk_override);
sof_sdw_quirk = quirk_override;
}
- log_quirks(card->dev);
+ log_quirks(&pdev->dev);
ctx->mc_quirk = sof_sdw_quirk;
/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
@@ -1507,13 +1507,13 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
amp_num += codec_info_list[i].amp_num;
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
" cfg-amp:%d", amp_num);
if (!card->components)
return -ENOMEM;
if (mach->mach_params.dmic_num) {
- card->components = devm_kasprintf(card->dev, GFP_KERNEL,
+ card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s mic:dmic cfg-mics:%d",
card->components,
mach->mach_params.dmic_num);
@@ -1524,7 +1524,7 @@ static int mc_probe(struct platform_device *pdev)
/* Register the card */
ret = devm_snd_soc_register_card(card->dev, card);
if (ret) {
- dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
asoc_sdw_mc_dailink_exit_loop(card);
return ret;
}
@@ -1542,8 +1542,8 @@ static void mc_remove(struct platform_device *pdev)
}
static const struct platform_device_id mc_id_table[] = {
- { "sof_sdw", },
- {}
+ { .name = "sof_sdw" },
+ { }
};
MODULE_DEVICE_TABLE(platform, mc_id_table);
diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h
index 3881164422b8..f68807c454c9 100644
--- a/sound/soc/intel/catpt/core.h
+++ b/sound/soc/intel/catpt/core.h
@@ -139,9 +139,7 @@ int catpt_dsp_send_msg(struct catpt_dev *cdev, struct catpt_ipc_msg request,
int catpt_first_boot_firmware(struct catpt_dev *cdev);
int catpt_boot_firmware(struct catpt_dev *cdev, bool restore);
-int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan);
-int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan);
-int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan);
+int catpt_store_firmware_context(struct catpt_dev *cdev);
int catpt_coredump(struct catpt_dev *cdev);
#include <sound/memalloc.h>
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index b176aebea9d5..e36eea8b5408 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -28,44 +28,17 @@
static int catpt_do_suspend(struct device *dev)
{
struct catpt_dev *cdev = dev_get_drvdata(dev);
- struct dma_chan *chan;
int ret;
- chan = catpt_dma_request_config_chan(cdev);
- if (IS_ERR(chan))
- return PTR_ERR(chan);
-
memset(&cdev->dx_ctx, 0, sizeof(cdev->dx_ctx));
ret = catpt_ipc_enter_dxstate(cdev, CATPT_DX_STATE_D3, &cdev->dx_ctx);
- if (ret) {
- ret = CATPT_IPC_RET(ret);
- goto release_dma_chan;
- }
-
- ret = catpt_dsp_stall(cdev, true);
if (ret)
- goto release_dma_chan;
-
- ret = catpt_store_memdumps(cdev, chan);
- if (ret) {
- dev_err(cdev->dev, "store memdumps failed: %d\n", ret);
- goto release_dma_chan;
- }
+ return CATPT_IPC_RET(ret);
- ret = catpt_store_module_states(cdev, chan);
- if (ret) {
- dev_err(cdev->dev, "store module states failed: %d\n", ret);
- goto release_dma_chan;
- }
-
- ret = catpt_store_streams_context(cdev, chan);
- if (ret)
- dev_err(cdev->dev, "store streams ctx failed: %d\n", ret);
-
-release_dma_chan:
- dma_release_channel(chan);
+ ret = catpt_store_firmware_context(cdev);
if (ret)
return ret;
+
return catpt_dsp_power_down(cdev);
}
diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c
index c577f2e17ddf..724cbe337db4 100644
--- a/sound/soc/intel/catpt/loader.c
+++ b/sound/soc/intel/catpt/loader.c
@@ -26,7 +26,7 @@ struct catpt_fw_hdr {
u32 reserved[4];
} __packed;
-struct catpt_fw_mod_hdr {
+struct catpt_fw_module_hdr {
char signature[FW_SIGNATURE_SIZE];
u32 mod_size;
u32 blocks;
@@ -81,7 +81,7 @@ catpt_request_region(struct resource *root, resource_size_t size)
return __request_region(root, addr, size, NULL, 0);
}
-int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
{
struct catpt_stream_runtime *stream;
@@ -108,7 +108,7 @@ int catpt_store_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
{
int i;
@@ -138,7 +138,7 @@ int catpt_store_module_states(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_store_dram_data(struct catpt_dev *cdev, struct dma_chan *chan)
{
int i;
@@ -171,6 +171,39 @@ int catpt_store_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
+int catpt_store_firmware_context(struct catpt_dev *cdev)
+{
+ struct dma_chan *chan;
+ int ret;
+
+ chan = catpt_dma_request_config_chan(cdev);
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+
+ ret = catpt_dsp_stall(cdev, true);
+ if (ret)
+ goto exit;
+
+ ret = catpt_store_dram_data(cdev, chan);
+ if (ret) {
+ dev_err(cdev->dev, "store memdumps failed: %d\n", ret);
+ goto exit;
+ }
+
+ ret = catpt_store_module_states(cdev, chan);
+ if (ret) {
+ dev_err(cdev->dev, "store module states failed: %d\n", ret);
+ goto exit;
+ }
+
+ ret = catpt_store_streams_context(cdev, chan);
+ if (ret)
+ dev_err(cdev->dev, "store streams ctx failed: %d\n", ret);
+exit:
+ dma_release_channel(chan);
+ return ret;
+}
+
static int
catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
{
@@ -199,7 +232,7 @@ catpt_restore_streams_context(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
+static int catpt_restore_dram_data(struct catpt_dev *cdev, struct dma_chan *chan)
{
int i;
@@ -234,9 +267,9 @@ static int catpt_restore_memdumps(struct catpt_dev *cdev, struct dma_chan *chan)
return 0;
}
-static int catpt_restore_fwimage(struct catpt_dev *cdev,
- struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_block_hdr *blk)
+static int catpt_restore_dram_rodata(struct catpt_dev *cdev,
+ struct dma_chan *chan, dma_addr_t paddr,
+ struct catpt_fw_block_hdr *blk)
{
struct resource r1 = {};
int i;
@@ -324,28 +357,26 @@ static int catpt_load_block(struct catpt_dev *cdev,
static int catpt_restore_basefw(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_mod_hdr *basefw)
+ struct catpt_fw_module_hdr *basefw)
{
- u32 offset = sizeof(*basefw);
+ u32 off = sizeof(*basefw);
int ret, i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
basefw, sizeof(*basefw), false);
- /* restore basefw image */
+ /* Restore IRAM and .rodata for DRAM based on the firmware image. */
for (i = 0; i < basefw->blocks; i++) {
struct catpt_fw_block_hdr *blk;
- blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + offset);
+ blk = (struct catpt_fw_block_hdr *)((u8 *)basefw + off);
switch (blk->ram_type) {
case CATPT_RAM_TYPE_IRAM:
- ret = catpt_load_block(cdev, chan, paddr + offset,
- blk, false);
+ ret = catpt_load_block(cdev, chan, paddr + off, blk, false);
break;
default:
- ret = catpt_restore_fwimage(cdev, chan, paddr + offset,
- blk);
+ ret = catpt_restore_dram_rodata(cdev, chan, paddr + off, blk);
break;
}
@@ -354,11 +385,11 @@ static int catpt_restore_basefw(struct catpt_dev *cdev,
return ret;
}
- offset += sizeof(*blk) + blk->size;
+ off += sizeof(*blk) + blk->size;
}
- /* then proceed with memory dumps */
- ret = catpt_restore_memdumps(cdev, chan);
+ /* Then proceed with DRAM .data saved before D3. */
+ ret = catpt_restore_dram_data(cdev, chan);
if (ret)
dev_err(cdev->dev, "restore memdumps failed: %d\n", ret);
@@ -367,9 +398,9 @@ static int catpt_restore_basefw(struct catpt_dev *cdev,
static int catpt_restore_module(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_mod_hdr *mod)
+ struct catpt_fw_module_hdr *mod)
{
- u32 offset = sizeof(*mod);
+ u32 off = sizeof(*mod);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
@@ -379,7 +410,7 @@ static int catpt_restore_module(struct catpt_dev *cdev,
struct catpt_fw_block_hdr *blk;
int ret;
- blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset);
+ blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off);
switch (blk->ram_type) {
case CATPT_RAM_TYPE_INSTANCE:
@@ -390,7 +421,7 @@ static int catpt_restore_module(struct catpt_dev *cdev,
ALIGN(blk->size, 4));
break;
default:
- ret = catpt_load_block(cdev, chan, paddr + offset,
+ ret = catpt_load_block(cdev, chan, paddr + off,
blk, false);
break;
}
@@ -400,7 +431,7 @@ static int catpt_restore_module(struct catpt_dev *cdev,
return ret;
}
- offset += sizeof(*blk) + blk->size;
+ off += sizeof(*blk) + blk->size;
}
return 0;
@@ -408,10 +439,10 @@ static int catpt_restore_module(struct catpt_dev *cdev,
static int catpt_load_module(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
- struct catpt_fw_mod_hdr *mod)
+ struct catpt_fw_module_hdr *mod)
{
struct catpt_module_type *type;
- u32 offset = sizeof(*mod);
+ u32 off = sizeof(*mod);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
@@ -423,9 +454,9 @@ static int catpt_load_module(struct catpt_dev *cdev,
struct catpt_fw_block_hdr *blk;
int ret;
- blk = (struct catpt_fw_block_hdr *)((u8 *)mod + offset);
+ blk = (struct catpt_fw_block_hdr *)((u8 *)mod + off);
- ret = catpt_load_block(cdev, chan, paddr + offset, blk, true);
+ ret = catpt_load_block(cdev, chan, paddr + off, blk, true);
if (ret) {
dev_err(cdev->dev, "load block failed: %d\n", ret);
return ret;
@@ -440,7 +471,7 @@ static int catpt_load_module(struct catpt_dev *cdev,
type->state_size = blk->size;
}
- offset += sizeof(*blk) + blk->size;
+ off += sizeof(*blk) + blk->size;
}
/* init module type static info */
@@ -457,17 +488,17 @@ static int catpt_restore_firmware(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
struct catpt_fw_hdr *fw)
{
- u32 offset = sizeof(*fw);
+ u32 off = sizeof(*fw);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
fw, sizeof(*fw), false);
for (i = 0; i < fw->modules; i++) {
- struct catpt_fw_mod_hdr *mod;
+ struct catpt_fw_module_hdr *mod;
int ret;
- mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset);
+ mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off);
if (strncmp(fw->signature, mod->signature,
FW_SIGNATURE_SIZE)) {
dev_err(cdev->dev, "module signature mismatch\n");
@@ -479,12 +510,10 @@ static int catpt_restore_firmware(struct catpt_dev *cdev,
switch (mod->module_id) {
case CATPT_MODID_BASE_FW:
- ret = catpt_restore_basefw(cdev, chan, paddr + offset,
- mod);
+ ret = catpt_restore_basefw(cdev, chan, paddr + off, mod);
break;
default:
- ret = catpt_restore_module(cdev, chan, paddr + offset,
- mod);
+ ret = catpt_restore_module(cdev, chan, paddr + off, mod);
break;
}
@@ -493,7 +522,7 @@ static int catpt_restore_firmware(struct catpt_dev *cdev,
return ret;
}
- offset += sizeof(*mod) + mod->mod_size;
+ off += sizeof(*mod) + mod->mod_size;
}
return 0;
@@ -503,17 +532,17 @@ static int catpt_load_firmware(struct catpt_dev *cdev,
struct dma_chan *chan, dma_addr_t paddr,
struct catpt_fw_hdr *fw)
{
- u32 offset = sizeof(*fw);
+ u32 off = sizeof(*fw);
int i;
print_hex_dump_debug(__func__, DUMP_PREFIX_OFFSET, 8, 4,
fw, sizeof(*fw), false);
for (i = 0; i < fw->modules; i++) {
- struct catpt_fw_mod_hdr *mod;
+ struct catpt_fw_module_hdr *mod;
int ret;
- mod = (struct catpt_fw_mod_hdr *)((u8 *)fw + offset);
+ mod = (struct catpt_fw_module_hdr *)((u8 *)fw + off);
if (strncmp(fw->signature, mod->signature,
FW_SIGNATURE_SIZE)) {
dev_err(cdev->dev, "module signature mismatch\n");
@@ -523,44 +552,40 @@ static int catpt_load_firmware(struct catpt_dev *cdev,
if (mod->module_id > CATPT_MODID_LAST)
return -EINVAL;
- ret = catpt_load_module(cdev, chan, paddr + offset, mod);
+ ret = catpt_load_module(cdev, chan, paddr + off, mod);
if (ret) {
dev_err(cdev->dev, "load module failed: %d\n", ret);
return ret;
}
- offset += sizeof(*mod) + mod->mod_size;
+ off += sizeof(*mod) + mod->mod_size;
}
return 0;
}
-static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan,
- const char *name, const char *signature,
- bool restore)
+static int catpt_request_load_firmware(struct catpt_dev *cdev, struct dma_chan *chan,
+ const char *name, bool restore)
{
struct catpt_fw_hdr *fw;
- struct firmware *img;
dma_addr_t paddr;
void *vaddr;
int ret;
- ret = request_firmware((const struct firmware **)&img, name, cdev->dev);
+ const struct firmware *img __free(firmware) = NULL;
+ ret = request_firmware(&img, name, cdev->dev);
if (ret)
return ret;
fw = (struct catpt_fw_hdr *)img->data;
- if (strncmp(fw->signature, signature, FW_SIGNATURE_SIZE)) {
+ if (strncmp(fw->signature, FW_SIGNATURE, FW_SIGNATURE_SIZE)) {
dev_err(cdev->dev, "firmware signature mismatch\n");
- ret = -EINVAL;
- goto release_fw;
+ return -EINVAL;
}
vaddr = dma_alloc_coherent(cdev->dev, img->size, &paddr, GFP_KERNEL);
- if (!vaddr) {
- ret = -ENOMEM;
- goto release_fw;
- }
+ if (!vaddr)
+ return -ENOMEM;
memcpy(vaddr, img->data, img->size);
fw = (struct catpt_fw_hdr *)vaddr;
@@ -570,12 +595,10 @@ static int catpt_load_image(struct catpt_dev *cdev, struct dma_chan *chan,
ret = catpt_load_firmware(cdev, chan, paddr, fw);
dma_free_coherent(cdev->dev, img->size, vaddr, paddr);
-release_fw:
- release_firmware(img);
return ret;
}
-static int catpt_load_images(struct catpt_dev *cdev, bool restore)
+static int catpt_request_dma_load_firmware(struct catpt_dev *cdev, bool restore)
{
struct dma_chan *chan;
int ret;
@@ -584,8 +607,7 @@ static int catpt_load_images(struct catpt_dev *cdev, bool restore)
if (IS_ERR(chan))
return PTR_ERR(chan);
- ret = catpt_load_image(cdev, chan, cdev->spec->fw_name,
- FW_SIGNATURE, restore);
+ ret = catpt_request_load_firmware(cdev, chan, cdev->spec->fw_name, restore);
if (ret)
goto release_dma_chan;
@@ -605,7 +627,7 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore)
catpt_dsp_stall(cdev, true);
- ret = catpt_load_images(cdev, restore);
+ ret = catpt_request_dma_load_firmware(cdev, restore);
if (ret) {
dev_err(cdev->dev, "load binaries failed: %d\n", ret);
return ret;
@@ -619,10 +641,10 @@ int catpt_boot_firmware(struct catpt_dev *cdev, bool restore)
if (!ret) {
dev_err(cdev->dev, "firmware ready timeout\n");
return -ETIMEDOUT;
+ }
/* Wake up does not mean FW is ready, an exception could occur. */
- } else if (!cdev->ipc.ready) {
+ if (!cdev->ipc.ready)
return -EREMOTEIO;
- }
/* update sram pg & clock once done booting */
catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c
index 8fb0efb67eb1..bbba0d959ea2 100644
--- a/sound/soc/intel/catpt/pcm.c
+++ b/sound/soc/intel/catpt/pcm.c
@@ -75,8 +75,8 @@ static struct catpt_stream_template *catpt_topology[] = {
static struct catpt_stream_template *
catpt_get_stream_template(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
enum catpt_stream_type type;
type = cpu_dai->driver->id;
@@ -159,11 +159,11 @@ static void catpt_stream_read_position(struct catpt_dev *cdev,
static void catpt_arrange_page_table(struct snd_pcm_substream *substream,
struct snd_dma_buffer *pgtbl)
{
- struct snd_pcm_runtime *rtm = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream);
int i, pages;
- pages = snd_sgbuf_aligned_pages(rtm->dma_bytes);
+ pages = snd_sgbuf_aligned_pages(runtime->dma_bytes);
for (i = 0; i < pages; i++) {
u32 pfn, offset;
@@ -386,7 +386,7 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *rtm = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *dmab;
struct catpt_stream_runtime *stream;
struct catpt_audio_format afmt;
@@ -412,8 +412,8 @@ static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
memset(&rinfo, 0, sizeof(rinfo));
rinfo.page_table_addr = stream->pgtbl.addr;
- rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE);
- rinfo.size = rtm->dma_bytes;
+ rinfo.num_pages = DIV_ROUND_UP(runtime->dma_bytes, PAGE_SIZE);
+ rinfo.size = runtime->dma_bytes;
rinfo.offset = 0;
rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0));
@@ -544,11 +544,11 @@ void catpt_stream_update_position(struct catpt_dev *cdev,
struct catpt_notify_position *pos)
{
struct snd_pcm_substream *substream = stream->substream;
- struct snd_pcm_runtime *r = substream->runtime;
+ struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t dsppos, newpos;
int ret;
- dsppos = bytes_to_frames(r, pos->stream_position);
+ dsppos = bytes_to_frames(runtime, pos->stream_position);
if (!stream->prepared)
goto exit;
@@ -556,8 +556,8 @@ void catpt_stream_update_position(struct catpt_dev *cdev,
if (stream->template->type != CATPT_STRM_TYPE_RENDER)
goto exit;
- if (dsppos >= r->buffer_size / 2)
- newpos = r->buffer_size / 2;
+ if (dsppos >= runtime->buffer_size / 2)
+ newpos = runtime->buffer_size / 2;
else
newpos = 0;
/*
@@ -565,7 +565,7 @@ void catpt_stream_update_position(struct catpt_dev *cdev,
* (buffer half consumed) update wp to allow stream progression.
*/
ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
- frames_to_bytes(r, newpos),
+ frames_to_bytes(runtime, newpos),
false, false);
if (ret) {
dev_err(cdev->dev, "update position for stream %d failed: %d\n",
@@ -600,11 +600,11 @@ static const struct snd_pcm_hardware catpt_pcm_hardware = {
};
static int catpt_component_pcm_new(struct snd_soc_component *component,
- struct snd_soc_pcm_runtime *rtm)
+ struct snd_soc_pcm_runtime *rtd)
{
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
- snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG,
+ snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV_SG,
cdev->dev,
catpt_pcm_hardware.buffer_bytes_max,
catpt_pcm_hardware.buffer_bytes_max);
@@ -615,9 +615,9 @@ static int catpt_component_pcm_new(struct snd_soc_component *component,
static int catpt_component_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- if (!rtm->dai_link->no_pcm)
+ if (!rtd->dai_link->no_pcm)
snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
return 0;
}
@@ -626,13 +626,13 @@ static snd_pcm_uframes_t
catpt_component_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtm = snd_soc_substream_to_rtd(substream);
- struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtm, 0);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct catpt_stream_runtime *stream;
struct catpt_dev *cdev = dev_get_drvdata(component->dev);
u32 pos;
- if (rtm->dai_link->no_pcm)
+ if (rtd->dai_link->no_pcm)
return 0;
stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
@@ -650,10 +650,10 @@ static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
.trigger = catpt_dai_trigger,
};
-static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
+static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_dai *dai)
{
- struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtm, 0);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
struct catpt_ssp_device_format devfmt;
struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
int ret;
@@ -871,8 +871,7 @@ static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol)
return CATPT_IPC_RET(ret);
}
-static int catpt_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static int catpt_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = CATPT_CHANNELS_MAX;
@@ -1073,18 +1072,14 @@ int catpt_arm_stream_templates(struct catpt_dev *cdev)
int catpt_register_plat_component(struct catpt_dev *cdev)
{
struct snd_soc_component *component;
- int ret;
- component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL);
+ component = snd_soc_component_alloc(cdev->dev);
if (!component)
return -ENOMEM;
- ret = snd_soc_component_initialize(component, &catpt_comp_driver,
- cdev->dev);
- if (ret)
- return ret;
+ snd_soc_component_set_name(component, catpt_comp_driver.name);
- component->name = catpt_comp_driver.name;
- return snd_soc_add_component(component, dai_drivers,
- ARRAY_SIZE(dai_drivers));
+ return snd_soc_register_component(component,
+ &catpt_comp_driver,
+ dai_drivers, ARRAY_SIZE(dai_drivers));
}
diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
index 59bfd5248819..1033f2d45c8a 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -572,6 +572,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.links = arl_rt711_l0_rt1316_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711-l0-rt1316-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(3),
@@ -600,12 +601,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.links = arl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = 0x1, /* link0 required */
.links = arl_sdca_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-arl-rt711-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(2),
diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
index 937a74a5d523..3b9758f73238 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -717,24 +717,28 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.links = lnl_3_in_1_sdca,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2) | BIT(3),
.links = lnl_cs42l43_l0_cs35l56_l23,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(1) | BIT(2) | BIT(3),
.links = lnl_cs42l43_l2_cs35l56x6_l13,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-cs42l43-l2-cs35l56x6-l13.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(3),
.links = lnl_cs42l43_l0_cs35l56_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -748,12 +752,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.links = lnl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(2) | BIT(3),
.links = lnl_712_only,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-lnl-rt712-l2-rt1712-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -766,19 +772,22 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.link_mask = GENMASK(2, 0),
.links = lnl_sdw_rt1318_l12_rt714_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg"
+ .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(2, 0),
.links = lnl_sdw_rt1320_l12_rt714_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg"
+ .sof_tplg_filename = "sof-lnl-rt1320-l12-rt714-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(1),
.links = lnl_sdw_rt713_l0_rt1318_l1,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg"
+ .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(1) | BIT(2),
diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
index 2e4222456f27..596582053d93 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -1321,60 +1321,70 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.links = tac5572_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tac5572.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tac5672_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tac5672.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tac5682_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tac5682.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tas2783_link0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tas2783.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
.links = tas2883_l0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-tas2883.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(3, 0),
.links = mtl_rt713_l0_rt1316_l12_rt1713_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(3, 0),
.links = mtl_rt713_l0_rt1318_l12_rt1713_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(1) | BIT(3),
.links = mtl_rt713_l0_rt1318_l1_rt1713_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = GENMASK(2, 0),
.links = mtl_rt713_l0_rt1316_l12,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(3) | BIT(0),
.links = mtl_712_l0_1712_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -1395,7 +1405,8 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.link_mask = GENMASK(2, 0),
.links = mtl_sdw_rt1318_l12_rt714_l0,
.drv_name = "sof_sdw",
- .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg"
+ .sof_tplg_filename = "sof-mtl-rt1318-l12-rt714-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2) | BIT(3),
@@ -1455,12 +1466,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.links = mtl_3_in_1_sdca,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = 0x9, /* 2 active links required */
.links = mtl_rt711_l0_rt1316_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l3.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0),
@@ -1474,18 +1487,21 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.links = mtl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = rt5682_link2_max98373_link0,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-sdw-rt5682-l2-max98373-l0.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(0) | BIT(2),
.links = cs42l42_link0_max98363_link2,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-sdw-cs42l42-l0-max98363-l2.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
index f7694b2a2b02..756bbf82a326 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -492,7 +492,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.links = ptl_rt722_l0_rt1320_l23,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-ptl-rt722-l0-rt1320-l23.tplg",
- .get_function_tplg_files = sof_sdw_get_tplg_files,
+ .machine_check = snd_soc_acpi_intel_no_function_topology,
},
{
.link_mask = BIT(1) | BIT(2),
@@ -522,14 +522,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.links = ptl_rvp,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-ptl-rt711.tplg",
+ .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{
.link_mask = BIT(3),
.links = ptl_sdw_rt712_vb_l3_rt1320_l3,
.drv_name = "sof_sdw",
- .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .machine_check = snd_soc_acpi_intel_rt712_vb_no_function_topology,
.sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg",
- .get_function_tplg_files = sof_sdw_get_tplg_files,
},
{},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
index 7caabc501b16..9fdeb6ad96ac 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c
@@ -53,6 +53,14 @@ bool snd_soc_acpi_intel_no_function_topology(void *arg)
}
EXPORT_SYMBOL_NS(snd_soc_acpi_intel_no_function_topology, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg)
+{
+ return snd_soc_acpi_intel_sdca_is_device_rt712_vb(arg) &&
+ snd_soc_acpi_intel_no_function_topology(arg);
+}
+EXPORT_SYMBOL_NS(snd_soc_acpi_intel_rt712_vb_no_function_topology,
+ "SND_SOC_ACPI_INTEL_SDCA_QUIRKS");
+
MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
index 2ea0a1881c4b..60b665ab5924 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
+++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h
@@ -11,5 +11,6 @@
bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg);
bool snd_soc_acpi_intel_no_function_topology(void *arg);
+bool snd_soc_acpi_intel_rt712_vb_no_function_topology(void *arg);
#endif
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index 6659e8060ef3..48f132f01878 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -873,6 +873,8 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
if (kmb_i2s->use_pio) {
irq = platform_get_irq_optional(pdev, 0);
+ if (irq == -EPROBE_DEFER)
+ return irq;
if (irq > 0) {
ret = devm_request_irq(dev, irq, kmb_i2s_irq_handler, 0,
pdev->name, kmb_i2s);
diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index 7910d5d9ac4f..25cd12eab4b1 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -2,24 +2,131 @@
//
// Loongson ASoC Audio Machine driver
//
-// Copyright (C) 2023 Loongson Technology Corporation Limited
+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
// Author: Yingkun Meng <mengyingkun@loongson.cn>
+// Binbin Zhou <zhoubinbin@loongson.cn>
//
-#include <linux/module.h>
-#include <sound/soc.h>
-#include <sound/soc-acpi.h>
#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
#include <linux/pci.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-acpi.h>
static char codec_name[SND_ACPI_I2C_ID_LEN];
struct loongson_card_data {
struct snd_soc_card snd_card;
unsigned int mclk_fs;
+ struct gpio_desc *gpiod_hp_det;
+ struct gpio_desc *gpiod_hp_ctl;
+ struct gpio_desc *gpiod_spkr_en;
+ const struct loongson_card_config *cfg;
+};
+
+struct loongson_card_config {
+ unsigned int fmt;
+ bool add_hp_jack;
+ bool add_dapm_widgets;
+ bool add_dapm_routes;
+};
+
+static const struct loongson_card_config ls2k1000_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = false,
+ .add_dapm_widgets = false,
+ .add_dapm_routes = false,
+};
+
+static const struct loongson_card_config ls2k0300_forever_pi_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = false,
+ .add_dapm_widgets = false,
+ .add_dapm_routes = false,
+};
+
+static const struct loongson_card_config ls2k0300_dl2k0300b_card_config = {
+ .fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,
+ .add_hp_jack = true,
+ .add_dapm_widgets = true,
+ .add_dapm_routes = true,
+};
+
+static int tegra_machine_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm);
+ struct loongson_card_data *priv = snd_soc_card_get_drvdata(card);
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "Speaker"))
+ gpiod_set_value_cansleep(priv->gpiod_spkr_en,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ if (!snd_soc_dapm_widget_name_cmp(w, "Headphone"))
+ gpiod_set_value_cansleep(priv->gpiod_hp_ctl,
+ SND_SOC_DAPM_EVENT_ON(event));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget loongson_aosc_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", tegra_machine_event),
+ SND_SOC_DAPM_SPK("Speaker", tegra_machine_event),
};
+/* Headphones Jack */
+
+static struct snd_soc_jack loongson_asoc_hp_jack;
+
+static struct snd_soc_jack_pin loongson_asoc_hp_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE
+ },
+ {
+ .pin = "Speaker",
+ .mask = SND_JACK_HEADPHONE,
+ .invert = 1
+ },
+};
+
+static struct snd_soc_jack_gpio loongson_asoc_hp_jack_gpio = {
+ .name = "Headphones detection",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+};
+
+static int loongson_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct loongson_card_data *ls_priv = snd_soc_card_get_drvdata(card);
+ int ret = 0;
+
+ if (!ls_priv->cfg->add_hp_jack || !ls_priv->gpiod_hp_det)
+ return 0;
+
+ ret = snd_soc_card_jack_new_pins(card, "Headphones Jack",
+ SND_JACK_HEADPHONE,
+ &loongson_asoc_hp_jack,
+ loongson_asoc_hp_jack_pins,
+ ARRAY_SIZE(loongson_asoc_hp_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headphones Jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ loongson_asoc_hp_jack_gpio.desc = ls_priv->gpiod_hp_det;
+
+ ret = snd_soc_jack_add_gpios(&loongson_asoc_hp_jack, 1, &loongson_asoc_hp_jack_gpio);
+ if (ret)
+ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
+
+ return ret;
+}
+
static int loongson_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -45,7 +152,7 @@ static int loongson_card_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- return 0;
+ return snd_soc_runtime_set_dai_fmt(rtd, ls_card->cfg->fmt);
}
static const struct snd_soc_ops loongson_ops = {
@@ -61,8 +168,7 @@ static struct snd_soc_dai_link loongson_dai_links[] = {
{
.name = "Loongson Audio Port",
.stream_name = "Loongson Audio",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF
- | SND_SOC_DAIFMT_CBC_CFC,
+ .init = loongson_asoc_machine_init,
SND_SOC_DAILINK_REG(analog),
.ops = &loongson_ops,
},
@@ -91,7 +197,7 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
const char *codec_dai_name;
struct acpi_device *adev;
struct device *phy_dev;
- int i;
+ int i, ret;
/* fixup platform name based on reference node */
adev = loongson_card_acpi_find_device(card, "cpu");
@@ -108,7 +214,9 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
return -ENOENT;
snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev));
- device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+ ret = device_property_read_string(card->dev, "codec-dai-name", &codec_dai_name);
+ if (ret)
+ return ret;
for (i = 0; i < card->num_links; i++) {
loongson_dai_links[i].platforms->name = dev_name(phy_dev);
@@ -121,16 +229,35 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
static int loongson_card_parse_of(struct loongson_card_data *data)
{
- struct device_node *cpu, *codec;
struct snd_soc_card *card = &data->snd_card;
+ struct device_node *cpu, *codec;
struct device *dev = card->dev;
int ret, i;
+ data->gpiod_hp_det = devm_gpiod_get_optional(dev, "hp-det", GPIOD_IN);
+ if (IS_ERR(data->gpiod_hp_det))
+ return PTR_ERR(data->gpiod_hp_det);
+
+ data->gpiod_hp_ctl = devm_gpiod_get_optional(dev, "hp-ctl", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpiod_hp_ctl))
+ return PTR_ERR(data->gpiod_hp_ctl);
+
+ data->gpiod_spkr_en = devm_gpiod_get_optional(dev, "spkr-en", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpiod_spkr_en))
+ return PTR_ERR(data->gpiod_spkr_en);
+
+ if (data->cfg->add_dapm_routes) {
+ ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+ if (ret)
+ return ret;
+ }
+
cpu = of_get_child_by_name(dev->of_node, "cpu");
if (!cpu) {
dev_err(dev, "platform property missing or invalid\n");
return -EINVAL;
}
+
codec = of_get_child_by_name(dev->of_node, "codec");
if (!codec) {
dev_err(dev, "audio-codec property missing or invalid\n");
@@ -175,12 +302,22 @@ static int loongson_asoc_card_probe(struct platform_device *pdev)
if (!ls_priv)
return -ENOMEM;
+ ls_priv->cfg = (const struct loongson_card_config *)device_get_match_data(dev);
+ if (!ls_priv->cfg)
+ return -EINVAL;
+
card = &ls_priv->snd_card;
card->dev = dev;
card->owner = THIS_MODULE;
card->dai_link = loongson_dai_links;
card->num_links = ARRAY_SIZE(loongson_dai_links);
+
+ if (ls_priv->cfg->add_dapm_widgets) {
+ card->dapm_widgets = loongson_aosc_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(loongson_aosc_dapm_widgets);
+ }
+
snd_soc_card_set_drvdata(card, ls_priv);
ret = device_property_read_string(dev, "model", &card->name);
@@ -200,7 +337,19 @@ static int loongson_asoc_card_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_asoc_dt_ids[] = {
- { .compatible = "loongson,ls-audio-card" },
+ /* Loongson-2K1000/Loongson-2K2000/LS7A */
+ {
+ .compatible = "loongson,ls-audio-card",
+ .data = &ls2k1000_card_config
+ },
+ {
+ .compatible = "loongson,ls2k0300-forever-pi-audio-card",
+ .data = &ls2k0300_forever_pi_card_config
+ },
+ {
+ .compatible = "loongson,ls2k0300-dl2k0300b-audio-card",
+ .data = &ls2k0300_dl2k0300b_card_config
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_asoc_dt_ids);
diff --git a/sound/soc/loongson/loongson_i2s_plat.c b/sound/soc/loongson/loongson_i2s_plat.c
index ac054b6ce632..82d95c6644ef 100644
--- a/sound/soc/loongson/loongson_i2s_plat.c
+++ b/sound/soc/loongson/loongson_i2s_plat.c
@@ -2,7 +2,7 @@
//
// Loongson I2S controller master mode dirver(platform device)
//
-// Copyright (C) 2023-2024 Loongson Technology Corporation Limited
+// Copyright (C) 2023-2026 Loongson Technology Corporation Limited
//
// Author: Yingkun Meng <mengyingkun@loongson.cn>
// Binbin Zhou <zhoubinbin@loongson.cn>
@@ -21,6 +21,7 @@
#include "loongson_i2s.h"
#include "loongson_dma.h"
+/* Loongson-2K1000 APBDMA routing */
#define LOONGSON_I2S_RX_DMA_OFFSET 21
#define LOONGSON_I2S_TX_DMA_OFFSET 18
@@ -30,6 +31,11 @@
#define LOONGSON_DMA3_CONF 0x3
#define LOONGSON_DMA4_CONF 0x4
+struct loongson_i2s_plat_config {
+ int rev_id;
+ int (*i2s_dma_config)(struct platform_device *pdev);
+};
+
static int loongson_i2s_apbdma_config(struct platform_device *pdev)
{
int val;
@@ -47,8 +53,18 @@ static int loongson_i2s_apbdma_config(struct platform_device *pdev)
return 0;
}
+static const struct loongson_i2s_plat_config ls2k0300_i2s_plat_config = {
+ .rev_id = 1,
+};
+
+static const struct loongson_i2s_plat_config ls2k1000_i2s_plat_config = {
+ .rev_id = 0,
+ .i2s_dma_config = loongson_i2s_apbdma_config,
+};
+
static int loongson_i2s_plat_probe(struct platform_device *pdev)
{
+ const struct loongson_i2s_plat_config *plat_config;
struct device *dev = &pdev->dev;
struct loongson_i2s *i2s;
struct resource *res;
@@ -59,12 +75,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (!i2s)
return -ENOMEM;
- ret = loongson_i2s_apbdma_config(pdev);
- if (ret)
- return ret;
+ plat_config = device_get_match_data(dev);
+ if (!plat_config)
+ return -EINVAL;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- i2s->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (plat_config->i2s_dma_config) {
+ ret = plat_config->i2s_dma_config(pdev);
+ if (ret)
+ return ret;
+ }
+
+ i2s->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(i2s->reg_base))
return dev_err_probe(dev, PTR_ERR(i2s->reg_base),
"devm_ioremap_resource failed\n");
@@ -87,11 +108,17 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
if (IS_ERR(i2s_clk))
return dev_err_probe(dev, PTR_ERR(i2s_clk), "clock property invalid\n");
i2s->clk_rate = clk_get_rate(i2s_clk);
+ i2s->rev_id = plat_config->rev_id;
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
dev_set_name(dev, LS_I2S_DRVNAME);
dev_set_drvdata(dev, i2s);
+ if (i2s->rev_id == 1) {
+ regmap_update_bits(i2s->regmap, LS_I2S_CTRL, I2S_CTRL_RESET, I2S_CTRL_RESET);
+ fsleep(200);
+ }
+
ret = devm_snd_soc_register_component(dev, &loongson_i2s_edma_component,
&loongson_i2s_dai, 1);
if (ret)
@@ -102,7 +129,8 @@ static int loongson_i2s_plat_probe(struct platform_device *pdev)
}
static const struct of_device_id loongson_i2s_ids[] = {
- { .compatible = "loongson,ls2k1000-i2s" },
+ { .compatible = "loongson,ls2k0300-i2s", .data = &ls2k0300_i2s_plat_config },
+ { .compatible = "loongson,ls2k1000-i2s", .data = &ls2k1000_i2s_plat_config },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, loongson_i2s_ids);
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 4af7bbb58010..224746e7664f 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -7,7 +7,7 @@ config SND_SOC_MEDIATEK
config SND_SOC_MT2701
tristate "ASoC support for Mediatek MT2701 chip"
- depends on ARCH_MEDIATEK
+ depends on ARCH_MEDIATEK || COMPILE_TEST
select SND_SOC_MEDIATEK
help
This adds ASoC driver for Mediatek MT2701 boards
diff --git a/sound/soc/mediatek/common/mtk-dsp-sof-common.c b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
index 17b9ea6be604..adefbed5bbe7 100644
--- a/sound/soc/mediatek/common/mtk-dsp-sof-common.c
+++ b/sound/soc/mediatek/common/mtk-dsp-sof-common.c
@@ -232,6 +232,7 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card,
const char *propname)
{
struct device_node *np = dev->of_node;
+ struct snd_soc_dai_link *dai_link;
struct snd_soc_dai_link *parsed_dai_link;
const char *dai_name = NULL;
int i, j, ret, num_links, parsed_num_links = 0;
@@ -254,9 +255,9 @@ int mtk_sof_dailink_parse_of(struct device *dev, struct snd_soc_card *card,
return ret;
}
dev_dbg(dev, "ASoC: Property get dai_name:%s\n", dai_name);
- for (j = 0; j < card->num_links; j++) {
- if (!strcmp(dai_name, card->dai_link[j].name)) {
- memcpy(&parsed_dai_link[parsed_num_links++], &card->dai_link[j],
+ for_each_card_prelinks(card, j, dai_link) {
+ if (!strcmp(dai_name, dai_link->name)) {
+ memcpy(&parsed_dai_link[parsed_num_links++], dai_link,
sizeof(struct snd_soc_dai_link));
break;
}
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 3d6d7bc05b87..8c5096482520 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -315,7 +315,7 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev)
&mt8173_rt5650_priv.pll_from);
if (ret) {
dev_err(&pdev->dev,
- "%s snd_soc_register_card fail %d\n",
+ "%s device_property_read_u32() fail %d\n",
__func__, ret);
}
}
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 983f3b91119a..aa3d1a588479 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -172,7 +172,7 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S32_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
@@ -184,7 +184,7 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index 0bc1f11e17aa..dea7ad167a49 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -99,7 +99,7 @@ static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to S32_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
return 0;
@@ -112,7 +112,7 @@ static int mt8183_rt1015_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
return 0;
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
index 22123b087c3c..b68f474b63f4 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
@@ -387,7 +387,7 @@ static int mt8186_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, fmt);
diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
index 55ebac0c3cef..75c90d1d165f 100644
--- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c
+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
@@ -623,7 +623,7 @@ static int mt8188_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to 32bit, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
diff --git a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
index ad5b9546ff63..5c41a6386204 100644
--- a/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
+++ b/sound/soc/mediatek/mt8189/mt8189-dai-adda.c
@@ -385,8 +385,6 @@ static int mtk_adda_pad_top_event(struct snd_soc_dapm_widget *w,
if (event == SND_SOC_DAPM_PRE_PMU) {
if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2_CLK_P2)
regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB8);
- else if (afe_priv->mtkaif_protocol == MTKAIF_PROTOCOL_2)
- regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
else
regmap_write(afe->regmap, AFE_AUD_PAD_TOP_CFG0, 0xB0);
}
diff --git a/sound/soc/mediatek/mt8189/mt8189-nau8825.c b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
index e849e7a649bc..5d652d0cf01e 100644
--- a/sound/soc/mediatek/mt8189/mt8189-nau8825.c
+++ b/sound/soc/mediatek/mt8189/mt8189-nau8825.c
@@ -174,7 +174,7 @@ static int mt8189_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to 32bit, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index 91c57765ab57..c86348691641 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -382,7 +382,7 @@ static int mt8192_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
@@ -1019,7 +1019,7 @@ static struct snd_soc_card mt8192_mt6359_rt1015p_rt5682x_card = {
.num_dapm_routes = ARRAY_SIZE(mt8192_mt6359_rt1015p_rt5682x_routes),
};
-static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card,
+static int mt8192_mt6359_card_set_be_link(struct device *dev,
struct snd_soc_dai_link *link,
struct device_node *node,
char *link_name)
@@ -1027,9 +1027,9 @@ static int mt8192_mt6359_card_set_be_link(struct snd_soc_card *card,
int ret;
if (node && strcmp(link->name, link_name) == 0) {
- ret = snd_soc_of_get_dai_link_codecs(card->dev, node, link);
+ ret = snd_soc_of_get_dai_link_codecs(dev, node, link);
if (ret < 0) {
- dev_err_probe(card->dev, ret, "get dai link codecs fail\n");
+ dev_err_probe(dev, ret, "get dai link codecs fail\n");
return ret;
}
}
@@ -1065,21 +1065,21 @@ static int mt8192_mt6359_legacy_probe(struct mtk_soc_card_data *soc_card_data)
}
for_each_card_prelinks(card, i, dai_link) {
- ret = mt8192_mt6359_card_set_be_link(card, dai_link, speaker_codec, "I2S3");
+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, speaker_codec, "I2S3");
if (ret) {
dev_err_probe(dev, ret, "%s set speaker_codec fail\n",
dai_link->name);
break;
}
- ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S8");
+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S8");
if (ret) {
dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
break;
}
- ret = mt8192_mt6359_card_set_be_link(card, dai_link, headset_codec, "I2S9");
+ ret = mt8192_mt6359_card_set_be_link(dev, dai_link, headset_codec, "I2S9");
if (ret) {
dev_err_probe(dev, ret, "%s set headset_codec fail\n",
dai_link->name);
diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
index 4d62bc654a58..fc293ca71502 100644
--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
@@ -387,7 +387,7 @@ static int mt8195_dptx_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
@@ -650,7 +650,7 @@ static int mt8195_etdm_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
{
/* fix BE i2s format to S24_LE, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
diff --git a/sound/soc/mediatek/mt8196/mt8196-nau8825.c b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
index c9424786c53d..dae62d684fea 100644
--- a/sound/soc/mediatek/mt8196/mt8196-nau8825.c
+++ b/sound/soc/mediatek/mt8196/mt8196-nau8825.c
@@ -104,8 +104,6 @@ static const struct snd_kcontrol_new mt8196_nau8825_controls[] = {
#define EXT_SPK_AMP_W_NAME "Ext_Speaker_Amp"
-static struct snd_soc_card mt8196_nau8825_soc_card;
-
static const struct snd_soc_dapm_widget mt8196_nau8825_card_widgets[] = {
/* SOF Uplink */
SND_SOC_DAPM_MIXER("SOF_DMA_UL0", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -180,7 +178,7 @@ static int mt8196_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
/* fix BE i2s format to 32bit, clean param mask first */
snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
- 0, (__force unsigned int)SNDRV_PCM_FORMAT_LAST);
+ 0, SNDRV_PCM_FORMAT_LAST);
params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
return 0;
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
index 5966ca18c7c9..e9497246f37c 100644
--- a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
@@ -2120,19 +2120,15 @@ static int mt8365_afe_pcm_dev_probe(struct platform_device *pdev)
spin_lock_init(&afe_priv->afe_ctrl_lock);
mutex_init(&afe_priv->afe_clk_mutex);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- afe->base_addr = devm_ioremap_resource(&pdev->dev, res);
+ afe->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(afe->base_addr))
return PTR_ERR(afe->base_addr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (res) {
- afe_priv->afe_sram_vir_addr =
- devm_ioremap_resource(&pdev->dev, res);
- if (!IS_ERR(afe_priv->afe_sram_vir_addr)) {
- afe_priv->afe_sram_phy_addr = res->start;
- afe_priv->afe_sram_size = resource_size(res);
- }
+ afe_priv->afe_sram_vir_addr =
+ devm_platform_get_and_ioremap_resource(pdev, 1, &res);
+ if (!IS_ERR(afe_priv->afe_sram_vir_addr)) {
+ afe_priv->afe_sram_phy_addr = res->start;
+ afe_priv->afe_sram_size = resource_size(res);
}
/* initial audio related clock */
diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
index 90448df6c0b2..dceee837c67d 100644
--- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c
+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
@@ -70,7 +70,8 @@ static const struct snd_soc_dapm_route mt8365_mt6357_routes[] = {
static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv;
int ret = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -101,7 +102,8 @@ static int mt8365_mt6357_int_adda_startup(struct snd_pcm_substream *substream)
static void mt8365_mt6357_int_adda_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv;
int ret = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -245,7 +247,8 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
static int mt8365_mt6357_gpio_probe(struct snd_soc_card *card)
{
- struct mt8365_mt6357_priv *priv = snd_soc_card_get_drvdata(card);
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(card);
+ struct mt8365_mt6357_priv *priv = soc_card_data->mach_priv;
struct device *dev = card->dev;
int ret, i;
@@ -294,7 +297,6 @@ static int mt8365_mt6357_dev_probe(struct mtk_soc_card_data *soc_card_data, bool
struct mt8365_mt6357_priv *mach_priv;
int ret;
- card->dev = dev;
ret = parse_dai_link_info(card);
if (ret)
goto err;
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
index 24078e4396b0..f9ec0ebb01f0 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -4,6 +4,8 @@ snd-soc-meson-aiu-y := aiu.o
snd-soc-meson-aiu-y += aiu-acodec-ctrl.o
snd-soc-meson-aiu-y += aiu-codec-ctrl.o
snd-soc-meson-aiu-y += aiu-encoder-i2s.o
+snd-soc-meson-aiu-y += gx-formatter.o
+snd-soc-meson-aiu-y += aiu-formatter-i2s.o
snd-soc-meson-aiu-y += aiu-encoder-spdif.o
snd-soc-meson-aiu-y += aiu-fifo.o
snd-soc-meson-aiu-y += aiu-fifo-i2s.o
diff --git a/sound/soc/meson/aiu-encoder-i2s.c b/sound/soc/meson/aiu-encoder-i2s.c
index 3b4061508c18..58dce9f08c9d 100644
--- a/sound/soc/meson/aiu-encoder-i2s.c
+++ b/sound/soc/meson/aiu-encoder-i2s.c
@@ -10,14 +10,11 @@
#include <sound/soc-dai.h>
#include "aiu.h"
+#include "gx-formatter.h"
+#include "gx-interface.h"
-#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
-#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
-#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
-#define AIU_RST_SOFT_I2S_FAST BIT(0)
-#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0)
#define AIU_CLK_CTRL_I2S_DIV GENMASK(3, 2)
#define AIU_CLK_CTRL_AOCLK_INVERT BIT(6)
@@ -35,49 +32,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
}
-static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
- struct snd_pcm_hw_params *params)
-{
- /* Always operate in split (classic interleaved) mode */
- unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT;
-
- /* Reset required to update the pipeline */
- snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
- snd_soc_component_read(component, AIU_I2S_SYNC);
-
- switch (params_physical_width(params)) {
- case 16: /* Nothing to do */
- break;
-
- case 32:
- desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT);
- break;
-
- default:
- return -EINVAL;
- }
-
- switch (params_channels(params)) {
- case 2: /* Nothing to do */
- break;
- case 8:
- desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
- break;
- default:
- return -EINVAL;
- }
-
- snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC,
- AIU_I2S_SOURCE_DESC_MODE_8CH |
- AIU_I2S_SOURCE_DESC_MODE_24BIT |
- AIU_I2S_SOURCE_DESC_MODE_32BIT |
- AIU_I2S_SOURCE_DESC_MODE_SPLIT,
- desc);
-
- return 0;
-}
-
static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
@@ -108,6 +62,32 @@ static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
return 0;
}
+/*
+ * Return true if the given combination of channels and sample width requires
+ * the bs quirk. Return false otherwise.
+ */
+static bool aiu_encoder_is_bs_quirk(unsigned int channels, int width)
+{
+ return (channels == 8) && (width == 16);
+}
+
+static int aiu_encoder_check_bs_quirk(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream);
+
+ /* Nothing to do if the other stream doesn't exist or it's not configured yet. */
+ if (!other_stream || !other_stream->channels)
+ return 0;
+
+ if (aiu_encoder_is_bs_quirk(other_stream->channels, other_stream->width) !=
+ aiu_encoder_is_bs_quirk(params_channels(params), params_width(params)))
+ return -EINVAL;
+
+ return 0;
+}
+
static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
struct snd_pcm_hw_params *params,
unsigned int bs)
@@ -119,7 +99,7 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
* increased by 50% to get the correct output rate.
* No idea why !
*/
- if (params_width(params) == 16 && params_channels(params) == 8) {
+ if (aiu_encoder_is_bs_quirk(params_channels(params), params_width(params))) {
if (bs % 2) {
dev_err(component->dev,
"Cannot increase i2s divider by 50%%\n");
@@ -141,25 +121,23 @@ static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
return 0;
}
-static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
- struct snd_pcm_hw_params *params)
+static int aiu_encoder_i2s_set_clocks(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
{
+ struct snd_soc_component *component = dai->component;
struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
unsigned int srate = params_rate(params);
unsigned int fs, bs;
int ret;
/* Get the oversampling factor */
- fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate);
+ fs = DIV_ROUND_CLOSEST(iface->mclk_rate, srate);
- if (fs % 64)
+ if ((fs % 64) || (fs == 0))
return -EINVAL;
- /* Send data MSB first */
- snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
- AIU_I2S_DAC_CFG_MSB_FIRST,
- AIU_I2S_DAC_CFG_MSB_FIRST);
-
/* Set bclk to lrlck ratio */
snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
AIU_CODEC_DAC_LRCLK_CTRL_DIV,
@@ -168,10 +146,22 @@ static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
bs = fs / 64;
- if (aiu->platform->has_clk_ctrl_more_i2s_div)
+ if (aiu->platform->has_clk_ctrl_more_i2s_div) {
+ /*
+ * The hw rules added in startup() make this unreachable in the
+ * sequential case, but both streams may be refined concurrently
+ * before either commits its config, since only ops->hw_params
+ * runs under the card's pcm_mutex. Re-check against the committed
+ * state of the other stream, which is stable under that mutex.
+ */
+ if (aiu_encoder_check_bs_quirk(substream, params, dai)) {
+ dev_err(dai->dev, "bclk requirements incompatible with other stream\n");
+ return -EINVAL;
+ }
ret = aiu_encoder_i2s_set_more_div(component, params, bs);
- else
+ } else {
ret = aiu_encoder_i2s_set_legacy_div(component, params, bs);
+ }
if (ret)
return ret;
@@ -188,23 +178,37 @@ static int aiu_encoder_i2s_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 gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
int ret;
- /* Disable the clock while changing the settings */
- aiu_encoder_i2s_divider_enable(component, false);
-
- ret = aiu_encoder_i2s_setup_desc(component, params);
+ ret = aiu_encoder_i2s_set_clocks(substream, params, dai);
if (ret) {
- dev_err(dai->dev, "setting i2s desc failed\n");
+ dev_err(dai->dev, "setting i2s clocks failed: %d\n", ret);
return ret;
}
- ret = aiu_encoder_i2s_set_clocks(component, params);
- if (ret) {
- dev_err(dai->dev, "setting i2s clocks failed\n");
+ ts->physical_width = params_physical_width(params);
+ ts->width = params_width(params);
+ ts->channels = params_channels(params);
+
+ return 0;
+}
+
+static int aiu_encoder_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ struct snd_soc_component *component = dai->component;
+ int ret;
+
+ if (ts->clk_enabled)
+ return 0;
+
+ ret = clk_prepare_enable(ts->iface->mclk);
+ if (ret)
return ret;
- }
+
+ ts->clk_enabled = true;
aiu_encoder_i2s_divider_enable(component, true);
@@ -214,9 +218,24 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
struct snd_soc_component *component = dai->component;
- aiu_encoder_i2s_divider_enable(component, false);
+ /*
+ * If this is the last substream being closed then disable the i2s
+ * clock divider.
+ */
+ if (snd_soc_dai_active(dai) <= 1)
+ aiu_encoder_i2s_divider_enable(component, 0);
+
+ if (ts->clk_enabled) {
+ clk_disable_unprepare(ts->iface->mclk);
+ ts->clk_enabled = false;
+ }
+
+ ts->channels = 0;
+ ts->width = 0;
+ ts->physical_width = 0;
return 0;
}
@@ -224,6 +243,8 @@ static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
+ struct aiu *aiu = snd_soc_component_get_drvdata(component);
+ struct gx_iface *iface = &aiu->i2s.iface;
unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
unsigned int val = 0;
unsigned int skew;
@@ -255,9 +276,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
skew = 0;
break;
default:
+ dev_err(dai->dev, "unsupported dai format\n");
return -EINVAL;
}
+ iface->fmt = fmt;
+
val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew);
snd_soc_component_update_bits(component, AIU_CLK_CTRL,
AIU_CLK_CTRL_LRCLK_INVERT |
@@ -272,6 +296,7 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir)
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
+ struct gx_iface *iface = &aiu->i2s.iface;
int ret;
if (WARN_ON(clk_id != 0))
@@ -280,11 +305,15 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
if (dir == SND_SOC_CLOCK_IN)
return 0;
- ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq);
- if (ret)
- dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
+ ret = clk_set_rate(iface->mclk, freq);
+ if (ret) {
+ dev_err(dai->dev, "Failed to set sysclk to %uHz: %d", freq, ret);
+ return ret;
+ }
- return ret;
+ iface->mclk_rate = freq;
+
+ return 0;
}
static const unsigned int hw_channels[] = {2, 8};
@@ -294,10 +323,45 @@ static const struct snd_pcm_hw_constraint_list hw_channel_constraints = {
.mask = 0,
};
+static int aiu_encoder_i2s_pcm_hw_rule(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct gx_stream *other = rule->private;
+ struct snd_interval *ch = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ /*
+ * The quirk is technically based on the significant bits whereas here
+ * we're using the physical width for simplicity. This works because
+ * S16_LE is the only format supported by this encoder that has:
+ * significant bits = physical width = 16-bits
+ */
+ struct snd_interval *phys_width = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+ struct snd_interval new_i;
+
+ if (other->channels == 0)
+ return 0;
+
+ snd_interval_any(&new_i);
+
+ if (rule->var == SNDRV_PCM_HW_PARAM_CHANNELS) {
+ if (aiu_encoder_is_bs_quirk(other->channels, other->width))
+ new_i.min = new_i.max = 8;
+ else if (snd_interval_single(phys_width) && phys_width->min == 16)
+ new_i.max = 2; /* Force 2ch */
+ } else { /* SNDRV_PCM_HW_PARAM_SAMPLE_BITS */
+ if (aiu_encoder_is_bs_quirk(other->channels, other->width))
+ new_i.min = new_i.max = 16;
+ else if (snd_interval_single(ch) && ch->min == 8)
+ new_i.min = 17; /* Request physical width > 16 bits */
+ }
+
+ return snd_interval_refine(hw_param_interval(params, rule->var), &new_i);
+}
+
static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
+ struct gx_stream *other_stream = snd_soc_dai_dma_data_get(dai, !substream->stream);
int ret;
/* Make sure the encoder gets either 2 or 8 channels */
@@ -305,15 +369,79 @@ static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_CHANNELS,
&hw_channel_constraints);
if (ret) {
- dev_err(dai->dev, "adding channels constraints failed\n");
+ dev_err(dai->dev, "adding channels constraints failed: %d\n", ret);
return ret;
}
- ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks);
- if (ret)
- dev_err(dai->dev, "failed to enable i2s clocks\n");
+ /*
+ * If DAI supports both playback and capture streams ensure the bs-quirk is
+ * handled correctly.
+ * This is only valid for GX platforms (has_clk_ctrl_more_i2s_div=true).
+ */
+ if (aiu->platform->has_clk_ctrl_more_i2s_div && other_stream) {
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ aiu_encoder_i2s_pcm_hw_rule,
+ other_stream,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+ if (ret)
+ return ret;
+
+ ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ aiu_encoder_i2s_pcm_hw_rule,
+ other_stream,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
+ if (ret)
+ return ret;
+ }
- return ret;
+ /*
+ * Enable only clocks which are required for the interface internal
+ * logic. MCLK is enabled/disabled from the formatter and the I2S
+ * divider is enabled/disabled in "hw_params"/"hw_free", respectively.
+ */
+ ret = clk_prepare_enable(aiu->i2s.clks[PCLK].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable PCLK: %d\n", ret);
+ return ret;
+ }
+ ret = clk_prepare_enable(aiu->i2s.clks[MIXER].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable MIXER: %d\n", ret);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+ return ret;
+ }
+ ret = clk_prepare_enable(aiu->i2s.clks[AOCLK].clk);
+ if (ret) {
+ dev_err(dai->dev, "failed to enable AOCLK: %d\n", ret);
+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+ return ret;
+ }
+
+ /*
+ * We're always operating in split mode for the playback stream.
+ *
+ * This setting arguably belong to the 'aiu-formatter', but it's kept
+ * here for backward compatibility reason. At reset the I2S encoder
+ * operates in normal mode which would only support 8ch, but by default
+ * only 2ch are enabled. If a playback stream is started without
+ * changing to split mode, then the I2S encoder doesn't consume audio
+ * samples and the playback fails.
+ * Moving this to 'aiu-formatter' would cause the split mode to be set
+ * only when the formatter is enabled, which doesn't happen at boot as
+ * the default value for "HDMI CTRL SRC" is "DISABLED".
+ */
+ ret = snd_soc_component_update_bits(dai->component, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT);
+ if (ret < 0)
+ dev_err(dai->dev, "failed to update AIU_I2S_SOURCE_DESC: %d", ret);
+
+ return 0;
}
static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
@@ -321,14 +449,89 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
{
struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
- clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks);
+ clk_disable_unprepare(aiu->i2s.clks[AOCLK].clk);
+ clk_disable_unprepare(aiu->i2s.clks[MIXER].clk);
+ clk_disable_unprepare(aiu->i2s.clks[PCLK].clk);
+}
+
+static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream,
+ int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = gx_stream_start(ts);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ gx_stream_stop(ts);
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aiu_encoder_i2s_remove_dai(struct snd_soc_dai *dai)
+{
+ int stream;
+
+ for_each_pcm_streams(stream) {
+ struct gx_stream *ts;
+
+ ts = snd_soc_dai_dma_data_get(dai, stream);
+ if (ts)
+ gx_stream_free(ts);
+
+ snd_soc_dai_dma_data_set(dai, stream, NULL);
+ }
+
+ return 0;
+}
+
+static int aiu_encoder_i2s_probe_dai(struct snd_soc_dai *dai)
+{
+ struct aiu *aiu = snd_soc_dai_get_drvdata(dai);
+ struct gx_iface *iface = &aiu->i2s.iface;
+ int stream;
+
+ for_each_pcm_streams(stream) {
+ struct gx_stream *ts;
+
+ if (!snd_soc_dai_get_widget(dai, stream))
+ continue;
+
+ ts = gx_stream_alloc(iface);
+ if (!ts) {
+ aiu_encoder_i2s_remove_dai(dai);
+ return -ENOMEM;
+ }
+ snd_soc_dai_dma_data_set(dai, stream, ts);
+ }
+
+ iface->mclk = aiu->i2s.clks[MCLK].clk;
+ iface->mclk_rate = clk_get_rate(iface->mclk);
+
+ return 0;
}
const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
+ .probe = aiu_encoder_i2s_probe_dai,
+ .remove = aiu_encoder_i2s_remove_dai,
.hw_params = aiu_encoder_i2s_hw_params,
+ .prepare = aiu_encoder_i2s_prepare,
.hw_free = aiu_encoder_i2s_hw_free,
.set_fmt = aiu_encoder_i2s_set_fmt,
.set_sysclk = aiu_encoder_i2s_set_sysclk,
.startup = aiu_encoder_i2s_startup,
.shutdown = aiu_encoder_i2s_shutdown,
+ .trigger = aiu_encoder_i2s_trigger,
};
diff --git a/sound/soc/meson/aiu-formatter-i2s.c b/sound/soc/meson/aiu-formatter-i2s.c
new file mode 100644
index 000000000000..cb554c2e7ce4
--- /dev/null
+++ b/sound/soc/meson/aiu-formatter-i2s.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2026 BayLibre, SAS.
+// Author: Valerio Setti <vsetti@baylibre.com>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "aiu.h"
+#include "gx-formatter.h"
+
+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
+
+#define AIU_I2S_DAC_CFG_MSB_FIRST BIT(2)
+
+static struct snd_soc_dai *
+aiu_formatter_i2s_get_be(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+ 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 = aiu_formatter_i2s_get_be(p->sink);
+ if (be)
+ return be;
+ }
+
+ return NULL;
+}
+
+static struct gx_stream *
+aiu_formatter_i2s_get_stream(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dai *be = aiu_formatter_i2s_get_be(w);
+
+ if (!be)
+ return NULL;
+
+ return snd_soc_dai_dma_data_get_playback(be);
+}
+
+static int aiu_formatter_i2s_prepare(struct regmap *map,
+ const struct gx_formatter_hw *quirks,
+ struct gx_stream *ts)
+{
+ /* Always operate in split (classic interleaved) mode */
+ unsigned int desc = 0;
+
+ /*
+ * Pipeline reset is already implemented in aiu_fifo_i2s_trigger() at
+ * trigger time.
+ */
+
+ switch (ts->physical_width) {
+ case 16: /* Nothing to do */
+ break;
+
+ case 32:
+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (ts->channels) {
+ case 2: /* Nothing to do */
+ break;
+ case 8:
+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(map, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_8CH |
+ AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT,
+ desc);
+
+ /* Send data MSB first */
+ regmap_update_bits(map, AIU_I2S_DAC_CFG,
+ AIU_I2S_DAC_CFG_MSB_FIRST,
+ AIU_I2S_DAC_CFG_MSB_FIRST);
+
+ return 0;
+}
+
+const struct gx_formatter_ops aiu_formatter_i2s_ops = {
+ .get_stream = aiu_formatter_i2s_get_stream,
+ .prepare = aiu_formatter_i2s_prepare,
+};
diff --git a/sound/soc/meson/aiu.c b/sound/soc/meson/aiu.c
index f2890111c1d2..535fbf7c1639 100644
--- a/sound/soc/meson/aiu.c
+++ b/sound/soc/meson/aiu.c
@@ -29,13 +29,22 @@ static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum, AIU_I2S_MISC,
static const struct snd_kcontrol_new aiu_spdif_encode_mux =
SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum);
-static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
- SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
- &aiu_spdif_encode_mux),
+#define AIU_WIDGET_SPDIF_SRC_SEL 0
+#define AIU_WIDGET_I2S_FORMATTER 1
+
+static struct snd_soc_dapm_widget aiu_cpu_dapm_widgets[] = {
+ [AIU_WIDGET_SPDIF_SRC_SEL] =
+ SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM, 0, 0,
+ &aiu_spdif_encode_mux),
+ [AIU_WIDGET_I2S_FORMATTER] =
+ SND_SOC_DAPM_PGA_E("I2S Formatter", SND_SOC_NOPM, 0, 0, NULL, 0,
+ gx_formatter_event,
+ (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD)),
};
static const struct snd_soc_dapm_route aiu_cpu_dapm_routes[] = {
- { "I2S Encoder Playback", NULL, "I2S FIFO Playback" },
+ { "I2S Formatter", NULL, "I2S FIFO Playback" },
+ { "I2S Encoder Playback", NULL, "I2S Formatter" },
{ "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
{ "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
{ "SPDIF Encoder Playback", NULL, "SPDIF SRC SEL" },
@@ -145,6 +154,7 @@ static struct snd_soc_dai_driver aiu_cpu_dai_drv[] = {
.formats = AIU_FORMATS,
},
.ops = &aiu_encoder_i2s_dai_ops,
+ .symmetric_rate = 1,
},
[CPU_SPDIF_ENCODER] = {
.name = "SPDIF Encoder",
@@ -172,6 +182,11 @@ static const struct regmap_config aiu_regmap_cfg = {
.max_register = 0x2ac,
};
+static const struct gx_formatter_driver aiu_formatter_i2s_drv = {
+ .regmap_cfg = &aiu_regmap_cfg,
+ .ops = &aiu_formatter_i2s_ops,
+};
+
static int aiu_clk_bulk_get(struct device *dev,
const char * const *ids,
unsigned int num,
@@ -282,6 +297,14 @@ static int aiu_probe(struct platform_device *pdev)
if (ret)
return ret;
+ /* Allocate the aiu-formatter into its widget */
+ ret = gx_formatter_create(dev, &aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER],
+ &aiu_formatter_i2s_drv, map);
+ if (ret) {
+ dev_err(dev, "Failed to allocate aiu formatter\n");
+ goto err;
+ }
+
/* Register the cpu component of the aiu */
ret = snd_soc_register_component(dev, &aiu_cpu_component,
aiu_cpu_dai_drv,
@@ -310,12 +333,14 @@ static int aiu_probe(struct platform_device *pdev)
return 0;
err:
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(dev);
return ret;
}
static void aiu_remove(struct platform_device *pdev)
{
+ gx_formatter_free(&aiu_cpu_dapm_widgets[AIU_WIDGET_I2S_FORMATTER]);
snd_soc_unregister_component(&pdev->dev);
}
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
index 0f94c8bf6081..7d0b98c1f351 100644
--- a/sound/soc/meson/aiu.h
+++ b/sound/soc/meson/aiu.h
@@ -7,6 +7,8 @@
#ifndef _MESON_AIU_H
#define _MESON_AIU_H
+#include "gx-formatter.h"
+
struct clk;
struct clk_bulk_data;
struct device;
@@ -25,6 +27,7 @@ struct aiu_interface {
struct clk_bulk_data *clks;
unsigned int clk_num;
int irq;
+ struct gx_iface iface;
};
struct aiu_platform_data {
@@ -58,6 +61,7 @@ extern const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops;
extern const struct snd_soc_dai_ops aiu_encoder_spdif_dai_ops;
+extern const struct gx_formatter_ops aiu_formatter_i2s_ops;
#define AIU_IEC958_BPF 0x000
#define AIU_958_MISC 0x010
diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c
index b4dca80e15e4..c36f727af4ba 100644
--- a/sound/soc/meson/axg-card.c
+++ b/sound/soc/meson/axg-card.c
@@ -107,6 +107,7 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
struct snd_soc_dai_link *pad;
struct snd_soc_dai_link *lb;
struct snd_soc_dai_link_component *dlc;
+ struct device *dev = card->dev;
int ret;
/* extend links */
@@ -117,11 +118,11 @@ static int axg_card_add_tdm_loopback(struct snd_soc_card *card,
pad = &card->dai_link[*index];
lb = &card->dai_link[*index + 1];
- lb->name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-lb", pad->name);
+ lb->name = devm_kasprintf(dev, GFP_KERNEL, "%s-lb", pad->name);
if (!lb->name)
return -ENOMEM;
- dlc = devm_kzalloc(card->dev, sizeof(*dlc), GFP_KERNEL);
+ dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL);
if (!dlc)
return -ENOMEM;
@@ -158,13 +159,14 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
struct device_node *node,
struct axg_dai_link_tdm_data *be)
{
+ struct device *dev = card->dev;
char propname[32];
u32 tx, rx;
int i;
- be->tx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+ be->tx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES,
sizeof(*be->tx_mask), GFP_KERNEL);
- be->rx_mask = devm_kcalloc(card->dev, AXG_TDM_NUM_LANES,
+ be->rx_mask = devm_kcalloc(dev, AXG_TDM_NUM_LANES,
sizeof(*be->rx_mask), GFP_KERNEL);
if (!be->tx_mask || !be->rx_mask)
return -ENOMEM;
@@ -191,7 +193,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
/* ... but the interface should at least have one direction */
if (!tx && !rx) {
- dev_err(card->dev, "tdm link has no cpu slots\n");
+ dev_err(dev, "tdm link has no cpu slots\n");
return -EINVAL;
}
@@ -207,7 +209,7 @@ static int axg_card_parse_cpu_tdm_slots(struct snd_soc_card *card,
* 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");
+ dev_err(dev, "bad slot number\n");
return -EINVAL;
}
@@ -222,8 +224,9 @@ static int axg_card_parse_codecs_masks(struct snd_soc_card *card,
struct axg_dai_link_tdm_data *be)
{
struct axg_dai_link_tdm_mask *codec_mask;
+ struct device *dev = card->dev;
- codec_mask = devm_kcalloc(card->dev, link->num_codecs,
+ codec_mask = devm_kcalloc(dev, link->num_codecs,
sizeof(*codec_mask), GFP_KERNEL);
if (!codec_mask)
return -ENOMEM;
@@ -249,10 +252,11 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
struct meson_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;
+ struct device *dev = card->dev;
int ret;
/* Allocate tdm link parameters */
- be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
+ be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL);
if (!be)
return -ENOMEM;
priv->link_data[*index] = be;
@@ -266,7 +270,7 @@ static int axg_card_parse_tdm(struct snd_soc_card *card,
ret = axg_card_parse_cpu_tdm_slots(card, link, node, be);
if (ret) {
- dev_err(card->dev, "error parsing tdm link slots\n");
+ dev_err(dev, "error parsing tdm link slots\n");
return ret;
}
@@ -310,9 +314,10 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np,
{
struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
struct snd_soc_dai_link_component *cpu;
+ struct device *dev = card->dev;
int ret;
- cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL);
+ cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL);
if (!cpu)
return -ENOMEM;
diff --git a/sound/soc/meson/g12a-toacodec.c b/sound/soc/meson/g12a-toacodec.c
index a95375b53f0a..21941ee552c5 100644
--- a/sound/soc/meson/g12a-toacodec.c
+++ b/sound/soc/meson/g12a-toacodec.c
@@ -312,7 +312,7 @@ static int g12a_toacodec_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c
index d541ca4acfaf..967109ca2b57 100644
--- a/sound/soc/meson/g12a-tohdmitx.c
+++ b/sound/soc/meson/g12a-tohdmitx.c
@@ -251,7 +251,7 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev)
ret = device_reset(dev);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/meson/gx-card.c b/sound/soc/meson/gx-card.c
index b408cc2bbc91..932be0a09306 100644
--- a/sound/soc/meson/gx-card.c
+++ b/sound/soc/meson/gx-card.c
@@ -48,9 +48,10 @@ static int gx_card_parse_i2s(struct snd_soc_card *card,
struct meson_card *priv = snd_soc_card_get_drvdata(card);
struct snd_soc_dai_link *link = &card->dai_link[*index];
struct gx_dai_link_i2s_data *be;
+ struct device *dev = card->dev;
/* Allocate i2s link parameters */
- be = devm_kzalloc(card->dev, sizeof(*be), GFP_KERNEL);
+ be = devm_kzalloc(dev, sizeof(*be), GFP_KERNEL);
if (!be)
return -ENOMEM;
priv->link_data[*index] = be;
@@ -81,9 +82,10 @@ static int gx_card_add_link(struct snd_soc_card *card, struct device_node *np,
{
struct snd_soc_dai_link *dai_link = &card->dai_link[*index];
struct snd_soc_dai_link_component *cpu;
+ struct device *dev = card->dev;
int ret;
- cpu = devm_kzalloc(card->dev, sizeof(*cpu), GFP_KERNEL);
+ cpu = devm_kzalloc(dev, sizeof(*cpu), GFP_KERNEL);
if (!cpu)
return -ENOMEM;
diff --git a/sound/soc/meson/gx-formatter.c b/sound/soc/meson/gx-formatter.c
new file mode 100644
index 000000000000..311e63affb23
--- /dev/null
+++ b/sound/soc/meson/gx-formatter.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+//
+// Copyright (c) 2026 BayLibre, SAS.
+// Author: Valerio Setti <vsetti@baylibre.com>
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+
+#include "gx-formatter.h"
+
+struct gx_formatter {
+ struct list_head list;
+ struct gx_stream *stream;
+ const struct gx_formatter_driver *drv;
+ bool enabled;
+ struct regmap *map;
+};
+
+static int gx_formatter_enable(struct gx_formatter *formatter)
+{
+ int ret;
+
+ /* Do nothing if the formatter is already enabled */
+ if (formatter->enabled)
+ return 0;
+
+ /* Setup the stream parameter in the formatter */
+ if (formatter->drv->ops->prepare) {
+ ret = formatter->drv->ops->prepare(formatter->map,
+ formatter->drv->quirks,
+ formatter->stream);
+ if (ret)
+ return ret;
+ }
+
+ /* Finally, actually enable the formatter */
+ if (formatter->drv->ops->enable)
+ formatter->drv->ops->enable(formatter->map);
+
+ formatter->enabled = true;
+
+ return 0;
+}
+
+static void gx_formatter_disable(struct gx_formatter *formatter)
+{
+ /* Do nothing if the formatter is already disabled */
+ if (!formatter->enabled)
+ return;
+
+ if (formatter->drv->ops->disable)
+ formatter->drv->ops->disable(formatter->map);
+
+ formatter->enabled = false;
+}
+
+static int gx_formatter_attach(struct gx_formatter *formatter)
+{
+ struct gx_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 = gx_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 gx_formatter_detach(struct gx_formatter *formatter)
+{
+ struct gx_stream *ts = formatter->stream;
+
+ if (!ts)
+ return;
+
+ mutex_lock(&ts->lock);
+ list_del(&formatter->list);
+ mutex_unlock(&ts->lock);
+
+ gx_formatter_disable(formatter);
+}
+
+static int gx_formatter_power_up(struct gx_formatter *formatter,
+ struct snd_soc_dapm_widget *w)
+{
+ struct gx_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;
+
+ formatter->stream = ts;
+ INIT_LIST_HEAD(&formatter->list);
+ ret = gx_formatter_attach(formatter);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void gx_formatter_power_down(struct gx_formatter *formatter)
+{
+ gx_formatter_detach(formatter);
+ formatter->stream = NULL;
+}
+
+int gx_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event)
+{
+ struct snd_soc_component *c;
+ struct gx_formatter *formatter;
+ int ret = 0;
+
+ c = snd_soc_dapm_to_component(w->dapm);
+
+ if (w->priv)
+ formatter = w->priv;
+ else
+ formatter = snd_soc_component_get_drvdata(c);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = gx_formatter_power_up(formatter, w);
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ gx_formatter_power_down(formatter);
+ break;
+
+ default:
+ dev_err(c->dev, "Unexpected event %d\n", event);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gx_formatter_event);
+
+int gx_formatter_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct gx_formatter_driver *drv;
+ struct gx_formatter *formatter;
+ void __iomem *regs;
+
+ 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;
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ 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);
+ }
+
+ return devm_snd_soc_register_component(dev, drv->component_drv,
+ NULL, 0);
+}
+EXPORT_SYMBOL_GPL(gx_formatter_probe);
+
+int gx_formatter_create(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ const struct gx_formatter_driver *drv,
+ struct regmap *regmap)
+{
+ struct gx_formatter *formatter;
+
+ formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+ if (!formatter)
+ return -ENOMEM;
+
+ formatter->drv = drv;
+ formatter->map = regmap;
+
+ w->priv = formatter;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gx_formatter_create);
+
+int gx_stream_start(struct gx_stream *ts)
+{
+ struct gx_formatter *formatter;
+ int ret = 0;
+
+ mutex_lock(&ts->lock);
+
+ /* Start all the formatters attached to the stream */
+ list_for_each_entry(formatter, &ts->formatter_list, list) {
+ ret = gx_formatter_enable(formatter);
+ if (ret) {
+ pr_err("failed to enable formatter\n");
+ goto out;
+ }
+ }
+
+ ts->ready = true;
+
+out:
+ mutex_unlock(&ts->lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gx_stream_start);
+
+void gx_stream_stop(struct gx_stream *ts)
+{
+ struct gx_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) {
+ gx_formatter_disable(formatter);
+ }
+
+ mutex_unlock(&ts->lock);
+}
+EXPORT_SYMBOL_GPL(gx_stream_stop);
+
+struct gx_stream *gx_stream_alloc(struct gx_iface *iface)
+{
+ struct gx_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(gx_stream_alloc);
+
+void gx_stream_free(struct gx_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
+ * 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(gx_stream_free);
+
+MODULE_DESCRIPTION("Amlogic GX formatter driver");
+MODULE_AUTHOR("Valerio Setti <vsetti@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/meson/gx-formatter.h b/sound/soc/meson/gx-formatter.h
new file mode 100644
index 000000000000..b90b1814d79b
--- /dev/null
+++ b/sound/soc/meson/gx-formatter.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2026 Baylibre SAS.
+ * Author: Valerio Setti <vsetti@baylibre.com>
+ */
+
+#ifndef _MESON_GX_FORMATTER_H
+#define _MESON_GX_FORMATTER_H
+
+#include "gx-interface.h"
+
+struct platform_device;
+struct regmap;
+struct snd_soc_dapm_widget;
+struct snd_kcontrol;
+
+struct gx_formatter_hw {
+ unsigned int skew_offset;
+};
+
+struct gx_formatter_ops {
+ struct gx_stream *(*get_stream)(struct snd_soc_dapm_widget *w);
+ void (*enable)(struct regmap *map);
+ void (*disable)(struct regmap *map);
+ int (*prepare)(struct regmap *map,
+ const struct gx_formatter_hw *quirks,
+ struct gx_stream *ts);
+};
+
+struct gx_formatter_driver {
+ const struct snd_soc_component_driver *component_drv;
+ const struct regmap_config *regmap_cfg;
+ const struct gx_formatter_ops *ops;
+ const struct gx_formatter_hw *quirks;
+};
+
+int gx_formatter_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *control,
+ int event);
+int gx_formatter_probe(struct platform_device *pdev);
+
+int gx_formatter_create(struct device *dev,
+ struct snd_soc_dapm_widget *w,
+ const struct gx_formatter_driver *drv,
+ struct regmap *regmap);
+
+/*
+ * Formatter data is already freed when the associated device is removed,
+ * so we just need to remove the pointer from the widget.
+ */
+static inline void gx_formatter_free(struct snd_soc_dapm_widget *w)
+{
+ w->priv = NULL;
+}
+
+#endif /* _MESON_GX_FORMATTER_H */
diff --git a/sound/soc/meson/gx-interface.h b/sound/soc/meson/gx-interface.h
new file mode 100644
index 000000000000..2a6207e393e8
--- /dev/null
+++ b/sound/soc/meson/gx-interface.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2026 Baylibre SAS.
+ * Author: Valerio Setti <vsetti@baylibre.com>
+ */
+
+#ifndef _MESON_GX_INTERFACE_H
+#define _MESON_GX_INTERFACE_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+struct gx_iface {
+ struct clk *mclk;
+ unsigned long mclk_rate;
+
+ /* format is common to all the DAIs of the iface */
+ unsigned int fmt;
+};
+
+struct gx_stream {
+ struct gx_iface *iface;
+ struct list_head formatter_list;
+ struct mutex lock;
+ unsigned int channels;
+ unsigned int width;
+ unsigned int physical_width;
+ bool ready;
+
+ /* For continuous clock tracking */
+ bool clk_enabled;
+};
+
+struct gx_stream *gx_stream_alloc(struct gx_iface *iface);
+void gx_stream_free(struct gx_stream *ts);
+int gx_stream_start(struct gx_stream *ts);
+void gx_stream_stop(struct gx_stream *ts);
+
+#endif /* _MESON_GX_INTERFACE_H */
diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
index cdb759b466ad..f2796dc84fa5 100644
--- a/sound/soc/meson/meson-card-utils.c
+++ b/sound/soc/meson/meson-card-utils.c
@@ -50,25 +50,20 @@ int meson_card_reallocate_links(struct snd_soc_card *card,
num_links * sizeof(*priv->card.dai_link),
GFP_KERNEL | __GFP_ZERO);
if (!links)
- goto err_links;
+ return -ENOMEM;
+
+ priv->card.dai_link = links;
+ priv->card.num_links = num_links;
ldata = krealloc(priv->link_data,
num_links * sizeof(*priv->link_data),
GFP_KERNEL | __GFP_ZERO);
+ /* meson_card_clean_references() will free the links on this error path */
if (!ldata)
- goto err_ldata;
+ return -ENOMEM;
- priv->card.dai_link = links;
priv->link_data = ldata;
- priv->card.num_links = num_links;
return 0;
-
-err_ldata:
- kfree(links);
-err_links:
- dev_err(priv->card.dev, "failed to allocate links\n");
- return -ENOMEM;
-
}
EXPORT_SYMBOL_GPL(meson_card_reallocate_links);
@@ -76,6 +71,7 @@ int meson_card_parse_dai(struct snd_soc_card *card,
struct device_node *node,
struct snd_soc_dai_link_component *dlc)
{
+ struct device *dev = card->dev;
int ret;
if (!dlc || !node)
@@ -83,7 +79,7 @@ int meson_card_parse_dai(struct snd_soc_card *card,
ret = snd_soc_of_get_dlc(node, NULL, dlc, 0);
if (ret)
- return dev_err_probe(card->dev, ret, "can't parse dai\n");
+ return dev_err_probe(dev, ret, "can't parse dai\n");
return ret;
}
@@ -94,7 +90,8 @@ static int meson_card_set_link_name(struct snd_soc_card *card,
struct device_node *node,
const char *prefix)
{
- char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s",
+ struct device *dev = card->dev;
+ char *name = devm_kasprintf(dev, GFP_KERNEL, "%s.%s",
prefix, node->full_name);
if (!name)
return -ENOMEM;
@@ -137,16 +134,17 @@ int meson_card_set_be_link(struct snd_soc_card *card,
struct device_node *node)
{
struct snd_soc_dai_link_component *codec;
+ struct device *dev = card->dev;
int ret, num_codecs;
num_codecs = of_get_child_count(node);
if (!num_codecs) {
- dev_err(card->dev, "be link %s has no codec\n",
+ dev_err(dev, "be link %s has no codec\n",
node->full_name);
return -EINVAL;
}
- codec = devm_kcalloc(card->dev, num_codecs, sizeof(*codec), GFP_KERNEL);
+ codec = devm_kcalloc(dev, num_codecs, sizeof(*codec), GFP_KERNEL);
if (!codec)
return -ENOMEM;
@@ -163,7 +161,7 @@ int meson_card_set_be_link(struct snd_soc_card *card,
ret = meson_card_set_link_name(card, link, node, "be");
if (ret)
- dev_err(card->dev, "error setting %pOFn link name\n", node);
+ dev_err(dev, "error setting %pOFn link name\n", node);
return ret;
}
@@ -194,12 +192,13 @@ EXPORT_SYMBOL_GPL(meson_card_set_fe_link);
static int meson_card_add_links(struct snd_soc_card *card)
{
struct meson_card *priv = snd_soc_card_get_drvdata(card);
- struct device_node *node = card->dev->of_node;
+ struct device *dev = card->dev;
+ struct device_node *node = dev->of_node;
int num, i, ret;
num = of_get_child_count(node);
if (!num) {
- dev_err(card->dev, "card has no links\n");
+ dev_err(dev, "card has no links\n");
return -EINVAL;
}
@@ -224,8 +223,10 @@ static int meson_card_parse_of_optional(struct snd_soc_card *card,
int (*func)(struct snd_soc_card *c,
const char *p))
{
+ struct device *dev = card->dev;
+
/* If property is not provided, don't fail ... */
- if (!of_property_present(card->dev->of_node, propname))
+ if (!of_property_present(dev->of_node, propname))
return 0;
/* ... but do fail if it is provided and the parsing fails */
diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
index 2ff6066e1b6c..8773bf06e154 100644
--- a/sound/soc/meson/meson-codec-glue.c
+++ b/sound/soc/meson/meson-codec-glue.c
@@ -74,7 +74,7 @@ int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
data->params.rate_min = params_rate(params);
data->params.rate_max = params_rate(params);
- data->params.formats = 1ULL << (__force int) params_format(params);
+ data->params.formats = 1ULL << params_format(params);
data->params.channels_min = params_channels(params);
data->params.channels_max = params_channels(params);
data->params.sig_bits = dai->driver->playback.sig_bits;
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index da1a93946d67..68b5323ca9c8 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -78,8 +78,14 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static const u64 t9015_dai_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_LEFT_J;
+
static const struct snd_soc_dai_ops t9015_dai_ops = {
.set_fmt = t9015_dai_set_fmt,
+ .auto_selectable_formats = &t9015_dai_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver t9015_dai = {
@@ -265,10 +271,8 @@ static int t9015_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(priv->avdd), "failed to AVDD\n");
ret = device_reset(dev);
- if (ret) {
- dev_err(dev, "reset failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to reset device\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs)) {
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index a01a680ad4d7..a77cd516a1bf 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -826,12 +826,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
mxs_saif[saif->id] = saif;
saif->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(saif->clk)) {
- ret = PTR_ERR(saif->clk);
- dev_err(&pdev->dev, "Cannot get the clock: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(saif->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(saif->clk),
+ "Cannot get the clock\n");
saif->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(saif->base))
@@ -844,10 +841,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
saif->dev = &pdev->dev;
ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0,
dev_name(&pdev->dev), saif);
- if (ret) {
- dev_err(&pdev->dev, "failed to request irq\n");
+ if (ret)
return ret;
- }
platform_set_drvdata(pdev, saif);
@@ -860,16 +855,12 @@ static int mxs_saif_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, &mxs_saif_component,
&mxs_saif_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "register DAI failed\n");
+ if (ret)
return ret;
- }
ret = mxs_pcm_platform_register(&pdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+ if (ret)
return ret;
- }
return 0;
}
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index f1c0e612313d..a253a48ca59c 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -155,8 +155,6 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret) {
- dev_err(&pdev->dev, "failed to parse audio-routing (%d)\n",
- ret);
mxs_saif_put_mclk(0);
return ret;
}
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index f8054c1c59fa..3a0abcb0bfbd 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -769,13 +769,10 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai)
goto err_priv;
}
- priv->extclk = devm_clk_get(dev, "extclk");
+ priv->extclk = devm_clk_get_optional(dev, "extclk");
if (IS_ERR(priv->extclk)) {
ret = PTR_ERR(priv->extclk);
- if (ret == -EPROBE_DEFER)
- goto err_priv;
-
- priv->extclk = NULL;
+ goto err_priv;
}
} else {
priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
diff --git a/sound/soc/pxa/pxa2xx-ac97-lib.c b/sound/soc/pxa/pxa2xx-ac97-lib.c
index d9c3935636da..d7f720431afb 100644
--- a/sound/soc/pxa/pxa2xx-ac97-lib.c
+++ b/sound/soc/pxa/pxa2xx-ac97-lib.c
@@ -316,10 +316,8 @@ int pxa2xx_ac97_hw_probe(struct platform_device *dev)
int irq;
ac97_reg_base = devm_platform_ioremap_resource(dev, 0);
- if (IS_ERR(ac97_reg_base)) {
- dev_err(&dev->dev, "Missing MMIO resource\n");
+ if (IS_ERR(ac97_reg_base))
return PTR_ERR(ac97_reg_base);
- }
if (cpu_is_pxa27x()) {
/* Assert reset using GPIOD_OUT_HIGH, because reset is GPIO_ACTIVE_LOW */
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index edc4611691f7..d231024206db 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -23,6 +23,161 @@ static const struct snd_soc_dapm_widget qcom_jack_snd_widgets[] = {
SND_SOC_DAPM_SPK("DP7 Jack", NULL),
};
+static struct device_node *qcom_snd_get_link_node(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_card *card = rtd->card;
+ struct of_phandle_args args;
+ int ret;
+
+ if (!card->dev || !card->dev->of_node)
+ return NULL;
+
+ for_each_available_child_of_node_scoped(card->dev->of_node, np) {
+ struct device_node *cpu_np __free(device_node) =
+ of_get_child_by_name(np, "cpu");
+
+ if (!cpu_np)
+ continue;
+
+ ret = of_parse_phandle_with_args(cpu_np, "sound-dai", "#sound-dai-cells", 0,
+ &args);
+ if (ret)
+ continue;
+
+ if (args.np == rtd->dai_link->cpus[0].of_node &&
+ args.args_count == 1 && args.args[0] == cpu_dai->id) {
+ of_node_put(args.np);
+ return of_node_get(np);
+ }
+
+ of_node_put(args.np);
+ }
+
+ return NULL;
+}
+
+static int qcom_snd_parse_tdm_slot(struct device_node *np,
+ struct qcom_snd_tdm_slot_cfg *cfg)
+{
+ memset(cfg, 0, sizeof(*cfg));
+
+ return snd_soc_of_parse_tdm_slot(np, &cfg->tx_mask, &cfg->rx_mask,
+ &cfg->slots, &cfg->slot_width);
+}
+
+static int qcom_snd_normalize_tdm_slots(struct qcom_snd_tdm_slot_cfg *cpu_cfg,
+ struct qcom_snd_tdm_slot_cfg *codec_cfg)
+{
+ unsigned int slots;
+ unsigned int slot_width;
+
+ if (cpu_cfg->slots && codec_cfg->slots && cpu_cfg->slots != codec_cfg->slots)
+ return -EINVAL;
+
+ if (cpu_cfg->slot_width && codec_cfg->slot_width &&
+ cpu_cfg->slot_width != codec_cfg->slot_width)
+ return -EINVAL;
+
+ slots = cpu_cfg->slots ?: codec_cfg->slots;
+ if (!slots)
+ return 0;
+
+ slot_width = cpu_cfg->slot_width ?: codec_cfg->slot_width;
+ if (!slot_width)
+ return -EINVAL;
+
+ cpu_cfg->slots = slots;
+ codec_cfg->slots = slots;
+ cpu_cfg->slot_width = slot_width;
+ codec_cfg->slot_width = slot_width;
+
+ return 0;
+}
+
+static int qcom_snd_parse_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd,
+ struct qcom_snd_tdm_slot_cfg *cpu_cfg,
+ struct qcom_snd_tdm_slot_cfg *codec_cfg)
+{
+ struct device_node *link_np __free(device_node) = qcom_snd_get_link_node(rtd);
+ int ret;
+
+ if (!link_np)
+ return -EINVAL;
+
+ struct device_node *cpu_np __free(device_node) =
+ of_get_child_by_name(link_np, "cpu");
+ struct device_node *codec_np __free(device_node) =
+ of_get_child_by_name(link_np, "codec");
+ if (!cpu_np || !codec_np)
+ return -EINVAL;
+
+ ret = qcom_snd_parse_tdm_slot(cpu_np, cpu_cfg);
+ if (ret)
+ return ret;
+
+ return qcom_snd_parse_tdm_slot(codec_np, codec_cfg);
+}
+
+int qcom_snd_get_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd,
+ struct qcom_snd_tdm_slot_cfg *cpu_cfg,
+ struct qcom_snd_tdm_slot_cfg *codec_cfg)
+{
+ int ret;
+
+ ret = qcom_snd_parse_dai_tdm_slots(rtd, cpu_cfg, codec_cfg);
+ if (ret)
+ return ret;
+
+ return qcom_snd_normalize_tdm_slots(cpu_cfg, codec_cfg);
+}
+EXPORT_SYMBOL_GPL(qcom_snd_get_dai_tdm_slots);
+
+int qcom_snd_apply_dai_tdm_slots_cfg(struct snd_soc_pcm_runtime *rtd,
+ const struct qcom_snd_tdm_slot_cfg *cpu_cfg,
+ const struct qcom_snd_tdm_slot_cfg *codec_cfg)
+{
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ int i;
+ int ret;
+
+ if (!cpu_cfg->slots)
+ return 0;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, cpu_cfg->tx_mask, cpu_cfg->rx_mask,
+ cpu_cfg->slots, cpu_cfg->slot_width);
+ if (ret)
+ return ret;
+
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai,
+ codec_cfg->tx_mask,
+ codec_cfg->rx_mask,
+ codec_cfg->slots,
+ codec_cfg->slot_width);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_apply_dai_tdm_slots_cfg);
+
+int qcom_snd_apply_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd)
+{
+ struct qcom_snd_tdm_slot_cfg cpu_cfg;
+ struct qcom_snd_tdm_slot_cfg codec_cfg;
+ int ret;
+
+ ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg);
+ if (ret)
+ return ret == -EINVAL ? 0 : ret;
+
+ return qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg);
+}
+EXPORT_SYMBOL_GPL(qcom_snd_apply_dai_tdm_slots);
+
int qcom_snd_parse_of(struct snd_soc_card *card)
{
struct device *dev = card->dev;
@@ -91,7 +246,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
ret = of_property_read_string(np, "link-name", &link->name);
if (ret) {
- dev_err(card->dev, "error getting codec dai_link name\n");
+ dev_err(dev, "error getting codec dai_link name\n");
return ret;
}
@@ -109,7 +264,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
ret = snd_soc_of_get_dlc(cpu, &args, link->cpus, 0);
if (ret) {
- dev_err_probe(card->dev, ret,
+ dev_err_probe(dev, ret,
"%s: error getting cpu dai name\n", link->name);
return ret;
}
@@ -126,7 +281,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
"sound-dai",
0);
if (!link->platforms->of_node) {
- dev_err(card->dev, "%s: platform dai not found\n", link->name);
+ dev_err(dev, "%s: platform dai not found\n", link->name);
return -EINVAL;
}
} else {
@@ -136,7 +291,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
if (codec) {
ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
if (ret < 0) {
- dev_err_probe(card->dev, ret,
+ dev_err_probe(dev, ret,
"%s: codec dai not found\n", link->name);
return ret;
}
@@ -215,6 +370,7 @@ int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
}
switch (cpu_dai->id) {
+ case LPI_MI2S_RX_0:
case TX_CODEC_DMA_TX_0:
case TX_CODEC_DMA_TX_1:
case TX_CODEC_DMA_TX_2:
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index ee6662885593..c1deac109f24 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -7,9 +7,23 @@
#include <dt-bindings/sound/qcom,q6afe.h>
#include <sound/soc.h>
-#define LPASS_MAX_PORT (SENARY_MI2S_TX + 1)
+#define LPASS_MAX_PORT (LPI_MI2S_TX_6 + 1)
+
+struct qcom_snd_tdm_slot_cfg {
+ unsigned int tx_mask;
+ unsigned int rx_mask;
+ unsigned int slots;
+ unsigned int slot_width;
+};
int qcom_snd_parse_of(struct snd_soc_card *card);
+int qcom_snd_get_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd,
+ struct qcom_snd_tdm_slot_cfg *cpu_cfg,
+ struct qcom_snd_tdm_slot_cfg *codec_cfg);
+int qcom_snd_apply_dai_tdm_slots_cfg(struct snd_soc_pcm_runtime *rtd,
+ const struct qcom_snd_tdm_slot_cfg *cpu_cfg,
+ const struct qcom_snd_tdm_slot_cfg *codec_cfg);
+int qcom_snd_apply_dai_tdm_slots(struct snd_soc_pcm_runtime *rtd);
int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
struct snd_soc_jack *jack, bool *jack_setup);
int qcom_snd_dp_jack_setup(struct snd_soc_pcm_runtime *rtd,
diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c
index e6e9eb2e85aa..cce0ad31ff0c 100644
--- a/sound/soc/qcom/qdsp6/audioreach.c
+++ b/sound/soc/qcom/qdsp6/audioreach.c
@@ -152,6 +152,13 @@ struct apm_i2s_module_intf_cfg {
#define APM_I2S_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_i2s_module_intf_cfg), 8)
+struct apm_audio_if_module_intf_cfg {
+ struct apm_module_param_data param_data;
+ struct param_id_audio_if_intf_cfg cfg;
+} __packed;
+
+#define APM_AUDIO_IF_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_audio_if_module_intf_cfg), 8)
+
struct apm_module_hw_ep_mf_cfg {
struct apm_module_param_data param_data;
struct param_id_hw_ep_mf mf;
@@ -168,6 +175,13 @@ struct apm_module_frame_size_factor_cfg {
#define APM_FS_CFG_PSIZE ALIGN(sizeof(struct apm_module_frame_size_factor_cfg), 8)
+struct apm_module_hw_ep_frame_duration_cfg {
+ struct apm_module_param_data param_data;
+ struct param_id_hw_ep_frame_duration frame_duration;
+} __packed;
+
+#define APM_HW_EP_FRAME_DURATION_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_frame_duration_cfg), 8)
+
struct apm_module_hw_ep_power_mode_cfg {
struct apm_module_param_data param_data;
struct param_id_hw_ep_power_mode_cfg power_mode;
@@ -703,6 +717,7 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
int pm_sz = APM_HW_EP_PMODE_CFG_PSIZE;
int size = ic_sz + ep_sz + fs_sz + pm_sz;
void *p;
+ int i;
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
if (IS_ERR(pkt))
@@ -741,7 +756,12 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph,
intf_cfg->cfg.lpaif_type = module->hw_interface_type;
intf_cfg->cfg.intf_index = module->hw_interface_idx;
- intf_cfg->cfg.active_channels_mask = (1 << cfg->num_channels) - 1;
+ intf_cfg->cfg.active_channels_mask = 0;
+ /* Convert the physical channel mapping into a bit field */
+ for (i = 0; i < AR_PCM_MAX_NUM_CHANNEL; i++)
+ if (cfg->channel_map[i])
+ intf_cfg->cfg.active_channels_mask |= BIT(i);
+
p += ic_sz;
pm_cfg = p;
@@ -840,7 +860,7 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
uint32_t num_channels = cfg->num_channels;
int payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) +
APM_MODULE_PARAM_DATA_SIZE;
- int i;
+ int i, j;
void *p;
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
@@ -860,8 +880,12 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph,
media_format->sample_rate = cfg->sample_rate;
media_format->bit_width = cfg->bit_width;
media_format->num_channels = cfg->num_channels;
- for (i = 0; i < num_channels; i++)
- media_format->channel_mapping[i] = cfg->channel_map[i];
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) {
+ if (!cfg->channel_map[i])
+ continue;
+ media_format->channel_mapping[j++] = cfg->channel_map[i];
+ }
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
@@ -1042,6 +1066,81 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph,
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
+static int audioreach_audio_if_set_media_format(struct q6apm_graph *graph,
+ const struct audioreach_module *module,
+ const struct audioreach_module_config *cfg)
+{
+ struct apm_module_hw_ep_frame_duration_cfg *fd_cfg;
+ struct apm_module_param_data *param_data;
+ struct apm_audio_if_module_intf_cfg *intf_cfg;
+ struct apm_module_hw_ep_mf_cfg *hw_cfg;
+ int ic_sz = APM_AUDIO_IF_INTF_CFG_PSIZE;
+ int ep_sz = APM_HW_EP_CFG_PSIZE;
+ int fd_sz = APM_HW_EP_FRAME_DURATION_PSIZE;
+ int size = ic_sz + ep_sz + fd_sz;
+ u32 slot_mask = cfg->slot_mask ? cfg->slot_mask : module->slot_mask;
+ u16 nslots_per_frame = cfg->nslots_per_frame ?
+ (u16)cfg->nslots_per_frame : module->nslots_per_frame;
+ u16 slot_width = cfg->slot_width ? (u16)cfg->slot_width : module->slot_width;
+ void *p;
+
+ struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0);
+ if (IS_ERR(pkt))
+ return PTR_ERR(pkt);
+
+ p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+ intf_cfg = p;
+
+ param_data = &intf_cfg->param_data;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_AUDIO_IF_INTF_CFG;
+ param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE;
+ intf_cfg->cfg.qaif_type = module->qaif_type;
+ intf_cfg->cfg.intf_idx = (u16)module->hw_interface_idx;
+ intf_cfg->cfg.intf_mode = module->intf_mode;
+ intf_cfg->cfg.ctrl_data_out_enable = module->ctrl_data_out_enable;
+ intf_cfg->cfg.active_slot_mask = slot_mask;
+ intf_cfg->cfg.nslots_per_frame = nslots_per_frame;
+ intf_cfg->cfg.slot_width = slot_width;
+ intf_cfg->cfg.active_lane_mask = module->active_lane_mask;
+ intf_cfg->cfg.frame_sync_rate = module->frame_sync_rate;
+ intf_cfg->cfg.frame_sync_src = module->sync_src;
+ intf_cfg->cfg.frame_sync_mode = module->sync_mode;
+ intf_cfg->cfg.invert_frame_sync_pulse = module->ctrl_invert_sync_pulse;
+ intf_cfg->cfg.frame_sync_data_delay = module->ctrl_sync_data_delay;
+ intf_cfg->cfg.bit_clk_type = module->bit_clk_type;
+ intf_cfg->cfg.inv_int_bit_clk = module->inv_int_bit_clk;
+ intf_cfg->cfg.inv_ext_bit_clk = module->inv_ext_bit_clk;
+
+ p += ic_sz;
+ hw_cfg = p;
+ param_data = &hw_cfg->param_data;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_HW_EP_MF_CFG;
+ param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE;
+
+ hw_cfg->mf.sample_rate = cfg->sample_rate;
+ hw_cfg->mf.bit_width = cfg->bit_width;
+ hw_cfg->mf.num_channels = cfg->num_channels;
+ hw_cfg->mf.data_format = module->data_format;
+
+ p += ep_sz;
+ fd_cfg = p;
+ param_data = &fd_cfg->param_data;
+ param_data->module_instance_id = module->instance_id;
+ param_data->error_code = 0;
+ param_data->param_id = PARAM_ID_HW_EP_FRAME_DURATION;
+ param_data->param_size = fd_sz - APM_MODULE_PARAM_DATA_SIZE;
+ fd_cfg->frame_duration.frame_duration_in_us = AUDIO_IF_FRAME_DURATION_US;
+ fd_cfg->frame_duration.allow_frame_duration_normalization = AUDIO_IF_FRAME_DURATION_NORMALIZATION_ENABLE;
+ fd_cfg->frame_duration.min_normalized_frame_dur_us = AUDIO_IF_FRAME_DURATION_MIN_US;
+ fd_cfg->frame_duration.max_normalized_frame_dur_us = AUDIO_IF_FRAME_DURATION_MAX_US;
+
+ return q6apm_send_cmd_sync(graph->apm, pkt, 0);
+}
+
static int audioreach_logging_set_media_format(struct q6apm_graph *graph,
const struct audioreach_module *module)
{
@@ -1080,6 +1179,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
struct apm_pcm_module_media_fmt_cmd *cfg;
struct apm_module_param_data *param_data;
int payload_size;
+ int i, j;
if (num_channels > 4) {
dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels);
@@ -1113,7 +1213,12 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
media_cfg->num_channels = mcfg->num_channels;
media_cfg->q_factor = mcfg->bit_width - 1;
media_cfg->bits_per_sample = mcfg->bit_width;
- memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < mcfg->num_channels; i++) {
+ if (!mcfg->channel_map[i])
+ continue;
+ media_cfg->channel_mapping[j++] = mcfg->channel_map[i];
+ }
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
}
@@ -1163,6 +1268,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
struct payload_media_fmt_pcm *cfg;
struct media_format *header;
int rc, payload_size;
+ int i, j;
void *p;
if (num_channels > 4) {
@@ -1202,7 +1308,12 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
cfg->q_factor = mcfg->bit_width - 1;
cfg->endianness = PCM_LITTLE_ENDIAN;
cfg->num_channels = mcfg->num_channels;
- memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels);
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < cfg->num_channels; i++) {
+ if (!mcfg->channel_map[i])
+ continue;
+ cfg->channel_mapping[j++] = mcfg->channel_map[i];
+ }
} else {
rc = audioreach_set_compr_media_format(header, p, mcfg);
if (rc)
@@ -1279,7 +1390,7 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph,
struct apm_module_sp_vi_ex_mode_cfg *ex_cfg;
int op_sz, cm_sz, ex_sz;
struct apm_module_param_data *param_data;
- int rc, i, payload_size;
+ int rc, i, payload_size, j;
struct gpr_pkt *pkt;
void *p;
@@ -1320,14 +1431,19 @@ static int audioreach_speaker_protection_vi(struct q6apm_graph *graph,
param_data->param_size = cm_sz - APM_MODULE_PARAM_DATA_SIZE;
cm_cfg->cfg.num_channels = num_channels * 2;
- for (i = 0; i < num_channels; i++) {
+ /* Convert the physical mapping to a logical mapping of the channels */
+ for (i = 0, j = 0; i < AR_PCM_MAX_NUM_CHANNEL && j < num_channels; i++) {
+ if (!mcfg->channel_map[i])
+ continue;
/*
* Map speakers into Vsense and then Isense of each channel.
* E.g. for PCM_CHANNEL_FL and PCM_CHANNEL_FR to:
* [1, 2, 3, 4]
*/
- cm_cfg->cfg.channel_mapping[2 * i] = (mcfg->channel_map[i] - 1) * 2 + 1;
- cm_cfg->cfg.channel_mapping[2 * i + 1] = (mcfg->channel_map[i] - 1) * 2 + 2;
+ cm_cfg->cfg.channel_mapping[2 * j] = (mcfg->channel_map[i] - 1) * 2 + 1;
+ cm_cfg->cfg.channel_mapping[2 * j + 1] = (mcfg->channel_map[i] - 1) * 2 + 2;
+
+ ++j;
}
p += cm_sz;
@@ -1411,6 +1527,10 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
if (!rc)
rc = audioreach_module_enable(graph, module, true);
break;
+ case MODULE_ID_AUDIO_IF_SOURCE:
+ case MODULE_ID_AUDIO_IF_SINK:
+ rc = audioreach_audio_if_set_media_format(graph, module, cfg);
+ break;
default:
rc = 0;
diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h
index 62a2fd79bbcb..35541b2d8c99 100644
--- a/sound/soc/qcom/qdsp6/audioreach.h
+++ b/sound/soc/qcom/qdsp6/audioreach.h
@@ -36,6 +36,8 @@ struct q6apm_graph;
#define MODULE_ID_SPEAKER_PROTECTION 0x070010E2
#define MODULE_ID_SPEAKER_PROTECTION_VI 0x070010E3
#define MODULE_ID_OPUS_DEC 0x07001174
+#define MODULE_ID_AUDIO_IF_SINK 0x0700117C
+#define MODULE_ID_AUDIO_IF_SOURCE 0x0700117D
#define APM_CMD_GET_SPF_STATE 0x01001021
#define APM_CMD_RSP_GET_SPF_STATE 0x02001007
@@ -544,6 +546,74 @@ struct param_id_i2s_intf_cfg {
#define PORT_ID_I2S_OUPUT 1
#define I2S_STACK_SIZE 2048
+#define PARAM_ID_AUDIO_IF_INTF_CFG 0x08001B11
+
+/*
+ * struct param_id_audio_if_intf_cfg - Audio interface configuration
+ * @qaif_type: Audio interface type (e.g. QAIF, QAIF_VA)
+ * @intf_idx: Interface instance index
+ * @intf_mode: Interface operating mode (TDM/PCM/I2S)
+ * @ctrl_data_out_enable: Enable sharing of data-out signal with other masters
+ * @active_slot_mask: Bitmask indicating active slots
+ * @nslots_per_frame: Number of slots per audio frame
+ * @slot_width: Width of each slot in bits
+ * @active_lane_mask: Bitmask of active data lanes
+ * @frame_sync_rate: Frame sync rate in Hz
+ * @frame_sync_src: Frame sync source selection
+ * @frame_sync_mode: Frame sync mode configuration
+ * @invert_frame_sync_pulse: Invert frame sync polarity when set
+ * @frame_sync_data_delay: Data delay from frame sync in bit clocks
+ * @bit_clk_type: Bit clock type (internal / external)
+ * @inv_int_bit_clk: Invert internal bit clock when set
+ * @inv_ext_bit_clk: Invert external bit clock when set
+ *
+ * This structure defines configuration parameters for the Qualcomm
+ * Audio Interface (QAIF) block. It is used to program interface
+ * characteristics such as slot configuration, clocking and frame
+ * synchronization behaviour.
+ */
+struct param_id_audio_if_intf_cfg {
+ uint16_t qaif_type;
+ uint16_t intf_idx;
+ uint16_t intf_mode;
+ uint16_t ctrl_data_out_enable;
+ uint32_t active_slot_mask;
+ uint16_t nslots_per_frame;
+ uint16_t slot_width;
+ uint32_t active_lane_mask;
+ uint32_t frame_sync_rate;
+ uint16_t frame_sync_src;
+ uint16_t frame_sync_mode;
+ uint16_t invert_frame_sync_pulse;
+ uint16_t frame_sync_data_delay;
+ uint16_t bit_clk_type;
+ uint8_t inv_int_bit_clk;
+ uint8_t inv_ext_bit_clk;
+} __packed;
+
+#define PARAM_ID_HW_EP_FRAME_DURATION 0x08001B2F
+#define AUDIO_IF_FRAME_DURATION_US 1000
+#define AUDIO_IF_FRAME_DURATION_NORMALIZATION_ENABLE 1
+#define AUDIO_IF_FRAME_DURATION_MIN_US 1
+#define AUDIO_IF_FRAME_DURATION_MAX_US 100000
+
+/**
+ * struct param_id_hw_ep_frame_duration - Hardware endpoint frame duration
+ * @frame_duration_in_us: Frame duration in microseconds.
+ * @allow_frame_duration_normalization: Permit SPF to normalize frame duration.
+ * @min_normalized_frame_dur_us: Minimum normalized frame duration in microseconds.
+ * @max_normalized_frame_dur_us: Maximum normalized frame duration in microseconds.
+ *
+ * This structure configures the frame duration for the Audio IF hardware
+ * endpoint and, when enabled, the allowed normalization range.
+ */
+struct param_id_hw_ep_frame_duration {
+ uint32_t frame_duration_in_us;
+ uint32_t allow_frame_duration_normalization;
+ uint32_t min_normalized_frame_dur_us;
+ uint32_t max_normalized_frame_dur_us;
+} __packed;
+
#define PARAM_ID_DISPLAY_PORT_INTF_CFG 0x08001154
struct param_id_display_port_intf_cfg {
@@ -877,6 +947,23 @@ struct audioreach_module {
uint32_t data_format;
uint32_t hw_interface_type;
+ /* Audio IF module (TDM/PCM/I2S) */
+ u32 slot_mask;
+ u32 active_lane_mask;
+ u32 frame_sync_rate;
+ u16 qaif_type;
+ u16 sync_src;
+ u16 ctrl_data_out_enable;
+ u16 nslots_per_frame;
+ u16 slot_width;
+ u16 intf_mode;
+ u16 sync_mode;
+ u16 ctrl_invert_sync_pulse;
+ u16 ctrl_sync_data_delay;
+ u16 bit_clk_type;
+ u8 inv_int_bit_clk;
+ u8 inv_ext_bit_clk;
+
/* PCM module specific */
uint32_t interleave_type;
@@ -907,6 +994,9 @@ struct audioreach_module_config {
u32 channel_allocation;
u32 sd_line_mask;
int fmt;
+ u32 slot_mask;
+ u16 nslots_per_frame;
+ u16 slot_width;
struct snd_codec codec;
u8 channel_map[AR_PCM_MAX_NUM_CHANNEL];
};
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index a0d21034a626..920345609d2c 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -412,6 +412,8 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
case SENARY_MI2S_RX ... SENARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6:
rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].i2s_cfg);
if (rc < 0) {
@@ -665,6 +667,21 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
/* USB playback AFE port receives data for playback, hence use the RX port */
{"USB Playback", NULL, "USB_RX"},
+
+ {"LPI RX0 MI2S Playback", NULL, "LPI_MI2S_RX_0"},
+ {"LPI_MI2S_TX_0", NULL, "LPI TX0 MI2S Capture"},
+ {"LPI RX1 MI2S Playback", NULL, "LPI_MI2S_RX_1"},
+ {"LPI_MI2S_TX_1", NULL, "LPI TX1 MI2S Capture"},
+ {"LPI RX2 MI2S Playback", NULL, "LPI_MI2S_RX_2"},
+ {"LPI_MI2S_TX_2", NULL, "LPI TX2 MI2S Capture"},
+ {"LPI RX3 MI2S Playback", NULL, "LPI_MI2S_RX_3"},
+ {"LPI_MI2S_TX_3", NULL, "LPI TX3 MI2S Capture"},
+ {"LPI RX4 MI2S Playback", NULL, "LPI_MI2S_RX_4"},
+ {"LPI_MI2S_TX_4", NULL, "LPI TX4 MI2S Capture"},
+ {"LPI RX5 MI2S Playback", NULL, "LPI_MI2S_RX_5"},
+ {"LPI_MI2S_TX_5", NULL, "LPI TX5 MI2S Capture"},
+ {"LPI RX6 MI2S Playback", NULL, "LPI_MI2S_RX_6"},
+ {"LPI_MI2S_TX_6", NULL, "LPI TX6 MI2S Capture"},
};
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
@@ -1011,6 +1028,35 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("USB_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_0", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_0", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_1", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_1", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_2", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_2", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_3", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_3", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_4", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_4", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_5", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_5", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("LPI_MI2S_RX_6", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("LPI_MI2S_TX_6", NULL,
+ 0, SND_SOC_NOPM, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
@@ -1045,6 +1091,8 @@ static void of_q6afe_parse_dai_data(struct device *dev,
case SENARY_MI2S_RX ... SENARY_MI2S_TX:
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6:
priv = &data->priv[id];
ret = of_property_read_variable_u32_array(node,
"qcom,sd-lines",
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 40237267fda0..1d68a80e8e0c 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -132,6 +132,20 @@
#define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017
#define AFE_PORT_ID_SENARY_MI2S_RX 0x1018
#define AFE_PORT_ID_SENARY_MI2S_TX 0x1019
+#define AFE_PORT_ID_INT0_MI2S_RX 0x102e
+#define AFE_PORT_ID_INT0_MI2S_TX 0x102f
+#define AFE_PORT_ID_INT1_MI2S_RX 0x1030
+#define AFE_PORT_ID_INT1_MI2S_TX 0x1031
+#define AFE_PORT_ID_INT2_MI2S_RX 0x1032
+#define AFE_PORT_ID_INT2_MI2S_TX 0x1033
+#define AFE_PORT_ID_INT3_MI2S_RX 0x1034
+#define AFE_PORT_ID_INT3_MI2S_TX 0x1035
+#define AFE_PORT_ID_INT4_MI2S_RX 0x1036
+#define AFE_PORT_ID_INT4_MI2S_TX 0x1037
+#define AFE_PORT_ID_INT5_MI2S_RX 0x1038
+#define AFE_PORT_ID_INT5_MI2S_TX 0x1039
+#define AFE_PORT_ID_INT6_MI2S_RX 0x103a
+#define AFE_PORT_ID_INT6_MI2S_TX 0x103b
/* Start of the range of port IDs for TDM devices. */
#define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000
@@ -931,6 +945,34 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = {
[RX_CODEC_DMA_RX_7] = { AFE_PORT_ID_RX_CODEC_DMA_RX_7,
RX_CODEC_DMA_RX_7, 1, 1},
[USB_RX] = { AFE_PORT_ID_USB_RX, USB_RX, 1, 1},
+ [LPI_MI2S_RX_0] = { AFE_PORT_ID_INT0_MI2S_RX,
+ LPI_MI2S_RX_0, 1, 1},
+ [LPI_MI2S_TX_0] = { AFE_PORT_ID_INT0_MI2S_TX,
+ LPI_MI2S_TX_0, 0, 1},
+ [LPI_MI2S_RX_1] = { AFE_PORT_ID_INT1_MI2S_RX,
+ LPI_MI2S_RX_1, 1, 1},
+ [LPI_MI2S_TX_1] = { AFE_PORT_ID_INT1_MI2S_TX,
+ LPI_MI2S_TX_1, 0, 1},
+ [LPI_MI2S_RX_2] = { AFE_PORT_ID_INT2_MI2S_RX,
+ LPI_MI2S_RX_2, 1, 1},
+ [LPI_MI2S_TX_2] = { AFE_PORT_ID_INT2_MI2S_TX,
+ LPI_MI2S_TX_2, 0, 1},
+ [LPI_MI2S_RX_3] = { AFE_PORT_ID_INT3_MI2S_RX,
+ LPI_MI2S_RX_3, 1, 1},
+ [LPI_MI2S_TX_3] = { AFE_PORT_ID_INT3_MI2S_TX,
+ LPI_MI2S_TX_3, 0, 1},
+ [LPI_MI2S_RX_4] = { AFE_PORT_ID_INT4_MI2S_RX,
+ LPI_MI2S_RX_4, 1, 1},
+ [LPI_MI2S_TX_4] = { AFE_PORT_ID_INT4_MI2S_TX,
+ LPI_MI2S_TX_4, 0, 1},
+ [LPI_MI2S_RX_5] = { AFE_PORT_ID_INT5_MI2S_RX,
+ LPI_MI2S_RX_5, 1, 1},
+ [LPI_MI2S_TX_5] = { AFE_PORT_ID_INT5_MI2S_TX,
+ LPI_MI2S_TX_5, 0, 1},
+ [LPI_MI2S_RX_6] = { AFE_PORT_ID_INT6_MI2S_RX,
+ LPI_MI2S_RX_6, 1, 1},
+ [LPI_MI2S_TX_6] = { AFE_PORT_ID_INT6_MI2S_TX,
+ LPI_MI2S_TX_6, 0, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -1785,6 +1827,20 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id)
case AFE_PORT_ID_QUINARY_MI2S_TX:
case AFE_PORT_ID_SENARY_MI2S_RX:
case AFE_PORT_ID_SENARY_MI2S_TX:
+ case AFE_PORT_ID_INT0_MI2S_RX:
+ case AFE_PORT_ID_INT0_MI2S_TX:
+ case AFE_PORT_ID_INT1_MI2S_RX:
+ case AFE_PORT_ID_INT1_MI2S_TX:
+ case AFE_PORT_ID_INT2_MI2S_RX:
+ case AFE_PORT_ID_INT2_MI2S_TX:
+ case AFE_PORT_ID_INT3_MI2S_RX:
+ case AFE_PORT_ID_INT3_MI2S_TX:
+ case AFE_PORT_ID_INT4_MI2S_RX:
+ case AFE_PORT_ID_INT4_MI2S_TX:
+ case AFE_PORT_ID_INT5_MI2S_RX:
+ case AFE_PORT_ID_INT5_MI2S_TX:
+ case AFE_PORT_ID_INT6_MI2S_RX:
+ case AFE_PORT_ID_INT6_MI2S_TX:
cfg_type = AFE_PARAM_ID_I2S_CONFIG;
break;
case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7:
diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
index 006b283484d9..e204fd59e512 100644
--- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
+++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
@@ -2,10 +2,12 @@
// Copyright (c) 2021, Linaro Limited
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/pcm.h>
@@ -15,15 +17,54 @@
#include "q6dsp-common.h"
#include "audioreach.h"
#include "q6apm.h"
+#include "q6prm.h"
#define AUDIOREACH_BE_PCM_BASE 16
+struct q6apm_dai_priv_data {
+ struct clk *mclk;
+ struct clk *bclk;
+ bool mclk_enabled, bclk_enabled;
+};
+
struct q6apm_lpass_dai_data {
struct q6apm_graph *graph[APM_PORT_MAX];
bool is_port_started[APM_PORT_MAX];
struct audioreach_module_config module_config[APM_PORT_MAX];
+ struct q6apm_dai_priv_data priv[APM_PORT_MAX];
};
+static void q6apm_lpass_dai_disable_clocks(struct q6apm_lpass_dai_data *dai_data, int id)
+{
+ if (dai_data->priv[id].mclk_enabled) {
+ clk_disable_unprepare(dai_data->priv[id].mclk);
+ dai_data->priv[id].mclk_enabled = false;
+ }
+
+ if (dai_data->priv[id].bclk_enabled) {
+ clk_disable_unprepare(dai_data->priv[id].bclk);
+ dai_data->priv[id].bclk_enabled = false;
+ }
+}
+
+static void q6apm_lpass_dai_put_clocks(struct q6apm_lpass_dai_data *dai_data)
+{
+ int i;
+
+ for (i = 0; i < APM_PORT_MAX; i++) {
+ q6apm_lpass_dai_disable_clocks(dai_data, i);
+
+ if (dai_data->priv[i].mclk) {
+ clk_put(dai_data->priv[i].mclk);
+ dai_data->priv[i].mclk = NULL;
+ }
+ if (dai_data->priv[i].bclk) {
+ clk_put(dai_data->priv[i].bclk);
+ dai_data->priv[i].bclk = NULL;
+ }
+ }
+}
+
static int q6dma_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num,
const unsigned int *tx_ch_mask,
@@ -251,6 +292,62 @@ static int q6apm_lpass_dai_startup(struct snd_pcm_substream *substream, struct s
return 0;
}
+static int q6i2s_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ return q6apm_lpass_dai_startup(substream, dai);
+}
+
+static void q6i2s_lpass_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ q6apm_lpass_dai_shutdown(substream, dai);
+ q6apm_lpass_dai_disable_clocks(dai_data, dai->id);
+}
+
+static int q6i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir)
+{
+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct clk *sysclk = NULL;
+ bool *enabled = NULL;
+ int ret = 0;
+
+ switch (clk_id) {
+ case LPAIF_MI2S_MCLK:
+ sysclk = dai_data->priv[dai->id].mclk;
+ enabled = &dai_data->priv[dai->id].mclk_enabled;
+ break;
+ case LPAIF_MI2S_BCLK:
+ sysclk = dai_data->priv[dai->id].bclk;
+ enabled = &dai_data->priv[dai->id].bclk_enabled;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (sysclk) {
+ ret = clk_set_rate(sysclk, freq);
+ if (ret) {
+ dev_err(dai->dev, "Error, Unable to set rate (%d) for sysclk %d\n",
+ freq, clk_id);
+ return ret;
+ }
+
+ if (*enabled)
+ return 0;
+
+ ret = clk_prepare_enable(sysclk);
+ if (ret) {
+ dev_err(dai->dev, "Error, Unable to prepare (%d) sysclk\n", clk_id);
+ return ret;
+ }
+
+ *enabled = true;
+ }
+
+ return ret;
+}
+
static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -261,6 +358,53 @@ static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct audioreach_module_config *cfg = &dai_data->module_config[dai->id];
+ unsigned int cap_mask, slot_mask;
+
+ if (slot_width != 16 && slot_width != 32) {
+ dev_err(dai->dev, "%s: invalid slot_width %d\n", __func__, slot_width);
+ return -EINVAL;
+ }
+
+ switch (slots) {
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ cap_mask = GENMASK(slots - 1, 0);
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid slots %d\n", __func__, slots);
+ return -EINVAL;
+ }
+
+ switch (dai->id) {
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ slot_mask = (dai->id & 0x1) ? tx_mask : rx_mask;
+ if (slot_mask & ~cap_mask) {
+ dev_err(dai->dev, "%s: invalid slot mask 0x%x for %d slots\n",
+ __func__, slot_mask, slots);
+ return -EINVAL;
+ }
+
+ cfg->nslots_per_frame = slots;
+ cfg->slot_width = slot_width;
+ cfg->slot_mask = slot_mask;
+ break;
+ default:
+ dev_err(dai->dev, "%s: invalid dai id 0x%x\n", __func__, dai->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops q6dma_ops = {
.prepare = q6apm_lpass_dai_prepare,
.startup = q6apm_lpass_dai_startup,
@@ -272,11 +416,12 @@ static const struct snd_soc_dai_ops q6dma_ops = {
static const struct snd_soc_dai_ops q6i2s_ops = {
.prepare = q6apm_lpass_dai_prepare,
- .startup = q6apm_lpass_dai_startup,
- .shutdown = q6apm_lpass_dai_shutdown,
+ .startup = q6i2s_dai_startup,
+ .shutdown = q6i2s_lpass_dai_shutdown,
.set_channel_map = q6dma_set_channel_map,
.hw_params = q6dma_hw_params,
.set_fmt = q6i2s_set_fmt,
+ .set_sysclk = q6i2s_set_sysclk,
.trigger = q6apm_lpass_dai_trigger,
};
@@ -289,6 +434,17 @@ static const struct snd_soc_dai_ops q6hdmi_ops = {
.trigger = q6apm_lpass_dai_trigger,
};
+static const struct snd_soc_dai_ops q6tdm_ops = {
+ .prepare = q6apm_lpass_dai_prepare,
+ .startup = q6apm_lpass_dai_startup,
+ .shutdown = q6i2s_lpass_dai_shutdown,
+ .set_tdm_slot = q6tdm_set_tdm_slot,
+ .hw_params = q6dma_hw_params,
+ .set_fmt = q6i2s_set_fmt,
+ .set_sysclk = q6i2s_set_sysclk,
+ .trigger = q6apm_lpass_dai_trigger,
+};
+
static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
.name = "q6apm-be-dai-component",
.of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name,
@@ -297,6 +453,65 @@ static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
.remove_order = SND_SOC_COMP_ORDER_FIRST,
};
+static int of_q6apm_parse_dai_data(struct device *dev,
+ struct q6apm_lpass_dai_data *data)
+{
+ int ret;
+
+ for_each_child_of_node_scoped(dev->of_node, node) {
+ struct q6apm_dai_priv_data *priv;
+ int id;
+
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id < 0 || id >= APM_PORT_MAX) {
+ dev_err(dev, "valid dai id not found:%d\n", ret);
+ continue;
+ }
+
+ switch (id) {
+ /* MI2S specific properties */
+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
+ case SENARY_MI2S_RX ... SENARY_MI2S_TX:
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ priv = &data->priv[id];
+ priv->mclk = of_clk_get_by_name(node, "mclk");
+ if (IS_ERR(priv->mclk)) {
+ int err = PTR_ERR(priv->mclk);
+
+ priv->mclk = NULL;
+ if (err == -EPROBE_DEFER) {
+ q6apm_lpass_dai_put_clocks(data);
+ return dev_err_probe(dev, err,
+ "unable to get mi2s mclk\n");
+ }
+ }
+
+ priv->bclk = of_clk_get_by_name(node, "bclk");
+ if (IS_ERR(priv->bclk)) {
+ int err = PTR_ERR(priv->bclk);
+
+ priv->bclk = NULL;
+ if (err == -EPROBE_DEFER) {
+ q6apm_lpass_dai_put_clocks(data);
+ return dev_err_probe(dev, err,
+ "unable to get mi2s bclk\n");
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void q6apm_lpass_dai_clocks_action(void *data)
+{
+ q6apm_lpass_dai_put_clocks(data);
+}
+
static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev)
{
struct q6dsp_audio_port_dai_driver_config cfg;
@@ -304,17 +519,26 @@ static int q6apm_lpass_dai_dev_probe(struct platform_device *pdev)
struct snd_soc_dai_driver *dais;
struct device *dev = &pdev->dev;
int num_dais;
+ int ret;
dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL);
if (!dai_data)
return -ENOMEM;
dev_set_drvdata(dev, dai_data);
+ ret = of_q6apm_parse_dai_data(dev, dai_data);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, q6apm_lpass_dai_clocks_action, dai_data);
+ if (ret)
+ return ret;
memset(&cfg, 0, sizeof(cfg));
cfg.q6i2s_ops = &q6i2s_ops;
cfg.q6dma_ops = &q6dma_ops;
cfg.q6hdmi_ops = &q6hdmi_ops;
+ cfg.q6tdm_ops = &q6tdm_ops;
dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais);
return devm_snd_soc_register_component(dev, &q6apm_lpass_dai_component, dais, num_dais);
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 641d6d243229..f167b9dae3fa 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -802,14 +802,17 @@ EXPORT_SYMBOL_GPL(q6apm_graph_prepare);
int q6apm_graph_start(struct q6apm_graph *graph)
{
struct audioreach_graph *ar_graph = graph->ar_graph;
- int ret = 0;
+ int ret;
- if (ar_graph->start_count == 0)
+ if (ar_graph->start_count == 0) {
ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START);
+ if (ret)
+ return ret;
+ }
ar_graph->start_count++;
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(q6apm_graph_start);
@@ -817,6 +820,9 @@ int q6apm_graph_stop(struct q6apm_graph *graph)
{
struct audioreach_graph *ar_graph = graph->ar_graph;
+ if (ar_graph->start_count == 0)
+ return 0;
+
if (--ar_graph->start_count > 0)
return 0;
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
index 03838582aead..ab7d20580638 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-clocks.c
@@ -12,7 +12,7 @@
#include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
#include "q6dsp-lpass-clocks.h"
-#define Q6DSP_MAX_CLK_ID 104
+#define Q6DSP_MAX_CLK_ID 105
#define Q6DSP_LPASS_CLK_ROOT_DEFAULT 0
diff --git a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
index e5cd82f77b55..c3d8116ad503 100644
--- a/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
+++ b/sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
@@ -553,11 +553,15 @@ static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = {
Q6AFE_MI2S_RX_DAI("LPI RX2", LPI_MI2S_RX_2),
Q6AFE_MI2S_RX_DAI("LPI RX3", LPI_MI2S_RX_3),
Q6AFE_MI2S_RX_DAI("LPI RX4", LPI_MI2S_RX_4),
+ Q6AFE_MI2S_RX_DAI("LPI RX5", LPI_MI2S_RX_5),
+ Q6AFE_MI2S_RX_DAI("LPI RX6", LPI_MI2S_RX_6),
Q6AFE_MI2S_TX_DAI("LPI TX0", LPI_MI2S_TX_0),
Q6AFE_MI2S_TX_DAI("LPI TX1", LPI_MI2S_TX_1),
Q6AFE_MI2S_TX_DAI("LPI TX2", LPI_MI2S_TX_2),
Q6AFE_MI2S_TX_DAI("LPI TX3", LPI_MI2S_TX_3),
Q6AFE_MI2S_TX_DAI("LPI TX4", LPI_MI2S_TX_4),
+ Q6AFE_MI2S_TX_DAI("LPI TX5", LPI_MI2S_TX_5),
+ Q6AFE_MI2S_TX_DAI("LPI TX6", LPI_MI2S_TX_6),
Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0),
Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1),
Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2),
@@ -712,6 +716,7 @@ struct snd_soc_dai_driver *q6dsp_audio_ports_set_config(struct device *dev,
case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ case LPI_MI2S_RX_5 ... LPI_MI2S_TX_6:
q6dsp_audio_fe_dais[i].ops = cfg->q6i2s_ops;
break;
case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
diff --git a/sound/soc/qcom/qdsp6/q6prm-clocks.c b/sound/soc/qcom/qdsp6/q6prm-clocks.c
index 4c574b48ab00..f613e2aee75e 100644
--- a/sound/soc/qcom/qdsp6/q6prm-clocks.c
+++ b/sound/soc/qcom/qdsp6/q6prm-clocks.c
@@ -42,6 +42,11 @@ static const struct q6dsp_clk_init q6prm_clks[] = {
Q6PRM_CLK(LPASS_CLK_ID_INT5_MI2S_IBIT),
Q6PRM_CLK(LPASS_CLK_ID_INT6_MI2S_IBIT),
Q6PRM_CLK(LPASS_CLK_ID_QUI_MI2S_OSR),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_1),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_2),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_3),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_4),
+ Q6PRM_CLK(LPASS_CLK_ID_MCLK_5),
Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_MCLK),
Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK),
Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_MCLK),
@@ -59,10 +64,40 @@ static const struct q6dsp_clk_init q6prm_clks[] = {
Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_MCLK),
Q6PRM_CLK(LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK),
Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF0_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF0_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF1_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF1_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF2_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF2_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF3_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF3_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF4_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF4_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF5_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF5_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF6_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF6_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF7_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF7_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF8_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF8_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF9_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF9_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF10_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF10_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF11_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF11_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF12_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_QAIF_IF12_EBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_VA_QAIF_IF0_IBIT),
+ Q6PRM_CLK(LAPSS_CLK_ID_VA_QAIF_IF0_EBIT),
Q6DSP_VOTE_CLK(LPASS_HW_MACRO_VOTE, Q6PRM_HW_CORE_ID_LPASS,
"LPASS_HW_MACRO"),
Q6DSP_VOTE_CLK(LPASS_HW_DCODEC_VOTE, Q6PRM_HW_CORE_ID_DCODEC,
"LPASS_HW_DCODEC"),
+ Q6DSP_VOTE_CLK(LPASS_HW_LPR_VOTE, Q6PRM_HW_LPR_VOTE,
+ "LPASS_HW_LPR_VOTE"),
};
static const struct q6dsp_clk_desc q6dsp_clk_q6prm __maybe_unused = {
diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c
index 04892fb4423f..1f3ce4cc0837 100644
--- a/sound/soc/qcom/qdsp6/q6prm.c
+++ b/sound/soc/qcom/qdsp6/q6prm.c
@@ -31,10 +31,16 @@ struct q6prm {
#define PARAM_ID_RSC_HW_CORE 0x08001032
#define PARAM_ID_RSC_LPASS_CORE 0x0800102B
#define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C
+#define PARAM_ID_RSC_CPU_LPR 0x08001A6E
+
+#define LPR_CPU_SS_SLEEP_DISABLE 0x1
struct prm_cmd_request_hw_core {
struct apm_module_param_data param_data;
- uint32_t hw_clk_id;
+ union {
+ u32 hw_clk_id;
+ u32 lpr_state;
+ };
} __packed;
struct prm_cmd_request_rsc {
@@ -62,6 +68,7 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool
struct prm_cmd_request_hw_core *req;
gpr_device_t *gdev = prm->gdev;
uint32_t opcode, rsp_opcode;
+ bool lpr_req = (hw_block_id == Q6PRM_HW_LPR_VOTE);
if (enable) {
opcode = PRM_CMD_REQUEST_HW_RSC;
@@ -82,10 +89,13 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool
param_data->module_instance_id = GPR_PRM_MODULE_IID;
param_data->error_code = 0;
- param_data->param_id = PARAM_ID_RSC_HW_CORE;
+ param_data->param_id = lpr_req ? PARAM_ID_RSC_CPU_LPR : PARAM_ID_RSC_HW_CORE;
param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE;
- req->hw_clk_id = hw_block_id;
+ if (lpr_req)
+ req->lpr_state = LPR_CPU_SS_SLEEP_DISABLE;
+ else
+ req->hw_clk_id = hw_block_id;
return q6prm_send_cmd_sync(prm, pkt, rsp_opcode);
}
diff --git a/sound/soc/qcom/qdsp6/q6prm.h b/sound/soc/qcom/qdsp6/q6prm.h
index a988a32086fe..cca77cd92bc1 100644
--- a/sound/soc/qcom/qdsp6/q6prm.h
+++ b/sound/soc/qcom/qdsp6/q6prm.h
@@ -3,6 +3,9 @@
#ifndef __Q6PRM_H__
#define __Q6PRM_H__
+#define LPAIF_MI2S_MCLK 1
+#define LPAIF_MI2S_BCLK 2
+
/* Clock ID for Primary I2S IBIT */
#define Q6PRM_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100
/* Clock ID for Primary I2S EBIT */
@@ -52,6 +55,17 @@
/* Clock ID for QUINARY MI2S OSR CLK */
#define Q6PRM_LPASS_CLK_ID_QUI_MI2S_OSR 0x116
+/* Clock ID for MCLK1 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_1 0x300
+/* Clock ID for MCLK2 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_2 0x301
+/* Clock ID for MCLK3 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_3 0x302
+/* Clock ID for MCLK4 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_4 0x303
+/* Clock ID for MCLK5 */
+#define Q6PRM_LPASS_CLK_ID_MCLK_5 0x304
+
#define Q6PRM_LPASS_CLK_ID_WSA_CORE_MCLK 0x305
#define Q6PRM_LPASS_CLK_ID_WSA_CORE_NPL_MCLK 0x306
@@ -83,10 +97,40 @@
/* Clock ID for RX CORE MCLK2 2X MCLK */
#define Q6PRM_LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK 0x318
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF0_IBIT 0x500
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF0_EBIT 0x501
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF1_IBIT 0x502
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF1_EBIT 0x503
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF2_IBIT 0x504
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF2_EBIT 0x505
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF3_IBIT 0x506
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF3_EBIT 0x507
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF4_IBIT 0x508
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF4_EBIT 0x509
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF5_IBIT 0x50A
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF5_EBIT 0x50B
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF6_IBIT 0x50C
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF6_EBIT 0x50D
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF7_IBIT 0x50E
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF7_EBIT 0x50F
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF8_IBIT 0x510
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF8_EBIT 0x511
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF9_IBIT 0x512
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF9_EBIT 0x513
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF10_IBIT 0x514
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF10_EBIT 0x515
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF11_IBIT 0x516
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF11_EBIT 0x517
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF12_IBIT 0x518
+#define Q6PRM_LAPSS_CLK_ID_QAIF_IF12_EBIT 0x519
+#define Q6PRM_LAPSS_CLK_ID_VA_QAIF_IF0_IBIT 0x550
+#define Q6PRM_LAPSS_CLK_ID_VA_QAIF_IF0_EBIT 0x551
+
#define Q6PRM_LPASS_CLK_SRC_INTERNAL 1
#define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0
#define Q6PRM_HW_CORE_ID_LPASS 1
#define Q6PRM_HW_CORE_ID_DCODEC 2
+#define Q6PRM_HW_LPR_VOTE 3
int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr,
int clk_root, unsigned int freq);
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 7386226046fa..d076c99f197f 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -127,7 +127,14 @@
{ mix_name, "TX_CODEC_DMA_TX_2", "TX_CODEC_DMA_TX_2"}, \
{ mix_name, "TX_CODEC_DMA_TX_3", "TX_CODEC_DMA_TX_3"}, \
{ mix_name, "TX_CODEC_DMA_TX_4", "TX_CODEC_DMA_TX_4"}, \
- { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}
+ { mix_name, "TX_CODEC_DMA_TX_5", "TX_CODEC_DMA_TX_5"}, \
+ { mix_name, "LPI_MI2S_TX_0", "LPI_MI2S_TX_0" }, \
+ { mix_name, "LPI_MI2S_TX_1", "LPI_MI2S_TX_1" }, \
+ { mix_name, "LPI_MI2S_TX_2", "LPI_MI2S_TX_2" }, \
+ { mix_name, "LPI_MI2S_TX_3", "LPI_MI2S_TX_3" }, \
+ { mix_name, "LPI_MI2S_TX_4", "LPI_MI2S_TX_4" }, \
+ { mix_name, "LPI_MI2S_TX_5", "LPI_MI2S_TX_5" }, \
+ { mix_name, "LPI_MI2S_TX_6", "LPI_MI2S_TX_6" }
#define Q6ROUTING_TX_MIXERS(id) \
SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, \
@@ -321,6 +328,27 @@
msm_routing_put_audio_mixer), \
SOC_SINGLE_EXT("TX_CODEC_DMA_TX_5", TX_CODEC_DMA_TX_5, \
id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_0", LPI_MI2S_TX_0, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_1", LPI_MI2S_TX_1, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_2", LPI_MI2S_TX_2, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_3", LPI_MI2S_TX_3, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_4", LPI_MI2S_TX_4, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_5", LPI_MI2S_TX_5, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
+ msm_routing_put_audio_mixer), \
+ SOC_SINGLE_EXT("LPI_MI2S_TX_6", LPI_MI2S_TX_6, \
+ id, 1, 0, msm_routing_get_audio_mixer, \
msm_routing_put_audio_mixer),
struct session_data {
@@ -709,6 +737,26 @@ static const struct snd_kcontrol_new rxcodec_dma_rx_6_mixer_controls[] = {
static const struct snd_kcontrol_new rx_codec_dma_rx_7_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(RX_CODEC_DMA_RX_7) };
+static const struct snd_kcontrol_new lpi_mi2s_rx_0_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_0) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_1_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_1) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_2_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_2) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_3_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_3) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_4_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_4) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_5_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_5) };
+
+static const struct snd_kcontrol_new lpi_mi2s_rx_6_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(LPI_MI2S_RX_6) };
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
Q6ROUTING_TX_MIXERS(MSM_FRONTEND_DAI_MULTIMEDIA1) };
@@ -938,6 +986,27 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_MIXER("USB_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
usb_rx_mixer_controls,
ARRAY_SIZE(usb_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_0 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_0_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_0_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_1 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_1_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_1_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_2 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_2_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_2_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_3 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_3_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_3_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_4 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_4_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_4_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_5 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_5_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_5_mixer_controls)),
+ SND_SOC_DAPM_MIXER("LPI_MI2S_RX_6 Audio Mixer", SND_SOC_NOPM, 0, 0,
+ lpi_mi2s_rx_6_mixer_controls,
+ ARRAY_SIZE(lpi_mi2s_rx_6_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0,
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
@@ -1031,6 +1100,13 @@ static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_6 Audio Mixer", "RX_CODEC_DMA_RX_6"),
Q6ROUTING_RX_DAPM_ROUTE("RX_CODEC_DMA_RX_7 Audio Mixer", "RX_CODEC_DMA_RX_7"),
Q6ROUTING_RX_DAPM_ROUTE("USB_RX Audio Mixer", "USB_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_0 Audio Mixer", "LPI_MI2S_RX_0"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_1 Audio Mixer", "LPI_MI2S_RX_1"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_2 Audio Mixer", "LPI_MI2S_RX_2"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_3 Audio Mixer", "LPI_MI2S_RX_3"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_4 Audio Mixer", "LPI_MI2S_RX_4"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_5 Audio Mixer", "LPI_MI2S_RX_5"),
+ Q6ROUTING_RX_DAPM_ROUTE("LPI_MI2S_RX_6 Audio Mixer", "LPI_MI2S_RX_6"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia1 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia2 Mixer"),
Q6ROUTING_TX_DAPM_ROUTE("MultiMedia3 Mixer"),
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index 1f69fba6de26..faafbc5c0ad0 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -753,6 +753,103 @@ static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
return 0;
}
+static int audioreach_widget_audio_if_module_load(struct audioreach_module *mod,
+ const struct snd_soc_tplg_vendor_array *mod_array)
+{
+ const struct snd_soc_tplg_vendor_value_elem *mod_elem;
+ int tkn_count = 0;
+ u32 val;
+
+ mod_elem = mod_array->value;
+
+ while (tkn_count < le32_to_cpu(mod_array->num_elems)) {
+ val = le32_to_cpu(mod_elem->value);
+ switch (le32_to_cpu(mod_elem->token)) {
+ case AR_TKN_U32_MODULE_HW_IF_IDX:
+ mod->hw_interface_idx = val;
+ break;
+ case AR_TKN_U32_MODULE_FMT_DATA:
+ mod->data_format = val;
+ break;
+ case AR_TKN_U16_MODULE_SYNC_SRC:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->sync_src = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_CTRL_DATA_OUT_ENABLE:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->ctrl_data_out_enable = (u16)val;
+ break;
+ case AR_TKN_U32_MODULE_SLOT_MASK:
+ mod->slot_mask = val;
+ break;
+ case AR_TKN_U16_MODULE_NSLOTS_PER_FRAME:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->nslots_per_frame = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_SLOT_WIDTH:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->slot_width = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_INTF_MODE:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->intf_mode = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_SYNC_MODE:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->sync_mode = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_CTRL_INVERT_SYNC_PULSE:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->ctrl_invert_sync_pulse = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_CTRL_SYNC_DATA_DELAY:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->ctrl_sync_data_delay = (u16)val;
+ break;
+ case AR_TKN_U16_MODULE_QAIF_TYPE:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->qaif_type = (u16)val;
+ break;
+ case AR_TKN_U32_MODULE_ACTIVE_LANE_MASK:
+ mod->active_lane_mask = val;
+ break;
+ case AR_TKN_U32_MODULE_FRAME_SYNC_RATE:
+ mod->frame_sync_rate = val;
+ break;
+ case AR_TKN_U16_MODULE_BIT_CLK_TYPE:
+ if (val > U16_MAX)
+ return -EINVAL;
+ mod->bit_clk_type = (u16)val;
+ break;
+ case AR_TKN_U8_MODULE_INV_INT_BIT_CLK:
+ if (val > U8_MAX)
+ return -EINVAL;
+ mod->inv_int_bit_clk = (u8)val;
+ break;
+ case AR_TKN_U8_MODULE_INV_EXT_BIT_CLK:
+ if (val > U8_MAX)
+ return -EINVAL;
+ mod->inv_ext_bit_clk = (u8)val;
+ break;
+ default:
+ break;
+ }
+ tkn_count++;
+ mod_elem++;
+ }
+
+ return 0;
+}
+
static int audioreach_widget_dp_module_load(struct audioreach_module *mod,
const struct snd_soc_tplg_vendor_array *mod_array)
{
@@ -806,6 +903,12 @@ static int audioreach_widget_load_buffer(struct snd_soc_component *component,
case MODULE_ID_I2S_SOURCE:
audioreach_widget_i2s_module_load(mod, mod_array);
break;
+ case MODULE_ID_AUDIO_IF_SINK:
+ case MODULE_ID_AUDIO_IF_SOURCE:
+ ret = audioreach_widget_audio_if_module_load(mod, mod_array);
+ if (ret)
+ return ret;
+ break;
case MODULE_ID_DISPLAY_PORT_SINK:
audioreach_widget_dp_module_load(mod, mod_array);
break;
@@ -1313,7 +1416,6 @@ int audioreach_tplg_init(struct snd_soc_component *component)
{
struct snd_soc_card *card = component->card;
struct device *dev = component->dev;
- const struct firmware *fw;
int ret;
/* Inline with Qualcomm UCM configs and linux-firmware path */
@@ -1323,6 +1425,7 @@ int audioreach_tplg_init(struct snd_soc_component *component)
if (!tplg_fw_name)
return -ENOMEM;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, tplg_fw_name, dev);
if (ret < 0) {
dev_err(dev, "tplg firmware loading %s failed %d\n", tplg_fw_name, ret);
@@ -1335,8 +1438,6 @@ int audioreach_tplg_init(struct snd_soc_component *component)
dev_err(dev, "tplg component load failed: %d\n", ret);
}
- release_firmware(fw);
-
return ret;
}
EXPORT_SYMBOL_GPL(audioreach_tplg_init);
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
index 98b15a527e37..1322601659d4 100644
--- a/sound/soc/qcom/sc8280xp.c
+++ b/sound/soc/qcom/sc8280xp.c
@@ -12,17 +12,157 @@
#include <sound/jack.h>
#include <linux/input-event-codes.h>
#include "qdsp6/q6afe.h"
+#include "qdsp6/q6apm.h"
+#include "qdsp6/q6prm.h"
+#include "qdsp6/q6dsp-common.h"
#include "common.h"
#include "sdw.h"
+#define I2S_MCLKFS 256
+
+#define I2S_MCLK_RATE(rate) \
+ ((rate) * (I2S_MCLKFS))
+#define I2S_BIT_RATE(rate, channels, format) \
+ ((rate) * (channels) * (format))
+
+static struct snd_soc_dapm_widget sc8280xp_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("DP0 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP1 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP2 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP3 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP4 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP5 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP6 Jack", NULL),
+ SND_SOC_DAPM_SPK("DP7 Jack", NULL),
+};
+
+static const struct snd_kcontrol_new max98090_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headset Mic12"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic56"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Receiver"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic12", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic56", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Receiver", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+struct qcom_snd_soc_common {
+ const char *driver_name;
+ const struct snd_soc_dapm_widget *dapm_widgets;
+ int num_dapm_widgets;
+ const struct snd_soc_dapm_route *dapm_routes;
+ int num_dapm_routes;
+ const struct snd_kcontrol_new *controls;
+ int num_controls;
+ unsigned int codec_dai_fmt;
+ bool codec_sysclk_set;
+ bool mi2s_mclk_enable;
+ bool mi2s_bclk_enable;
+ bool wcd_jack;
+ int (*snd_prepare)(struct snd_pcm_substream *substream);
+};
+
struct sc8280xp_snd_data {
bool stream_prepared[AFE_PORT_MAX];
struct snd_soc_card *card;
struct snd_soc_jack jack;
struct snd_soc_jack dp_jack[8];
+ const struct qcom_snd_soc_common *priv;
bool jack_setup;
};
+static inline int sc8280xp_get_mclk_freq(struct snd_pcm_hw_params *params)
+{
+ int rate = params_rate(params);
+
+ switch (rate) {
+ case 11025:
+ case 44100:
+ case 88200:
+ return I2S_MCLK_RATE(44100);
+ default:
+ break;
+ }
+
+ return I2S_MCLK_RATE(rate);
+}
+
+static inline int sc8280xp_get_bclk_freq(struct snd_pcm_hw_params *params)
+{
+ return I2S_BIT_RATE(params_rate(params),
+ params_channels(params),
+ snd_pcm_format_width(params_format(params)));
+}
+
+static int sc8280xp_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct snd_soc_dai *codec_dai;
+ struct qcom_snd_tdm_slot_cfg cpu_cfg;
+ struct qcom_snd_tdm_slot_cfg codec_cfg;
+ unsigned int bclk_freq;
+ int ret;
+ int i;
+
+ ret = qcom_snd_get_dai_tdm_slots(rtd, &cpu_cfg, &codec_cfg);
+ if (ret)
+ return ret == -EINVAL ? 0 : ret;
+
+ if (!cpu_cfg.slots)
+ return 0;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
+ if (ret)
+ return ret;
+
+ ret = qcom_snd_apply_dai_tdm_slots_cfg(rtd, &cpu_cfg, &codec_cfg);
+ if (ret)
+ return ret;
+
+ bclk_freq = snd_soc_tdm_params_to_bclk(params, cpu_cfg.slot_width, cpu_cfg.slots, 1);
+ if (!bclk_freq)
+ return -EINVAL;
+
+ if (data->priv->mi2s_bclk_enable) {
+ ret = snd_soc_dai_set_sysclk(cpu_dai, LPAIF_MI2S_BCLK, bclk_freq,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(rtd->dev, "%s: failed to set cpu sysclk: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ }
+
+ if (data->priv->codec_sysclk_set) {
+ for_each_rtd_codec_dais(rtd, i, codec_dai) {
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, bclk_freq,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(rtd->dev, "%s: failed to set codec sysclk on %s: %d\n",
+ __func__, codec_dai->name, ret);
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
@@ -32,10 +172,6 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
int dp_pcm_id = 0;
switch (cpu_dai->id) {
- case PRIMARY_MI2S_RX...QUATERNARY_MI2S_TX:
- case QUINARY_MI2S_RX...QUINARY_MI2S_TX:
- snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
- break;
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
/*
@@ -64,7 +200,10 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
if (dp_jack)
return qcom_snd_dp_jack_setup(rtd, dp_jack, dp_pcm_id);
- return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+ if (data->priv->wcd_jack)
+ return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+
+ return 0;
}
static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -96,12 +235,118 @@ static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ int mclk_freq = sc8280xp_get_mclk_freq(params);
+ int bclk_freq = sc8280xp_get_bclk_freq(params);
+ int ret;
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
+ case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
+ case SENARY_MI2S_RX ... SENARY_MI2S_TX:
+ case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4:
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_BP_FP);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+
+ if (data->priv->codec_dai_fmt) {
+ ret = snd_soc_dai_set_fmt(codec_dai,
+ data->priv->codec_dai_fmt);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+
+ if (data->priv->mi2s_mclk_enable) {
+ ret = snd_soc_dai_set_sysclk(cpu_dai,
+ LPAIF_MI2S_MCLK, mclk_freq,
+ SND_SOC_CLOCK_OUT);
+ if (ret)
+ return ret;
+ }
+
+ if (data->priv->mi2s_bclk_enable) {
+ ret = snd_soc_dai_set_sysclk(cpu_dai,
+ LPAIF_MI2S_BCLK, bclk_freq,
+ SND_SOC_CLOCK_OUT);
+ if (ret)
+ return ret;
+ }
+
+ if (data->priv->codec_sysclk_set) {
+ ret = snd_soc_dai_set_sysclk(codec_dai,
+ 0, mclk_freq,
+ SND_SOC_CLOCK_IN);
+ if (ret && ret != -ENOTSUPP)
+ return ret;
+ }
+ break;
+ case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+ return sc8280xp_tdm_hw_params(substream, params);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * WSA and WSA2 are handled as a single interface with the
+ * following channels mask:
+ * __________________________________________________
+ * | Bits | 3 | 2 | 1 | 0 |
+ * ---------------------------------------------------
+ * | Line | WSA2 Ch2 | WSA2 Ch1 | WSA Ch2 | WSA Ch1 |
+ * ---------------------------------------------------
+ *
+ * The Ayaneo Pocket S2 speakers are connected only to
+ * the WSA2 interface and the WSA interface is not enabled.
+ *
+ * Set the channel mapping on the WSA2 channels only.
+ */
+static const unsigned int ayaneo_ps2_channels_mapping[] = {
+ 0, /* WSA Ch1 */
+ 0, /* WSA Ch2 */
+ PCM_CHANNEL_FL, /* WSA2 Ch1 */
+ PCM_CHANNEL_FR /* WSA2 Ch2 */
+};
+
+static int ayaneo_ps2_snd_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
+ unsigned int channels = substream->runtime->channels;
+
+ if (cpu_dai->id != WSA_CODEC_DMA_RX_0)
+ return 0;
+
+ if (channels != 2)
+ return -EINVAL;
+
+ return snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ ARRAY_SIZE(ayaneo_ps2_channels_mapping),
+ ayaneo_ps2_channels_mapping);
+}
+
static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+ if (data->priv->snd_prepare) {
+ int ret;
+
+ ret = data->priv->snd_prepare(substream);
+ if (ret)
+ return ret;
+ }
+
return qcom_snd_sdw_prepare(substream, &data->stream_prepared[cpu_dai->id]);
}
@@ -117,6 +362,7 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
static const struct snd_soc_ops sc8280xp_be_ops = {
.startup = qcom_snd_sdw_startup,
.shutdown = qcom_snd_sdw_shutdown,
+ .hw_params = sc8280xp_snd_hw_params,
.hw_free = sc8280xp_snd_hw_free,
.prepare = sc8280xp_snd_prepare,
};
@@ -145,38 +391,182 @@ static int sc8280xp_platform_probe(struct platform_device *pdev)
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
- card->owner = THIS_MODULE;
+
/* Allocate the private data */
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ data->priv = of_device_get_match_data(dev);
+ if (!data->priv)
+ return -ENODEV;
+
+ card->owner = THIS_MODULE;
card->dev = dev;
dev_set_drvdata(dev, card);
snd_soc_card_set_drvdata(card, data);
+ card->dapm_widgets = data->priv->dapm_widgets;
+ card->num_dapm_widgets = data->priv->num_dapm_widgets;
+ card->dapm_routes = data->priv->dapm_routes;
+ card->num_dapm_routes = data->priv->num_dapm_routes;
+ card->controls = data->priv->controls;
+ card->num_controls = data->priv->num_controls;
+
ret = qcom_snd_parse_of(card);
if (ret)
return ret;
- card->driver_name = of_device_get_match_data(dev);
+ card->driver_name = data->priv->driver_name;
sc8280xp_add_be_ops(card);
return devm_snd_soc_register_card(dev, card);
}
+static struct qcom_snd_soc_common ayaneo_ps2_priv_data = {
+ .driver_name = "ayaneo-ps2",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .snd_prepare = ayaneo_ps2_snd_prepare,
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common eliza_priv_data = {
+ .driver_name = "eliza",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common hawi_priv_data = {
+ .driver_name = "hawi",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .codec_sysclk_set = true,
+ .mi2s_bclk_enable = true,
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common kaanapali_priv_data = {
+ .driver_name = "kaanapali",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common qcs9100_priv_data = {
+ .driver_name = "sa8775p",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+};
+
+static const struct qcom_snd_soc_common qcs615_priv_data = {
+ .driver_name = "qcs615",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .codec_sysclk_set = true,
+};
+
+static const struct qcom_snd_soc_common qcm6490_priv_data = {
+ .driver_name = "qcm6490",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common qcs6490_priv_data = {
+ .driver_name = "qcs6490",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common qcs8275_priv_data = {
+ .driver_name = "qcs8300",
+ .dapm_widgets = max98090_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(max98090_dapm_widgets),
+ .controls = max98090_controls,
+ .num_controls = ARRAY_SIZE(max98090_controls),
+ .codec_sysclk_set = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_BC_FC,
+};
+
+static const struct qcom_snd_soc_common sc8280xp_priv_data = {
+ .driver_name = "sc8280xp",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common sm8450_priv_data = {
+ .driver_name = "sm8450",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+ /* I2S Connected to HDMI */
+ .mi2s_mclk_enable = true,
+ .mi2s_bclk_enable = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S,
+};
+
+static const struct qcom_snd_soc_common sm8475_priv_data = {
+ .driver_name = "sm8475",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
+static const struct qcom_snd_soc_common sm8550_priv_data = {
+ .driver_name = "sm8550",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+ /* I2S Connected to HDMI */
+ .mi2s_mclk_enable = true,
+ .mi2s_bclk_enable = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S,
+};
+
+static const struct qcom_snd_soc_common sm8650_priv_data = {
+ .driver_name = "sm8650",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+ /* I2S Connected to HDMI */
+ .mi2s_mclk_enable = true,
+ .mi2s_bclk_enable = true,
+ .codec_dai_fmt = SND_SOC_DAIFMT_BC_FC |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_I2S,
+};
+
+static const struct qcom_snd_soc_common sm8750_priv_data = {
+ .driver_name = "sm8750",
+ .dapm_widgets = sc8280xp_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sc8280xp_dapm_widgets),
+ .wcd_jack = true,
+};
+
static const struct of_device_id snd_sc8280xp_dt_match[] = {
- {.compatible = "qcom,eliza-sndcard", "eliza"},
- {.compatible = "qcom,kaanapali-sndcard", "kaanapali"},
- {.compatible = "qcom,qcm6490-idp-sndcard", "qcm6490"},
- {.compatible = "qcom,qcs615-sndcard", "qcs615"},
- {.compatible = "qcom,qcs6490-rb3gen2-sndcard", "qcs6490"},
- {.compatible = "qcom,qcs8275-sndcard", "qcs8300"},
- {.compatible = "qcom,qcs9075-sndcard", "sa8775p"},
- {.compatible = "qcom,qcs9100-sndcard", "sa8775p"},
- {.compatible = "qcom,sc8280xp-sndcard", "sc8280xp"},
- {.compatible = "qcom,sm8450-sndcard", "sm8450"},
- {.compatible = "qcom,sm8550-sndcard", "sm8550"},
- {.compatible = "qcom,sm8650-sndcard", "sm8650"},
- {.compatible = "qcom,sm8750-sndcard", "sm8750"},
+ { .compatible = "ayaneo,pocket-s2-sndcard", .data = &ayaneo_ps2_priv_data },
+ { .compatible = "qcom,eliza-sndcard", .data = &eliza_priv_data },
+ { .compatible = "qcom,hawi-sndcard", .data = &hawi_priv_data },
+ { .compatible = "qcom,kaanapali-sndcard", .data = &kaanapali_priv_data },
+ { .compatible = "qcom,maili-sndcard", .data = &hawi_priv_data },
+ { .compatible = "qcom,qcm6490-idp-sndcard", .data = &qcm6490_priv_data },
+ { .compatible = "qcom,qcs615-sndcard", .data = &qcs615_priv_data },
+ { .compatible = "qcom,qcs6490-rb3gen2-sndcard", .data = &qcs6490_priv_data },
+ { .compatible = "qcom,qcs8275-sndcard", .data = &qcs8275_priv_data },
+ { .compatible = "qcom,qcs9075-sndcard", .data = &qcs9100_priv_data },
+ { .compatible = "qcom,qcs9100-sndcard", .data = &qcs9100_priv_data },
+ { .compatible = "qcom,sc8280xp-sndcard", .data = &sc8280xp_priv_data },
+ { .compatible = "qcom,sm8450-sndcard", .data = &sm8450_priv_data },
+ { .compatible = "qcom,sm8475-sndcard", .data = &sm8475_priv_data },
+ { .compatible = "qcom,sm8550-sndcard", .data = &sm8550_priv_data },
+ { .compatible = "qcom,sm8650-sndcard", .data = &sm8650_priv_data },
+ { .compatible = "qcom,sm8750-sndcard", .data = &sm8750_priv_data },
{}
};
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 0ce9dff4dc52..6843ab8ba017 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -36,7 +36,6 @@ struct sdm845_snd_data {
bool jack_setup;
bool slim_port_setup;
bool stream_prepared[AFE_PORT_MAX];
- struct snd_soc_card *card;
uint32_t pri_mi2s_clk_count;
uint32_t sec_mi2s_clk_count;
uint32_t quat_tdm_clk_count;
@@ -564,7 +563,6 @@ static int sdm845_snd_platform_probe(struct platform_device *pdev)
if (ret)
return ret;
- data->card = card;
snd_soc_card_set_drvdata(card, data);
sdm845_add_ops(card);
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index f193d0ba63d0..76dc3a3f4a31 100644
--- a/sound/soc/qcom/sm8250.c
+++ b/sound/soc/qcom/sm8250.c
@@ -112,6 +112,22 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
snd_soc_dai_set_fmt(cpu_dai, fmt);
snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
break;
+ case LPI_MI2S_RX_0:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
+ case LPI_MI2S_TX_3:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
default:
break;
}
@@ -194,6 +210,7 @@ static const struct of_device_id snd_sm8250_dt_match[] = {
{ .compatible = "qcom,qrb2210-sndcard", .data = "qcm2290" },
{ .compatible = "qcom,qrb4210-rb2-sndcard", .data = "sm4250" },
{ .compatible = "qcom,qrb5165-rb5-sndcard", .data = "sm8250" },
+ { .compatible = "qcom,sdm660-sndcard", .data = "sdm660" },
{ .compatible = "qcom,sm8250-sndcard", .data = "sm8250" },
{}
};
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c
index 1e0eda8c24c4..6b42fbfd27ca 100644
--- a/sound/soc/qcom/storm.c
+++ b/sound/soc/qcom/storm.c
@@ -64,21 +64,21 @@ static struct snd_soc_dai_link storm_dai_link = {
SND_SOC_DAILINK_REG(hifi),
};
-static int storm_parse_of(struct snd_soc_card *card)
+static int storm_parse_of(struct device *dev)
{
- struct snd_soc_dai_link *dai_link = card->dai_link;
- struct device_node *np = card->dev->of_node;
+ struct snd_soc_dai_link *dai_link = &storm_dai_link;
+ struct device_node *np = dev->of_node;
dai_link->cpus->of_node = of_parse_phandle(np, "cpu", 0);
if (!dai_link->cpus->of_node) {
- dev_err(card->dev, "error getting cpu phandle\n");
+ dev_err(dev, "error getting cpu phandle\n");
return -EINVAL;
}
dai_link->platforms->of_node = dai_link->cpus->of_node;
dai_link->codecs->of_node = of_parse_phandle(np, "codec", 0);
if (!dai_link->codecs->of_node) {
- dev_err(card->dev, "error getting codec phandle\n");
+ dev_err(dev, "error getting codec phandle\n");
return -EINVAL;
}
@@ -106,7 +106,7 @@ static int storm_platform_probe(struct platform_device *pdev)
card->dai_link = &storm_dai_link;
card->num_links = 1;
- ret = storm_parse_of(card);
+ ret = storm_parse_of(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "error resolving dai links: %d\n", ret);
return ret;
diff --git a/sound/soc/renesas/fsi.c b/sound/soc/renesas/fsi.c
index ae86014c3819..23b7e63596d3 100644
--- a/sound/soc/renesas/fsi.c
+++ b/sound/soc/renesas/fsi.c
@@ -1979,8 +1979,8 @@ static const struct of_device_id fsi_of_match[] = {
MODULE_DEVICE_TABLE(of, fsi_of_match);
static const struct platform_device_id fsi_id_table[] = {
- { "sh_fsi", (kernel_ulong_t)&fsi1_core },
- {},
+ /* an array with no valid entry prevents matching on driver name */
+ { }
};
MODULE_DEVICE_TABLE(platform, fsi_id_table);
@@ -1992,7 +1992,7 @@ static int fsi_probe(struct platform_device *pdev)
const struct fsi_core *core;
struct fsi_priv *fsi;
struct resource *res;
- unsigned int irq;
+ int irq;
int ret;
memset(&info, 0, sizeof(info));
@@ -2007,12 +2007,15 @@ static int fsi_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
+ if (!res) {
dev_err(&pdev->dev, "Not enough FSI platform resources.\n");
return -ENODEV;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
master = devm_kzalloc(&pdev->dev, sizeof(*master), GFP_KERNEL);
if (!master)
return -ENOMEM;
diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c
index 53efd1be5139..2a74d89ba39d 100644
--- a/sound/soc/renesas/rcar/adg.c
+++ b/sound/soc/renesas/rcar/adg.c
@@ -565,7 +565,7 @@ static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
struct clk *clk;
clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
- if (IS_ERR_OR_NULL(clk)) {
+ if (IS_ERR(clk)) {
dev_err(dev, "create null clk error\n");
return ERR_CAST(clk);
}
@@ -618,7 +618,7 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
* No "adg" is not error
*/
clk = devm_clk_get(dev, "adg");
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
clk = rsnd_adg_null_clk_get(priv);
adg->adg = clk;
@@ -626,9 +626,9 @@ static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
for (i = 0; i < clkin_size; i++) {
clk = devm_clk_get(dev, clkin_name[i]);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
clk = rsnd_adg_null_clk_get(priv);
- if (IS_ERR_OR_NULL(clk))
+ if (IS_ERR(clk))
goto err;
adg->clkin[i] = clk;
diff --git a/sound/soc/renesas/siu_dai.c b/sound/soc/renesas/siu_dai.c
index 039b1264d90d..85dee9025710 100644
--- a/sound/soc/renesas/siu_dai.c
+++ b/sound/soc/renesas/siu_dai.c
@@ -715,7 +715,6 @@ static struct snd_soc_dai_driver siu_i2s_dai = {
static int siu_probe(struct platform_device *pdev)
{
- const struct firmware *fw_entry;
struct resource *res, *region;
struct siu_info *info;
int ret;
@@ -726,6 +725,7 @@ static int siu_probe(struct platform_device *pdev)
siu_i2s_data = info;
info->dev = &pdev->dev;
+ const struct firmware *fw_entry __free(firmware) = NULL;
ret = request_firmware(&fw_entry, "siu_spb.bin", &pdev->dev);
if (ret)
return ret;
@@ -736,8 +736,6 @@ static int siu_probe(struct platform_device *pdev)
*/
memcpy(&info->fw, fw_entry->data, fw_entry->size);
- release_firmware(fw_entry);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index cf642a23c38a..541163ed56fc 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -185,10 +185,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
gpiod_set_consumer_name(machine->gpio_hp_en, "hp_en");
ret = snd_soc_of_parse_card_name(card, "rockchip,model");
- if (ret) {
- dev_err(card->dev, "SoC parse card name failed %d\n", ret);
+ if (ret)
return ret;
- }
rk_dailink.codecs[0].of_node = of_parse_phandle(np,
"rockchip,audio-codec",
@@ -207,10 +205,9 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
}
ret = snd_soc_get_dai_name(&args, &rk_dailink.codecs[0].dai_name);
- if (ret) {
- dev_err(&pdev->dev, "Unable to get codec_dai_name\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Unable to get codec_dai_name\n");
rk_dailink.cpus->of_node = of_parse_phandle(np, "rockchip,i2s-controller",
0);
@@ -223,11 +220,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
rk_dailink.platforms->of_node = rk_dailink.cpus->of_node;
ret = snd_soc_of_parse_audio_routing(card, "rockchip,routing");
- if (ret) {
- dev_err(&pdev->dev,
- "Unable to parse 'rockchip,routing' property\n");
+ if (ret)
return ret;
- }
snd_soc_card_set_drvdata(card, machine);
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 64c90316fa02..261f36d4c2fd 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -767,16 +767,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
/* try to prepare related clocks */
i2s->hclk = devm_clk_get_enabled(&pdev->dev, "i2s_hclk");
- if (IS_ERR(i2s->hclk)) {
- dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
- return PTR_ERR(i2s->hclk);
- }
+ if (IS_ERR(i2s->hclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->hclk),
+ "Can't retrieve i2s bus clock\n");
i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk");
- if (IS_ERR(i2s->mclk)) {
- dev_err(&pdev->dev, "Can't retrieve i2s master clock\n");
- return PTR_ERR(i2s->mclk);
- }
+ if (IS_ERR(i2s->mclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->mclk),
+ "Can't retrieve i2s master clock\n");
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(regs))
@@ -792,7 +790,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
i2s->bclk_ratio = 64;
i2s->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (!IS_ERR(i2s->pinctrl)) {
+ if (IS_ERR(i2s->pinctrl)) {
+ if (PTR_ERR(i2s->pinctrl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n");
+ } else {
i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl, "bclk_on");
if (!IS_ERR_OR_NULL(i2s->bclk_on)) {
i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl, "bclk_off");
@@ -801,8 +803,6 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
return -EINVAL;
}
}
- } else {
- dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n");
}
i2s_pinctrl_select_bclk_off(i2s);
@@ -831,16 +831,12 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
&rockchip_i2s_component,
dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Could not register DAI\n");
+ if (ret)
return ret;
- }
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "Could not register PCM\n");
+ if (ret)
return ret;
- }
return 0;
}
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index e6229a325ffe..5ef7f109706d 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -1263,16 +1263,14 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
i2s_tdm->tx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"tx-m");
if (IS_ERR(i2s_tdm->tx_reset)) {
- ret = PTR_ERR(i2s_tdm->tx_reset);
- return dev_err_probe(i2s_tdm->dev, ret,
+ return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->tx_reset),
"Error in tx-m reset control\n");
}
i2s_tdm->rx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"rx-m");
if (IS_ERR(i2s_tdm->rx_reset)) {
- ret = PTR_ERR(i2s_tdm->rx_reset);
- return dev_err_probe(i2s_tdm->dev, ret,
+ return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->rx_reset),
"Error in rx-m reset control\n");
}
@@ -1363,17 +1361,12 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev,
&rockchip_i2s_tdm_component,
i2s_tdm->dai, 1);
-
- if (ret) {
- dev_err(&pdev->dev, "Could not register DAI\n");
+ if (ret)
goto err_suspend;
- }
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "Could not register PCM\n");
+ if (ret)
goto err_suspend;
- }
return 0;
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 075d0990a126..426506a8e18e 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -428,11 +428,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
/* Parse card name. */
ret = snd_soc_of_parse_card_name(card, "rockchip,model");
- if (ret) {
- dev_err(&pdev->dev,
- "Soc parse card name failed %d\n", ret);
+ if (ret)
return ret;
- }
/* register the soc card */
ret = devm_snd_soc_register_card(&pdev->dev, card);
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index 115e90d3bbfe..343fda478901 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -630,10 +630,8 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
&rockchip_pdm_component,
&rockchip_pdm_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "could not register dai: %d\n", ret);
+ if (ret)
goto err_suspend;
- }
rockchip_pdm_rxctrl(pdm, 0);
@@ -642,10 +640,8 @@ static int rockchip_pdm_probe(struct platform_device *pdev)
goto err_suspend;
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "could not register pcm: %d\n", ret);
+ if (ret)
goto err_suspend;
- }
return 0;
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index 590b64b362f6..0432eeabc64e 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -191,11 +191,8 @@ static int snd_rk_mc_probe(struct platform_device *pdev)
rk_dailink.platforms->of_node = rk_dailink.cpus->of_node;
ret = snd_soc_of_parse_card_name(card, "rockchip,model");
- if (ret) {
- dev_err(&pdev->dev,
- "Soc parse card name failed %d\n", ret);
+ if (ret)
goto put_cpu_of_node;
- }
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) {
diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index 585e89f61f0d..30b5e71d0937 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -1428,12 +1428,13 @@ static int rockchip_sai_probe(struct platform_device *pdev)
"Failed to initialize regmap\n");
irq = platform_get_irq_optional(pdev, 0);
+ if (irq == -EPROBE_DEFER)
+ return irq;
if (irq > 0) {
ret = devm_request_irq(&pdev->dev, irq, rockchip_sai_isr,
IRQF_SHARED, node->name, sai);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "Failed to request irq %d\n", irq);
+ return ret;
} else {
dev_dbg(&pdev->dev, "Asked for an IRQ but got %d\n", irq);
}
@@ -1456,7 +1457,7 @@ static int rockchip_sai_probe(struct platform_device *pdev)
ret = rockchip_sai_parse_paths(sai, node);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "Failed to parse paths\n");
+ return ret;
/*
* From here on, all register accesses need to be wrapped in
@@ -1471,18 +1472,14 @@ static int rockchip_sai_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, ret, "Failed to resume device\n");
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register PCM: %d\n", ret);
+ if (ret)
goto err_runtime_suspend;
- }
ret = devm_snd_soc_register_component(&pdev->dev,
&rockchip_sai_component,
dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register component: %d\n", ret);
+ if (ret)
goto err_runtime_suspend;
- }
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_put(&pdev->dev);
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index 7f15bc7f8f35..2d53efd5dd2e 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -396,13 +396,13 @@ static int rk_spdif_probe(struct platform_device *pdev)
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "Could not register PCM\n");
+ return ret;
ret = devm_snd_soc_register_component(&pdev->dev,
&rk_spdif_component,
&rk_spdif_dai, 1);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "Could not register DAI\n");
+ return ret;
return 0;
}
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 48ccc1d1854b..6db91b73f25c 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -658,6 +658,7 @@ static int aries_audio_probe(struct platform_device *pdev)
goto out;
}
+ of_node_get(aries_dai[0].cpus->of_node);
aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node;
/* Set CPU of_node for BT DAI */
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index f80f697a5d55..3e76cb81462f 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -8,6 +8,7 @@
#include <dt-bindings/sound/samsung-i2s.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
@@ -512,7 +513,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
u32 mod, mask, val = 0;
int ret = 0;
- pm_runtime_get_sync(dai->dev);
+ guard(pm_runtime_active)(dai->dev);
scoped_guard(spinlock_irqsave, &priv->lock)
mod = readl(priv->addr + I2SMOD);
@@ -537,8 +538,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
&& (mod & cdcon_mask))))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- ret = -EAGAIN;
- goto err;
+ return -EAGAIN;
}
if (dir == SND_SOC_CLOCK_IN)
@@ -566,7 +566,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
} else {
priv->rclk_srcrate =
clk_get_rate(priv->op_clk);
- goto done;
+ return 0;
}
}
@@ -580,14 +580,14 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
if (WARN_ON(IS_ERR(priv->op_clk))) {
ret = PTR_ERR(priv->op_clk);
priv->op_clk = NULL;
- goto err;
+ return ret;
}
ret = clk_prepare_enable(priv->op_clk);
if (ret) {
clk_put(priv->op_clk);
priv->op_clk = NULL;
- goto err;
+ return ret;
}
priv->rclk_srcrate = clk_get_rate(priv->op_clk);
@@ -595,11 +595,10 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
|| (clk_id && !(mod & rsrc_mask))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
- ret = -EAGAIN;
- goto err;
+ return -EAGAIN;
} else {
/* Call can't be on the active DAI */
- goto done;
+ return 0;
}
if (clk_id == 1)
@@ -607,8 +606,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
break;
default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n");
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
scoped_guard(spinlock_irqsave, &priv->lock) {
@@ -616,13 +614,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
mod = (mod & ~mask) | val;
writel(mod, priv->addr + I2SMOD);
}
-done:
- pm_runtime_put(dai->dev);
return 0;
-err:
- pm_runtime_put(dai->dev);
- return ret;
}
static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
@@ -1123,15 +1116,31 @@ static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = {
static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = {
{ "Playback Mixer", NULL, "Primary Playback" },
- { "Playback Mixer", NULL, "Secondary Playback" },
-
{ "Mixer DAI TX", NULL, "Playback Mixer" },
{ "Primary Capture", NULL, "Mixer DAI RX" },
};
+static const struct snd_soc_dapm_route samsung_i2s_dapm_routes_sec_play[] = {
+ { "Playback Mixer", NULL, "Secondary Playback" },
+};
+
+static int samsung_i2s_component_probe(struct snd_soc_component *component)
+{
+ struct samsung_i2s_priv *priv = snd_soc_component_get_drvdata(component);
+
+ if (priv->quirks & QUIRK_SEC_DAI)
+ snd_soc_dapm_add_routes(snd_soc_component_to_dapm(component),
+ samsung_i2s_dapm_routes_sec_play,
+ ARRAY_SIZE(samsung_i2s_dapm_routes_sec_play));
+
+ return 0;
+}
+
static const struct snd_soc_component_driver samsung_i2s_component = {
.name = "samsung-i2s",
+ .probe = samsung_i2s_component_probe,
+
.dapm_widgets = samsung_i2s_widgets,
.num_dapm_widgets = ARRAY_SIZE(samsung_i2s_widgets),
@@ -1448,10 +1457,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
regs_base = res->start;
priv->clk = devm_clk_get(&pdev->dev, "iis");
- if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "Failed to get iis clock\n");
- return PTR_ERR(priv->clk);
- }
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
+ "Failed to get iis clock\n");
+
ret = clk_prepare_enable(priv->clk);
if (ret != 0) {
@@ -1657,8 +1666,7 @@ static const struct samsung_i2s_dai_data i2sv6_dai_type __maybe_unused = {
};
static const struct samsung_i2s_dai_data i2sv7_dai_type __maybe_unused = {
- .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
- QUIRK_SUPPORTS_TDM,
+ .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR | QUIRK_SUPPORTS_TDM,
.pcm_rates = SNDRV_PCM_RATE_8000_192000,
.i2s_variant_regs = &i2sv7_regs,
};
@@ -1682,7 +1690,7 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = {
.name = "samsung-i2s",
.driver_data = (kernel_ulong_t)&i2sv3_dai_type,
},
- {},
+ { }
};
MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c
index 2474eb619882..515e4dfc1432 100644
--- a/sound/soc/samsung/smdk_spdif.c
+++ b/sound/soc/samsung/smdk_spdif.c
@@ -130,12 +130,8 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
return ret;
/* Set S/PDIF uses internal source clock */
- ret = snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
- rclk_rate, SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return ret;
+ return snd_soc_dai_set_sysclk(cpu_dai, SND_SOC_SPDIF_INT_MCLK,
+ rclk_rate, SND_SOC_CLOCK_IN);
}
static const struct snd_soc_ops smdk_spdif_ops = {
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c
index 7fc46d55c522..53eaabaf8956 100644
--- a/sound/soc/samsung/spdif.c
+++ b/sound/soc/samsung/spdif.c
@@ -380,8 +380,8 @@ static int spdif_probe(struct platform_device *pdev)
spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
if (IS_ERR(spdif->pclk)) {
- dev_err(&pdev->dev, "failed to get peri-clock\n");
- ret = -ENOENT;
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->pclk),
+ "failed to get peri-clock\n");
goto err0;
}
ret = clk_prepare_enable(spdif->pclk);
@@ -390,8 +390,8 @@ static int spdif_probe(struct platform_device *pdev)
spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
if (IS_ERR(spdif->sclk)) {
- dev_err(&pdev->dev, "failed to get internal source clock\n");
- ret = -ENOENT;
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(spdif->sclk),
+ "failed to get internal source clock\n");
goto err1;
}
ret = clk_prepare_enable(spdif->sclk);
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index b4dedba719dc..ce2e7c270765 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -364,7 +364,6 @@ static int entity_parse_ot(struct device *dev,
/**
* sdca_asoc_pde_poll_actual_ps - Verify PDE power state reached target state
- * @dev: Pointer to the device for error logging.
* @regmap: Register map for reading ACTUAL_PS register.
* @function_id: SDCA function identifier.
* @entity_id: SDCA entity identifier for the power domain.
@@ -389,11 +388,11 @@ static int entity_parse_ot(struct device *dev,
* polling times out before reaching the target state, or a negative error code if
* a register read fails.
*/
-int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
+int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap,
int function_id, int entity_id,
- int from_ps, int to_ps,
- const struct sdca_pde_delay *pde_delays,
- int num_delays)
+ int from_ps, int to_ps,
+ const struct sdca_pde_delay *pde_delays,
+ int num_delays)
{
static const int polls = 100;
static const int default_poll_us = 1000;
@@ -451,14 +450,14 @@ static int entity_pde_event(struct snd_soc_dapm_widget *widget,
return 0;
}
- ret = sdca_asoc_pde_poll_actual_ps(component->dev, component->regmap,
+ ret = sdca_asoc_pde_poll_actual_ps(component->regmap,
SDW_SDCA_CTL_FUNC(widget->reg),
SDW_SDCA_CTL_ENT(widget->reg),
from, to,
entity->pde.max_delay,
entity->pde.num_max_delay);
if (ret)
- dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n",
+ dev_err(component->dev, "%s: pde transition %x -> %x failed: %d\n",
entity->label, from, to, ret);
return ret;
@@ -1231,7 +1230,7 @@ static u64 width_find_mask(unsigned int bits)
}
}
-static int populate_rate_format(struct device *dev,
+int sdca_asoc_populate_rate_format(struct device *dev,
struct sdca_function_data *function,
struct sdca_entity *entity,
struct snd_soc_pcm_stream *stream)
@@ -1292,6 +1291,7 @@ static int populate_rate_format(struct device *dev,
return 0;
}
+EXPORT_SYMBOL_NS(sdca_asoc_populate_rate_format, "SND_SOC_SDCA");
/**
* sdca_asoc_populate_dais - fill in an array of DAI drivers for a Function
@@ -1344,7 +1344,7 @@ int sdca_asoc_populate_dais(struct device *dev, struct sdca_function_data *funct
stream->channels_min = 1;
stream->channels_max = SDCA_MAX_CHANNEL_COUNT;
- ret = populate_rate_format(dev, function, entity, stream);
+ ret = sdca_asoc_populate_rate_format(dev, function, entity, stream);
if (ret)
return ret;
diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c
index 2fb2b043c979..cc7045dc26e6 100644
--- a/sound/soc/sdca/sdca_class_function.c
+++ b/sound/soc/sdca/sdca_class_function.c
@@ -329,7 +329,7 @@ static int class_function_probe(struct auxiliary_device *auxdev,
drv->core = core;
drv->function = &sdev->function;
- ret = sdca_parse_function(dev, core->sdw, drv->function);
+ ret = sdca_parse_function(dev, drv->function);
if (ret)
return ret;
diff --git a/sound/soc/sdca/sdca_fdl.c b/sound/soc/sdca/sdca_fdl.c
index dbe572336f8c..150e36ed24bc 100644
--- a/sound/soc/sdca/sdca_fdl.c
+++ b/sound/soc/sdca/sdca_fdl.c
@@ -195,7 +195,6 @@ static int fdl_load_file(struct sdca_interrupt *interrupt,
{
struct device *dev = interrupt->dev;
struct sdca_fdl_data *fdl_data = &interrupt->function->fdl_data;
- const struct firmware *firmware = NULL;
struct acpi_sw_file *swf = NULL, *tmp;
struct sdca_fdl_file *fdl_file;
char *disk_filename;
@@ -230,6 +229,7 @@ static int fdl_load_file(struct sdca_interrupt *interrupt,
dev_dbg(dev, "FDL disk filename: %s\n", disk_filename);
+ const struct firmware *firmware __free(firmware) = NULL;
ret = firmware_request_nowarn(&firmware, disk_filename, dev);
kfree(disk_filename);
if (ret) {
@@ -258,8 +258,7 @@ static int fdl_load_file(struct sdca_interrupt *interrupt,
if (!swf) {
dev_err(dev, "failed to locate SWF\n");
- ret = -ENOENT;
- goto error;
+ return -ENOENT;
}
dev_info(dev, "loading SWF: %x-%x-%x\n",
@@ -271,9 +270,6 @@ static int fdl_load_file(struct sdca_interrupt *interrupt,
SDCA_CTL_XU_FDL_MESSAGEOFFSET, fdl_file->fdl_offset,
SDCA_CTL_XU_FDL_MESSAGELENGTH, swf->data,
swf->file_length - offsetof(struct acpi_sw_file, data));
-
-error:
- release_firmware(firmware);
return ret;
}
diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c
index b5ca98283a88..54604872ae0d 100644
--- a/sound/soc/sdca/sdca_function_device.c
+++ b/sound/soc/sdca/sdca_function_device.c
@@ -32,7 +32,8 @@ static void sdca_dev_release(struct device *dev)
/* alloc, init and add link devices */
static struct sdca_dev *sdca_dev_register(struct device *parent,
- struct sdca_function_desc *function_desc)
+ struct sdca_function_desc *function_desc,
+ struct acpi_table_swft *swft)
{
struct sdca_dev *sdev;
struct auxiliary_device *auxdev;
@@ -50,6 +51,7 @@ static struct sdca_dev *sdca_dev_register(struct device *parent,
auxdev->dev.release = sdca_dev_release;
sdev->function.desc = function_desc;
+ sdev->function.fdl_data.swft = swft;
rc = ida_alloc(&sdca_function_ida, GFP_KERNEL);
if (rc < 0) {
@@ -99,7 +101,8 @@ int sdca_dev_register_functions(struct sdw_slave *slave)
struct sdca_dev *func_dev;
func_dev = sdca_dev_register(&slave->dev,
- &sdca_data->function[i]);
+ &sdca_data->function[i],
+ sdca_data->swft);
if (IS_ERR(func_dev)) {
ret = PTR_ERR(func_dev);
/*
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 7a7a9f1a4938..e01d91eb3cc8 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -7,6 +7,7 @@
*/
#include <linux/acpi.h>
+#include <linux/array_size.h>
#include <linux/byteorder/generic.h>
#include <linux/cleanup.h>
#include <linux/device.h>
@@ -18,7 +19,6 @@
#include <linux/types.h>
#include <sound/sdca.h>
#include <sound/sdca_function.h>
-#include <sound/sdca_hid.h>
/*
* Should be long enough to encompass all the MIPI DisCo properties.
@@ -1365,90 +1365,76 @@ bad_list:
return -EINVAL;
}
-static int
-find_sdca_entity_hide(struct device *dev, struct sdw_slave *sdw,
- struct fwnode_handle *function_node,
- struct fwnode_handle *entity_node, struct sdca_entity *entity)
+static int find_sdca_entity_hide(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
{
struct sdca_entity_hide *hide = &entity->hide;
- unsigned int delay, *af_list = hide->af_number_list;
- int nval, ret;
- unsigned char *report_desc = NULL;
+ int num_reports, ret;
+ unsigned int delay;
ret = fwnode_property_read_u32(entity_node,
- "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay);
+ "mipi-sdca-RxUMP-ownership-transition-max-delay",
+ &delay);
if (!ret)
hide->max_delay = delay;
- nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDTx-supported-report-ids");
- if (nval > 0) {
- hide->num_hidtx_ids = nval;
+ num_reports = fwnode_property_count_u32(entity_node,
+ "mipi-sdca-HIDTx-supported-report-ids");
+ if (num_reports < 0 && num_reports != -EINVAL) {
+ dev_err(dev, "%pfwP: failed to read hid tx ids: %d\n",
+ entity_node, num_reports);
+ return num_reports;
+ } else if (num_reports > 0) {
+ hide->num_hidtx_ids = num_reports;
hide->hidtx_ids = devm_kcalloc(dev, hide->num_hidtx_ids,
sizeof(*hide->hidtx_ids), GFP_KERNEL);
if (!hide->hidtx_ids)
return -ENOMEM;
- ret = fwnode_property_read_u32_array(entity_node,
- "mipi-sdca-HIDTx-supported-report-ids",
- hide->hidtx_ids,
- hide->num_hidtx_ids);
- if (ret < 0)
- return ret;
+ fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-HIDTx-supported-report-ids",
+ hide->hidtx_ids, hide->num_hidtx_ids);
}
- nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDRx-supported-report-ids");
- if (nval > 0) {
- hide->num_hidrx_ids = nval;
+ num_reports = fwnode_property_count_u32(entity_node,
+ "mipi-sdca-HIDRx-supported-report-ids");
+ if (num_reports < 0 && num_reports != -EINVAL) {
+ dev_err(dev, "%pfwP: failed to read hid rx ids: %d\n",
+ entity_node, num_reports);
+ return num_reports;
+ } else if (num_reports > 0) {
+ hide->num_hidrx_ids = num_reports;
hide->hidrx_ids = devm_kcalloc(dev, hide->num_hidrx_ids,
sizeof(*hide->hidrx_ids), GFP_KERNEL);
if (!hide->hidrx_ids)
return -ENOMEM;
- ret = fwnode_property_read_u32_array(entity_node,
- "mipi-sdca-HIDRx-supported-report-ids",
- hide->hidrx_ids,
- hide->num_hidrx_ids);
- if (ret < 0)
- return ret;
+ fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-HIDRx-supported-report-ids",
+ hide->hidrx_ids, hide->num_hidrx_ids);
}
- nval = fwnode_property_count_u32(entity_node, "mipi-sdca-hide-related-audio-function-list");
- if (nval <= 0) {
+ /*
+ * FIXME: This should probably link to the actual sdca_function_data pointer,
+ * but updating to do so should probably wait until we have a user.
+ */
+ num_reports = fwnode_property_count_u32(entity_node,
+ "mipi-sdca-hide-related-audio-function-list");
+ if (num_reports <= 0) {
dev_err(dev, "%pfwP: audio function numbers list missing: %d\n",
- entity_node, nval);
+ entity_node, num_reports);
return -EINVAL;
- } else if (nval > SDCA_MAX_FUNCTION_COUNT) {
- dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", entity_node);
+ } else if (num_reports > ARRAY_SIZE(hide->af_number_list)) {
+ dev_err(dev, "%pfwP: maximum number of audio function exceeded\n",
+ entity_node);
return -EINVAL;
}
- hide->hide_reside_function_num = nval;
+ hide->hide_reside_function_num = num_reports;
fwnode_property_read_u32_array(entity_node,
- "mipi-sdca-hide-related-audio-function-list", af_list, nval);
-
- nval = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor");
- if (nval)
- fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor",
- (u8 *)&hide->hid_desc, nval);
-
- if (hide->hid_desc.bNumDescriptors) {
- nval = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor");
- if (nval) {
- report_desc = devm_kzalloc(dev, nval, GFP_KERNEL);
- if (!report_desc)
- return -ENOMEM;
- hide->hid_report_desc = report_desc;
- fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor",
- report_desc, nval);
-
- /* add HID device */
- ret = sdca_add_hid_device(dev, sdw, entity);
- if (ret) {
- dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret);
- return ret;
- }
- }
- }
+ "mipi-sdca-hide-related-audio-function-list",
+ hide->af_number_list, num_reports);
return 0;
}
@@ -1475,8 +1461,7 @@ static int find_sdca_entity_xu(struct device *dev,
return 0;
}
-static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
- struct sdca_function_data *function,
+static int find_sdca_entity(struct device *dev, struct sdca_function_data *function,
struct fwnode_handle *function_node,
struct fwnode_handle *entity_node,
struct sdca_entity *entity)
@@ -1528,8 +1513,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
ret = find_sdca_entity_ge(dev, entity_node, entity);
break;
case SDCA_ENTITY_TYPE_HIDE:
- ret = find_sdca_entity_hide(dev, sdw, function_node,
- entity_node, entity);
+ ret = find_sdca_entity_hide(dev, entity_node, entity);
break;
default:
break;
@@ -1544,8 +1528,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw,
return 0;
}
-static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
- struct fwnode_handle *function_node,
+static int find_sdca_entities(struct device *dev, struct fwnode_handle *function_node,
struct sdca_function_data *function)
{
struct sdca_entity *entities;
@@ -1596,7 +1579,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
return -EINVAL;
}
- ret = find_sdca_entity(dev, sdw, function, function_node,
+ ret = find_sdca_entity(dev, function, function_node,
entity_node, &entities[i]);
fwnode_handle_put(entity_node);
if (ret)
@@ -1619,7 +1602,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw,
return 0;
}
-static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function,
+struct sdca_entity *sdca_find_entity_by_label(struct sdca_function_data *function,
const char *entity_label)
{
struct sdca_entity *entity = NULL;
@@ -1648,6 +1631,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *
return NULL;
}
+EXPORT_SYMBOL_NS(sdca_find_entity_by_label, "SND_SOC_SDCA");
static struct sdca_entity *find_sdca_entity_by_id(struct sdca_function_data *function,
const int id)
@@ -1688,7 +1672,7 @@ static int find_sdca_entity_connection_iot(struct device *dev,
return ret;
}
- clock_entity = find_sdca_entity_by_label(function, clock_label);
+ clock_entity = sdca_find_entity_by_label(function, clock_label);
if (!clock_entity) {
dev_err(dev, "%s: failed to find clock with label %s\n",
entity->label, clock_label);
@@ -1873,7 +1857,7 @@ static int find_sdca_entity_connection(struct device *dev,
return ret;
}
- connected_entity = find_sdca_entity_by_label(function, connected_label);
+ connected_entity = sdca_find_entity_by_label(function, connected_label);
if (!connected_entity) {
dev_err(dev, "%s: failed to find entity with label %s\n",
entity->label, connected_label);
@@ -2088,8 +2072,7 @@ static int find_sdca_clusters(struct device *dev,
return 0;
}
-static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
- struct fwnode_handle *function_node,
+static int find_sdca_filesets(struct device *dev, struct fwnode_handle *function_node,
struct sdca_function_data *function)
{
static const int mult_fileset = 3;
@@ -2171,23 +2154,65 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw,
set->files = files;
}
- function->fdl_data.swft = sdw->sdca_data.swft;
function->fdl_data.num_sets = num_sets;
function->fdl_data.sets = sets;
return 0;
}
+static int find_sdca_hid(struct device *dev, struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ int num_desc;
+
+ num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor");
+ if (!num_desc) {
+ return 0;
+ } else if (num_desc < 0) {
+ dev_err(dev, "%pfwP: failed to read hid descriptor: %d\n",
+ function_node, num_desc);
+ return num_desc;
+ } else if (num_desc > sizeof(function->hid.desc)) {
+ dev_err(dev, "%pfwP: hid descriptor too large: %d\n",
+ function_node, num_desc);
+ return -EINVAL;
+ }
+
+ fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor",
+ (u8 *)&function->hid.desc, num_desc);
+
+ if (!function->hid.desc.bNumDescriptors)
+ return 0;
+
+ num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor");
+ if (num_desc <= 0) {
+ dev_err(dev, "%pfwP: failed to read report descriptor: %d\n",
+ function_node, num_desc);
+
+ if (!num_desc)
+ return -EINVAL;
+
+ return num_desc;
+ }
+
+ function->hid.report_desc = devm_kzalloc(dev, num_desc, GFP_KERNEL);
+ if (!function->hid.report_desc)
+ return -ENOMEM;
+
+ fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor",
+ function->hid.report_desc, num_desc);
+
+ return 0;
+}
+
/**
* sdca_parse_function - parse ACPI DisCo for a Function
* @dev: Pointer to device against which function data will be allocated.
- * @sdw: SoundWire slave device to be processed.
* @function: Pointer to the Function information, to be populated.
*
* Return: Returns 0 for success.
*/
-int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
- struct sdca_function_data *function)
+int sdca_parse_function(struct device *dev, struct sdca_function_data *function)
{
struct fwnode_handle *node = function->desc->node;
u32 tmp;
@@ -2213,7 +2238,7 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
if (ret)
return ret;
- ret = find_sdca_entities(dev, sdw, node, function);
+ ret = find_sdca_entities(dev, node, function);
if (ret)
return ret;
@@ -2225,10 +2250,20 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw,
if (ret < 0)
return ret;
- ret = find_sdca_filesets(dev, sdw, node, function);
+ ret = find_sdca_filesets(dev, node, function);
if (ret)
return ret;
+ switch (function->desc->type) {
+ case SDCA_FUNCTION_TYPE_HID:
+ ret = find_sdca_hid(dev, node, function);
+ if (ret)
+ return ret;
+ break;
+ default:
+ break;
+ }
+
return 0;
}
EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c
index abbd56a3d297..bee1b83c05f2 100644
--- a/sound/soc/sdca/sdca_hid.c
+++ b/sound/soc/sdca/sdca_hid.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/property.h>
#include <linux/soundwire/sdw.h>
+#include <linux/string.h>
#include <linux/types.h>
#include <sound/sdca.h>
#include <sound/sdca_function.h>
@@ -23,18 +24,18 @@
static int sdwhid_parse(struct hid_device *hid)
{
- struct sdca_entity *entity = hid->driver_data;
+ struct sdca_function_data *function = hid->driver_data;
unsigned int rsize;
int ret;
- rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength);
+ rsize = le16_to_cpu(function->hid.desc.rpt_desc.wDescriptorLength);
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize);
return -EINVAL;
}
- ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize);
+ ret = hid_parse_report(hid, function->hid.report_desc, rsize);
if (!ret)
return 0;
@@ -85,10 +86,16 @@ static const struct hid_ll_driver sdw_hid_driver = {
.raw_request = sdwhid_raw_request,
};
-int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
- struct sdca_entity *entity)
+/**
+ * sdca_add_hid_device - create a new SDCA HID device
+ * @interrupt: Pointer to the SDCA interrupt information structure.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+int sdca_add_hid_device(struct sdca_interrupt *interrupt)
{
- struct sdw_bus *bus = sdw->bus;
+ struct device *dev = interrupt->dev;
+ struct sdca_function_data *function = interrupt->function;
struct hid_device *hid;
int ret;
@@ -100,16 +107,13 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
hid->dev.parent = dev;
hid->bus = BUS_SDW;
- hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID);
-
- snprintf(hid->name, sizeof(hid->name),
- "HID sdw:%01x:%01x:%04x:%04x:%02x",
- bus->controller_id, bus->link_id, sdw->id.mfg_id,
- sdw->id.part_id, sdw->id.class_id);
+ hid->version = le16_to_cpu(function->hid.desc.bcdHID);
- snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name);
+ strscpy(hid->phys, dev_name(dev));
+ snprintf(hid->name, sizeof(hid->name), "SDCA %s:%02x",
+ function->desc->name, function->desc->adr);
- hid->driver_data = entity;
+ hid->driver_data = function;
ret = hid_add_device(hid);
if (ret && ret != -ENODEV) {
@@ -118,13 +122,25 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw,
return ret;
}
- entity->hide.hid = hid;
+ interrupt->priv = hid;
return 0;
}
EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA");
/**
+ * sdca_destroy_hid_device - destroy the HID device
+ * @interrupt: Pointer to the SDCA interrupt information structure.
+ */
+void sdca_destroy_hid_device(struct sdca_interrupt *interrupt)
+{
+ struct hid_device *hid = interrupt->priv;
+
+ hid_destroy_device(hid);
+}
+EXPORT_SYMBOL_NS(sdca_destroy_hid_device, "SND_SOC_SDCA");
+
+/**
* sdca_hid_process_report - read a HID event from the device and report
* @interrupt: Pointer to the SDCA interrupt information structure.
*
@@ -133,7 +149,7 @@ EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA");
int sdca_hid_process_report(struct sdca_interrupt *interrupt)
{
struct device *dev = interrupt->dev;
- struct hid_device *hid = interrupt->entity->hide.hid;
+ struct hid_device *hid = interrupt->priv;
void *val __free(kfree) = NULL;
int len, ret;
diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c
index 42fbd3af8a75..7aebc721a847 100644
--- a/sound/soc/sdca/sdca_interrupts.c
+++ b/sound/soc/sdca/sdca_interrupts.c
@@ -487,6 +487,12 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap,
}
break;
case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ interrupt->free_priv = sdca_destroy_hid_device;
+
+ ret = sdca_add_hid_device(interrupt);
+ if (ret)
+ return ret;
+
interrupt->handler = hid_handler;
break;
default:
diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
index e0e32a279787..129a437ae397 100644
--- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
@@ -99,11 +99,9 @@ static const struct snd_soc_dai_link bridge_dai_template = {
SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai),
};
-int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
+int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx,
int *num_dais, int *num_devs)
{
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
-
if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) {
(*num_dais)++;
(*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes);
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index d8db8fc5313e..8a07ba2a29e5 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -836,6 +836,35 @@ struct asoc_sdw_codec_info codec_info_list[] = {
},
{
.vendor_id = 0x01fa,
+ .part_id = 0x3562,
+ .name_prefix = "AMP",
+ .is_amp = true,
+ .dais = {
+ {
+ .direction = {true, false},
+ .dai_name = "cs35l56-sdw1",
+ .component_name = "cs35l56",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ .init = asoc_sdw_cs_amp_init,
+ .rtd_init = asoc_sdw_cs_spk_rtd_init,
+ .controls = generic_spk_controls,
+ .num_controls = ARRAY_SIZE(generic_spk_controls),
+ .widgets = generic_spk_widgets,
+ .num_widgets = ARRAY_SIZE(generic_spk_widgets),
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "cs35l56-sdw1c",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
+ },
+ },
+ .dai_num = 2,
+ },
+ {
+ .vendor_id = 0x01fa,
.part_id = 0x3563,
.name_prefix = "AMP",
.is_amp = true,
@@ -1789,9 +1818,7 @@ static int is_sdca_aux_dev_present(struct device *dev,
int adr_index)
{
struct sdw_slave *slave;
- struct device *sdw_dev;
const char *sdw_codec_name;
- int ret = 0;
int i;
if (!aux_codec_name)
@@ -1801,7 +1828,8 @@ static int is_sdca_aux_dev_present(struct device *dev,
if (!sdw_codec_name)
return -ENOMEM;
- sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
+ struct device *sdw_dev __free(put_device) =
+ bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
if (!sdw_dev) {
dev_err(dev, "codec %s not found\n", sdw_codec_name);
return -EINVAL;
@@ -1811,24 +1839,19 @@ static int is_sdca_aux_dev_present(struct device *dev,
if (!slave->sdca_data.interface_revision) {
dev_warn(dev, "No SDCA properties, assuming aux '%s' present\n", aux_codec_name);
- ret = 1;
- goto put_dev;
+ return 1;
}
for (i = 0; i < slave->sdca_data.num_functions; i++) {
const char *fname = slave->sdca_data.function[i].name;
- if (fname && strstr(aux_codec_name, fname)) {
- ret = 1;
- goto put_dev;
- }
+ if (fname && strstr(aux_codec_name, fname))
+ return 1;
}
dev_dbg(dev, "SDCA function for aux '%s' NOT FOUND on slave, skipping\n", aux_codec_name);
-put_dev:
- put_device(sdw_dev);
- return ret;
+ return 0;
}
int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card,
@@ -1928,9 +1951,8 @@ static int is_sdca_endpoint_present(struct device *dev,
const struct snd_soc_acpi_endpoint *adr_end;
const struct asoc_sdw_dai_info *dai_info;
struct sdw_slave *slave;
- struct device *sdw_dev;
const char *sdw_codec_name;
- int ret, i;
+ int i;
adr_end = &adr_dev->endpoints[end_index];
dai_info = &codec_info->dais[adr_end->num];
@@ -1939,7 +1961,8 @@ static int is_sdca_endpoint_present(struct device *dev,
if (!sdw_codec_name)
return -ENOMEM;
- sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
+ struct device *sdw_dev __free(put_device) =
+ bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
if (!sdw_dev) {
dev_err(dev, "codec %s not found\n", sdw_codec_name);
return -EINVAL;
@@ -1950,8 +1973,7 @@ static int is_sdca_endpoint_present(struct device *dev,
/* Make sure BIOS provides SDCA properties */
if (!slave->sdca_data.interface_revision) {
dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
- ret = 1;
- goto put_device;
+ return 1;
}
for (i = 0; i < slave->sdca_data.num_functions; i++) {
@@ -1960,8 +1982,7 @@ static int is_sdca_endpoint_present(struct device *dev,
if (dai_type == dai_info->dai_type) {
dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
dai_type, slave->sdca_data.function[i].name);
- ret = 1;
- goto put_device;
+ return 1;
}
}
@@ -1969,21 +1990,16 @@ static int is_sdca_endpoint_present(struct device *dev,
"SDCA device function for DAI type %d not supported, skip endpoint\n",
dai_info->dai_type);
- ret = 0;
-
-put_device:
- put_device(sdw_dev);
- return ret;
+ return 0;
}
-int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
+int asoc_sdw_parse_sdw_endpoints(struct device *dev,
+ struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
int *num_devs)
{
- struct device *dev = card->dev;
- struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
const struct snd_soc_acpi_link_adr *adr_link;
@@ -2045,7 +2061,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
if (codec_info->count_sidecar && codec_info->add_sidecar) {
- ret = codec_info->count_sidecar(card, &num_dais, num_devs);
+ ret = codec_info->count_sidecar(ctx, &num_dais, num_devs);
if (ret)
return ret;
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index 2ce24513fac5..dc7d203cb76a 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -29,17 +29,42 @@ static inline int _soc_component_ret_reg_rw(struct snd_soc_component *component,
func, component->name, reg);
}
-static inline int soc_component_field_shift(struct snd_soc_component *component,
- unsigned int mask)
+struct snd_soc_component *snd_soc_component_alloc(struct device *dev)
{
- if (!mask) {
- dev_err(component->dev, "ASoC: error field mask is zero for %s\n",
- component->name);
- return 0;
- }
+ struct snd_soc_component *component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
- return (ffs(mask) - 1);
+ if (!component)
+ return NULL;
+
+ component->dev = dev;
+
+ return component;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_alloc);
+
+void snd_soc_component_set_name(struct snd_soc_component *component, const char *name)
+{
+ component->name = name;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_name);
+
+const char *snd_soc_component_name(struct snd_soc_component *component)
+{
+ return component->name;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_name);
+
+void snd_soc_component_set_priv(struct snd_soc_component *component, void *priv)
+{
+ component->priv = priv;
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_set_priv);
+
+void *snd_soc_component_to_priv(struct snd_soc_component *component)
+{
+ return component->priv;
}
+EXPORT_SYMBOL_GPL(snd_soc_component_to_priv);
/*
* We might want to check substream by using list.
@@ -820,6 +845,18 @@ int snd_soc_component_update_bits_async(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(snd_soc_component_update_bits_async);
+static inline int soc_component_field_shift(struct snd_soc_component *component,
+ unsigned int mask)
+{
+ if (!mask) {
+ dev_err(component->dev, "ASoC: error field mask is zero for %s\n",
+ component->name);
+ return 0;
+ }
+
+ return (ffs(mask) - 1);
+}
+
/**
* snd_soc_component_read_field() - Read register field value
* @component: Component to read from
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 44f9bb4473f5..b9c70268d49f 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2707,10 +2707,11 @@ static void snd_soc_del_component_unlocked(struct snd_soc_component *component)
list_del(&component->list);
}
-int snd_soc_component_initialize(struct snd_soc_component *component,
- const struct snd_soc_component_driver *driver,
- struct device *dev)
+static int soc_component_initialize(struct snd_soc_component *component,
+ const struct snd_soc_component_driver *driver)
{
+ struct device *dev = component->dev;
+
component->dapm = snd_soc_dapm_alloc(dev);
if (!component->dapm)
return -ENOMEM;
@@ -2730,16 +2731,14 @@ int snd_soc_component_initialize(struct snd_soc_component *component,
}
}
- component->dev = dev;
component->driver = driver;
return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_component_initialize);
-int snd_soc_add_component(struct snd_soc_component *component,
- struct snd_soc_dai_driver *dai_drv,
- int num_dai)
+static int soc_component_add(struct snd_soc_component *component,
+ struct snd_soc_dai_driver *dai_drv,
+ int num_dai)
{
struct snd_soc_card *card, *c;
int ret;
@@ -2778,27 +2777,36 @@ err_cleanup:
return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_add_component);
-int snd_soc_register_component(struct device *dev,
+int snd_soc_register_component_c(struct snd_soc_component *component,
const struct snd_soc_component_driver *component_driver,
struct snd_soc_dai_driver *dai_drv,
int num_dai)
{
- struct snd_soc_component *component;
int ret;
- component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
- if (!component)
- return -ENOMEM;
-
- ret = snd_soc_component_initialize(component, component_driver, dev);
+ ret = soc_component_initialize(component, component_driver);
if (ret < 0)
return ret;
- return snd_soc_add_component(component, dai_drv, num_dai);
+ return soc_component_add(component, dai_drv, num_dai);
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_component_c);
+
+int snd_soc_register_component_d(struct device *dev,
+ const struct snd_soc_component_driver *component_driver,
+ struct snd_soc_dai_driver *dai_drv,
+ int num_dai)
+{
+ struct snd_soc_component *component;
+
+ component = snd_soc_component_alloc(dev);
+ if (!component)
+ return -ENOMEM;
+
+ return snd_soc_register_component_c(component, component_driver, dai_drv, num_dai);
}
-EXPORT_SYMBOL_GPL(snd_soc_register_component);
+EXPORT_SYMBOL_GPL(snd_soc_register_component_d);
/**
* snd_soc_unregister_component_by_driver - Unregister component using a given driver
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 4ad126bd4f70..c98e917cc911 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1203,6 +1203,8 @@ static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_pga:
case snd_soc_dapm_effect:
case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_encoder:
+ case snd_soc_dapm_decoder:
wname_in_long_name = true;
kcname_in_long_name = true;
break;
@@ -2785,6 +2787,8 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *component,
case snd_soc_dapm_pga:
case snd_soc_dapm_effect:
case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_encoder:
+ case snd_soc_dapm_decoder:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_supply:
@@ -3367,6 +3371,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
case snd_soc_dapm_pga:
case snd_soc_dapm_effect:
case snd_soc_dapm_out_drv:
+ case snd_soc_dapm_encoder:
+ case snd_soc_dapm_decoder:
dapm_new_pga(w);
break;
case snd_soc_dapm_dai_link:
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 467426d2b5e4..3b18d90e81c3 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -3,6 +3,7 @@
// Copyright (C) 2013, Analog Devices Inc.
// Author: Lars-Peter Clausen <lars@metafoo.de>
+#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dmaengine.h>
@@ -77,7 +78,7 @@ static int dmaengine_pcm_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct dma_slave_config slave_config;
int ret;
@@ -99,7 +100,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
struct device *dma_dev = dmaengine_dma_dev(pcm, substream);
struct dma_chan *chan = pcm->chan[substream->stream];
struct snd_dmaengine_dai_dma_data *dma_data;
@@ -148,7 +149,7 @@ dmaengine_pcm_set_runtime_hwparams(struct snd_soc_component *component,
static int dmaengine_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
struct dma_chan *chan = pcm->chan[substream->stream];
int ret;
@@ -176,7 +177,7 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_substream *substream)
{
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
struct snd_dmaengine_dai_dma_data *dma_data;
if (rtd->dai_link->num_cpus > 1) {
@@ -219,7 +220,7 @@ static bool dmaengine_pcm_can_report_residue(struct device *dev,
static int dmaengine_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
const struct snd_dmaengine_pcm_config *config = pcm->config;
struct device *dev = component->dev;
size_t prealloc_buffer_size;
@@ -279,7 +280,7 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
return snd_dmaengine_pcm_pointer_no_residue(substream);
@@ -293,7 +294,7 @@ static int dmaengine_copy(struct snd_soc_component *component,
struct iov_iter *iter, unsigned long bytes)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ struct dmaengine_pcm *pcm = snd_soc_component_to_priv(component);
int (*process)(struct snd_pcm_substream *substream,
int channel, unsigned long hwoff,
unsigned long bytes) = pcm->config->process;
@@ -395,6 +396,27 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
*/
if (PTR_ERR(chan) == -EPROBE_DEFER)
return -EPROBE_DEFER;
+
+ bool has_fw_node = dev->of_node || is_acpi_device_node(dev->fwnode);
+ bool name_exists_in_fw = false;
+
+ if (has_fw_node)
+ name_exists_in_fw = device_property_match_string(dev,
+ "dma-names",
+ name) >= 0;
+
+ if (has_fw_node && name_exists_in_fw)
+ dev_warn(dev, "DTS/ACPI DMA channel '%s' request failed (%ld)\n",
+ name, PTR_ERR(chan));
+
+ if (has_fw_node && !name_exists_in_fw)
+ dev_warn(dev, "DTS/ACPI name '%s' not found, legacy failed (%ld)\n",
+ name, PTR_ERR(chan));
+
+ if (!has_fw_node)
+ dev_warn(dev, "Legacy DMA channel '%s' request failed (%ld)\n",
+ name, PTR_ERR(chan));
+
pcm->chan[i] = NULL;
} else {
pcm->chan[i] = chan;
@@ -406,6 +428,12 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm,
if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX)
pcm->chan[1] = pcm->chan[0];
+ if (!pcm->chan[0] &&
+ !pcm->chan[1]) {
+ dev_err(dev, "no DMA channel found for either playback or capture\n");
+ return -ENODEV;
+ }
+
return 0;
}
@@ -435,10 +463,15 @@ static const struct snd_dmaengine_pcm_config snd_dmaengine_pcm_default_config =
int snd_dmaengine_pcm_register(struct device *dev,
const struct snd_dmaengine_pcm_config *config, unsigned int flags)
{
+ struct snd_soc_component *component;
const struct snd_soc_component_driver *driver;
struct dmaengine_pcm *pcm;
int ret;
+ component = snd_soc_component_alloc(dev);
+ if (!component)
+ return -ENOMEM;
+
pcm = kzalloc_obj(*pcm);
if (!pcm)
return -ENOMEM;
@@ -449,7 +482,8 @@ int snd_dmaengine_pcm_register(struct device *dev,
pcm->flags = flags;
if (config->name)
- pcm->component.name = config->name;
+ snd_soc_component_set_name(component, config->name);
+ snd_soc_component_set_priv(component, pcm);
ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
if (ret)
@@ -460,11 +494,7 @@ int snd_dmaengine_pcm_register(struct device *dev,
else
driver = &dmaengine_pcm_component;
- ret = snd_soc_component_initialize(&pcm->component, driver, dev);
- if (ret)
- goto err_free_dma;
-
- ret = snd_soc_add_component(&pcm->component, NULL, 0);
+ ret = snd_soc_register_component(component, driver, NULL, 0);
if (ret)
goto err_free_dma;
@@ -493,7 +523,7 @@ void snd_dmaengine_pcm_unregister(struct device *dev)
if (!component)
return;
- pcm = soc_component_to_pcm(component);
+ pcm = snd_soc_component_to_priv(component);
snd_soc_unregister_component_by_driver(dev, component->driver);
dmaengine_pcm_release_chan(pcm);
diff --git a/sound/soc/soc-topology-test.c b/sound/soc/soc-topology-test.c
index c8f2ec29e970..346a52d3006a 100644
--- a/sound/soc/soc-topology-test.c
+++ b/sound/soc/soc-topology-test.c
@@ -45,15 +45,13 @@ static void snd_soc_tplg_test_exit(struct kunit *test)
struct kunit_soc_component {
struct kunit *kunit;
int expect; /* what result we expect when loading topology */
- struct snd_soc_component comp;
struct snd_soc_card card;
struct firmware fw;
};
static int d_probe(struct snd_soc_component *component)
{
- struct kunit_soc_component *kunit_comp =
- container_of(component, struct kunit_soc_component, comp);
+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component);
int ret;
ret = snd_soc_tplg_component_load(component, NULL, &kunit_comp->fw);
@@ -65,8 +63,7 @@ static int d_probe(struct snd_soc_component *component)
static void d_remove(struct snd_soc_component *component)
{
- struct kunit_soc_component *kunit_comp =
- container_of(component, struct kunit_soc_component, comp);
+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component);
int ret;
ret = snd_soc_tplg_component_remove(component);
@@ -214,8 +211,7 @@ static struct tplg_tmpl_002 tplg_tmpl_with_pcm = {
*/
static int d_probe_null_comp(struct snd_soc_component *component)
{
- struct kunit_soc_component *kunit_comp =
- container_of(component, struct kunit_soc_component, comp);
+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component);
int ret;
/* instead of passing component pointer as first argument, pass NULL here */
@@ -234,6 +230,7 @@ static const struct snd_soc_component_driver test_component_null_comp = {
static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
int ret;
/* prepare */
@@ -249,15 +246,17 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_comp, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component_null_comp, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -276,6 +275,7 @@ static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
int ret;
/* prepare */
@@ -291,15 +291,17 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -318,8 +320,7 @@ static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
*/
static int d_probe_null_fw(struct snd_soc_component *component)
{
- struct kunit_soc_component *kunit_comp =
- container_of(component, struct kunit_soc_component, comp);
+ struct kunit_soc_component *kunit_comp = snd_soc_component_to_priv(component);
int ret;
/* instead of passing fw pointer as third argument, pass NULL here */
@@ -338,6 +339,7 @@ static const struct snd_soc_component_driver test_component_null_fw = {
static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
int ret;
/* prepare */
@@ -353,15 +355,17 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_fw, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component_null_fw, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -375,6 +379,7 @@ static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
struct tplg_tmpl_001 *data;
int size;
int ret;
@@ -401,15 +406,17 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -425,6 +432,7 @@ static void snd_soc_tplg_test_load_empty_tplg(struct kunit *test)
static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
struct tplg_tmpl_001 *data;
int size;
int ret;
@@ -456,15 +464,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -480,6 +490,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_magic(struct kunit *test)
static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
struct tplg_tmpl_001 *data;
int size;
int ret;
@@ -511,15 +522,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -535,6 +548,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_abi(struct kunit *test)
static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
struct tplg_tmpl_001 *data;
int size;
int ret;
@@ -566,15 +580,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -590,6 +606,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_size(struct kunit *test)
static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
struct tplg_tmpl_001 *data;
int size;
int ret;
@@ -622,15 +639,17 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
@@ -644,6 +663,7 @@ static void snd_soc_tplg_test_load_empty_tplg_bad_payload_size(struct kunit *tes
static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
u8 *data;
int size;
int ret;
@@ -670,15 +690,17 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
-
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
snd_soc_unregister_component(test_dev);
@@ -693,6 +715,7 @@ static void snd_soc_tplg_test_load_pcm_tplg(struct kunit *test)
static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
u8 *data;
int size;
int ret;
@@ -720,16 +743,19 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
+
+ snd_soc_component_set_priv(component, kunit_comp);
+
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
for (i = 0; i < 100; i++) {
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
snd_soc_unregister_component(test_dev);
@@ -745,6 +771,7 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_comp(struct kunit *test)
static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
+ struct snd_soc_component *component;
u8 *data;
int size;
int ret;
@@ -772,11 +799,13 @@ static void snd_soc_tplg_test_load_pcm_tplg_reload_card(struct kunit *test)
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links);
kunit_comp->card.fully_routed = true;
- /* run test */
- ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
- KUNIT_EXPECT_EQ(test, 0, ret);
+ component = snd_soc_component_alloc(test_dev);
+ KUNIT_ASSERT_NOT_NULL(test, component);
- ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
+ snd_soc_component_set_priv(component, kunit_comp);
+
+ /* run test */
+ ret = snd_soc_register_component(component, &test_component, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
for (i = 0; i < 100; i++) {
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index 05faf1c6d6fc..903e7ec3b3ba 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -104,4 +104,15 @@ config SND_SOC_SOF_AMD_ACP70
AMD ACP7.0/ACP7.1 version based platforms.
Say Y if you want to enable SOF on ACP7.0/ACP7.1 based platforms.
+config SND_SOC_SOF_AMD_ACP7X
+ tristate "SOF support for ACP7.B/7.F platforms"
+ depends on SND_SOC_SOF_PCI
+ depends on AMD_NODE
+ select SND_SOC_SOF_AMD_COMMON
+ help
+ Select this option for SOF support on AMD ACP7.B and ACP7.F PCI
+ revision based platforms.
+ Say Y if you want to enable SOF on ACP7.B/7.F based platforms.
+ If unsure select "N".
+
endif
diff --git a/sound/soc/sof/amd/Makefile b/sound/soc/sof/amd/Makefile
index 6ae39fd5a836..bb1c0ddef69d 100644
--- a/sound/soc/sof/amd/Makefile
+++ b/sound/soc/sof/amd/Makefile
@@ -11,6 +11,7 @@ snd-sof-amd-rembrandt-y := pci-rmb.o rembrandt.o
snd-sof-amd-vangogh-y := pci-vangogh.o vangogh.o
snd-sof-amd-acp63-y := pci-acp63.o acp63.o
snd-sof-amd-acp70-y := pci-acp70.o acp70.o
+snd-sof-amd-acp7x-y := pci-acp7x.o acp7x.o
obj-$(CONFIG_SND_SOC_SOF_AMD_COMMON) += snd-sof-amd-acp.o
obj-$(CONFIG_SND_SOC_SOF_AMD_RENOIR) += snd-sof-amd-renoir.o
@@ -18,3 +19,4 @@ obj-$(CONFIG_SND_SOC_SOF_AMD_REMBRANDT) += snd-sof-amd-rembrandt.o
obj-$(CONFIG_SND_SOC_SOF_AMD_VANGOGH) += snd-sof-amd-vangogh.o
obj-$(CONFIG_SND_SOC_SOF_AMD_ACP63) += snd-sof-amd-acp63.o
obj-$(CONFIG_SND_SOC_SOF_AMD_ACP70) += snd-sof-amd-acp70.o
+obj-$(CONFIG_SND_SOC_SOF_AMD_ACP7X) += snd-sof-amd-acp7x.o
diff --git a/sound/soc/sof/amd/acp-dsp-offset.h b/sound/soc/sof/amd/acp-dsp-offset.h
index 08583a91afbc..bea1bd3afa70 100644
--- a/sound/soc/sof/amd/acp-dsp-offset.h
+++ b/sound/soc/sof/amd/acp-dsp-offset.h
@@ -68,12 +68,14 @@
#define ACP5X_PGFSM_BASE 0x1424
#define ACP6X_PGFSM_BASE 0x1024
#define ACP70_PGFSM_BASE ACP6X_PGFSM_BASE
+#define ACP7X_PGFSM_BASE ACP6X_PGFSM_BASE
#define PGFSM_CONTROL_OFFSET 0x0
#define PGFSM_STATUS_OFFSET 0x4
#define ACP3X_CLKMUX_SEL 0x1424
#define ACP5X_CLKMUX_SEL 0x142C
#define ACP6X_CLKMUX_SEL 0x102C
#define ACP70_CLKMUX_SEL ACP6X_CLKMUX_SEL
+#define ACP7X_CLKMUX_SEL ACP6X_CLKMUX_SEL
/* Registers from ACP_INTR block */
#define ACP3X_EXT_INTR_STAT 0x1808
@@ -86,21 +88,31 @@
#define ACP70_EXTERNAL_INTR_CNTL ACP6X_EXTERNAL_INTR_CNTL
#define ACP70_EXT_INTR_STAT ACP6X_EXT_INTR_STAT
#define ACP70_EXT_INTR_STAT1 ACP6X_EXT_INTR_STAT1
+#define ACP7X_EXTERNAL_INTR_ENB ACP6X_EXTERNAL_INTR_ENB
+#define ACP7X_EXTERNAL_INTR_CNTL 0x1A04
+#define ACP7X_EXT_INTR_STAT 0x1A1C
+#define ACP7X_EXTERNAL_INTR_CNTL1 0x1A08
+#define ACP7X_EXT_INTR_STAT1 0x1A20
#define ACP3X_DSP_SW_INTR_BASE 0x1814
#define ACP5X_DSP_SW_INTR_BASE 0x1814
#define ACP6X_DSP_SW_INTR_BASE 0x1808
#define ACP70_DSP_SW_INTR_BASE ACP6X_DSP_SW_INTR_BASE
+#define ACP7X_DSP_SW_INTR_BASE 0x1860
#define DSP_SW_INTR_CNTL_OFFSET 0x0
#define DSP_SW_INTR_STAT_OFFSET 0x4
+#define ACP7X_DSP_SW_INTR_STAT (ACP7X_DSP_SW_INTR_BASE + DSP_SW_INTR_STAT_OFFSET)
#define DSP_SW_INTR_TRIG_OFFSET 0x8
+#define ACP7X_DSP_SW_INTR_TRIG_OFFSET 0x30
#define ACP3X_ERROR_STATUS 0x18C4
#define ACP6X_ERROR_STATUS 0x1A4C
#define ACP70_ERROR_STATUS ACP6X_ERROR_STATUS
+#define ACP7X_ERROR_STATUS 0x1A88
#define ACP3X_AXI2DAGB_SEM_0 0x1880
#define ACP5X_AXI2DAGB_SEM_0 0x1884
#define ACP6X_AXI2DAGB_SEM_0 0x1874
#define ACP70_AXI2DAGB_SEM_0 ACP6X_AXI2DAGB_SEM_0
+#define ACP7X_AXI2DAGB_SEM_0 0x18F4
/* ACP common registers to report errors related to I2S & SoundWire interfaces */
#define ACP3X_SW_I2S_ERROR_REASON 0x18C8
@@ -123,6 +135,7 @@
#define ACP_SCRATCH_REG_0 0x10000
#define ACP6X_DSP_FUSION_RUNSTALL 0x0644
#define ACP70_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL
+#define ACP7X_DSP_FUSION_RUNSTALL ACP6X_DSP_FUSION_RUNSTALL
/* Cache window registers */
#define ACP_DSP0_CACHE_OFFSET0 0x0420
@@ -139,5 +152,9 @@
#define ACP70_SDW1_HOST_WAKE_STAT BIT(25)
#define ACP70_SDW0_PME_STAT BIT(26)
#define ACP70_SDW1_PME_STAT BIT(27)
+#define ACP7X_DSP0_IDMA_ERROR_MASK 0x4B0
+#define ACP7X_IDMA_ERROR_MASK 0x1FF9FF
+#define ACP7X_ZSC_DSP_CTRL 0x001014
+#define ACP7X_PME_EN ACP70_PME_EN
#endif
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index 94025bc799ea..494f9cb0c06f 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -32,11 +32,20 @@ static void acpbus_trigger_host_to_dsp_swintr(struct acp_dev_data *adata)
struct snd_sof_dev *sdev = adata->dev;
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
u32 swintr_trigger;
-
+ unsigned int swintr_trigger_reg_offset;
+
+ switch (adata->pci_rev) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ swintr_trigger_reg_offset = ACP7X_DSP_SW_INTR_TRIG_OFFSET;
+ break;
+ default:
+ swintr_trigger_reg_offset = DSP_SW_INTR_TRIG_OFFSET;
+ }
swintr_trigger = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->dsp_intr_base +
- DSP_SW_INTR_TRIG_OFFSET);
+ swintr_trigger_reg_offset);
swintr_trigger |= 0x01;
- snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + DSP_SW_INTR_TRIG_OFFSET,
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->dsp_intr_base + swintr_trigger_reg_offset,
swintr_trigger);
}
diff --git a/sound/soc/sof/amd/acp-loader.c b/sound/soc/sof/amd/acp-loader.c
index 98324bbade15..f1ec85694323 100644
--- a/sound/soc/sof/amd/acp-loader.c
+++ b/sound/soc/sof/amd/acp-loader.c
@@ -14,6 +14,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/unaligned.h>
#include "../ops.h"
#include "acp-dsp-offset.h"
@@ -173,10 +174,31 @@ int acp_dsp_pre_fw_run(struct snd_sof_dev *sdev)
adata = sdev->pdata->hw_pdata;
- if (adata->quirks && adata->quirks->signed_fw_image)
+ if (adata->pci_rev >= ACP7B_PCI_ID) {
+ if (adata->acp_sof_signed_firmware_image) {
+ if (adata->fw_bin_size <= ACP_IMAGE_HEADER_SIZE) {
+ dev_err(sdev->dev, "Invalid signed firmware size %u\n",
+ adata->fw_bin_size);
+ return -EINVAL;
+ }
+ size_fw = get_unaligned_le32(adata->bin_buf +
+ ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF);
+ if (!size_fw ||
+ size_fw > adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE) {
+ dev_err(sdev->dev,
+ "Invalid signed firmware payload size %u (max %u)\n",
+ size_fw, adata->fw_bin_size - ACP_IMAGE_HEADER_SIZE);
+ return -EINVAL;
+ }
+ size_fw += ACP_IMAGE_HEADER_SIZE;
+ } else {
+ size_fw = adata->fw_bin_size;
+ }
+ } else if (adata->quirks && adata->quirks->signed_fw_image) {
size_fw = adata->fw_bin_size - ACP_FIRMWARE_SIGNATURE;
- else
+ } else {
size_fw = adata->fw_bin_size;
+ }
page_count = PAGE_ALIGN(size_fw) >> PAGE_SHIFT;
adata->fw_bin_page_count = page_count;
@@ -312,9 +334,14 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
}
kfree(fw_filename);
- ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
- (void *)adata->fw_dbin->data,
- adata->fw_dbin->size);
+ if (adata->pci_rev >= ACP7B_PCI_ID)
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_SRAM, 0,
+ (void *)adata->fw_dbin->data,
+ adata->fw_dbin->size);
+ else
+ ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
+ (void *)adata->fw_dbin->data,
+ adata->fw_dbin->size);
return ret;
}
EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, "SND_SOC_SOF_AMD_COMMON");
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index e6af8927baa0..f89ad86260b4 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -12,6 +12,7 @@
* Hardware interface for generic AMD ACP processor
*/
+#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -60,6 +61,8 @@ static void init_dma_descriptor(struct acp_dev_data *adata)
case ACP70_PCI_ID:
case ACP71_PCI_ID:
case ACP72_PCI_ID:
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
acp_dma_desc_base_addr = ACP70_DMA_DESC_BASE_ADDR;
acp_dma_desc_max_num_dscr = ACP70_DMA_DESC_MAX_NUM_DSCR;
break;
@@ -101,6 +104,8 @@ static int config_dma_channel(struct acp_dev_data *adata, unsigned int ch,
case ACP70_PCI_ID:
case ACP71_PCI_ID:
case ACP72_PCI_ID:
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
acp_dma_cntl_0 = ACP70_DMA_CNTL_0;
acp_dma_ch_rst_sts = ACP70_DMA_CH_RST_STS;
acp_dma_dscr_err_sts_0 = ACP70_DMA_ERR_STS_0;
@@ -283,7 +288,8 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
}
}
- if (adata->quirks && adata->quirks->signed_fw_image)
+ if ((adata->quirks && adata->quirks->signed_fw_image) ||
+ adata->acp_sof_signed_firmware_image)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_INCLUDE_HDR, ACP_SHA_HEADER);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SHA_DMA_STRT_ADDR, start_addr);
@@ -342,6 +348,8 @@ int acp_dma_status(struct acp_dev_data *adata, unsigned char ch)
case ACP70_PCI_ID:
case ACP71_PCI_ID:
case ACP72_PCI_ID:
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
acp_dma_ch_sts = ACP70_DMA_CH_STS;
break;
default:
@@ -534,8 +542,17 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0);
/* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */
- if (adata->pci_rev >= ACP_RMB_PCI_ID)
+ switch (adata->pci_rev) {
+ case ACP_RMB_PCI_ID:
+ case ACP63_PCI_ID:
+ case ACP70_PCI_ID:
+ case ACP71_PCI_ID:
+ case ACP72_PCI_ID:
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0);
+ break;
+ default:
+ break;
+ }
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
irq_flag = 1;
}
@@ -564,6 +581,35 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static irqreturn_t acp7x_irq_handler(int irq, void *dev_id)
+{
+ struct snd_sof_dev *sdev = dev_id;
+ const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
+ unsigned int base = desc->dsp_intr_base;
+ unsigned int val;
+ unsigned int ext_intr_stat;
+ int irq_flag = 0;
+
+ val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
+ if (val & ACP_DSP_TO_HOST_IRQ) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
+ ACP_DSP_TO_HOST_IRQ);
+ return IRQ_WAKE_THREAD;
+ }
+
+ ext_intr_stat = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
+ if (ext_intr_stat & ACP_ERROR_IRQ_MASK) {
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
+ irq_flag = 1;
+ }
+
+ if (irq_flag)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
static int acp_power_on(struct snd_sof_dev *sdev)
{
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
@@ -571,6 +617,7 @@ static int acp_power_on(struct snd_sof_dev *sdev)
unsigned int base = desc->pgfsm_base;
unsigned int val;
unsigned int acp_pgfsm_status_mask, acp_pgfsm_cntl_mask;
+ bool use_masked_status = false;
int ret;
val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET);
@@ -595,6 +642,12 @@ static int acp_power_on(struct snd_sof_dev *sdev)
acp_pgfsm_status_mask = ACP70_PGFSM_STATUS_MASK;
acp_pgfsm_cntl_mask = ACP70_PGFSM_CNTL_POWER_ON_MASK;
break;
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ acp_pgfsm_status_mask = ACP7X_PGFSM_STATUS_MASK;
+ acp_pgfsm_cntl_mask = ACP7X_PGFSM_CNTL_POWER_ON_MASK;
+ use_masked_status = true;
+ break;
default:
return -EINVAL;
}
@@ -603,8 +656,17 @@ static int acp_power_on(struct snd_sof_dev *sdev)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + PGFSM_CONTROL_OFFSET,
acp_pgfsm_cntl_mask);
- ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, base + PGFSM_STATUS_OFFSET, val,
- !val, ACP_REG_POLL_INTERVAL, ACP_REG_POLL_TIMEOUT_US);
+ if (use_masked_status)
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR,
+ base + PGFSM_STATUS_OFFSET, val,
+ !(val & acp_pgfsm_status_mask),
+ ACP_REG_POLL_INTERVAL,
+ ACP_REG_POLL_TIMEOUT_US);
+ else
+ ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR,
+ base + PGFSM_STATUS_OFFSET, val,
+ !val, ACP_REG_POLL_INTERVAL,
+ ACP_REG_POLL_TIMEOUT_US);
if (ret < 0)
dev_err(sdev->dev, "timeout in ACP_PGFSM_STATUS read\n");
@@ -703,6 +765,13 @@ static int acp_init(struct snd_sof_dev *sdev)
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP70_PME_EN, 1);
break;
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 0);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_DSP0_IDMA_ERROR_MASK,
+ ACP7X_IDMA_ERROR_MASK);
+ break;
}
return 0;
}
@@ -749,6 +818,8 @@ int amd_sof_acp_suspend(struct snd_sof_dev *sdev, u32 target_state)
case ACP72_PCI_ID:
enable = true;
break;
+ default:
+ break;
}
snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);
@@ -990,6 +1061,194 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
}
EXPORT_SYMBOL_NS(amd_sof_acp_remove, "SND_SOC_SOF_AMD_COMMON");
+int amd_sof_acp7x_probe(struct snd_sof_dev *sdev)
+{
+ struct pci_dev *pci = to_pci_dev(sdev->dev);
+ struct acp_dev_data *adata;
+ const struct sof_amd_acp_desc *chip;
+ const union acpi_object *obj;
+ struct acpi_device *adev;
+ unsigned int addr;
+ unsigned int irqflags;
+ int ret;
+
+ chip = get_chip_info(sdev->pdata);
+ if (!chip) {
+ dev_err(sdev->dev, "no such device supported, chip id:%x\n", pci->device);
+ return -EIO;
+ }
+ adata = devm_kzalloc(sdev->dev, sizeof(struct acp_dev_data), GFP_KERNEL);
+ if (!adata)
+ return -ENOMEM;
+
+ adata->dev = sdev;
+ adata->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
+ PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(adata->dmic_dev)) {
+ dev_err(sdev->dev, "failed to register platform for dmic codec\n");
+ return PTR_ERR(adata->dmic_dev);
+ }
+
+ addr = pci_resource_start(pci, ACP_DSP_BAR);
+ sdev->bar[ACP_DSP_BAR] = devm_ioremap(sdev->dev, addr, pci_resource_len(pci, ACP_DSP_BAR));
+ if (!sdev->bar[ACP_DSP_BAR]) {
+ dev_err(sdev->dev, "ioremap error\n");
+ ret = -ENXIO;
+ goto unregister_dev;
+ }
+
+ pci_set_master(pci);
+ adata->addr = addr;
+ adata->reg_range = chip->reg_end_addr - chip->reg_start_addr;
+ adata->pci_rev = pci->revision;
+ mutex_init(&adata->acp_lock);
+ sdev->pdata->hw_pdata = adata;
+
+ ret = acp_init(sdev);
+ if (ret < 0)
+ goto unregister_dev;
+
+ adev = ACPI_COMPANION(&pci->dev);
+
+ sdev->ipc_irq = pci->irq;
+ irqflags = IRQF_SHARED;
+
+ ret = request_threaded_irq(pci->irq, acp7x_irq_handler, acp_irq_thread,
+ irqflags, "AudioDSP", sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq);
+ goto unregister_dev;
+ }
+
+ if (adev) {
+ if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image",
+ ACPI_TYPE_INTEGER, &obj))
+ adata->acp_sof_signed_firmware_image = obj->integer.value;
+ }
+
+ sdev->dsp_box.offset = 0;
+ sdev->dsp_box.size = BOX_SIZE_512;
+
+ sdev->host_box.offset = sdev->dsp_box.offset + sdev->dsp_box.size;
+ sdev->host_box.size = BOX_SIZE_512;
+
+ sdev->debug_box.offset = sdev->host_box.offset + sdev->host_box.size;
+ sdev->debug_box.size = BOX_SIZE_1024;
+
+ if (adata->acp_sof_signed_firmware_image) {
+ adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-code.bin", chip->name);
+ if (!adata->fw_code_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+ adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-data.bin", chip->name);
+ if (!adata->fw_data_bin) {
+ ret = -ENOMEM;
+ goto free_ipc_irq;
+ }
+ }
+
+ adata->enable_fw_debug = enable_fw_debug;
+ acp_memory_init(sdev);
+ acp_dsp_stream_init(sdev);
+
+ return 0;
+
+free_ipc_irq:
+ free_irq(sdev->ipc_irq, sdev);
+unregister_dev:
+ platform_device_unregister(adata->dmic_dev);
+ return ret;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_probe, "SND_SOC_SOF_AMD_COMMON");
+
+void amd_sof_acp7x_remove(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *adata = sdev->pdata->hw_pdata;
+
+ if (sdev->ipc_irq)
+ free_irq(sdev->ipc_irq, sdev);
+
+ if (adata->dmic_dev)
+ platform_device_unregister(adata->dmic_dev);
+
+ acp_reset(sdev);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_remove, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state)
+{
+ struct acp_dev_data *acp_data;
+ int ret;
+ bool enable = false;
+
+ acp_data = sdev->pdata->hw_pdata;
+
+ ret = acp_reset(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Reset failed\n");
+ return ret;
+ }
+ switch (acp_data->pci_rev) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ enable = true;
+ break;
+ default:
+ break;
+ }
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_CONTROL, enable);
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_ZSC_DSP_CTRL, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev)
+{
+ struct acp_dev_data *acp_data;
+ int ret;
+
+ acp_data = sdev->pdata->hw_pdata;
+
+ ret = acp_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Init failed\n");
+ return ret;
+ }
+ ret = acp_memory_init(sdev);
+ if (ret) {
+ dev_err(sdev->dev, "ACP Memory init failed\n");
+ return ret;
+ }
+
+ switch (acp_data->pci_rev) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP7X_PME_EN, 1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev)
+{
+ return amd_sof_acp7x_suspend(sdev, 0);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_suspend_runtime, "SND_SOC_SOF_AMD_COMMON");
+
+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev)
+{
+ return amd_sof_acp7x_resume(sdev);
+}
+EXPORT_SYMBOL_NS(amd_sof_acp7x_resume_runtime, "SND_SOC_SOF_AMD_COMMON");
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("AMD ACP sof driver");
MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 7bcb76676a98..16d66b2eaa70 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -76,6 +76,12 @@
#define ACP70_PCI_ID 0x70
#define ACP71_PCI_ID 0x71
#define ACP72_PCI_ID 0x72
+#define ACP7B_PCI_ID 0x7B
+#define ACP7F_PCI_ID 0x7F
+
+#define ACP7X_PGFSM_CNTL_POWER_ON_MASK 0x7F
+#define ACP7X_PGFSM_STATUS_MASK 0xFFF
+#define ACP7X_SRAM_PTE_OFFSET ACP6X_SRAM_PTE_OFFSET
#define HOST_BRIDGE_CZN 0x1630
#define HOST_BRIDGE_VGH 0x1645
@@ -107,6 +113,9 @@
#define PROBE_STATUS_BIT BIT(31)
#define ACP_FIRMWARE_SIGNATURE 0x100
+#define ACP_IMAGE_HEADER_SIZE ACP_FIRMWARE_SIGNATURE
+#define ACP_IMAGE_HDR_SIZE_FW_SIGNED_OFF 0x14
+
#define ACP_ERROR_IRQ_MASK BIT(29)
#define ACP_SDW0_IRQ_MASK BIT(21)
#define ACP_SDW1_IRQ_MASK BIT(2)
@@ -271,6 +280,7 @@ struct acp_dev_data {
/* acp70_sdw1_wake_event flag set to true when wake irq asserted for SW1 instance */
bool acp70_sdw1_wake_event;
unsigned int pci_rev;
+ int acp_sof_signed_firmware_image;
};
void memcpy_to_scratch(struct snd_sof_dev *sdev, u32 offset, unsigned int *src, size_t bytes);
@@ -344,6 +354,16 @@ int sof_acp63_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_acp70_ops;
int sof_acp70_ops_init(struct snd_sof_dev *sdev);
+extern struct snd_sof_dsp_ops sof_acp7x_ops;
+int sof_acp7x_ops_init(struct snd_sof_dev *sdev);
+
+int amd_sof_acp7x_probe(struct snd_sof_dev *sdev);
+void amd_sof_acp7x_remove(struct snd_sof_dev *sdev);
+int amd_sof_acp7x_suspend(struct snd_sof_dev *sdev, u32 target_state);
+int amd_sof_acp7x_resume(struct snd_sof_dev *sdev);
+int amd_sof_acp7x_suspend_runtime(struct snd_sof_dev *sdev);
+int amd_sof_acp7x_resume_runtime(struct snd_sof_dev *sdev);
+
struct snd_soc_acpi_mach *amd_sof_machine_select(struct snd_sof_dev *sdev);
/* Machine configuration */
int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/sof/amd/acp7x.c b/sound/soc/sof/amd/acp7x.c
new file mode 100644
index 000000000000..b6722d11168c
--- /dev/null
+++ b/sound/soc/sof/amd/acp7x.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2025 Advanced Micro Devices, Inc.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * Hardware interface for Audio DSP on ACP7.B/7.F platforms
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+
+#include "../ops.h"
+#include "../sof-audio.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define I2S_TDM0_INSTANCE 0
+#define I2S_TDM1_INSTANCE 1
+#define I2S_TDM2_INSTANCE 2
+#define PDM0_DMIC_INSTANCE 3
+#define PDM1_DMIC_INSTANCE 4
+
+static struct snd_soc_dai_driver acp7x_sof_dai[] = {
+ [I2S_TDM0_INSTANCE] = {
+ .id = I2S_TDM0_INSTANCE,
+ .name = "acp-sof-i2s0",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S HS controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_TDM1_INSTANCE] = {
+ .id = I2S_TDM1_INSTANCE,
+ .name = "acp-sof-i2s1",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S BT controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [I2S_TDM2_INSTANCE] = {
+ .id = I2S_TDM2_INSTANCE,
+ .name = "acp-sof-i2s2",
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+ /* Supporting only stereo for I2S SP controller capture */
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM0_DMIC_INSTANCE] = {
+ .id = PDM0_DMIC_INSTANCE,
+ .name = "acp-sof-dmic0",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ },
+
+ [PDM1_DMIC_INSTANCE] = {
+ .id = PDM1_DMIC_INSTANCE,
+ .name = "acp-sof-dmic1",
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .channels_min = 2,
+ .channels_max = 4,
+ .rate_min = 8000,
+ .rate_max = 96000,
+ },
+ },
+};
+
+static int sof_acp7x_post_fw_run_delay(struct snd_sof_dev *sdev)
+{
+ /*
+ * Resuming from suspend in some cases may cause the DSP firmware
+ * to enter an unrecoverable faulty state. Delaying a bit any host
+ * to DSP transmission right after firmware boot completion seems
+ * to resolve the issue.
+ */
+ if (!sdev->first_boot)
+ usleep_range(100, 150);
+
+ return 0;
+}
+
+struct snd_sof_dsp_ops sof_acp7x_ops;
+EXPORT_SYMBOL_NS(sof_acp7x_ops, "SND_SOC_SOF_AMD_COMMON");
+
+int sof_acp7x_ops_init(struct snd_sof_dev *sdev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&to_pci_dev(sdev->dev)->dev);
+ const union acpi_object *obj;
+ int acp_sof_signed_firmware_image = 0;
+ int acp_sof_post_fw_run_delay = 0;
+
+ /* common defaults */
+ memcpy(&sof_acp7x_ops, &sof_acp_common_ops, sizeof(struct snd_sof_dsp_ops));
+
+ sof_acp7x_ops.drv = acp7x_sof_dai;
+ sof_acp7x_ops.num_drv = ARRAY_SIZE(acp7x_sof_dai);
+ sof_acp7x_ops.probe = amd_sof_acp7x_probe;
+ sof_acp7x_ops.remove = amd_sof_acp7x_remove;
+
+ if (adev) {
+ if (!acpi_dev_get_property(adev, "acp-sof-signed-firmware-image",
+ ACPI_TYPE_INTEGER, &obj))
+ acp_sof_signed_firmware_image = obj->integer.value;
+
+ if (!acpi_dev_get_property(adev, "acp-sof-post_fw_run_delay",
+ ACPI_TYPE_INTEGER, &obj))
+ acp_sof_post_fw_run_delay = obj->integer.value;
+ }
+
+ if (acp_sof_signed_firmware_image)
+ sof_acp7x_ops.load_firmware = acp_sof_load_signed_firmware;
+
+ if (acp_sof_post_fw_run_delay)
+ sof_acp7x_ops.post_fw_run = sof_acp7x_post_fw_run_delay;
+
+ sof_acp7x_ops.suspend = amd_sof_acp7x_suspend;
+ sof_acp7x_ops.resume = amd_sof_acp7x_resume;
+ sof_acp7x_ops.runtime_suspend = amd_sof_acp7x_suspend_runtime;
+ sof_acp7x_ops.runtime_resume = amd_sof_acp7x_resume_runtime;
+
+ return 0;
+}
diff --git a/sound/soc/sof/amd/pci-acp7x.c b/sound/soc/sof/amd/pci-acp7x.c
new file mode 100644
index 000000000000..532e15313795
--- /dev/null
+++ b/sound/soc/sof/amd/pci-acp7x.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2025 Advanced Micro Devices, Inc. All rights reserved.
+//
+// Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+
+/*
+ * PCI interface for ACP7.B/7.F devices
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/sof.h>
+#include <sound/soc-acpi.h>
+
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+#include "../../amd/mach-config.h"
+#include "acp.h"
+#include "acp-dsp-offset.h"
+
+#define ACP7X_FUTURE_REG_ACLK_0 0x18e0
+#define ACP7X_REG_START 0x1240000
+#define ACP7X_REG_END 0x125C000
+
+static const struct sof_amd_acp_desc acp7x_chip_info = {
+ .name = "acp7x",
+ .pgfsm_base = ACP7X_PGFSM_BASE,
+ .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB,
+ .ext_intr_cntl = ACP7X_EXTERNAL_INTR_CNTL,
+ .ext_intr_stat = ACP7X_EXT_INTR_STAT,
+ .ext_intr_stat1 = ACP7X_EXT_INTR_STAT1,
+ .dsp_intr_base = ACP7X_DSP_SW_INTR_BASE,
+ .acp_error_stat = ACP7X_ERROR_STATUS,
+ .sram_pte_offset = ACP7X_SRAM_PTE_OFFSET,
+ .hw_semaphore_offset = ACP7X_AXI2DAGB_SEM_0,
+ .fusion_dsp_offset = ACP7X_DSP_FUSION_RUNSTALL,
+ .probe_reg_offset = ACP7X_FUTURE_REG_ACLK_0,
+ .reg_start_addr = ACP7X_REG_START,
+ .reg_end_addr = ACP7X_REG_END,
+};
+
+static const struct sof_dev_desc acp7x_desc = {
+ .machines = snd_soc_acpi_amd_acp7x_sof_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &acp7x_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
+ .ipc_default = SOF_IPC_TYPE_3,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_3] = "amd/sof-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_3] = "sof-acp7x.ri",
+ },
+ .nocodec_tplg_filename = "sof-acp.tplg",
+ .ops = &sof_acp7x_ops,
+ .ops_init = sof_acp7x_ops_init,
+};
+
+static int acp7x_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
+ unsigned int flag;
+
+ switch (pci->revision) {
+ case ACP7B_PCI_ID:
+ case ACP7F_PCI_ID:
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ flag = snd_amd_acp_find_config(pci);
+ if (flag != FLAG_AMD_SOF && flag != FLAG_AMD_SOF_ONLY_DMIC)
+ return -ENODEV;
+
+ return sof_pci_probe(pci, pci_id);
+}
+
+static void acp7x_pci_remove(struct pci_dev *pci)
+{
+ sof_pci_remove(pci);
+}
+
+/* PCI IDs */
+static const struct pci_device_id acp7x_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, ACP_PCI_DEV_ID),
+ .driver_data = (unsigned long)&acp7x_desc},
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, acp7x_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_amd_acp7x_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = acp7x_pci_ids,
+ .probe = acp7x_pci_probe,
+ .remove = acp7x_pci_remove,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_amd_acp7x_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("ACP7X SOF Driver");
+MODULE_IMPORT_NS("SND_SOC_SOF_AMD_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c
index 76bde2e0be1d..fcd57f04ca36 100644
--- a/sound/soc/sof/fw-file-profile.c
+++ b/sound/soc/sof/fw-file-profile.c
@@ -16,20 +16,19 @@ static int sof_test_firmware_file(struct device *dev,
enum sof_ipc_type *ipc_type_to_adjust)
{
enum sof_ipc_type fw_ipc_type;
- const struct firmware *fw;
- const char *fw_filename;
const u32 *magic;
int ret;
- fw_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path,
- profile->fw_name);
+ const char *fw_filename __free(kfree) =
+ kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path,
+ profile->fw_name);
if (!fw_filename)
return -ENOMEM;
+ const struct firmware *fw __free(firmware) = NULL;
ret = firmware_request_nowarn(&fw, fw_filename, dev);
if (ret < 0) {
dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename);
- kfree(fw_filename);
return ret;
}
@@ -44,8 +43,7 @@ static int sof_test_firmware_file(struct device *dev,
break;
default:
dev_err(dev, "Invalid firmware magic: %#x\n", *magic);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (ipc_type_to_adjust) {
@@ -54,13 +52,10 @@ static int sof_test_firmware_file(struct device *dev,
dev_err(dev,
"ipc type mismatch between %s and expected: %d vs %d\n",
fw_filename, fw_ipc_type, profile->ipc_type);
- ret = -EINVAL;
+ return -EINVAL;
}
-out:
- release_firmware(fw);
- kfree(fw_filename);
- return ret;
+ return 0;
}
static int sof_test_topology_file(struct device *dev,
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index 8332d4bda558..aeb34310eebd 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -186,6 +186,7 @@ EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON"
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct hdac_stream *stream;
int sd_offset, ret = 0;
u32 gctl;
@@ -193,6 +194,16 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
if (bus->chip_init)
return 0;
+ /*
+ * The controller reset clears the ACE2+ link DMA stream allocation
+ * constraints; reset the masks to reflect this.
+ */
+ memset(sof_hda->link_dma_active_sdw_mask, 0,
+ sizeof(sof_hda->link_dma_active_sdw_mask));
+ memset(sof_hda->link_dma_active_multi_mask, 0,
+ sizeof(sof_hda->link_dma_active_multi_mask));
+ sof_hda->link_dma_out_hda_used_mask = 0;
+
hda_codec_set_codec_wakeup(sdev, true);
hda_dsp_ctrl_misc_clock_gating(sdev, false);
@@ -223,6 +234,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
/* Accept unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+ /* Perform a one-time enumeration of the Multi-Link capability */
+ ret = hda_bus_ml_init(bus);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: failed to enumerate multi-links\n",
+ __func__);
+ goto err;
+ }
+
if (detect_codec)
hda_codec_detect_mask(sdev);
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index b2c559559962..f0be42048db3 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -20,7 +20,7 @@
/* These ops are only applicable for the HDA DAI's in their current form */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
/*
- * This function checks if the host dma channel corresponding
+ * This function checks if the host DMA stream corresponding
* to the link DMA stream_tag argument is assigned to one
* of the FEs connected to the BE DAI.
*/
@@ -42,23 +42,53 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
}
static struct hdac_ext_stream *
-hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
+hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream,
+ enum hda_bus_ml_link_type link_type)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct sof_intel_hda_stream *hda_stream;
const struct sof_intel_dsp_desc *chip;
struct snd_sof_dev *sdev;
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
-
int stream_dir = substream->stream;
+ bool is_multi = link_type == HDA_BUS_ML_LINK_HDA || link_type == HDA_BUS_ML_LINK_UAOL;
+ bool is_play = stream_dir == SNDRV_PCM_STREAM_PLAYBACK;
+ bool is_sdw = link_type == HDA_BUS_ML_LINK_SDW;
+ bool is_hda = link_type == HDA_BUS_ML_LINK_HDA;
+ u32 concur_block_mask = 0;
+ u32 seq_block_mask = 0;
+ unsigned int stream_idx;
if (!bus->ppcap) {
dev_err(bus->dev, "stream type not supported\n");
return NULL;
}
+ /*
+ * On ACE2+ the link DMA stream allocator must avoid two HW errata,
+ * see the comment on struct sof_intel_hda_dev.
+ *
+ * - Concurrent cross-direction: SoundWire conflicts with HDA, iDisp
+ * and UAOL on the same physical stream index; SSP and DMIC are safe.
+ * - Sequential playback: a stream index previously used by an HDA/iDisp
+ * link cannot drive any non-HDA/iDisp link in the same direction
+ * until the next controller reset.
+ *
+ * The masks are protected by bus->reg_lock; sample them inside the
+ * lock together with the stream walk to keep the decision atomic
+ * with concurrent allocations and releases.
+ */
guard(spinlock_irq)(&bus->reg_lock);
+
+ if (is_sdw)
+ concur_block_mask = sof_hda->link_dma_active_multi_mask[!stream_dir];
+ else if (is_multi)
+ concur_block_mask = sof_hda->link_dma_active_sdw_mask[!stream_dir];
+ if (is_play && !is_hda)
+ seq_block_mask = sof_hda->link_dma_out_hda_used_mask;
+
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream =
stream_to_hdac_ext_stream(hstream);
@@ -69,6 +99,12 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
sdev = hda_stream->sdev;
chip = get_chip_info(sdev->pdata);
+ stream_idx = hstream->stream_tag - 1;
+
+ /* skip streams blocked by the ACE2+ allocator constraints */
+ if ((concur_block_mask | seq_block_mask) & BIT(stream_idx))
+ continue;
+
/* check if link is available */
if (!hext_stream->link_locked) {
/*
@@ -95,7 +131,7 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
/*
* This must be a hostless stream.
- * So reserve the host DMA channel.
+ * So reserve the host DMA stream.
*/
hda_stream->host_reserved = 1;
break;
@@ -109,6 +145,16 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
res->link_locked = 1;
res->link_substream = substream;
+
+ stream_idx = res->hstream.stream_tag - 1;
+ if (is_sdw)
+ sof_hda->link_dma_active_sdw_mask[stream_dir] |= BIT(stream_idx);
+ else if (is_multi)
+ sof_hda->link_dma_active_multi_mask[stream_dir] |= BIT(stream_idx);
+
+ /* persistent OUT HDA/iDisp shadow, cleared only on CRST# */
+ if (is_hda && is_play)
+ sof_hda->link_dma_out_hda_used_mask |= BIT(stream_idx);
}
return res;
@@ -143,11 +189,13 @@ static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev
static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream)
+ struct snd_pcm_substream *substream,
+ struct hdac_ext_link *hlink)
{
struct hdac_ext_stream *hext_stream;
+ enum hda_bus_ml_link_type link_type = hda_bus_ml_link_get_type(hlink);
- hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+ hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream, link_type);
if (!hext_stream)
return NULL;
@@ -160,6 +208,22 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
+ struct sof_intel_hda_dev *sof_hda = sdev->pdata->hw_pdata;
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ int dir = substream->stream;
+ unsigned int stream_idx = hext_stream->hstream.stream_tag - 1;
+
+ /*
+ * Drop the stream index from the per-direction active concurrency masks.
+ * The two masks are mutually exclusive for a given stream/direction
+ * (and a stream of the SSP/DMIC kind appears in neither), so a blind
+ * clear of both is safe and lets us avoid having to remember the
+ * link type at allocation time.
+ */
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ sof_hda->link_dma_active_sdw_mask[dir] &= ~BIT(stream_idx);
+ sof_hda->link_dma_active_multi_mask[dir] &= ~BIT(stream_idx);
+ }
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 15faedeec16d..bb44d4f8a4da 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -188,7 +188,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream) {
if (ops->assign_hext_stream)
- hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
+ hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream, hlink);
}
if (!hext_stream)
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index e9f092f082a1..b9b2bdff4ccb 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -1114,11 +1114,7 @@ static int hda_dsp_s5_quirk(struct snd_sof_dev *sdev)
usleep_range(500, 1000);
/* Restore state for shutdown, back to reset */
- ret = hda_dsp_ctrl_link_reset(sdev, true);
- if (ret < 0)
- return ret;
-
- return ret;
+ return hda_dsp_ctrl_link_reset(sdev, true);
}
int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev)
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 2b3abcf75d55..4347e71337f9 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -216,9 +216,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int
EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax)
{
- return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, false);
+ return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream,
+ is_iccmax, false);
}
EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
@@ -302,7 +303,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab,
- persistent_cl_buffer, iccmax_stream);
+ persistent_cl_buffer, iccmax_stream, true);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@@ -458,7 +459,7 @@ cleanup:
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab,
- persistent_cl_buffer, hext_stream);
+ persistent_cl_buffer, hext_stream, false);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@@ -587,7 +588,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
cleanup:
/* clean up even in case of error and return the first error */
ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer,
- hext_stream);
+ hext_stream, false);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index 92314e3b568a..6f02fb5b70ce 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -432,6 +432,10 @@ int hda_bus_ml_init(struct hdac_bus *bus)
if (!bus->mlcap)
return 0;
+ /* Enumeration is a one time operation, skip if already done */
+ if (!list_empty(&bus->hlink_list))
+ return 0;
+
link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count);
@@ -880,19 +884,6 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK");
-void hda_bus_ml_put_all(struct hdac_bus *bus)
-{
- struct hdac_ext_link *hlink;
-
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
-
- if (!h2link->alt)
- snd_hdac_ext_bus_link_put(bus, hlink);
- }
-}
-EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK");
-
void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
@@ -903,6 +894,24 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
}
EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK");
+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink)
+{
+ struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
+
+ if (!h2link->alt)
+ return HDA_BUS_ML_LINK_HDA;
+
+ switch (h2link->elid) {
+ case AZX_REG_ML_LEPTR_ID_SDW:
+ return HDA_BUS_ML_LINK_SDW;
+ case AZX_REG_ML_LEPTR_ID_INTEL_UAOL:
+ return HDA_BUS_ML_LINK_UAOL;
+ default:
+ return HDA_BUS_ML_LINK_OTHER;
+ }
+}
+EXPORT_SYMBOL_NS(hda_bus_ml_link_get_type, "SND_SOC_SOF_HDA_MLINK");
+
int hda_bus_ml_resume(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
index 7351a0870725..ba9fbd662b85 100644
--- a/sound/soc/sof/intel/hda-sdw-bpt.c
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -163,7 +163,7 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream
u32 mask;
int ret;
- ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, true);
+ ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, false, true);
if (ret < 0) {
dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n",
__func__);
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 5c1f3b427cdb..c95230487a1b 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -198,13 +198,18 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
mask = (1 << hstream->index);
+ /* Reset the spib_addr before disabling SPIB */
+ if (!enable)
+ sof_io_write(sdev, hstream->spib_addr, 0);
+
/* enable/disable SPIB for the stream */
snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR,
SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask,
enable << hstream->index);
/* set the SPIB value */
- sof_io_write(sdev, hstream->spib_addr, size);
+ if (enable)
+ sof_io_write(sdev, hstream->spib_addr, size);
return 0;
}
@@ -608,6 +613,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return ret;
}
+ /* Host DMA is not running */
+ hstream->running = false;
+
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
@@ -1323,16 +1331,18 @@ out_put:
EXPORT_SYMBOL_NS(hda_data_stream_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream,
+ bool is_iccmax, bool pair)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = hdac_stream(hext_stream);
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret = 0;
- if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ if (!is_iccmax)
ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
- else
+
+ if (hstream->direction == SNDRV_PCM_STREAM_CAPTURE)
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_SD_CTL_DMA_START, 0);
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index dc85903b8d46..4dbba9186b29 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -421,6 +421,20 @@ static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { }
/* pre fw run operations */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+ int ret;
+
+ /* Power down DSP if left enabled to ensure a clean boot state. */
+ if (hda_dsp_core_is_enabled(sdev, chip->host_managed_cores_mask)) {
+ dev_dbg(sdev->dev, "DSP core enabled, power down DSP first\n");
+
+ ret = chip->power_down_dsp(sdev);
+ if (ret < 0)
+ dev_warn(sdev->dev,
+ "%s: failed to power down already-enabled DSP\n", __func__);
+ }
+
/* disable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, false);
}
@@ -625,8 +639,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
return ret;
}
- hda_bus_ml_init(bus);
-
/* Skip SoundWire if it is not supported */
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
@@ -670,8 +682,6 @@ skip_soundwire:
if (!HDA_IDISP_CODEC(bus->codec_mask))
hda_codec_i915_display_power(sdev, false);
- hda_bus_ml_put_all(bus);
-
return 0;
}
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 3f0966477ace..1609589929a1 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -523,6 +523,29 @@ struct sof_intel_hda_dev {
/* the maximum number of streams (playback + capture) supported */
u32 stream_max;
+ /*
+ * ACE2+ link DMA stream allocation constraints (stream index =
+ * stream_tag - 1, shared between input and output directions). All
+ * masks are cleared by hda_dsp_ctrl_init_chip() on controller reset
+ * (CRST#).
+ *
+ * - Concurrent (cross-direction) constraint: a SoundWire stream and
+ * a HDA/iDisp/UAOL stream cannot share a physical stream index
+ * across directions, the resulting LLP/timestamp values are wrong.
+ * link_dma_active_sdw_mask and link_dma_active_multi_mask
+ * (indexed by SNDRV_PCM_STREAM_*) track currently allocated
+ * streams per direction in each of the conflicting groups; SSP
+ * and DMIC do not participate. Bits are cleared on stream release.
+ *
+ * - Sequential (playback only) constraint: once a HDA/iDisp link
+ * has used a playback stream index, that index cannot drive a
+ * non-HDA/iDisp link in the same direction until the next CRST#.
+ * link_dma_out_hda_used_mask records this.
+ */
+ u32 link_dma_active_sdw_mask[SNDRV_PCM_STREAM_LAST + 1];
+ u32 link_dma_active_multi_mask[SNDRV_PCM_STREAM_LAST + 1];
+ u32 link_dma_out_hda_used_mask;
+
/* PM related */
bool l1_disabled;/* is DMI link L1 disabled? */
@@ -739,7 +762,7 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd);
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
@@ -911,7 +934,8 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si
bool is_iccmax, bool pair);
int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream,
+ bool is_iccmax, bool pair);
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
@@ -1030,7 +1054,8 @@ struct hda_dai_widget_dma_ops {
struct snd_pcm_substream *substream);
struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream);
+ struct snd_pcm_substream *substream,
+ struct hdac_ext_link *hlink);
void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream);
void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index c1018893750c..549bb4ca73e1 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -9,10 +9,14 @@
* Hardware interface for audio DSP on IceLake.
*/
-#include <linux/kernel.h>
-#include <linux/kconfig.h>
-#include <linux/export.h>
+#include <linux/array_size.h>
#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
#include "../ipc4-priv.h"
#include "../ops.h"
#include "hda.h"
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 9503d00e6002..3d67d6777f1b 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -236,6 +236,17 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
}
EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL");
+static bool mtl_dsp_is_enabled(struct snd_sof_dev *sdev)
+{
+ int val;
+
+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);
+ if (val & MTL_HFDSSCS_CPA_MASK)
+ return true;
+
+ return false;
+}
+
/* pre fw run operations */
static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
@@ -249,6 +260,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
u32 dsppwrsts;
const struct sof_intel_dsp_desc *chip;
+ /* Power down the DSP if it is left enabled to ensure clean boot state */
+ if (mtl_dsp_is_enabled(sdev)) {
+ dev_dbg(sdev->dev, "powering down DSP first\n");
+
+ ret = mtl_power_down_dsp(sdev);
+ if (ret < 0) {
+ dev_warn(sdev->dev,
+ "%s: failed to power down already-enabled DSP\n", __func__);
+ /* Continue anyway to attempt recovery */
+ }
+ }
+
chip = get_chip_info(sdev->pdata);
if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) {
dsppwrctl = PTL_HFPWRCTL2;
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 90ef5d99f626..143bf0fe8dd9 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -421,6 +421,12 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n",
channels->min, channels->max);
break;
+ case SOF_DAI_AMD_I2S:
+ rate->min = private->dai_config->acp_i2s.fsync_rate;
+ rate->max = private->dai_config->acp_i2s.fsync_rate;
+ channels->min = private->dai_config->acp_i2s.tdm_slots;
+ channels->max = private->dai_config->acp_i2s.tdm_slots;
+ break;
default:
dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
break;
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 4e066bbded91..26d85ca9be26 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -281,7 +281,10 @@ static const struct sof_topology_token acpdmic_tokens[] = {
offsetof(struct sof_ipc_dai_acpdmic_params, pdm_ch)},
};
-/* ACPI2S */
+/*
+ * ACPI2S tokens fill struct sof_ipc_dai_acp_params; SOF_DAI_AMD_I2S (ACPTDM
+ * on ACP7.B/7.F) reuses this tuple group rather than defining a parallel set.
+ */
static const struct sof_topology_token acpi2s_tokens[] = {
{SOF_TKN_AMD_ACPI2S_RATE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_dai_acp_params, fsync_rate)},
@@ -289,6 +292,8 @@ static const struct sof_topology_token acpi2s_tokens[] = {
offsetof(struct sof_ipc_dai_acp_params, tdm_slots)},
{SOF_TKN_AMD_ACPI2S_TDM_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
+ {SOF_TKN_AMD_ACPI2S_FORMAT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_acp_params, format)},
};
/* MICFIL PDM */
@@ -1363,6 +1368,35 @@ static int sof_link_acp_sdw_load(struct snd_soc_component *scomp, struct snd_sof
return 0;
}
+static int sof_link_acp_i2s_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
+ struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
+{
+ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
+ struct sof_dai_private_data *private = dai->private;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ /* init IPC */
+ memset(&config->acp_i2s, 0, sizeof(config->acp_i2s));
+ config->hdr.size = size;
+
+ ret = sof_update_ipc_object(scomp, &config->acp_i2s, SOF_ACPI2S_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
+
+ dai->number_configs = 1;
+ dai->current_config = 0;
+ private->dai_config = kmemdup(config, size, GFP_KERNEL);
+ if (!private->dai_config)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_link_afe_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
{
@@ -1692,6 +1726,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
case SOF_DAI_AMD_SDW:
ret = sof_link_acp_sdw_load(scomp, slink, config, dai);
break;
+ case SOF_DAI_AMD_I2S:
+ ret = sof_link_acp_i2s_load(scomp, slink, config, dai);
+ break;
default:
break;
}
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index 6fdfb667cce8..24a1175dd690 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -163,11 +163,11 @@ static const struct sof_topology_token comp_ext_tokens[] = {
{SOF_TKN_COMP_SCHED_DOMAIN, SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_domain,
offsetof(struct snd_sof_widget, comp_domain)},
{SOF_TKN_COMP_DOMAIN_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_domain_id)},
+ offsetof(struct snd_sof_widget, domain_id)},
{SOF_TKN_COMP_HEAP_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_heap_bytes)},
+ offsetof(struct snd_sof_widget, heap_bytes)},
{SOF_TKN_COMP_STACK_BYTES_REQUIREMENT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
- offsetof(struct snd_sof_widget, dp_stack_bytes)},
+ offsetof(struct snd_sof_widget, stack_bytes)},
};
static const struct sof_topology_token gain_tokens[] = {
@@ -406,6 +406,39 @@ sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index)
return NULL;
}
+static void
+sof_ipc4_evaluate_params_change(struct sof_ipc4_available_audio_format *available_fmt)
+{
+ struct sof_ipc4_audio_format *fmt;
+ u32 in_rate, in_channels, in_valid_bits;
+ u32 out_rate, out_channels, out_valid_bits;
+ u32 changed_params = 0;
+ int i, j;
+
+ for (i = 0; i < available_fmt->num_input_formats; i++) {
+ fmt = &available_fmt->input_pin_fmts[i].audio_fmt;
+ in_rate = fmt->sampling_frequency;
+ in_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ in_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ for (j = 0; j < available_fmt->num_output_formats; j++) {
+ fmt = &available_fmt->output_pin_fmts[j].audio_fmt;
+ out_rate = fmt->sampling_frequency;
+ out_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg);
+ out_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg);
+
+ if (in_rate != out_rate)
+ changed_params |= BIT(SNDRV_PCM_HW_PARAM_RATE);
+ if (in_channels != out_channels)
+ changed_params |= BIT(SNDRV_PCM_HW_PARAM_CHANNELS);
+ if (in_valid_bits != out_valid_bits)
+ changed_params |= BIT(SNDRV_PCM_HW_PARAM_FORMAT);
+ }
+ }
+
+ available_fmt->changed_params = changed_params;
+}
+
/**
* sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples
* @scomp: pointer to pointer to SOC component
@@ -497,6 +530,8 @@ static int sof_ipc4_get_audio_fmt(struct snd_soc_component *scomp,
available_fmt->num_output_formats);
}
+ sof_ipc4_evaluate_params_change(available_fmt);
+
return 0;
err_out:
@@ -661,6 +696,9 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
if (ret)
goto free_copier;
+ /* Copier can only change format */
+ available_fmt->changed_params &= BIT(SNDRV_PCM_HW_PARAM_FORMAT);
+
/*
* This callback is used by host copier and module-to-module copier,
* and only host copier needs to set gtw_cfg.
@@ -789,6 +827,9 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
if (ret)
goto free_copier;
+ /* Copier can only change format */
+ available_fmt->changed_params &= BIT(SNDRV_PCM_HW_PARAM_FORMAT);
+
ret = sof_update_ipc_object(scomp, &node_type,
SOF_COPIER_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(node_type), 1);
@@ -1127,6 +1168,7 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
"Invalid number of formats: input: %d, output: %d\n",
src->available_fmt.num_input_formats,
src->available_fmt.num_output_formats);
+ ret = -EINVAL;
goto err;
}
@@ -1179,6 +1221,7 @@ static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget)
"Invalid number of formats: input: %d, output: %d\n",
asrc->available_fmt.num_input_formats,
asrc->available_fmt.num_output_formats);
+ ret = -EINVAL;
goto err;
}
@@ -1369,6 +1412,22 @@ sof_ipc4_update_resource_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *
pipeline = pipe_widget->private;
pipeline->mem_usage += total;
+ /*
+ * If this is not a Data Processing module instance, add the
+ * required heap sizes to the sum of all module instances belonging
+ * to the same pipeline, and find the maximum stack requirement
+ * among all module instances belonging to the same pipeline.
+ */
+ if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) {
+ pipe_widget->heap_bytes += swidget->heap_bytes;
+ if (pipe_widget->stack_bytes < swidget->stack_bytes)
+ pipe_widget->stack_bytes = swidget->stack_bytes;
+
+ dev_dbg(sdev->dev, "%s mem reqs to %s heap %u stack %u",
+ swidget->widget->name, pipe_widget->widget->name,
+ pipe_widget->heap_bytes, pipe_widget->stack_bytes);
+ }
+
/* Update base_config->cpc from the module manifest */
sof_ipc4_update_cpc_from_manifest(sdev, fw_module, base_config);
@@ -1686,6 +1745,8 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
pipe_widget = swidget->spipe->pipe_widget;
pipeline = pipe_widget->private;
pipeline->mem_usage = 0;
+ pipe_widget->heap_bytes = 0;
+ pipe_widget->stack_bytes = 0;
if (WIDGET_IS_AIF(swidget->id) || swidget->id == snd_soc_dapm_buffer) {
if (pipeline->use_chain_dma) {
@@ -2063,10 +2124,57 @@ static void sof_ipc4_host_config(struct snd_sof_dev *sdev, struct snd_sof_widget
}
static int
-sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
- struct snd_pcm_hw_params *fe_params,
- struct snd_sof_platform_stream_params *platform_params,
- struct snd_pcm_hw_params *pipeline_params, int dir)
+sof_ipc4_copier_module_update_params(struct snd_sof_widget *swidget,
+ struct snd_pcm_hw_params *pipeline_params)
+{
+ struct snd_soc_component *scomp = swidget->scomp;
+ struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+ struct sof_ipc4_copier_data *copier_data;
+ struct sof_ipc4_copier *ipc4_copier;
+
+ switch (swidget->id) {
+ case snd_soc_dapm_aif_in:
+ case snd_soc_dapm_aif_out:
+ case snd_soc_dapm_buffer:
+ ipc4_copier = swidget->private;
+ copier_data = &ipc4_copier->data;
+ break;
+ case snd_soc_dapm_dai_in:
+ case snd_soc_dapm_dai_out:
+ {
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ struct snd_sof_dai *dai;
+
+ if (pipeline->use_chain_dma)
+ return 0;
+
+ dai = swidget->private;
+
+ ipc4_copier = (struct sof_ipc4_copier *)dai->private;
+ copier_data = &ipc4_copier->data;
+
+ break;
+ }
+ default:
+ dev_err(sdev->dev, "unsupported type %d for copier %s",
+ swidget->id, swidget->widget->name);
+ return -EINVAL;
+ }
+
+ /* modify the input params for the next widget */
+ return sof_ipc4_update_hw_params(sdev, pipeline_params,
+ &copier_data->out_format,
+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
+ BIT(SNDRV_PCM_HW_PARAM_RATE));
+}
+
+static int
+_sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ struct snd_pcm_hw_params *pipeline_params, int dir)
{
struct sof_ipc4_available_audio_format *available_fmt;
struct snd_soc_component *scomp = swidget->scomp;
@@ -2538,6 +2646,21 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
return 0;
}
+static int
+sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
+ struct snd_pcm_hw_params *fe_params,
+ struct snd_sof_platform_stream_params *platform_params,
+ struct snd_pcm_hw_params *pipeline_params, int dir)
+{
+ if (swidget->prepared)
+ return sof_ipc4_copier_module_update_params(swidget,
+ pipeline_params);
+
+ return _sof_ipc4_prepare_copier_module(swidget, fe_params,
+ platform_params, pipeline_params,
+ dir);
+}
+
static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
struct snd_pcm_hw_params *fe_params,
struct snd_sof_platform_stream_params *platform_params,
@@ -2551,6 +2674,10 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
int input_fmt_index, output_fmt_index;
+ /* This cannot happen */
+ if (unlikely(swidget->prepared))
+ return 0;
+
input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
&gain->data.base_config,
pipeline_params,
@@ -2596,6 +2723,10 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
int input_fmt_index, output_fmt_index;
+ /* Already prepared, nothing to do */
+ if (swidget->prepared)
+ return 0;
+
input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
&mixer->base_config,
pipeline_params,
@@ -2642,6 +2773,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type;
int output_fmt_index, input_fmt_index;
+ /* This cannot happen */
+ if (unlikely(swidget->prepared))
+ return 0;
+
input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
&src->data.base_config,
pipeline_params,
@@ -2808,6 +2943,18 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
int ret;
if (available_fmt->num_input_formats) {
+ if (swidget->prepared) {
+ if (!available_fmt->num_output_formats)
+ return 0;
+
+ /* modify the pipeline params with the output format */
+ return sof_ipc4_update_hw_params(sdev, pipeline_params,
+ &process->output_format,
+ BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
+ BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
+ BIT(SNDRV_PCM_HW_PARAM_RATE));
+ }
+
input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
&process->base_config,
pipeline_params,
@@ -2820,39 +2967,69 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
if (available_fmt->num_output_formats) {
struct sof_ipc4_audio_format *in_fmt;
struct sof_ipc4_pin_format *pin_fmt;
- u32 out_ref_rate, out_ref_channels;
- int out_ref_valid_bits, out_ref_type;
+ u32 ref_rate, ref_channels;
+ int ref_valid_bits, ref_type;
if (available_fmt->num_input_formats) {
+ /*
+ * The process module can change parameters and their operation
+ * depends on the direction:
+ * Playback: typically they have single output format. This is
+ * to 'force' the conversion from input to output.
+ * Use the input format as reference since the single
+ * format is going to be picked.
+ * Capture: typically they have multiple output formats to
+ * convert from dai (input) to FE (output) parameters.
+ * Use the input format as base and replace the param
+ * which is changed by the module with the FE parameter
+ * Reason: we can have module which changes the
+ * parameters in path, we cannot use the full
+ * FE param set for the module output lookup.
+ */
in_fmt = &available_fmt->input_pin_fmts[input_fmt_index].audio_fmt;
- out_ref_rate = in_fmt->sampling_frequency;
- out_ref_channels =
+ ref_rate = in_fmt->sampling_frequency;
+ ref_channels =
SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
- out_ref_valid_bits =
+ ref_valid_bits =
SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
- out_ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
+ ref_type = sof_ipc4_fmt_cfg_to_type(in_fmt->fmt_cfg);
} else {
/* for modules without input formats, use FE params as reference */
- out_ref_rate = params_rate(fe_params);
- out_ref_channels = params_channels(fe_params);
+ ref_rate = params_rate(fe_params);
+ ref_channels = params_channels(fe_params);
ret = sof_ipc4_get_sample_type(sdev, fe_params);
if (ret < 0)
return ret;
- out_ref_type = (u32)ret;
+ ref_type = (u32)ret;
- out_ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
- if (out_ref_valid_bits < 0)
- return out_ref_valid_bits;
+ ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
+ if (ref_valid_bits < 0)
+ return ref_valid_bits;
}
+ if (dir == SNDRV_PCM_STREAM_CAPTURE) {
+ if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_RATE))
+ ref_rate = params_rate(fe_params);
+ if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_CHANNELS))
+ ref_channels = params_channels(fe_params);
+ if (available_fmt->changed_params & BIT(SNDRV_PCM_HW_PARAM_FORMAT)) {
+ ref_valid_bits = sof_ipc4_get_valid_bits(sdev, fe_params);
+ if (ref_valid_bits < 0)
+ return ref_valid_bits;
+
+ ref_type = sof_ipc4_get_sample_type(sdev, fe_params);
+ if (ref_type < 0)
+ return ref_type;
+ }
+ }
output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget,
&process->base_config,
available_fmt,
- out_ref_rate,
- out_ref_channels,
- out_ref_valid_bits,
- out_ref_type);
+ ref_rate,
+ ref_channels,
+ ref_valid_bits,
+ ref_type);
if (output_fmt_index < 0)
return output_fmt_index;
@@ -2866,9 +3043,7 @@ static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget,
/* modify the pipeline params with the output format */
ret = sof_ipc4_update_hw_params(sdev, pipeline_params,
&process->output_format,
- BIT(SNDRV_PCM_HW_PARAM_FORMAT) |
- BIT(SNDRV_PCM_HW_PARAM_CHANNELS) |
- BIT(SNDRV_PCM_HW_PARAM_RATE));
+ available_fmt->changed_params);
if (ret)
return ret;
}
@@ -3083,27 +3258,47 @@ static int sof_ipc4_control_setup(struct snd_sof_dev *sdev, struct snd_sof_contr
return 0;
}
-static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
- struct snd_sof_widget *swidget,
- struct sof_ipc4_msg *msg,
- void *ipc_data, u32 ipc_size,
- void **new_data)
+static void sof_ipc4_add_init_ext_dp_memory_data(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ u32 *payload, u32 *ext_pos,
+ struct sof_ipc4_module_init_ext_object **hdr)
+{
+ /* Add memory_data if comp_domain indicates DP */
+ if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) {
+ struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data;
+
+ *hdr = (struct sof_ipc4_module_init_ext_object *)&payload[*ext_pos];
+ (*hdr)->header =
+ SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) |
+ SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data),
+ sizeof(u32)));
+ *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32));
+ dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[*ext_pos];
+ dp_mem_data->domain_id = swidget->domain_id;
+ dp_mem_data->stack_bytes = swidget->stack_bytes;
+ dp_mem_data->heap_bytes = swidget->heap_bytes;
+ *ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32));
+ }
+}
+
+static int sof_ipc4_widget_mod_init_msg_payload(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_msg *msg,
+ void *ipc_data, u32 ipc_size,
+ void **new_data)
{
- struct sof_ipc4_mod_init_ext_dp_memory_data *dp_mem_data;
struct sof_ipc4_module_init_ext_init *ext_init;
- struct sof_ipc4_module_init_ext_object *hdr;
+ struct sof_ipc4_module_init_ext_object *hdr = NULL;
int new_size;
u32 *payload;
u32 ext_pos;
- /* For the moment the only reason for adding init_ext_init payload is DP
- * memory data. If both stack and heap size are 0 (= use default), then
- * there is no need for init_ext_init payload.
+ /*
+ * Only DP widgets currently add init-ext objects here. Avoid allocating
+ * a max-sized payload buffer for widgets that will immediately return 0.
*/
- if (swidget->comp_domain != SOF_COMP_DOMAIN_DP) {
- msg->extension &= ~SOF_IPC4_MOD_EXT_EXTENDED_INIT_MASK;
+ if (swidget->comp_domain != SOF_COMP_DOMAIN_DP)
return 0;
- }
payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL);
if (!payload)
@@ -3111,27 +3306,26 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
/* Add ext_init first and set objects array flag to 1 */
ext_init = (struct sof_ipc4_module_init_ext_init *)payload;
- ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK;
ext_pos = DIV_ROUND_UP(sizeof(*ext_init), sizeof(u32));
/* Add object array objects after ext_init */
- /* Add dp_memory_data if comp_domain indicates DP */
- if (swidget->comp_domain == SOF_COMP_DOMAIN_DP) {
- hdr = (struct sof_ipc4_module_init_ext_object *)&payload[ext_pos];
- hdr->header = SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK |
- SOF_IPC4_MOD_INIT_EXT_OBJ_ID(SOF_IPC4_MOD_INIT_DATA_ID_DP_DATA) |
- SOF_IPC4_MOD_INIT_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*dp_mem_data),
- sizeof(u32)));
- ext_pos += DIV_ROUND_UP(sizeof(*hdr), sizeof(u32));
- dp_mem_data = (struct sof_ipc4_mod_init_ext_dp_memory_data *)&payload[ext_pos];
- dp_mem_data->domain_id = swidget->dp_domain_id;
- dp_mem_data->stack_bytes = swidget->dp_stack_bytes;
- dp_mem_data->heap_bytes = swidget->dp_heap_bytes;
- ext_pos += DIV_ROUND_UP(sizeof(*dp_mem_data), sizeof(u32));
+ sof_ipc4_add_init_ext_dp_memory_data(sdev, swidget, payload, &ext_pos, &hdr);
+
+ /* Add following object array items here */
+
+ if (!hdr) {
+ /*
+ * NOTE: Remove this early bail out, when struct
+ * sof_ipc4_module_init_ext_init alone has some
+ * function.
+ */
+ kfree(payload);
+ return 0;
}
- /* If another array object is added, remember clear previous OBJ_LAST bit */
+ ext_init->word0 |= SOF_IPC4_MOD_INIT_EXT_OBJ_ARRAY_MASK;
+ hdr->header |= SOF_IPC4_MOD_INIT_EXT_OBJ_LAST_MASK;
/* Calculate final size and check that it fits to max payload size */
new_size = ext_pos * sizeof(u32) + ipc_size;
@@ -3154,6 +3348,69 @@ static int sof_ipc4_widget_setup_msg_payload(struct snd_sof_dev *sdev,
return new_size;
}
+static void sof_ipc4_widget_pipe_ext_obj_memory_data(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ u32 *payload, u32 *ext_pos,
+ struct sof_ipc4_glb_pipe_ext_object **hdr)
+{
+ struct sof_ipc4_glb_pipe_ext_obj_memory_data *mem_data;
+
+ *hdr = (struct sof_ipc4_glb_pipe_ext_object *)&payload[*ext_pos];
+ (*hdr)->header =
+ SOF_IPC4_GLB_PIPE_EXT_OBJ_ID(SOF_IPC4_GLB_PIPE_DATA_ID_MEM_DATA) |
+ SOF_IPC4_GLB_PIPE_EXT_OBJ_WORDS(DIV_ROUND_UP(sizeof(*mem_data),
+ sizeof(u32)));
+ *ext_pos += DIV_ROUND_UP(sizeof(**hdr), sizeof(u32));
+ mem_data = (struct sof_ipc4_glb_pipe_ext_obj_memory_data *)&payload[*ext_pos];
+ mem_data->domain_id = swidget->domain_id;
+ mem_data->stack_bytes = swidget->stack_bytes;
+ mem_data->heap_bytes = swidget->heap_bytes;
+ *ext_pos += DIV_ROUND_UP(sizeof(*mem_data), sizeof(u32));
+
+ dev_dbg(sdev->dev,
+ "%s; domain_id %u stack %u heap %u bytes",
+ swidget->widget->name, mem_data->domain_id, mem_data->stack_bytes,
+ mem_data->heap_bytes);
+}
+
+static int sof_ipc4_widget_pipe_create_msg_payload(struct snd_sof_dev *sdev,
+ struct snd_sof_widget *swidget,
+ struct sof_ipc4_msg *msg,
+ void **new_data)
+{
+ struct sof_ipc4_glb_pipe_payload *payload_hdr;
+ struct sof_ipc4_glb_pipe_ext_object *hdr = NULL;
+ u32 *payload;
+ u32 ext_pos;
+
+ payload = kzalloc(sdev->ipc->max_payload_size, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ /* Add sof_ipc4_glb_pipe_payload and set array bit to 1 */
+ payload_hdr = (struct sof_ipc4_glb_pipe_payload *)payload;
+ payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_EXT_OBJ_ARRAY_MASK;
+ ext_pos = DIV_ROUND_UP(sizeof(*payload_hdr), sizeof(u32));
+
+ sof_ipc4_widget_pipe_ext_obj_memory_data(sdev, swidget, payload, &ext_pos, &hdr);
+ /* Add following array objects here */
+
+ /* Mark end of object array */
+ hdr->header |= SOF_IPC4_GLB_PIPE_EXT_OBJ_LAST_MASK;
+
+ /* Put total payload size in words to the payload header */
+ payload_hdr->word0 |= SOF_IPC4_GLB_PIPE_PAYLOAD_WORDS(ext_pos);
+ *new_data = payload;
+
+ /* Update msg extension bits according to the payload changes */
+ msg->extension |= SOF_IPC4_GLB_PIPE_PAYLOAD_MASK;
+
+ dev_dbg(sdev->dev, "%s: payload word0 %#x", swidget->widget->name,
+ payload_hdr->word0);
+
+ return ext_pos * sizeof(int32_t);
+}
+
static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
@@ -3340,8 +3597,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
swidget->widget->name, swidget->pipeline_id, module_id,
swidget->instance_id, swidget->core);
- ret = sof_ipc4_widget_setup_msg_payload(sdev, swidget, msg, ipc_data, ipc_size,
- &ext_data);
+ ret = sof_ipc4_widget_mod_init_msg_payload(sdev, swidget, msg, ipc_data, ipc_size,
+ &ext_data);
if (ret < 0)
goto fail;
@@ -3353,6 +3610,17 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
swidget->widget->name, swidget->pipeline_id,
swidget->instance_id, swidget->core);
+
+ msg->extension &= ~SOF_IPC4_GLB_PIPE_PAYLOAD_MASK;
+ ret = sof_ipc4_widget_pipe_create_msg_payload(sdev, swidget, msg,
+ &ext_data);
+ if (ret < 0)
+ goto fail;
+
+ if (ret > 0) {
+ ipc_size = ret;
+ ipc_data = ext_data;
+ }
}
msg->data_size = ipc_size;
@@ -3410,6 +3678,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
swidget->widget->name);
pipeline->mem_usage = 0;
+ swidget->heap_bytes = 0;
+ swidget->stack_bytes = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
ida_free(&pipeline_ida, swidget->instance_id);
swidget->instance_id = -EINVAL;
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index a289c1d8f3ff..c9fe9f2e4083 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -167,7 +167,7 @@ struct sof_ipc4_pipeline {
};
/**
- * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data
+ * struct ipc4_pipeline_set_state_data - multi pipeline trigger IPC data
* @count: Number of pipelines to be triggered
* @pipeline_instance_ids: Flexible array of IDs of the pipelines to be triggered
*/
@@ -197,12 +197,15 @@ struct sof_ipc4_pin_format {
* @input_pin_fmts: Available input pin formats
* @num_input_formats: Number of input pin formats
* @num_output_formats: Number of output pin formats
+ * @changed_params: Mask of changed params by the module instance between it's
+ * input and output formts (rate, channels, depth)
*/
struct sof_ipc4_available_audio_format {
struct sof_ipc4_pin_format *output_pin_fmts;
struct sof_ipc4_pin_format *input_pin_fmts;
u32 num_input_formats;
u32 num_output_formats;
+ u32 changed_params;
};
/**
@@ -210,7 +213,7 @@ struct sof_ipc4_available_audio_format {
* @node_id: ID of Gateway Node
* @dma_buffer_size: Preferred Gateway DMA buffer size (in bytes)
* @config_length: Length of gateway node configuration blob specified in #config_data
- * config_data: Gateway node configuration blob
+ * @config_data: Gateway node configuration blob
*/
struct sof_copier_gateway_cfg {
uint32_t node_id;
@@ -285,7 +288,9 @@ struct sof_ipc4_dma_stream_ch_map {
struct sof_ipc4_dma_config {
uint8_t dma_method;
uint8_t pre_allocated_by_host;
+ /* private: */
uint16_t rsvd;
+ /* public: */
uint32_t dma_channel_id;
uint32_t stream_id;
struct sof_ipc4_dma_stream_ch_map dma_stream_channel_map;
@@ -296,7 +301,7 @@ struct sof_ipc4_dma_config {
#define SOF_IPC4_GTW_DMA_CONFIG_ID 0x1000
/**
- * struct sof_ipc4_dma_config: DMA configuration
+ * struct sof_ipc4_dma_config_tlv - DMA configuration
* @type: set to SOF_IPC4_GTW_DMA_CONFIG_ID
* @length: sizeof(struct sof_ipc4_dma_config) + dma_config.dma_priv_config_size
* @dma_config: actual DMA configuration
@@ -321,6 +326,7 @@ struct sof_ipc4_alh_configuration_blob {
* @data: IPC copier data
* @copier_config: Copier + blob
* @ipc_config_size: Size of copier_config
+ * @ipc_config_data: Copier module config data
* @available_fmt: Available audio format
* @frame_fmt: frame format
* @msg: message structure for copier
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index c9c6c0c52c62..e77f73390bd8 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -289,6 +289,89 @@ static void sof_ipc4_dump_payload(struct snd_sof_dev *sdev,
16, 4, ipc_data, size, false);
}
+static const char *sof_ipc4_resource_type_str(u32 type)
+{
+ switch (type) {
+ case SOF_IPC4_MODULE_INSTANCE:
+ return "resource: MODULE_INSTANCE";
+ case SOF_IPC4_PIPELINE:
+ return "resource: PIPELINE";
+ case SOF_IPC4_GATEWAY:
+ return "resource: GATEWAY";
+ case SOF_IPC4_EDF_TASK:
+ return "resource: EDF_TASK";
+ case SOF_IPC4_INVALID_RESOURCE_TYPE:
+ return "Resource is invalid";
+ default:
+ return "Unknown resource type";
+ }
+}
+
+static const char *sof_ipc4_resource_event_type_str(u32 event_type)
+{
+ switch (event_type) {
+ case SOF_IPC4_MIXER_UNDERRUN_DETECTED:
+ return "event: MIXER_UNDERRUN_DETECTED";
+ case SOF_IPC4_PROCESS_DATA_ERROR:
+ return "event: PROCESS_DATA_ERROR";
+ case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED:
+ return "event: GATEWAY_UNDERRUN_DETECTED";
+ case SOF_IPC4_GATEWAY_OVERRUN_DETECTED:
+ return "event: GATEWAY_OVERRUN_DETECTED";
+ default:
+ return "Unknown event type";
+ }
+}
+
+static void sof_ipc4_resource_event_handler(struct snd_sof_dev *sdev,
+ struct sof_ipc4_msg *ipc4_msg)
+{
+ struct sof_ipc4_notify_resource_data *data = ipc4_msg->data_ptr;
+
+ /* Print event details */
+ switch (data->event_type) {
+ case SOF_IPC4_MIXER_UNDERRUN_DETECTED:
+ dev_dbg(sdev->dev, "%s (%u): eos %u, mixed %u, expected %u\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type, data->data.mixer_underrun.eos_flag,
+ data->data.mixer_underrun.data_mixed,
+ data->data.mixer_underrun.expected_data_mixed);
+ break;
+ case SOF_IPC4_PROCESS_DATA_ERROR:
+ dev_dbg(sdev->dev, "%s (%u): error_code %#x\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type, data->data.process_data_error.error_code);
+ break;
+ case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED:
+ case SOF_IPC4_GATEWAY_OVERRUN_DETECTED:
+ dev_dbg(sdev->dev, "%s (%u)\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type);
+ break;
+ default:
+ dev_dbg(sdev->dev, "%s (%u): raw dws %#x %#x %#x %#x %#x %#x\n",
+ sof_ipc4_resource_event_type_str(data->event_type),
+ data->event_type,
+ data->data.dws[0], data->data.dws[1], data->data.dws[2],
+ data->data.dws[3], data->data.dws[4], data->data.dws[5]);
+ break;
+ }
+
+ /* Print resource details */
+ if (data->resource_type == SOF_IPC4_MODULE_INSTANCE) {
+ u32 module_id = SOF_IPC4_MOD_ID_GET(data->resource_id);
+ u32 instance_id = SOF_IPC4_MOD_INSTANCE_GET(data->resource_id);
+
+ dev_dbg(sdev->dev, "%s (%u), module_id %u, instance_id %u\n",
+ sof_ipc4_resource_type_str(data->resource_type),
+ data->resource_type, module_id, instance_id);
+ } else if (data->resource_type != SOF_IPC4_INVALID_RESOURCE_TYPE) {
+ dev_dbg(sdev->dev, "%s (%u), id %u\n",
+ sof_ipc4_resource_type_str(data->resource_type),
+ data->resource_type, data->resource_id);
+ }
+}
+
static int sof_ipc4_get_reply(struct snd_sof_dev *sdev)
{
struct snd_sof_ipc_msg *msg = sdev->msg;
@@ -734,6 +817,7 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
break;
case SOF_IPC4_NOTIFY_RESOURCE_EVENT:
data_size = sizeof(struct sof_ipc4_notify_resource_data);
+ handler_func = sof_ipc4_resource_event_handler;
break;
case SOF_IPC4_NOTIFY_LOG_BUFFER_STATUS:
sof_ipc4_mtrace_update_pos(sdev, SOF_IPC4_LOG_CORE_GET(ipc4_msg->primary));
diff --git a/sound/soc/sof/nocodec.c b/sound/soc/sof/nocodec.c
index 11a95dba3c9c..34744f8ae34a 100644
--- a/sound/soc/sof/nocodec.c
+++ b/sound/soc/sof/nocodec.c
@@ -21,12 +21,13 @@ static struct snd_soc_card sof_nocodec_card = {
static int sof_nocodec_bes_setup(struct device *dev,
struct snd_soc_dai_driver *drv,
struct snd_soc_dai_link *links,
- int link_num, struct snd_soc_card *card)
+ int link_num)
{
+ struct snd_soc_card *card = &sof_nocodec_card;
struct snd_soc_dai_link_component *dlc;
int i;
- if (!drv || !links || !card)
+ if (!drv || !links)
return -EINVAL;
/* set up BE dai_links */
@@ -67,10 +68,10 @@ static int sof_nocodec_bes_setup(struct device *dev,
return 0;
}
-static int sof_nocodec_setup(struct device *dev,
- u32 num_dai_drivers,
- struct snd_soc_dai_driver *dai_drivers)
+static int sof_nocodec_setup(struct device *dev, struct snd_soc_acpi_mach *mach)
{
+ u32 num_dai_drivers = mach->mach_params.num_dai_drivers;
+ struct snd_soc_dai_driver *dai_drivers = mach->mach_params.dai_drivers;
struct snd_soc_dai_link *links;
/* create dummy BE dai_links */
@@ -78,7 +79,7 @@ static int sof_nocodec_setup(struct device *dev,
if (!links)
return -ENOMEM;
- return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers, &sof_nocodec_card);
+ return sof_nocodec_bes_setup(dev, dai_drivers, links, num_dai_drivers);
}
static int sof_nocodec_probe(struct platform_device *pdev)
@@ -92,8 +93,7 @@ static int sof_nocodec_probe(struct platform_device *pdev)
snd_soc_card_set_topology_name(card, "sof");
- ret = sof_nocodec_setup(card->dev, mach->mach_params.num_dai_drivers,
- mach->mach_params.dai_drivers);
+ ret = sof_nocodec_setup(card->dev, mach);
if (ret < 0)
return ret;
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index b2071edeaea6..f748d072109a 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -62,7 +62,7 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
* To avoid sending IPC before the previous IPC is handled, we
* schedule delayed work here to call the snd_pcm_period_elapsed().
*/
- schedule_work(&spcm->stream[substream->stream].period_elapsed_work);
+ queue_work(system_highpri_wq, &spcm->stream[substream->stream].period_elapsed_work);
}
EXPORT_SYMBOL(snd_sof_pcm_period_elapsed);
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 24614e506019..72ff03b0b80d 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -501,9 +501,8 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
!sof_widget_in_same_direction(swidget, dir))
return 0;
- /* skip widgets already prepared or aggregated DAI widgets*/
- if (!widget_ops[widget->id].ipc_prepare || swidget->prepared ||
- is_aggregated_dai(swidget))
+ /* skip widgets aggregated DAI widgets */
+ if (!widget_ops[widget->id].ipc_prepare || is_aggregated_dai(swidget))
goto sink_prepare;
/* prepare the source widget */
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 138e5fcc2dd0..ae95efc9be1c 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -459,10 +459,10 @@ struct snd_sof_widget {
/* Scheduling domain (enum sof_comp_domain), unset, Low Latency, or Data Processing */
u32 comp_domain;
- /* The values below are added to mod_init pay load if comp_domain indicates DP component */
- u32 dp_domain_id; /* DP process userspace domain ID */
- u32 dp_stack_bytes; /* DP process stack size requirement in bytes */
- u32 dp_heap_bytes; /* DP process heap size requirement in bytes */
+ /* Module instance's memory configuration. */
+ u32 domain_id; /* Module instance's userspace domain ID */
+ u32 stack_bytes; /* Module instance's stack size requirement */
+ u32 heap_bytes; /* Module instance's heap size requirement */
struct snd_soc_dapm_widget *widget;
struct list_head list; /* list in sdev widget list */
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 42a2d90bb705..8338133899ab 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -309,7 +309,7 @@ static const struct sof_dai_types sof_dais[] = {
{"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL},
{"MICFIL", SOF_DAI_IMX_MICFIL},
{"ACP_SDW", SOF_DAI_AMD_SDW},
-
+ {"ACPTDM", SOF_DAI_AMD_I2S},
};
static enum sof_ipc_dai_type find_dai(const char *name)
@@ -846,6 +846,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
struct snd_soc_tplg_mixer_control *mc =
container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
int tlv[SOF_TLV_ITEMS];
+ u32 min, max;
unsigned int mask;
int ret;
@@ -853,6 +854,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN)
return -EINVAL;
+ min = le32_to_cpu(mc->min);
+ max = le32_to_cpu(mc->max);
+ if (min > max || max >= INT_MAX)
+ return -EINVAL;
+
/*
* If control has more than 2 channels we need to override the info. This is because even if
* ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
@@ -863,12 +869,12 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
kc->info = snd_sof_volume_info;
scontrol->comp_id = sdev->next_comp_id;
- scontrol->min_volume_step = le32_to_cpu(mc->min);
- scontrol->max_volume_step = le32_to_cpu(mc->max);
+ scontrol->min_volume_step = min;
+ scontrol->max_volume_step = max;
scontrol->num_channels = le32_to_cpu(mc->num_channels);
- scontrol->max = le32_to_cpu(mc->max);
- if (le32_to_cpu(mc->max) == 1)
+ scontrol->max = max;
+ if (max == 1)
goto skip;
/* extract tlv data */
@@ -878,7 +884,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
}
/* set up volume table */
- ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1);
+ ret = set_up_volume_table(scontrol, tlv, max + 1);
if (ret < 0) {
dev_err(scomp->dev, "error: setting up volume table\n");
return ret;
@@ -911,7 +917,7 @@ skip:
return 0;
err:
- if (le32_to_cpu(mc->max) > 1)
+ if (max > 1)
kfree(scontrol->volume_table);
return ret;
@@ -1102,7 +1108,7 @@ static int sof_connect_dai_widget(struct snd_soc_component *scomp,
full = NULL;
partial = NULL;
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/* does stream match DAI link ? */
if (rtd->dai_link->stream_name) {
if (!strcmp(rtd->dai_link->stream_name, w->sname)) {
@@ -1167,7 +1173,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
else
return;
- list_for_each_entry(rtd, &card->rtd_list, list) {
+ for_each_card_rtds(card, rtd) {
/* does stream match DAI link ? */
if (!rtd->dai_link->stream_name ||
!strstr(rtd->dai_link->stream_name, sname))
@@ -1943,8 +1949,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
private->array, le32_to_cpu(private->size));
if (ret < 0) {
dev_err(scomp->dev, "Failed tp parse common DAI link tokens\n");
- kfree(slink);
- return ret;
+ goto free_slink;
}
token_list = tplg_ops ? tplg_ops->token_list : NULL;
@@ -1995,6 +2000,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
case SOF_DAI_AMD_HS:
case SOF_DAI_AMD_SP_VIRTUAL:
case SOF_DAI_AMD_HS_VIRTUAL:
+ case SOF_DAI_AMD_I2S:
token_id = SOF_ACPI2S_TOKENS;
num_tuples += token_list[SOF_ACPI2S_TOKENS].count;
break;
@@ -2013,8 +2019,8 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
/* allocate memory for tuples array */
slink->tuples = kzalloc_objs(*slink->tuples, num_tuples);
if (!slink->tuples) {
- kfree(slink);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto free_slink;
}
if (token_list[SOF_DAI_LINK_TOKENS].tokens) {
@@ -2070,6 +2076,7 @@ out:
err:
kfree(slink->tuples);
+free_slink:
kfree(slink);
return ret;
@@ -2505,13 +2512,12 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_pdata *sof_pdata = sdev->pdata;
const char *tplg_filename_prefix = sof_pdata->tplg_filename_prefix;
- const struct firmware *fw;
- const char **tplg_files;
int tplg_cnt = 0;
int ret;
int i;
- tplg_files = kcalloc(scomp->card->num_links, sizeof(char *), GFP_KERNEL);
+ const char **tplg_files __free(kfree) =
+ kcalloc(scomp->card->num_links, sizeof(char *), GFP_KERNEL);
if (!tplg_files)
return -ENOMEM;
@@ -2537,10 +2543,8 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
tplg_filename_prefix,
&tplg_files,
no_fallback);
- if (tplg_cnt < 0) {
- kfree(tplg_files);
+ if (tplg_cnt < 0)
return tplg_cnt;
- }
}
/*
@@ -2551,8 +2555,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
if (strstr(file, "dummy")) {
dev_err(scomp->dev,
"Function topology is required, please upgrade sof-firmware\n");
-
- kfree(tplg_files);
return -EINVAL;
}
tplg_files[0] = file;
@@ -2567,6 +2569,7 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
if (tplg_files[0] != file)
dev_info(scomp->dev, "loading topology %d: %s\n", i, tplg_files[i]);
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, tplg_files[i], scomp->dev);
if (ret < 0) {
/*
@@ -2585,8 +2588,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
else
ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
- release_firmware(fw);
-
if (ret < 0) {
dev_err(scomp->dev, "tplg %s component load failed %d\n",
tplg_files[i], ret);
@@ -2605,6 +2606,8 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
goto out;
}
dev_info(scomp->dev, "loading feature topology %d: %s\n", i, feature_topology);
+
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, feature_topology, scomp->dev);
if (ret < 0) {
/*
@@ -2629,8 +2632,6 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file)
else
ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw);
- release_firmware(fw);
-
if (ret < 0) {
dev_err(scomp->dev, "feature tplg %s component load failed %d\n",
feature_topologies[i], ret);
@@ -2649,8 +2650,6 @@ out:
if (ret >= 0 && sdev->led_present)
ret = snd_ctl_led_request();
- kfree(tplg_files);
-
return ret;
}
EXPORT_SYMBOL(snd_sof_load_topology);
diff --git a/sound/soc/sophgo/cv1800b-tdm.c b/sound/soc/sophgo/cv1800b-tdm.c
index 4cbac8c1160f..4badb6e3e08b 100644
--- a/sound/soc/sophgo/cv1800b-tdm.c
+++ b/sound/soc/sophgo/cv1800b-tdm.c
@@ -558,7 +558,7 @@ static const struct snd_soc_dai_ops cv1800b_i2s_dai_ops = {
.set_sysclk = cv1800b_i2s_dai_set_sysclk,
};
-static const struct snd_soc_dai_driver cv1800b_i2s_dai_template = {
+static struct snd_soc_dai_driver cv1800b_i2s_dai_template = {
.name = "cv1800b-i2s",
.playback = {
.stream_name = "Playback",
@@ -636,7 +636,6 @@ static int cv1800b_i2s_probe(struct platform_device *pdev)
struct cv1800b_i2s *i2s;
struct resource *res;
void __iomem *regs;
- struct snd_soc_dai_driver *dai;
int ret;
i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
@@ -666,21 +665,14 @@ static int cv1800b_i2s_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2s);
cv1800b_i2s_setup_tdm(i2s);
- dai = devm_kmemdup(dev, &cv1800b_i2s_dai_template, sizeof(*dai),
- GFP_KERNEL);
- if (!dai)
- return -ENOMEM;
-
- ret = devm_snd_soc_register_component(dev, &cv1800b_i2s_component, dai,
- 1);
+ ret = devm_snd_soc_register_component(dev, &cv1800b_i2s_component,
+ &cv1800b_i2s_dai_template, 1);
if (ret)
return ret;
ret = devm_snd_dmaengine_pcm_register(dev, &cv1800b_i2s_pcm_config, 0);
- if (ret) {
- dev_err(dev, "dmaengine_pcm_register failed: %d\n", ret);
+ if (ret)
return ret;
- }
return 0;
}
diff --git a/sound/soc/spacemit/k1_i2s.c b/sound/soc/spacemit/k1_i2s.c
index 8871fc15b29c..28a762769253 100644
--- a/sound/soc/spacemit/k1_i2s.c
+++ b/sound/soc/spacemit/k1_i2s.c
@@ -52,7 +52,7 @@ struct spacemit_i2s_dev {
struct clk *sysclk;
struct clk *bclk;
- struct clk *sspa_clk;
+ struct clk *func_clk;
struct clk *sysclk_div;
struct clk *c_sysclk;
struct clk *c_bclk;
@@ -221,7 +221,7 @@ static int spacemit_i2s_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
- return clk_set_rate(i2s->sspa_clk, bclk_rate);
+ return clk_set_rate(i2s->func_clk, bclk_rate);
}
static int spacemit_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
@@ -335,6 +335,11 @@ static int spacemit_i2s_dai_remove(struct snd_soc_dai *dai)
return 0;
}
+static const u64 spacemit_i2s_selectable_formats =
+ SND_SOC_POSSIBLE_DAIFMT_I2S |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_A |
+ SND_SOC_POSSIBLE_DAIFMT_DSP_B;
+
static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.probe = spacemit_i2s_dai_probe,
.remove = spacemit_i2s_dai_remove,
@@ -343,26 +348,12 @@ static const struct snd_soc_dai_ops spacemit_i2s_dai_ops = {
.set_sysclk = spacemit_i2s_set_sysclk,
.set_fmt = spacemit_i2s_set_fmt,
.trigger = spacemit_i2s_trigger,
+ .auto_selectable_formats = &spacemit_i2s_selectable_formats,
+ .num_auto_selectable_formats = 1,
};
static struct snd_soc_dai_driver spacemit_i2s_dai = {
.ops = &spacemit_i2s_dai_ops,
- .playback = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SPACEMIT_PCM_RATES,
- .rate_min = SNDRV_PCM_RATE_8000,
- .rate_max = SNDRV_PCM_RATE_48000,
- .formats = SPACEMIT_PCM_FORMATS,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 2,
- .rates = SPACEMIT_PCM_RATES,
- .rate_min = SNDRV_PCM_RATE_8000,
- .rate_max = SNDRV_PCM_RATE_48000,
- .formats = SPACEMIT_PCM_FORMATS,
- },
.symmetric_rate = 1,
};
@@ -392,6 +383,8 @@ static int spacemit_i2s_init_dai(struct spacemit_i2s_dev *i2s,
dai->playback.channels_min = 1;
dai->playback.channels_max = 2;
dai->playback.rates = SPACEMIT_PCM_RATES;
+ dai->playback.rate_min = SNDRV_PCM_RATE_8000;
+ dai->playback.rate_max = SNDRV_PCM_RATE_48000;
dai->playback.formats = SPACEMIT_PCM_FORMATS;
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -404,6 +397,8 @@ static int spacemit_i2s_init_dai(struct spacemit_i2s_dev *i2s,
dai->capture.channels_min = 1;
dai->capture.channels_max = 2;
dai->capture.rates = SPACEMIT_PCM_RATES;
+ dai->capture.rate_min = SNDRV_PCM_RATE_8000;
+ dai->capture.rate_max = SNDRV_PCM_RATE_48000;
dai->capture.formats = SPACEMIT_PCM_FORMATS;
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -445,14 +440,14 @@ static int spacemit_i2s_probe(struct platform_device *pdev)
if (IS_ERR(i2s->bclk))
return dev_err_probe(i2s->dev, PTR_ERR(i2s->bclk), "failed to enable bit clock\n");
- clk = devm_clk_get_enabled(i2s->dev, "sspa_bus");
+ clk = devm_clk_get_enabled(i2s->dev, "bus");
if (IS_ERR(clk))
- return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable sspa_bus clock\n");
+ return dev_err_probe(i2s->dev, PTR_ERR(clk), "failed to enable bus clock\n");
- i2s->sspa_clk = devm_clk_get_enabled(i2s->dev, "sspa");
- if (IS_ERR(i2s->sspa_clk))
- return dev_err_probe(i2s->dev, PTR_ERR(i2s->sspa_clk),
- "failed to enable sspa clock\n");
+ i2s->func_clk = devm_clk_get_enabled(i2s->dev, "func");
+ if (IS_ERR(i2s->func_clk))
+ return dev_err_probe(i2s->dev, PTR_ERR(i2s->func_clk),
+ "failed to enable func clock\n");
i2s->sysclk_div = devm_clk_get_optional_enabled(i2s->dev, "sysclk_div");
if (IS_ERR(i2s->sysclk_div))
@@ -471,7 +466,7 @@ static int spacemit_i2s_probe(struct platform_device *pdev)
i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(i2s->base))
- return dev_err_probe(i2s->dev, PTR_ERR(i2s->base), "failed to map registers\n");
+ return PTR_ERR(i2s->base);
i2s->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(i2s->reset))
@@ -488,7 +483,7 @@ static int spacemit_i2s_probe(struct platform_device *pdev)
&spacemit_i2s_component,
dai, 1);
if (ret)
- return dev_err_probe(i2s->dev, ret, "failed to register component");
+ return ret;
return devm_snd_dmaengine_pcm_register(&pdev->dev, &spacemit_dmaengine_pcm_config, 0);
}
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c
index b31b120a85de..dd1e176193af 100644
--- a/sound/soc/spear/spdif_in.c
+++ b/sound/soc/spear/spdif_in.c
@@ -55,7 +55,7 @@ static int spdif_in_dai_probe(struct snd_soc_dai *dai)
struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai);
host->dma_params_rx.filter_data = &host->dma_params;
- dai->capture_dma_data = &host->dma_params_rx;
+ snd_soc_dai_dma_data_set_capture(dai, &host->dma_params_rx);
return 0;
}
@@ -150,12 +150,12 @@ static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd,
static const struct snd_soc_dai_ops spdif_in_dai_ops = {
.shutdown = spdif_in_shutdown,
+ .probe = spdif_in_dai_probe,
.trigger = spdif_in_trigger,
.hw_params = spdif_in_hw_params,
};
static struct snd_soc_dai_driver spdif_in_dai = {
- .probe = spdif_in_dai_probe,
.capture = {
.channels_min = 2,
.channels_max = 2,
@@ -218,10 +218,8 @@ static int spdif_in_probe(struct platform_device *pdev)
host->io_base = io_base;
host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- dev_warn(&pdev->dev, "failed to get IRQ: %d\n", host->irq);
+ if (host->irq < 0)
return host->irq;
- }
host->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk))
@@ -243,10 +241,8 @@ static int spdif_in_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0,
"spdif-in", host);
- if (ret) {
- dev_warn(&pdev->dev, "request_irq failed\n");
+ if (ret)
return ret;
- }
ret = devm_snd_soc_register_component(&pdev->dev, &spdif_in_component,
&spdif_in_dai, 1);
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c
index c06f09c646a8..01dc2cef7448 100644
--- a/sound/soc/spear/spdif_out.c
+++ b/sound/soc/spear/spdif_out.c
@@ -249,6 +249,7 @@ static int spdif_soc_dai_probe(struct snd_soc_dai *dai)
}
static const struct snd_soc_dai_ops spdif_out_dai_ops = {
+ .probe = spdif_soc_dai_probe,
.mute_stream = spdif_mute,
.startup = spdif_out_startup,
.shutdown = spdif_out_shutdown,
@@ -266,7 +267,6 @@ static struct snd_soc_dai_driver spdif_out_dai = {
SNDRV_PCM_RATE_192000),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
- .probe = spdif_soc_dai_probe,
.ops = &spdif_out_dai_ops,
};
diff --git a/sound/soc/sprd/sprd-mcdt.c b/sound/soc/sprd/sprd-mcdt.c
index 5f3a2a7bce31..d9a7bbd6c0b6 100644
--- a/sound/soc/sprd/sprd-mcdt.c
+++ b/sound/soc/sprd/sprd-mcdt.c
@@ -931,10 +931,8 @@ static int sprd_mcdt_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler,
0, "sprd-mcdt", mcdt);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request MCDT IRQ\n");
+ if (ret)
return ret;
- }
sprd_mcdt_init_chans(mcdt, res);
diff --git a/sound/soc/sprd/sprd-pcm-dma.c b/sound/soc/sprd/sprd-pcm-dma.c
index cbf5bf82d96e..f509a4601de2 100644
--- a/sound/soc/sprd/sprd-pcm-dma.c
+++ b/sound/soc/sprd/sprd-pcm-dma.c
@@ -469,8 +469,6 @@ static int sprd_soc_platform_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component,
NULL, 0);
- if (ret)
- dev_err(&pdev->dev, "could not register platform:%d\n", ret);
return ret;
}
diff --git a/sound/soc/starfive/jh7110_pwmdac.c b/sound/soc/starfive/jh7110_pwmdac.c
index a603dd17931c..5953c3a4e373 100644
--- a/sound/soc/starfive/jh7110_pwmdac.c
+++ b/sound/soc/starfive/jh7110_pwmdac.c
@@ -477,25 +477,22 @@ static int jh7110_pwmdac_probe(struct platform_device *pdev)
&jh7110_pwmdac_component,
&jh7110_pwmdac_dai, 1);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "failed to register dai\n");
+ return ret;
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "failed to register pcm\n");
+ return ret;
pm_runtime_enable(dev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = jh7110_pwmdac_runtime_resume(&pdev->dev);
- if (ret)
- goto err_pm_disable;
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+ }
}
return 0;
-
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static void jh7110_pwmdac_remove(struct platform_device *pdev)
diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c
index afdcde7df91a..f7522bfbe8e6 100644
--- a/sound/soc/starfive/jh7110_tdm.c
+++ b/sound/soc/starfive/jh7110_tdm.c
@@ -559,10 +559,8 @@ static int jh7110_tdm_clk_reset_get(struct platform_device *pdev,
tdm->clks[5].id = "tdm";
ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(tdm->clks), tdm->clks);
- if (ret) {
- dev_err(&pdev->dev, "Failed to get tdm clocks\n");
+ if (ret)
return ret;
- }
tdm->resets = devm_reset_control_array_get_exclusive(&pdev->dev);
if (IS_ERR(tdm->resets)) {
@@ -589,42 +587,33 @@ static int jh7110_tdm_probe(struct platform_device *pdev)
tdm->dev = &pdev->dev;
ret = jh7110_tdm_clk_reset_get(pdev, tdm);
- if (ret) {
- dev_err(&pdev->dev, "Failed to enable audio-tdm clock\n");
+ if (ret)
return ret;
- }
jh7110_tdm_init_params(tdm);
dev_set_drvdata(&pdev->dev, tdm);
ret = devm_snd_soc_register_component(&pdev->dev, &jh7110_tdm_component,
&jh7110_tdm_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register dai\n");
+ if (ret)
return ret;
- }
ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
&jh7110_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_COMPAT);
- if (ret) {
- dev_err(&pdev->dev, "Could not register pcm: %d\n", ret);
+ if (ret)
return ret;
- }
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = jh7110_tdm_runtime_resume(&pdev->dev);
- if (ret)
- goto err_pm_disable;
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+ }
}
return 0;
-
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-
- return ret;
}
static void jh7110_tdm_dev_remove(struct platform_device *pdev)
diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c
index 66efb9a0acb9..73c6460a6327 100644
--- a/sound/soc/stm/stm32_adfsdm.c
+++ b/sound/soc/stm/stm32_adfsdm.c
@@ -360,11 +360,8 @@ static int stm32_adfsdm_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev,
&stm32_adfsdm_soc_platform,
NULL, 0);
- if (ret < 0) {
- dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
- __func__);
+ if (ret < 0)
return ret;
- }
pm_runtime_enable(&pdev->dev);
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index ae9e25657f3f..83b51893b37c 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -1238,10 +1238,8 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev,
ret = devm_request_irq(&pdev->dev, irq, stm32_i2s_isr, 0,
dev_name(&pdev->dev), i2s);
- if (ret) {
- dev_err(&pdev->dev, "irq request returned %d\n", ret);
+ if (ret)
return ret;
- }
/* Reset */
rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
@@ -1295,7 +1293,7 @@ static int stm32_i2s_probe(struct platform_device *pdev)
ret = snd_dmaengine_pcm_register(&pdev->dev, &stm32_i2s_pcm_config, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n");
+ return ret;
ret = snd_soc_register_component(&pdev->dev, &stm32_i2s_component,
i2s->dai_drv, 1);
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index ea9e8bddd63f..9a201bdb306f 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1696,19 +1696,15 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr,
IRQF_SHARED, dev_name(&pdev->dev), sai);
- if (ret) {
- dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
+ if (ret)
goto err_unprepare_pclk;
- }
if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
conf = &stm32_sai_pcm_config_spdif;
ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
- if (ret) {
- ret = dev_err_probe(&pdev->dev, ret, "Could not register pcm dma\n");
+ if (ret)
goto err_unprepare_pclk;
- }
ret = snd_soc_register_component(&pdev->dev, &stm32_component,
&sai->cpu_dai_drv, 1);
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 2f83ca989e68..e0fef47a227e 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -970,10 +970,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0,
dev_name(&pdev->dev), spdifrx);
- if (ret) {
- dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
+ if (ret)
return ret;
- }
rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
if (IS_ERR(rst))
@@ -987,7 +985,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev)
pcm_config = &stm32_spdifrx_pcm_config;
ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0);
if (ret)
- return dev_err_probe(&pdev->dev, ret, "PCM DMA register error\n");
+ return ret;
ret = snd_soc_register_component(&pdev->dev,
&stm32_spdifrx_component,
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 93f511fb6190..ff56700a9fe9 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -22,13 +22,13 @@
#include <linux/gpio/consumer.h>
#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
-#include <sound/initval.h>
-#include <sound/dmaengine_pcm.h>
/* Codec DAC digital controls and FIFO registers */
#define SUN4I_CODEC_DAC_DPC (0x00)
@@ -2317,67 +2317,54 @@ static int sun4i_codec_probe(struct platform_device *pdev)
scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
quirks->regmap_config);
- if (IS_ERR(scodec->regmap)) {
- dev_err(&pdev->dev, "Failed to create our regmap\n");
- return PTR_ERR(scodec->regmap);
- }
+ if (IS_ERR(scodec->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->regmap),
+ "Failed to create our regmap\n");
/* Get the clocks from the DT */
scodec->clk_apb = devm_clk_get_enabled(&pdev->dev, "apb");
- if (IS_ERR(scodec->clk_apb)) {
- dev_err(&pdev->dev, "Failed to get the APB clock\n");
- return PTR_ERR(scodec->clk_apb);
- }
+ if (IS_ERR(scodec->clk_apb))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_apb),
+ "Failed to get the APB clock\n");
scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
- if (IS_ERR(scodec->clk_module)) {
- dev_err(&pdev->dev, "Failed to get the module clock\n");
- return PTR_ERR(scodec->clk_module);
- }
+ if (IS_ERR(scodec->clk_module))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->clk_module),
+ "Failed to get the module clock\n");
if (quirks->has_reset) {
scodec->rst = devm_reset_control_get_exclusive_deasserted(&pdev->dev, NULL);
- if (IS_ERR(scodec->rst)) {
- dev_err(&pdev->dev, "Failed to get reset control\n");
- return PTR_ERR(scodec->rst);
- }
+ if (IS_ERR(scodec->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->rst),
+ "Failed to get reset control\n");
}
scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa",
GPIOD_OUT_LOW);
- if (IS_ERR(scodec->gpio_pa)) {
- ret = PTR_ERR(scodec->gpio_pa);
- dev_err_probe(&pdev->dev, ret, "Failed to get pa gpio\n");
- return ret;
- }
+ if (IS_ERR(scodec->gpio_pa))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_pa),
+ "Failed to get pa gpio\n");
+
scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN);
- if (IS_ERR(scodec->gpio_hp)) {
- ret = PTR_ERR(scodec->gpio_hp);
- dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n");
- return ret;
- }
+ if (IS_ERR(scodec->gpio_hp))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->gpio_hp),
+ "Failed to get hp-det gpio\n");
/* reg_field setup */
scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
scodec->regmap,
quirks->reg_adc_fifoc);
- if (IS_ERR(scodec->reg_adc_fifoc)) {
- ret = PTR_ERR(scodec->reg_adc_fifoc);
- dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(scodec->reg_adc_fifoc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_adc_fifoc),
+ "Failed to create regmap fields\n");
scodec->reg_dac_fifoc = devm_regmap_field_alloc(&pdev->dev,
scodec->regmap,
quirks->reg_dac_fifoc);
- if (IS_ERR(scodec->reg_dac_fifoc)) {
- ret = PTR_ERR(scodec->reg_dac_fifoc);
- dev_err(&pdev->dev, "Failed to create regmap fields: %d\n",
- ret);
- return ret;
- }
+ if (IS_ERR(scodec->reg_dac_fifoc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(scodec->reg_dac_fifoc),
+ "Failed to create regmap fields\n");
/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
@@ -2394,39 +2381,29 @@ static int sun4i_codec_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, quirks->codec,
&sun4i_codec_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register our codec\n");
+ if (ret)
return ret;
- }
ret = devm_snd_soc_register_component(&pdev->dev,
&sun4i_codec_component,
&dummy_cpu_dai, 1);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register our DAI\n");
+ if (ret)
return ret;
- }
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret) {
- dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
+ if (ret)
return ret;
- }
card = quirks->create_card(&pdev->dev);
- if (IS_ERR(card)) {
- ret = PTR_ERR(card);
- dev_err(&pdev->dev, "Failed to create our card\n");
- return ret;
- }
+ if (IS_ERR(card))
+ return PTR_ERR(card);
snd_soc_card_set_drvdata(card, scodec);
ret = snd_soc_register_card(card);
- if (ret) {
- dev_err_probe(&pdev->dev, ret, "Failed to register our card\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to register our card\n");
return 0;
}
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 40de99a34bc3..716fa4d872ff 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -1550,30 +1550,26 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
- if (IS_ERR(i2s->bus_clk)) {
- dev_err(&pdev->dev, "Can't get our bus clock\n");
- return PTR_ERR(i2s->bus_clk);
- }
+ if (IS_ERR(i2s->bus_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->bus_clk),
+ "Can't get our bus clock\n");
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
i2s->variant->sun4i_i2s_regmap);
- if (IS_ERR(i2s->regmap)) {
- dev_err(&pdev->dev, "Regmap initialisation failed\n");
- return PTR_ERR(i2s->regmap);
- }
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap),
+ "Regmap initialisation failed\n");
i2s->mod_clk = devm_clk_get(&pdev->dev, "mod");
- if (IS_ERR(i2s->mod_clk)) {
- dev_err(&pdev->dev, "Can't get our mod clock\n");
- return PTR_ERR(i2s->mod_clk);
- }
+ if (IS_ERR(i2s->mod_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->mod_clk),
+ "Can't get our mod clock\n");
if (i2s->variant->has_reset) {
i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
- if (IS_ERR(i2s->rst)) {
- dev_err(&pdev->dev, "Failed to get reset control\n");
- return PTR_ERR(i2s->rst);
- }
+ if (IS_ERR(i2s->rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->rst),
+ "Failed to get reset control\n");
}
if (!IS_ERR(i2s->rst)) {
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index c2ec19437cd7..d979bb00312f 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -684,26 +684,23 @@ static int sun4i_spdif_probe(struct platform_device *pdev)
host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
&sun4i_spdif_regmap_config);
- if (IS_ERR(host->regmap)) {
- dev_err(&pdev->dev, "failed to initialise regmap.\n");
- return PTR_ERR(host->regmap);
- }
+ if (IS_ERR(host->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->regmap),
+ "failed to initialise regmap.\n");
/* Clocks */
host->apb_clk = devm_clk_get(&pdev->dev, "apb");
- if (IS_ERR(host->apb_clk)) {
- dev_err(&pdev->dev, "failed to get a apb clock.\n");
- return PTR_ERR(host->apb_clk);
- }
+ if (IS_ERR(host->apb_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->apb_clk),
+ "failed to get a apb clock.\n");
if (quirks->tx_clk_name)
tx_clk_name = quirks->tx_clk_name;
host->spdif_clk = devm_clk_get(&pdev->dev, tx_clk_name);
- if (IS_ERR(host->spdif_clk)) {
- dev_err(&pdev->dev, "failed to get the \"%s\" clock.\n",
- tx_clk_name);
- return PTR_ERR(host->spdif_clk);
- }
+ if (IS_ERR(host->spdif_clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(host->spdif_clk),
+ "failed to get the \"%s\" clock.\n",
+ tx_clk_name);
host->dma_params_tx.addr = res->start + quirks->reg_dac_txdata;
host->dma_params_tx.maxburst = 8;
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
index 9f5b067a8ccc..50c0dee8c433 100644
--- a/sound/soc/sunxi/sun50i-codec-analog.c
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -551,16 +551,13 @@ static int sun50i_codec_analog_probe(struct platform_device *pdev)
bool enable;
base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- dev_err(&pdev->dev, "Failed to map the registers\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
- if (IS_ERR(regmap)) {
- dev_err(&pdev->dev, "Failed to create regmap\n");
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+ "Failed to create regmap\n");
enable = device_property_read_bool(&pdev->dev,
"allwinner,internal-bias-resistor");
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
index 2024e2b2553e..3335855c6311 100644
--- a/sound/soc/sunxi/sun8i-codec-analog.c
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -822,16 +822,13 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev)
void __iomem *base;
base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base)) {
- dev_err(&pdev->dev, "Failed to map the registers\n");
+ if (IS_ERR(base))
return PTR_ERR(base);
- }
regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
- if (IS_ERR(regmap)) {
- dev_err(&pdev->dev, "Failed to create regmap\n");
- return PTR_ERR(regmap);
- }
+ if (IS_ERR(regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(regmap),
+ "Failed to create regmap\n");
return devm_snd_soc_register_component(&pdev->dev,
&sun8i_codec_analog_cmpnt_drv,
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
index b48cc4a6967b..ea8bc9bcfa67 100644
--- a/sound/soc/tegra/tegra20_das.c
+++ b/sound/soc/tegra/tegra20_das.c
@@ -167,10 +167,9 @@ static int tegra20_das_probe(struct platform_device *pdev)
das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
&tegra20_das_regmap_config);
- if (IS_ERR(das->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- return PTR_ERR(das->regmap);
- }
+ if (IS_ERR(das->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(das->regmap),
+ "regmap init failed\n");
tegra20_das_connect_dap_to_dac(das, TEGRA20_DAS_DAP_ID_1,
TEGRA20_DAS_DAP_SEL_DAC1);
diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c
index 15a94196ee1a..e75bf50f8fb0 100644
--- a/sound/soc/tegra/tegra210_adx.c
+++ b/sound/soc/tegra/tegra210_adx.c
@@ -496,16 +496,12 @@ static struct snd_kcontrol_new tegra264_adx_controls[] = {
static int tegra210_adx_component_probe(struct snd_soc_component *component)
{
struct tegra210_adx *adx = snd_soc_component_get_drvdata(component);
- int err = 0;
- if (adx->soc_data->num_controls) {
- err = snd_soc_add_component_controls(component, adx->soc_data->controls,
- adx->soc_data->num_controls);
- if (err)
- dev_err(component->dev, "can't add ADX controls, err: %d\n", err);
- }
+ if (adx->soc_data->num_controls)
+ return snd_soc_add_component_controls(component, adx->soc_data->controls,
+ adx->soc_data->num_controls);
- return err;
+ return 0;
}
static const struct snd_soc_component_driver tegra210_adx_cmpnt = {
diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c
index cc1f9c158191..6a67ce6128b4 100644
--- a/sound/soc/tegra/tegra210_amx.c
+++ b/sound/soc/tegra/tegra210_amx.c
@@ -504,16 +504,12 @@ static struct snd_kcontrol_new tegra264_amx_controls[] = {
static int tegra210_amx_component_probe(struct snd_soc_component *component)
{
struct tegra210_amx *amx = snd_soc_component_get_drvdata(component);
- int err = 0;
- if (amx->soc_data->num_controls) {
- err = snd_soc_add_component_controls(component, amx->soc_data->controls,
- amx->soc_data->num_controls);
- if (err)
- dev_err(component->dev, "can't add AMX controls, err: %d\n", err);
- }
+ if (amx->soc_data->num_controls)
+ return snd_soc_add_component_controls(component, amx->soc_data->controls,
+ amx->soc_data->num_controls);
- return err;
+ return 0;
}
static const struct snd_soc_component_driver tegra210_amx_cmpnt = {
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index ff8c72fc38c5..84506576437d 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -23,9 +23,9 @@ static const struct reg_default tegra210_i2s_reg_defaults[] = {
{ TEGRA210_I2S_RX_CIF_CTRL, 0x00007700 },
{ TEGRA210_I2S_TX_INT_MASK, 0x00000003 },
{ TEGRA210_I2S_TX_CIF_CTRL, 0x00007700 },
+ { TEGRA210_I2S_ENABLE, 0x1 },
{ TEGRA210_I2S_CG, 0x1 },
{ TEGRA210_I2S_TIMING, 0x0000001f },
- { TEGRA210_I2S_ENABLE, 0x1 },
/*
* Below update does not have any effect on Tegra186 and Tegra194.
* On Tegra210, I2S4 has "i2s4a" and "i2s4b" pins and below update
@@ -38,13 +38,13 @@ static const struct reg_default tegra210_i2s_reg_defaults[] = {
static const struct reg_default tegra264_i2s_reg_defaults[] = {
{ TEGRA210_I2S_RX_INT_MASK, 0x00000003 },
{ TEGRA210_I2S_RX_CIF_CTRL, 0x00003f00 },
+ { TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE, 0x1 },
{ TEGRA264_I2S_TX_INT_MASK, 0x00000003 },
{ TEGRA264_I2S_TX_CIF_CTRL, 0x00003f00 },
+ { TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE, 0x1 },
+ { TEGRA264_I2S_ENABLE, 0x1 },
{ TEGRA264_I2S_CG, 0x1 },
{ TEGRA264_I2S_TIMING, 0x0000001f },
- { TEGRA264_I2S_ENABLE, 0x1 },
- { TEGRA264_I2S_RX_FIFO_WR_ACCESS_MODE, 0x1 },
- { TEGRA264_I2S_TX_FIFO_RD_ACCESS_MODE, 0x1 },
};
static void tegra210_i2s_set_slot_ctrl(struct tegra210_i2s *i2s,
@@ -1078,13 +1078,13 @@ static int tegra210_i2s_probe(struct platform_device *pdev)
"can't retrieve I2S bit clock\n");
/*
- * Not an error, as this clock is needed only when some other I/O
- * requires input clock from current I2S instance, which is
- * configurable from DT.
+ * This clock is optional and is only needed when another I/O uses
+ * the current I2S instance as its input clock, as configured in DT.
*/
- i2s->clk_sync_input = devm_clk_get(dev, "sync_input");
+ i2s->clk_sync_input = devm_clk_get_optional(dev, "sync_input");
if (IS_ERR(i2s->clk_sync_input))
- dev_dbg(dev, "can't retrieve I2S sync input clock\n");
+ return dev_err_probe(dev, PTR_ERR(i2s->clk_sync_input),
+ "can't retrieve I2S sync input clock\n");
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c
index a69774578d69..8eb4e54b954b 100644
--- a/sound/soc/tegra/tegra210_mixer.c
+++ b/sound/soc/tegra/tegra210_mixer.c
@@ -57,10 +57,10 @@ static const struct reg_default tegra210_mixer_reg_defaults[] = {
MIXER_TX_REG_DEFAULTS(3),
MIXER_TX_REG_DEFAULTS(4),
+ { TEGRA210_MIXER_ENABLE, 0x1 },
{ TEGRA210_MIXER_CG, 0x00000001},
{ TEGRA210_MIXER_GAIN_CFG_RAM_CTRL, 0x00004000},
{ TEGRA210_MIXER_PEAKM_RAM_CTRL, 0x00004000},
- { TEGRA210_MIXER_ENABLE, 0x1 },
};
/* Default gain parameters */
diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c
index 61252359d5cb..b4f6be2ab4c8 100644
--- a/sound/soc/ti/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
@@ -562,21 +562,21 @@ static int ams_delta_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
- handset_mute = devm_gpiod_get(card->dev, "handset_mute",
+ handset_mute = devm_gpiod_get(&pdev->dev, "handset_mute",
GPIOD_OUT_HIGH);
if (IS_ERR(handset_mute))
return PTR_ERR(handset_mute);
- handsfree_mute = devm_gpiod_get(card->dev, "handsfree_mute",
+ handsfree_mute = devm_gpiod_get(&pdev->dev, "handsfree_mute",
GPIOD_OUT_HIGH);
if (IS_ERR(handsfree_mute))
return PTR_ERR(handsfree_mute);
ret = snd_soc_register_card(card);
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
card->dev = NULL;
- return ret;
+ return dev_err_probe(&pdev->dev, ret,
+ "snd_soc_register_card() failed\n");
}
return 0;
}
diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index ad514c2e5a25..3156d87a3a12 100644
--- a/sound/soc/ti/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -245,9 +245,8 @@ static int davinci_evm_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
-
if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n");
goto err_put;
}
diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c
index c214ae0d7b95..600897a3e1c5 100644
--- a/sound/soc/ti/j721e-evm.c
+++ b/sound/soc/ti/j721e-evm.c
@@ -4,6 +4,7 @@
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -263,7 +264,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
int ret = 0;
int i;
- guard(mutex)(&priv->mutex);
+ mutex_lock(&priv->mutex);
domain->active++;
@@ -303,6 +304,7 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
out:
if (ret)
domain->active--;
+ mutex_unlock(&priv->mutex);
return ret;
}
@@ -868,10 +870,9 @@ static int j721e_soc_probe(struct platform_device *pdev)
card->num_dapm_routes = ARRAY_SIZE(j721e_cpb_dapm_routes);
card->fully_routed = 1;
- if (snd_soc_of_parse_card_name(card, "model")) {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
+ ret = snd_soc_of_parse_card_name(card, "model");
+ if (ret)
+ return ret;
link_cnt = 0;
conf_cnt = 0;
diff --git a/sound/soc/ti/omap-abe-twl6040.c b/sound/soc/ti/omap-abe-twl6040.c
index 56aa4b22083b..05239ccc1f41 100644
--- a/sound/soc/ti/omap-abe-twl6040.c
+++ b/sound/soc/ti/omap-abe-twl6040.c
@@ -234,16 +234,13 @@ static int omap_abe_probe(struct platform_device *pdev)
card->dapm_routes = audio_map;
card->num_dapm_routes = ARRAY_SIZE(audio_map);
- if (snd_soc_of_parse_card_name(card, "ti,model")) {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
+ ret = snd_soc_of_parse_card_name(card, "ti,model");
+ if (ret)
+ return ret;
ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
- if (ret) {
- dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
+ if (ret)
return ret;
- }
dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
if (!dai_node) {
@@ -299,8 +296,8 @@ static int omap_abe_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
- dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
- ret);
+ dev_err_probe(&pdev->dev, ret,
+ "devm_snd_soc_register_card() failed\n");
return ret;
}
diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c
index b795b9f66b0e..c8d791f05ae4 100644
--- a/sound/soc/ti/omap-dmic.c
+++ b/sound/soc/ti/omap-dmic.c
@@ -465,10 +465,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
mutex_init(&dmic->mutex);
dmic->fclk = devm_clk_get(dmic->dev, "fck");
- if (IS_ERR(dmic->fclk)) {
- dev_err(dmic->dev, "can't get fck\n");
- return -ENODEV;
- }
+ if (IS_ERR(dmic->fclk))
+ return dev_err_probe(dmic->dev, PTR_ERR(dmic->fclk),
+ "can't get fck\n");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
if (!res) {
diff --git a/sound/soc/ti/omap-hdmi.c b/sound/soc/ti/omap-hdmi.c
index e60f5b483fc5..c3034a8979dd 100644
--- a/sound/soc/ti/omap-hdmi.c
+++ b/sound/soc/ti/omap-hdmi.c
@@ -24,8 +24,6 @@
#define DRV_NAME "omap-hdmi-audio"
struct hdmi_audio_data {
- struct snd_soc_card *card;
-
const struct omap_hdmi_audio_ops *ops;
struct device *dssdev;
struct snd_dmaengine_dai_dma_data dma_data;
@@ -375,12 +373,9 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev)
card->dev = dev;
ret = devm_snd_soc_register_card(dev, card);
- if (ret) {
- dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "snd_soc_register_card() failed\n");
- ad->card = card;
snd_soc_card_set_drvdata(card, ad);
dev_set_drvdata(dev, ad);
diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c
index 4d80f8a7a947..a3ab52b2b64e 100644
--- a/sound/soc/ti/omap-twl4030.c
+++ b/sound/soc/ti/omap-twl4030.c
@@ -17,7 +17,6 @@
*/
#include <linux/platform_device.h>
-#include <linux/platform_data/omap-twl4030.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -29,6 +28,7 @@
#include "omap-mcbsp.h"
struct omap_twl4030 {
+ struct snd_soc_jack_gpio hs_jack_gpio;
struct snd_soc_jack hs_jack;
};
@@ -124,38 +124,18 @@ static struct snd_soc_jack_pin hs_jack_pins[] = {
},
};
-/* Headset jack detection gpios */
-static struct snd_soc_jack_gpio hs_jack_gpios[] = {
- {
- .name = "ti,jack-det",
- .report = SND_JACK_HEADSET,
- .debounce_time = 200,
- },
-};
-
-static inline void twl4030_disconnect_pin(struct snd_soc_dapm_context *dapm,
- int connected, char *pin)
-{
- if (!connected)
- snd_soc_dapm_disable_pin(dapm, pin);
-}
-
static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
- struct omap_tw4030_pdata *pdata = dev_get_platdata(card->dev);
+
struct omap_twl4030 *priv = snd_soc_card_get_drvdata(card);
- int ret = 0;
+ int ret;
/*
* This is a bit of a hack, but the GPIO is optional so we
* only want to add the jack detection if the GPIO is there.
*/
if (of_property_present(card->dev->of_node, "ti,jack-det-gpio")) {
- hs_jack_gpios[0].gpiod_dev = card->dev;
- hs_jack_gpios[0].idx = 0;
-
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
SND_JACK_HEADSET,
&priv->hs_jack, hs_jack_pins,
@@ -163,36 +143,19 @@ static int omap_twl4030_init(struct snd_soc_pcm_runtime *rtd)
if (ret)
return ret;
- ret = snd_soc_jack_add_gpios(&priv->hs_jack,
- ARRAY_SIZE(hs_jack_gpios),
- hs_jack_gpios);
+ priv->hs_jack_gpio.name = "ti,jack-det";
+ priv->hs_jack_gpio.report = SND_JACK_HEADSET;
+ priv->hs_jack_gpio.debounce_time = 200;
+ priv->hs_jack_gpio.gpiod_dev = card->dev;
+ priv->hs_jack_gpio.idx = 0;
+
+ ret = snd_soc_jack_add_gpios(&priv->hs_jack, 1,
+ &priv->hs_jack_gpio);
if (ret)
return ret;
}
- /*
- * NULL pdata means we booted with DT. In this case the routing is
- * provided and the card is fully routed, no need to mark pins.
- */
- if (!pdata || !pdata->custom_routing)
- return ret;
-
- /* Disable not connected paths if not used */
- twl4030_disconnect_pin(dapm, pdata->has_ear, "Earpiece Spk");
- twl4030_disconnect_pin(dapm, pdata->has_hf, "Handsfree Spk");
- twl4030_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
- twl4030_disconnect_pin(dapm, pdata->has_predriv, "Ext Spk");
- twl4030_disconnect_pin(dapm, pdata->has_carkit, "Carkit Spk");
-
- twl4030_disconnect_pin(dapm, pdata->has_mainmic, "Main Mic");
- twl4030_disconnect_pin(dapm, pdata->has_submic, "Sub Mic");
- twl4030_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
- twl4030_disconnect_pin(dapm, pdata->has_carkitmic, "Carkit Mic");
- twl4030_disconnect_pin(dapm, pdata->has_digimic0, "Digital0 Mic");
- twl4030_disconnect_pin(dapm, pdata->has_digimic1, "Digital1 Mic");
- twl4030_disconnect_pin(dapm, pdata->has_linein, "Line In");
-
- return ret;
+ return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
@@ -237,11 +200,15 @@ static struct snd_soc_card omap_twl4030_card = {
static int omap_twl4030_probe(struct platform_device *pdev)
{
- struct omap_tw4030_pdata *pdata = dev_get_platdata(&pdev->dev);
- struct device_node *node = pdev->dev.of_node;
struct snd_soc_card *card = &omap_twl4030_card;
+ struct device_node *node, *dai_node;
struct omap_twl4030 *priv;
- int ret = 0;
+ struct property *prop;
+ int ret;
+
+ node = pdev->dev.of_node;
+ if (!node)
+ return -ENODEV;
card->dev = &pdev->dev;
@@ -249,69 +216,52 @@ static int omap_twl4030_probe(struct platform_device *pdev)
if (priv == NULL)
return -ENOMEM;
- if (node) {
- struct device_node *dai_node;
- struct property *prop;
-
- if (snd_soc_of_parse_card_name(card, "ti,model")) {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
-
- dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
- if (!dai_node) {
- dev_err(&pdev->dev, "McBSP node is not provided\n");
- return -EINVAL;
- }
- omap_twl4030_dai_links[0].cpus->dai_name = NULL;
- omap_twl4030_dai_links[0].cpus->of_node = dai_node;
-
- omap_twl4030_dai_links[0].platforms->name = NULL;
- omap_twl4030_dai_links[0].platforms->of_node = dai_node;
-
- dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
- if (!dai_node) {
- card->num_links = 1;
- } else {
- omap_twl4030_dai_links[1].cpus->dai_name = NULL;
- omap_twl4030_dai_links[1].cpus->of_node = dai_node;
-
- omap_twl4030_dai_links[1].platforms->name = NULL;
- omap_twl4030_dai_links[1].platforms->of_node = dai_node;
- }
-
- /* Optional: audio routing can be provided */
- prop = of_find_property(node, "ti,audio-routing", NULL);
- if (prop) {
- ret = snd_soc_of_parse_audio_routing(card,
- "ti,audio-routing");
- if (ret)
- return ret;
-
- card->fully_routed = 1;
- }
- } else if (pdata) {
- if (pdata->card_name) {
- card->name = pdata->card_name;
- } else {
- dev_err(&pdev->dev, "Card name is not provided\n");
- return -ENODEV;
- }
-
- if (!pdata->voice_connected)
- card->num_links = 1;
- } else {
- dev_err(&pdev->dev, "Missing pdata\n");
+ ret = snd_soc_of_parse_card_name(card, "ti,model");
+ if (ret)
+ return ret;
+
+ if (!card->name) {
+ dev_err(&pdev->dev, "Card name is not provided\n");
return -ENODEV;
}
+ dai_node = of_parse_phandle(node, "ti,mcbsp", 0);
+ if (!dai_node) {
+ dev_err(&pdev->dev, "McBSP node is not provided\n");
+ return -EINVAL;
+ }
+ omap_twl4030_dai_links[0].cpus->dai_name = NULL;
+ omap_twl4030_dai_links[0].cpus->of_node = dai_node;
+
+ omap_twl4030_dai_links[0].platforms->name = NULL;
+ omap_twl4030_dai_links[0].platforms->of_node = dai_node;
+
+ dai_node = of_parse_phandle(node, "ti,mcbsp-voice", 0);
+ if (!dai_node) {
+ card->num_links = 1;
+ } else {
+ omap_twl4030_dai_links[1].cpus->dai_name = NULL;
+ omap_twl4030_dai_links[1].cpus->of_node = dai_node;
+
+ omap_twl4030_dai_links[1].platforms->name = NULL;
+ omap_twl4030_dai_links[1].platforms->of_node = dai_node;
+ }
+
+ /* Optional: audio routing can be provided */
+ prop = of_find_property(node, "ti,audio-routing", NULL);
+ if (prop) {
+ ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+ if (ret)
+ return ret;
+
+ card->fully_routed = 1;
+ }
+
snd_soc_card_set_drvdata(card, priv);
ret = devm_snd_soc_register_card(&pdev->dev, card);
- if (ret) {
- dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "devm_snd_soc_register_card() failed\n");
return 0;
}
diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c
index cfc23e0838c2..b4b26cb0cac5 100644
--- a/sound/soc/ti/rx51.c
+++ b/sound/soc/ti/rx51.c
@@ -358,21 +358,22 @@ static struct snd_soc_card rx51_sound_card = {
static int rx51_soc_probe(struct platform_device *pdev)
{
struct rx51_audio_pdata *pdata;
- struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
struct snd_soc_card *card = &rx51_sound_card;
int err;
if (!of_machine_is_compatible("nokia,omap3-n900"))
return -ENODEV;
- card->dev = &pdev->dev;
+ card->dev = dev;
if (np) {
struct device_node *dai_node;
dai_node = of_parse_phandle(np, "nokia,cpu-dai", 0);
if (!dai_node) {
- dev_err(card->dev, "McBSP node is not provided\n");
+ dev_err(dev, "McBSP node is not provided\n");
return -EINVAL;
}
rx51_dai[0].cpus->dai_name = NULL;
@@ -382,7 +383,7 @@ static int rx51_soc_probe(struct platform_device *pdev)
dai_node = of_parse_phandle(np, "nokia,audio-codec", 0);
if (!dai_node) {
- dev_err(card->dev, "Codec node is not provided\n");
+ dev_err(dev, "Codec node is not provided\n");
return -EINVAL;
}
rx51_dai[0].codecs->name = NULL;
@@ -390,7 +391,7 @@ static int rx51_soc_probe(struct platform_device *pdev)
dai_node = of_parse_phandle(np, "nokia,audio-codec", 1);
if (!dai_node) {
- dev_err(card->dev, "Auxiliary Codec node is not provided\n");
+ dev_err(dev, "Auxiliary Codec node is not provided\n");
return -EINVAL;
}
rx51_aux_dev[0].dlc.name = NULL;
@@ -400,7 +401,7 @@ static int rx51_soc_probe(struct platform_device *pdev)
dai_node = of_parse_phandle(np, "nokia,headphone-amplifier", 0);
if (!dai_node) {
- dev_err(card->dev, "Headphone amplifier node is not provided\n");
+ dev_err(dev, "Headphone amplifier node is not provided\n");
return -EINVAL;
}
rx51_aux_dev[1].dlc.name = NULL;
@@ -409,40 +410,36 @@ static int rx51_soc_probe(struct platform_device *pdev)
rx51_codec_conf[1].dlc.of_node = dai_node;
}
- pdata = devm_kzalloc(card->dev, sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (pdata == NULL)
return -ENOMEM;
snd_soc_card_set_drvdata(card, pdata);
- pdata->tvout_selection_gpio = devm_gpiod_get(card->dev,
+ pdata->tvout_selection_gpio = devm_gpiod_get(dev,
"tvout-selection",
GPIOD_OUT_LOW);
- if (IS_ERR(pdata->tvout_selection_gpio)) {
- dev_err(card->dev, "could not get tvout selection gpio\n");
- return PTR_ERR(pdata->tvout_selection_gpio);
- }
+ if (IS_ERR(pdata->tvout_selection_gpio))
+ return dev_err_probe(dev, PTR_ERR(pdata->tvout_selection_gpio),
+ "could not get tvout selection gpio\n");
- pdata->eci_sw_gpio = devm_gpiod_get(card->dev, "eci-switch",
+ pdata->eci_sw_gpio = devm_gpiod_get(dev, "eci-switch",
GPIOD_OUT_HIGH);
- if (IS_ERR(pdata->eci_sw_gpio)) {
- dev_err(card->dev, "could not get eci switch gpio\n");
- return PTR_ERR(pdata->eci_sw_gpio);
- }
+ if (IS_ERR(pdata->eci_sw_gpio))
+ return dev_err_probe(dev, PTR_ERR(pdata->eci_sw_gpio),
+ "could not get eci switch gpio\n");
- pdata->speaker_amp_gpio = devm_gpiod_get(card->dev,
+ pdata->speaker_amp_gpio = devm_gpiod_get(dev,
"speaker-amplifier",
GPIOD_OUT_LOW);
- if (IS_ERR(pdata->speaker_amp_gpio)) {
- dev_err(card->dev, "could not get speaker enable gpio\n");
- return PTR_ERR(pdata->speaker_amp_gpio);
- }
-
- err = devm_snd_soc_register_card(card->dev, card);
- if (err) {
- dev_err(card->dev, "snd_soc_register_card failed (%d)\n", err);
- return err;
- }
+ if (IS_ERR(pdata->speaker_amp_gpio))
+ return dev_err_probe(dev, PTR_ERR(pdata->speaker_amp_gpio),
+ "could not get speaker enable gpio\n");
+
+ err = devm_snd_soc_register_card(dev, card);
+ if (err)
+ return dev_err_probe(dev, err,
+ "snd_soc_register_card() failed\n");
return 0;
}
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index d3dba21b2d04..78c82bf42a8f 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -795,16 +795,12 @@ int uniphier_aio_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(dev, &uniphier_aio_component,
chip->chip_spec->dais,
chip->chip_spec->num_dais);
- if (ret) {
- dev_err(dev, "Register component failed.\n");
+ if (ret)
goto err_out_reset;
- }
ret = uniphier_aiodma_soc_register_platform(pdev);
- if (ret) {
- dev_err(dev, "Register platform failed.\n");
+ if (ret)
goto err_out_reset;
- }
return 0;
diff --git a/sound/soc/uniphier/aio.h b/sound/soc/uniphier/aio.h
index d9fd61dd976f..1900ea01ce3d 100644
--- a/sound/soc/uniphier/aio.h
+++ b/sound/soc/uniphier/aio.h
@@ -156,7 +156,7 @@ struct uniphier_aio_selector {
int hw;
};
-/**
+/*
* 'SoftWare MAPping' setting of UniPhier AIO registers.
*
* We have to setup 'virtual' register maps to access 'real' registers of AIO.
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index ae6d326167d1..6d196b4b8802 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -68,10 +68,11 @@ static void mop500_of_node_put(void)
of_node_put(mop500_dai_links[0].codecs->of_node);
}
-static int mop500_of_probe(struct platform_device *pdev,
- struct device_node *np)
+static int mop500_of_probe(struct snd_soc_card *card)
{
+ struct device *dev = card->dev;
struct device_node *codec_np, *msp_np[2];
+ struct device_node *np = dev->of_node;
int i;
msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0);
@@ -79,7 +80,7 @@ static int mop500_of_probe(struct platform_device *pdev,
codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0);
if (!(msp_np[0] && msp_np[1] && codec_np)) {
- dev_err(&pdev->dev, "Phandle missing or invalid\n");
+ dev_err(dev, "Phandle missing or invalid\n");
for (i = 0; i < 2; i++)
of_node_put(msp_np[i]);
of_node_put(codec_np);
@@ -95,21 +96,20 @@ static int mop500_of_probe(struct platform_device *pdev,
mop500_dai_links[i].codecs->name = NULL;
}
- snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name");
+ snd_soc_of_parse_card_name(card, "stericsson,card-name");
return 0;
}
static int mop500_probe(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node;
int ret;
dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
mop500_card.dev = &pdev->dev;
- ret = mop500_of_probe(pdev, np);
+ ret = mop500_of_probe(&mop500_card);
if (ret)
return ret;
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c
index 2a459267f0f9..feb683c55d11 100644
--- a/sound/soc/ux500/mop500_ab8500.c
+++ b/sound/soc/ux500/mop500_ab8500.c
@@ -433,5 +433,5 @@ void mop500_ab8500_remove(struct snd_soc_card *card)
clk_put(drvdata->clk_ptr_ulpclk);
clk_put(drvdata->clk_ptr_intclk);
- snd_soc_card_set_drvdata(card, drvdata);
+ snd_soc_card_set_drvdata(card, NULL);
}
diff --git a/sound/soc/xilinx/xlnx_formatter_pcm.c b/sound/soc/xilinx/xlnx_formatter_pcm.c
index f15336197ed3..95312b4ddc5b 100644
--- a/sound/soc/xilinx/xlnx_formatter_pcm.c
+++ b/sound/soc/xilinx/xlnx_formatter_pcm.c
@@ -9,8 +9,6 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
#include <linux/sizes.h>
#include <sound/asoundef.h>
@@ -384,7 +382,7 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
if (err) {
dev_err(component->dev,
"Unable to set constraint on period bytes\n");
- return err;
+ goto error;
}
/* Resize the buffer bytes as divisible by 64 */
@@ -394,7 +392,7 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
if (err) {
dev_err(component->dev,
"Unable to set constraint on buffer bytes\n");
- return err;
+ goto error;
}
/* Set periods as integer multiple */
@@ -403,7 +401,7 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
if (err < 0) {
dev_err(component->dev,
"Unable to set constraint on periods to be integer\n");
- return err;
+ goto error;
}
/* enable DMA IOC irq */
@@ -412,6 +410,14 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
writel(val, stream_data->mmio + XLNX_AUD_CTRL);
return 0;
+
+error:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ adata->play_stream = NULL;
+ else
+ adata->capture_stream = NULL;
+ kfree(stream_data);
+ return err;
}
static int xlnx_formatter_pcm_close(struct snd_soc_component *component,
diff --git a/sound/soc/xilinx/xlnx_i2s.c b/sound/soc/xilinx/xlnx_i2s.c
index ca915a001ad5..273258125497 100644
--- a/sound/soc/xilinx/xlnx_i2s.c
+++ b/sound/soc/xilinx/xlnx_i2s.c
@@ -9,9 +9,8 @@
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -174,7 +173,6 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
int ret;
u32 format;
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
@@ -184,18 +182,16 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
if (IS_ERR(drv_data->base))
return PTR_ERR(drv_data->base);
- ret = of_property_read_u32(node, "xlnx,num-channels", &drv_data->channels);
- if (ret < 0) {
- dev_err(dev, "cannot get supported channels\n");
- return ret;
- }
+ ret = device_property_read_u32(dev, "xlnx,num-channels", &drv_data->channels);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get supported channels\n");
+
drv_data->channels *= 2;
- ret = of_property_read_u32(node, "xlnx,dwidth", &drv_data->data_width);
- if (ret < 0) {
- dev_err(dev, "cannot get data width\n");
- return ret;
- }
+ ret = device_property_read_u32(dev, "xlnx,dwidth", &drv_data->data_width);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get data width\n");
+
switch (drv_data->data_width) {
case 16:
format = SNDRV_PCM_FMTBIT_S16_LE;
@@ -207,7 +203,7 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (of_device_is_compatible(node, "xlnx,i2s-transmitter-1.0")) {
+ if (device_is_compatible(dev, "xlnx,i2s-transmitter-1.0")) {
drv_data->dai_drv.name = "xlnx_i2s_playback";
drv_data->dai_drv.playback.stream_name = "Playback";
drv_data->dai_drv.playback.formats = format;
@@ -215,7 +211,7 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
drv_data->dai_drv.playback.channels_max = drv_data->channels;
drv_data->dai_drv.playback.rates = SNDRV_PCM_RATE_8000_192000;
drv_data->dai_drv.ops = &xlnx_i2s_dai_ops;
- } else if (of_device_is_compatible(node, "xlnx,i2s-receiver-1.0")) {
+ } else if (device_is_compatible(dev, "xlnx,i2s-receiver-1.0")) {
drv_data->dai_drv.name = "xlnx_i2s_capture";
drv_data->dai_drv.capture.stream_name = "Capture";
drv_data->dai_drv.capture.formats = format;
@@ -233,10 +229,8 @@ static int xlnx_i2s_probe(struct platform_device *pdev)
ret = devm_snd_soc_register_component(&pdev->dev, &xlnx_i2s_component,
&drv_data->dai_drv, 1);
- if (ret) {
- dev_err(&pdev->dev, "i2s component registration failed\n");
+ if (ret)
return ret;
- }
dev_info(&pdev->dev, "%s DAI registered\n", drv_data->dai_drv.name);
diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c
index 017a64ab9f1e..a70ca6beb646 100644
--- a/sound/soc/xilinx/xlnx_spdif.c
+++ b/sound/soc/xilinx/xlnx_spdif.c
@@ -10,8 +10,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/property.h>
#include <linux/platform_device.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -242,28 +241,24 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
struct spdif_dev_data *ctx;
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->axi_clk = devm_clk_get_enabled(dev, "s_axi_aclk");
- if (IS_ERR(ctx->axi_clk)) {
- ret = PTR_ERR(ctx->axi_clk);
- dev_err(dev, "failed to get s_axi_aclk(%d)\n", ret);
- return ret;
- }
+ if (IS_ERR(ctx->axi_clk))
+ return dev_err_probe(dev, PTR_ERR(ctx->axi_clk),
+ "failed to get s_axi_aclk\n");
ctx->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ctx->base))
return PTR_ERR(ctx->base);
- ret = of_property_read_u32(node, "xlnx,spdif-mode", &ctx->mode);
- if (ret < 0) {
- dev_err(dev, "cannot get SPDIF mode\n");
- return ret;
- }
+ ret = device_property_read_u32(dev, "xlnx,spdif-mode", &ctx->mode);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get SPDIF mode\n");
+
if (ctx->mode) {
dai_drv = &xlnx_spdif_tx_dai;
} else {
@@ -274,29 +269,23 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, ret,
xlnx_spdifrx_irq_handler,
0, "XLNX_SPDIF_RX", ctx);
- if (ret) {
- dev_err(dev, "spdif rx irq request failed\n");
- return -ENODEV;
- }
+ if (ret)
+ return ret;
init_waitqueue_head(&ctx->chsts_q);
dai_drv = &xlnx_spdif_rx_dai;
}
- ret = of_property_read_u32(node, "xlnx,aud_clk_i", &ctx->aclk);
- if (ret < 0) {
- dev_err(dev, "cannot get aud_clk_i value\n");
- return ret;
- }
+ ret = device_property_read_u32(dev, "xlnx,aud_clk_i", &ctx->aclk);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot get aud_clk_i value\n");
dev_set_drvdata(dev, ctx);
ret = devm_snd_soc_register_component(dev, &xlnx_spdif_component,
dai_drv, 1);
- if (ret) {
- dev_err(dev, "SPDIF component registration failed\n");
+ if (ret)
return ret;
- }
writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG);
dev_info(dev, "%s DAI registered\n", dai_drv->name);
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index 9ad86c54e3ea..fd0990201b40 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -533,34 +533,25 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
int err, irq;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
- if (!i2s) {
- err = -ENOMEM;
- goto err;
- }
+ if (!i2s)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, i2s);
i2s->dev = &pdev->dev;
dev_dbg(&pdev->dev, "dev: %p, i2s: %p\n", &pdev->dev, i2s);
i2s->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(i2s->regs)) {
- err = PTR_ERR(i2s->regs);
- goto err;
- }
+ if (IS_ERR(i2s->regs))
+ return PTR_ERR(i2s->regs);
i2s->regmap = devm_regmap_init_mmio(&pdev->dev, i2s->regs,
&xtfpga_i2s_regmap_config);
- if (IS_ERR(i2s->regmap)) {
- dev_err(&pdev->dev, "regmap init failed\n");
- err = PTR_ERR(i2s->regmap);
- goto err;
- }
+ if (IS_ERR(i2s->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->regmap), "regmap init failed\n");
i2s->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2s->clk)) {
- dev_err(&pdev->dev, "couldn't get clock\n");
- err = PTR_ERR(i2s->clk);
- goto err;
- }
+ if (IS_ERR(i2s->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(i2s->clk), "couldn't get clock\n");
regmap_write(i2s->regmap, XTFPGA_I2S_CONFIG,
(0x1 << XTFPGA_I2S_CONFIG_CHANNEL_BASE));
@@ -568,41 +559,34 @@ static int xtfpga_i2s_probe(struct platform_device *pdev)
regmap_write(i2s->regmap, XTFPGA_I2S_INT_MASK, XTFPGA_I2S_INT_UNDERRUN);
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- err = irq;
- goto err;
- }
+ if (irq < 0)
+ return irq;
+
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
xtfpga_i2s_threaded_irq_handler,
IRQF_SHARED | IRQF_ONESHOT,
pdev->name, i2s);
- if (err < 0) {
- dev_err(&pdev->dev, "request_irq failed\n");
- goto err;
- }
+ if (err < 0)
+ return err;
err = devm_snd_soc_register_component(&pdev->dev,
&xtfpga_i2s_component,
xtfpga_i2s_dai,
ARRAY_SIZE(xtfpga_i2s_dai));
- if (err < 0) {
- dev_err(&pdev->dev, "couldn't register component\n");
- goto err;
- }
+ if (err < 0)
+ return err;
+
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
err = xtfpga_i2s_runtime_resume(&pdev->dev);
- if (err)
- goto err_pm_disable;
+ if (err) {
+ pm_runtime_disable(&pdev->dev);
+ return err;
+ }
}
- return 0;
-err_pm_disable:
- pm_runtime_disable(&pdev->dev);
-err:
- dev_err(&pdev->dev, "%s: err = %d\n", __func__, err);
- return err;
+ return 0;
}
static void xtfpga_i2s_remove(struct platform_device *pdev)
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 2f5f62079fa4..ccaa36525f8d 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -1840,6 +1840,7 @@ static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x)
int rval = D_INTR_GETRVAL(x);
#endif
+#ifdef DBRI_DEBUG
if (channel == D_INTR_CMD) {
dprintk(D_CMD, "INTR: Command: %-5s Value:%d\n",
cmds[command], val);
@@ -1847,6 +1848,7 @@ static void dbri_process_one_interrupt(struct snd_dbri *dbri, int x)
dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n",
channel, code, rval);
}
+#endif
switch (code) {
case D_INTR_CMDI:
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
index 9a0b85653c61..d3b7cab85699 100644
--- a/sound/usb/6fire/comm.c
+++ b/sound/usb/6fire/comm.c
@@ -36,11 +36,14 @@ static void usb6fire_comm_receiver_handler(struct urb *urb)
struct midi_runtime *midi_rt = rt->chip->midi;
if (!urb->status) {
- if (rt->receiver_buffer[0] == 0x10) /* midi in event */
+ u8 len = rt->receiver_buffer[1];
+
+ if (rt->receiver_buffer[0] == 0x10 && /* midi in event */
+ len <= COMM_RECEIVER_BUFSIZE - 2 &&
+ urb->actual_length >= len + 2)
if (midi_rt)
midi_rt->in_received(midi_rt,
- rt->receiver_buffer + 2,
- rt->receiver_buffer[1]);
+ rt->receiver_buffer + 2, len);
}
if (!rt->chip->shutdown) {
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 123c1c6539b8..d9dd8f44b047 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -194,23 +194,20 @@ static int usb6fire_fw_ezusb_upload(
int ret;
u8 data;
struct usb_device *device = interface_to_usbdev(intf);
- const struct firmware *fw = NULL;
- struct ihex_record *rec = kmalloc_obj(struct ihex_record);
+ struct ihex_record *rec __free(kfree) = kmalloc_obj(struct ihex_record);
if (!rec)
return -ENOMEM;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
- kfree(rec);
dev_err(&intf->dev,
"error requesting ezusb firmware %s.\n", fwname);
return ret;
}
ret = usb6fire_fw_ihex_init(fw, rec);
if (ret < 0) {
- kfree(rec);
- release_firmware(fw);
dev_err(&intf->dev,
"error validating ezusb firmware %s.\n", fwname);
return ret;
@@ -219,8 +216,6 @@ static int usb6fire_fw_ezusb_upload(
data = 0x01; /* stop ezusb cpu */
ret = usb6fire_fw_ezusb_write(device, 0xa0, 0xe600, &data, 1);
if (ret) {
- kfree(rec);
- release_firmware(fw);
dev_err(&intf->dev,
"unable to upload ezusb firmware %s: begin message.\n",
fwname);
@@ -231,8 +226,6 @@ static int usb6fire_fw_ezusb_upload(
ret = usb6fire_fw_ezusb_write(device, 0xa0, rec->address,
rec->data, rec->len);
if (ret) {
- kfree(rec);
- release_firmware(fw);
dev_err(&intf->dev,
"unable to upload ezusb firmware %s: data urb.\n",
fwname);
@@ -240,8 +233,6 @@ static int usb6fire_fw_ezusb_upload(
}
}
- release_firmware(fw);
- kfree(rec);
if (postdata) { /* write data after firmware has been uploaded */
ret = usb6fire_fw_ezusb_write(device, 0xa0, postaddr,
postdata, postlen);
@@ -270,19 +261,18 @@ static int usb6fire_fw_fpga_upload(
int ret;
int i;
struct usb_device *device = interface_to_usbdev(intf);
- u8 *buffer = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
+ u8 *buffer __free(kfree) = kmalloc(FPGA_BUFSIZE, GFP_KERNEL);
const char *c;
const char *end;
- const struct firmware *fw;
if (!buffer)
return -ENOMEM;
+ const struct firmware *fw __free(firmware) = NULL;
ret = request_firmware(&fw, fwname, &device->dev);
if (ret < 0) {
dev_err(&intf->dev, "unable to get fpga firmware %s.\n",
fwname);
- kfree(buffer);
return -EIO;
}
@@ -291,8 +281,6 @@ static int usb6fire_fw_fpga_upload(
ret = usb6fire_fw_ezusb_write(device, 8, 0, NULL, 0);
if (ret) {
- kfree(buffer);
- release_firmware(fw);
dev_err(&intf->dev,
"unable to upload fpga firmware: begin urb.\n");
return ret;
@@ -304,15 +292,11 @@ static int usb6fire_fw_fpga_upload(
ret = usb6fire_fw_fpga_write(device, buffer, i);
if (ret < 0) {
- release_firmware(fw);
- kfree(buffer);
dev_err(&intf->dev,
"unable to upload fpga firmware: fw urb.\n");
return ret;
}
}
- release_firmware(fw);
- kfree(buffer);
ret = usb6fire_fw_ezusb_write(device, 9, 0, NULL, 0);
if (ret) {
diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c
index bebb48cb9abc..c5c542d17ccc 100644
--- a/sound/usb/bcd2000/bcd2000.c
+++ b/sound/usb/bcd2000/bcd2000.c
@@ -134,6 +134,9 @@ static void bcd2000_midi_send(struct bcd2000 *bcd2k)
if (!midi_out_substream)
return;
+ if (!bcd2k->midi_out_urb)
+ return;
+
/* copy command prefix bytes */
memcpy(bcd2k->midi_out_buf, device_cmd_prefix,
sizeof(device_cmd_prefix));
@@ -178,7 +181,7 @@ static int bcd2000_midi_output_close(struct snd_rawmidi_substream *substream)
{
struct bcd2000 *bcd2k = substream->rmidi->private_data;
- if (bcd2k->midi_out_active) {
+ if (bcd2k->midi_out_active && bcd2k->midi_out_urb) {
usb_kill_urb(bcd2k->midi_out_urb);
bcd2k->midi_out_active = 0;
}
@@ -348,11 +351,13 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k)
static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k,
struct usb_interface *interface)
{
- usb_kill_urb(bcd2k->midi_out_urb);
- usb_kill_urb(bcd2k->midi_in_urb);
+ usb_poison_urb(bcd2k->midi_out_urb);
+ usb_poison_urb(bcd2k->midi_in_urb);
usb_free_urb(bcd2k->midi_out_urb);
usb_free_urb(bcd2k->midi_in_urb);
+ bcd2k->midi_out_urb = NULL;
+ bcd2k->midi_in_urb = NULL;
if (bcd2k->intf) {
usb_set_intfdata(bcd2k->intf, NULL);
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 6a3b576fb067..24112e491779 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -715,7 +715,7 @@ static void snd_usb_init_quirk_flags(int idx, struct snd_usb_audio *chip)
/* old style option found: the position-based integer value */
if (quirk_flags[idx] &&
- !kstrtou32(quirk_flags[idx], 0, &chip->quirk_flags)) {
+ !kstrtou64(quirk_flags[idx], 0, &chip->quirk_flags)) {
snd_usb_apply_flag_dbg("module param", chip, chip->quirk_flags);
return;
}
@@ -905,6 +905,40 @@ static int try_to_register_card(struct snd_usb_audio *chip, int ifnum)
return 0;
}
+static void usb_audio_disconnect_components(struct snd_usb_audio *chip)
+{
+ struct snd_usb_stream *as;
+ struct snd_usb_endpoint *ep;
+ struct usb_mixer_interface *mixer;
+ struct list_head *p;
+
+ /* release the pcm resources */
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ snd_usb_stream_disconnect(as);
+ }
+ /* release the endpoint resources */
+ list_for_each_entry(ep, &chip->ep_list, list) {
+ snd_usb_endpoint_release(ep);
+ }
+ /* release the midi resources */
+ list_for_each(p, &chip->midi_list) {
+ snd_usbmidi_disconnect(p);
+ }
+ snd_usb_midi_v2_disconnect_all(chip);
+ /*
+ * Nice to check quirk && quirk->shares_media_device and
+ * then call the snd_media_device_delete(). Don't have
+ * access to the quirk here. snd_media_device_delete()
+ * accesses mixer_list
+ */
+ snd_media_device_delete(chip);
+
+ /* release mixer resources */
+ list_for_each_entry(mixer, &chip->mixer_list, list) {
+ snd_usb_mixer_disconnect(mixer);
+ }
+}
+
/*
* probe the active usb device
*
@@ -1077,8 +1111,10 @@ static int usb_audio_probe(struct usb_interface *intf,
* decrement before memory is possibly returned.
*/
atomic_dec(&chip->active);
- if (!chip->num_interfaces)
+ if (!chip->num_interfaces) {
+ usb_audio_disconnect_components(chip);
snd_card_free(chip->card);
+ }
}
return err;
}
@@ -1091,48 +1127,18 @@ static bool __usb_audio_disconnect(struct usb_interface *intf,
struct snd_usb_audio *chip,
struct snd_card *card)
{
- struct list_head *p;
-
guard(mutex)(&register_mutex);
if (platform_ops && platform_ops->disconnect_cb)
platform_ops->disconnect_cb(chip);
if (atomic_inc_return(&chip->shutdown) == 1) {
- struct snd_usb_stream *as;
- struct snd_usb_endpoint *ep;
- struct usb_mixer_interface *mixer;
-
/* wait until all pending tasks done;
* they are protected by snd_usb_lock_shutdown()
*/
snd_refcount_sync(&chip->usage_count);
snd_card_disconnect(card);
- /* release the pcm resources */
- list_for_each_entry(as, &chip->pcm_list, list) {
- snd_usb_stream_disconnect(as);
- }
- /* release the endpoint resources */
- list_for_each_entry(ep, &chip->ep_list, list) {
- snd_usb_endpoint_release(ep);
- }
- /* release the midi resources */
- list_for_each(p, &chip->midi_list) {
- snd_usbmidi_disconnect(p);
- }
- snd_usb_midi_v2_disconnect_all(chip);
- /*
- * Nice to check quirk && quirk->shares_media_device and
- * then call the snd_media_device_delete(). Don't have
- * access to the quirk here. snd_media_device_delete()
- * accesses mixer_list
- */
- snd_media_device_delete(chip);
-
- /* release mixer resources */
- list_for_each_entry(mixer, &chip->mixer_list, list) {
- snd_usb_mixer_disconnect(mixer);
- }
+ usb_audio_disconnect_components(chip);
}
if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND)
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 2e0c18e35281..34832183a1f0 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -600,7 +600,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
const struct audioformat *fmt, int rate)
{
- int cur_rate, prev_rate;
+ int cur_rate, prev_rate = 0;
int clock;
/* First, try to find a valid clock. This may trigger
@@ -625,9 +625,12 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip,
return clock;
}
- prev_rate = get_sample_rate_v2v3(chip, fmt->iface, fmt->altsetting, clock);
- if (prev_rate == rate)
- goto validation;
+ if (!(chip->quirk_flags & QUIRK_FLAG_ALWAYS_SET_RATE)) {
+ prev_rate = get_sample_rate_v2v3(chip, fmt->iface,
+ fmt->altsetting, clock);
+ if (prev_rate == rate)
+ goto validation;
+ }
cur_rate = snd_usb_set_sample_rate_v2v3(chip, fmt, clock, rate);
if (cur_rate < 0) {
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index a1d449f2a342..0835943d7b0e 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -1236,7 +1236,10 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
/* try to use enough URBs to contain an entire ALSA buffer */
max_urbs = min((unsigned) MAX_URBS,
MAX_QUEUE * packs_per_ms / urb_packs);
- ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
+ if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP)
+ ep->nurbs = MAX_URBS;
+ else
+ ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods);
}
/* allocate and initialize data urbs */
@@ -1260,6 +1263,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep)
goto out_of_memory;
u->urb->pipe = ep->pipe;
u->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ if (chip->quirk_flags & QUIRK_FLAG_PLAYBACK_URB_FIXUP)
+ u->urb->transfer_flags |= URB_ISO_ASAP;
u->urb->interval = 1 << ep->datainterval;
u->urb->context = u;
u->urb->complete = snd_complete_urb;
diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c
index 2bf572c6fdc4..5fc2131b4561 100644
--- a/sound/usb/fcp.c
+++ b/sound/usb/fcp.c
@@ -82,6 +82,7 @@ struct fcp_data {
struct mutex mutex; /* serialise access to the device */
struct completion cmd_done; /* wait for command completion */
struct file *file; /* hwdep file */
+ struct urb *urb; /* FCP notification endpoint */
struct fcp_notify notify;
@@ -190,7 +191,7 @@ static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode,
const int max_retries = 5;
int err;
- if (!mixer->urb)
+ if (!private->urb)
return -ENODEV;
struct fcp_usb_packet *req __free(kfree) = NULL;
@@ -305,7 +306,7 @@ static int fcp_reinit(struct usb_mixer_interface *mixer)
{
struct fcp_data *private = mixer->private_data;
- if (mixer->urb)
+ if (private->urb)
return 0;
void *step0_resp __free(kfree) =
@@ -493,7 +494,7 @@ static int fcp_ioctl_init(struct usb_mixer_interface *mixer,
buf_size = init.step0_resp_size + init.step2_resp_size;
void *resp __free(kfree) =
- kmalloc(buf_size, GFP_KERNEL);
+ kzalloc(buf_size, GFP_KERNEL);
if (!resp)
return -ENOMEM;
@@ -901,13 +902,15 @@ static int fcp_hwdep_init(struct usb_mixer_interface *mixer)
static void fcp_cleanup_urb(struct usb_mixer_interface *mixer)
{
- if (!mixer->urb)
+ struct fcp_data *private = mixer->private_data;
+
+ if (!private->urb)
return;
- usb_kill_urb(mixer->urb);
- kfree(mixer->urb->transfer_buffer);
- usb_free_urb(mixer->urb);
- mixer->urb = NULL;
+ usb_kill_urb(private->urb);
+ kfree(private->urb->transfer_buffer);
+ usb_free_urb(private->urb);
+ private->urb = NULL;
}
static void fcp_private_free(struct usb_mixer_interface *mixer)
@@ -978,37 +981,37 @@ static int fcp_init_notify(struct usb_mixer_interface *mixer)
int err;
/* Already set up */
- if (mixer->urb)
+ if (private->urb)
return 0;
if (usb_pipe_type_check(dev, pipe))
return -EINVAL;
- mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!mixer->urb)
+ private->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!private->urb)
return -ENOMEM;
transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
if (!transfer_buffer) {
- usb_free_urb(mixer->urb);
- mixer->urb = NULL;
+ usb_free_urb(private->urb);
+ private->urb = NULL;
return -ENOMEM;
}
- usb_fill_int_urb(mixer->urb, dev, pipe,
+ usb_fill_int_urb(private->urb, dev, pipe,
transfer_buffer, private->wMaxPacketSize,
fcp_notify, mixer, private->bInterval);
- init_completion(&private->cmd_done);
+ reinit_completion(&private->cmd_done);
- err = usb_submit_urb(mixer->urb, GFP_KERNEL);
+ err = usb_submit_urb(private->urb, GFP_KERNEL);
if (err) {
usb_audio_err(mixer->chip,
"%s: usb_submit_urb failed: %d\n",
__func__, err);
kfree(transfer_buffer);
- usb_free_urb(mixer->urb);
- mixer->urb = NULL;
+ usb_free_urb(private->urb);
+ private->urb = NULL;
}
return err;
@@ -1030,6 +1033,8 @@ static int fcp_init(struct usb_mixer_interface *mixer,
step0_resp, private->step0_resp_size);
if (err < 0)
return err;
+ if (err != private->step0_resp_size)
+ return -EIO;
err = fcp_init_notify(mixer);
if (err < 0)
@@ -1059,6 +1064,7 @@ static int fcp_init_private(struct usb_mixer_interface *mixer)
return -ENOMEM;
mutex_init(&private->mutex);
+ init_completion(&private->cmd_done);
init_waitqueue_head(&private->notify.queue);
spin_lock_init(&private->notify.lock);
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 703c118f9d4e..5de182181ede 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -3935,6 +3935,12 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer)
struct usb_mixer_elem_list *list;
int id, err;
+ if (mixer->private_resume) {
+ err = mixer->private_resume(mixer);
+ if (err < 0)
+ return err;
+ }
+
/* restore cached mixer values */
for (id = 0; id < MAX_ID_ELEMS; id++) {
for_each_mixer_elem(list, mixer, id) {
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3fa1bd96f858..037b446d8b6f 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -18,6 +18,7 @@ struct usb_mixer_interface {
struct usb_host_interface *hostif;
struct list_head list;
unsigned int ignore_ctl_error;
+ /* UAC2 status interrupt endpoint; owned by mixer.c */
struct urb *urb;
/* array[MAX_ID_ELEMS], indexed by unit id */
struct usb_mixer_elem_list **id_elems;
@@ -42,6 +43,7 @@ struct usb_mixer_interface {
void *private_data;
void (*private_free)(struct usb_mixer_interface *mixer);
void (*private_suspend)(struct usb_mixer_interface *mixer);
+ int (*private_resume)(struct usb_mixer_interface *mixer);
};
#define MAX_CHANNELS 64 /* max logical channels */
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index ce27fc871f51..8046d5987d5b 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -505,6 +505,19 @@ static const struct usbmix_connector_map gigabyte_b450_connector_map[] = {
{}
};
+/* Audient iD14: FU 12 advertises Volume on only 4 of its 6 logical channels
+ * and sits on the monitor mixer branch, but it is traced through to the
+ * Speaker output terminal and gets named "Speaker Playback Volume". Userspace
+ * then adopts it as the stream's hardware volume, and any setting below 0 dB
+ * attenuates some channels but not others (20 dB imbalance at 80%). Give it a
+ * non-standard name so that it is no longer taken for the stream's master
+ * volume, while remaining reachable for anyone who wants the monitor gain.
+ */
+static const struct usbmix_name_map audient_id14_map[] = {
+ { 12, "Monitor Mix Playback" }, /* FU, partial coverage */
+ {}
+};
+
/*
* Control map entries
*/
@@ -589,6 +602,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
.map = maya44_map,
},
{
+ /* Audient iD14 */
+ .id = USB_ID(0x2708, 0x0008),
+ .map = audient_id14_map,
+ },
+ {
/* KEF X300A */
.id = USB_ID(0x27ac, 0x1000),
.map = scms_usb3318_map,
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 74d26fd86efb..a1f5592cc5d5 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -3920,6 +3920,7 @@ static int snd_rme_digiface_controls_create(struct usb_mixer_interface *mixer)
#define SND_DJM_450_IDX 0x5
#define SND_DJM_A9_IDX 0x6
#define SND_DJM_V10_IDX 0x7
+#define SND_DJM_S11_IDX 0x8
#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
.name = _name, \
@@ -4260,6 +4261,21 @@ static const struct snd_djm_ctl snd_djm_ctls_v10[] = {
// playback channels are fixed and controlled by hardware knobs on the mixer
};
+// DJM-S11
+static const u16 snd_djm_opts_s11_cap1[] = {
+ 0x0100, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d };
+static const u16 snd_djm_opts_s11_cap2[] = {
+ 0x0200, 0x0203, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d };
+static const u16 snd_djm_opts_s11_cap3[] = {
+ 0x0307, 0x0308, 0x0309, 0x030a, 0x030d, 0x0311, 0x0312 };
+
+static const struct snd_djm_ctl snd_djm_ctls_s11[] = {
+ SND_DJM_CTL("Master Input Level Capture Switch", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+ SND_DJM_CTL("Input 1 Capture Switch", s11_cap1, 1, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Input 2 Capture Switch", s11_cap2, 1, SND_DJM_WINDEX_CAP),
+ SND_DJM_CTL("Input 3 Capture Switch", s11_cap3, 3, SND_DJM_WINDEX_CAP)
+};
+
static const struct snd_djm_device snd_djm_devices[] = {
[SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2),
[SND_DJM_750_IDX] = SND_DJM_DEVICE(750),
@@ -4269,6 +4285,7 @@ static const struct snd_djm_device snd_djm_devices[] = {
[SND_DJM_450_IDX] = SND_DJM_DEVICE(450),
[SND_DJM_A9_IDX] = SND_DJM_DEVICE(a9),
[SND_DJM_V10_IDX] = SND_DJM_DEVICE(v10),
+ [SND_DJM_S11_IDX] = SND_DJM_DEVICE(s11),
};
static int snd_djm_controls_info(struct snd_kcontrol *kctl,
@@ -4573,6 +4590,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x2b73, 0x0034): /* Pioneer DJ DJM-V10 */
err = snd_djm_controls_create(mixer, SND_DJM_V10_IDX);
break;
+ case USB_ID(0x2b73, 0x0037): /* Pioneer DJ DJM-S11 */
+ err = snd_djm_controls_create(mixer, SND_DJM_S11_IDX);
+ break;
case USB_ID(0x03f0, 0x0269): /* HP TB Dock G2 */
err = hp_dock_mixer_create(mixer);
break;
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index 78fb72e626ca..502854cc9f9f 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -1403,6 +1403,7 @@ struct scarlett2_data {
struct usb_mixer_interface *mixer;
struct mutex usb_mutex; /* prevent sending concurrent USB requests */
struct completion cmd_done;
+ struct urb *urb; /* notification endpoint */
struct mutex data_mutex; /* lock access to this data */
u8 running;
u8 hwdep_in_use;
@@ -8565,13 +8566,70 @@ requeue:
}
}
-/*** Cleanup/Suspend Callbacks ***/
+/*** Notification URB and Cleanup/Suspend Callbacks ***/
+
+/* Submit a URB to receive notifications from the device */
+static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
+{
+ struct usb_device *dev = mixer->chip->dev;
+ struct scarlett2_data *private = mixer->private_data;
+ unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
+ void *transfer_buffer;
+ int err;
+
+ /* Already set up */
+ if (private->urb)
+ return 0;
+
+ if (usb_pipe_type_check(dev, pipe))
+ return -EINVAL;
+
+ private->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!private->urb)
+ return -ENOMEM;
+
+ transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
+ if (!transfer_buffer) {
+ usb_free_urb(private->urb);
+ private->urb = NULL;
+ return -ENOMEM;
+ }
+
+ usb_fill_int_urb(private->urb, dev, pipe,
+ transfer_buffer, private->wMaxPacketSize,
+ scarlett2_notify, mixer, private->bInterval);
+
+ reinit_completion(&private->cmd_done);
+
+ err = usb_submit_urb(private->urb, GFP_KERNEL);
+ if (err) {
+ kfree(transfer_buffer);
+ usb_free_urb(private->urb);
+ private->urb = NULL;
+ }
+
+ return err;
+}
+
+static void scarlett2_cleanup_urb(struct usb_mixer_interface *mixer)
+{
+ struct scarlett2_data *private = mixer->private_data;
+
+ if (!private->urb)
+ return;
+
+ usb_kill_urb(private->urb);
+ kfree(private->urb->transfer_buffer);
+ usb_free_urb(private->urb);
+ private->urb = NULL;
+}
static void scarlett2_private_free(struct usb_mixer_interface *mixer)
{
struct scarlett2_data *private = mixer->private_data;
cancel_delayed_work_sync(&private->work);
+ scarlett2_cleanup_urb(mixer);
kfree(private);
mixer->private_data = NULL;
}
@@ -8582,6 +8640,8 @@ static void scarlett2_private_suspend(struct usb_mixer_interface *mixer)
if (cancel_delayed_work_sync(&private->work))
scarlett2_config_save(private->mixer);
+
+ scarlett2_cleanup_urb(mixer);
}
/*** Initialisation ***/
@@ -8701,11 +8761,13 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer,
mutex_init(&private->usb_mutex);
mutex_init(&private->data_mutex);
+ init_completion(&private->cmd_done);
INIT_DELAYED_WORK(&private->work, scarlett2_config_save_work);
mixer->private_data = private;
mixer->private_free = scarlett2_private_free;
mixer->private_suspend = scarlett2_private_suspend;
+ mixer->private_resume = scarlett2_init_notify;
private->info = entry->info;
@@ -8722,40 +8784,6 @@ static int scarlett2_init_private(struct usb_mixer_interface *mixer,
return scarlett2_find_fc_interface(mixer->chip->dev, private);
}
-/* Submit a URB to receive notifications from the device */
-static int scarlett2_init_notify(struct usb_mixer_interface *mixer)
-{
- struct usb_device *dev = mixer->chip->dev;
- struct scarlett2_data *private = mixer->private_data;
- unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
- void *transfer_buffer;
-
- if (mixer->urb) {
- usb_audio_err(mixer->chip,
- "%s: mixer urb already in use!\n", __func__);
- return 0;
- }
-
- if (usb_pipe_type_check(dev, pipe))
- return -EINVAL;
-
- mixer->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!mixer->urb)
- return -ENOMEM;
-
- transfer_buffer = kmalloc(private->wMaxPacketSize, GFP_KERNEL);
- if (!transfer_buffer)
- return -ENOMEM;
-
- usb_fill_int_urb(mixer->urb, dev, pipe,
- transfer_buffer, private->wMaxPacketSize,
- scarlett2_notify, mixer, private->bInterval);
-
- init_completion(&private->cmd_done);
-
- return usb_submit_urb(mixer->urb, GFP_KERNEL);
-}
-
/* Cargo cult proprietary initialisation sequence */
static int scarlett2_usb_init(struct usb_mixer_interface *mixer)
{
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 71444c2898b4..0a3d39b8385b 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2692,6 +2692,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
{
QUIRK_DATA_AUDIOFORMAT(2) {
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .fmt_bits = 24,
.channels = 2,
.iface = 2,
.altsetting = 1,
@@ -2703,11 +2704,16 @@ YAMAHA_DEVICE(0x7010, "UB99"),
SNDRV_PCM_RATE_48000,
.rate_min = 44100,
.rate_max = 48000,
+ .nr_rates = 2,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000
+ },
}
},
{
QUIRK_DATA_AUDIOFORMAT(3) {
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .fmt_bits = 24,
.channels = 2,
.iface = 3,
.altsetting = 1,
@@ -2719,6 +2725,10 @@ YAMAHA_DEVICE(0x7010, "UB99"),
SNDRV_PCM_RATE_48000,
.rate_min = 44100,
.rate_max = 48000,
+ .nr_rates = 2,
+ .rate_table = (unsigned int[]) {
+ 44100, 48000
+ },
}
},
QUIRK_COMPOSITE_END
@@ -3310,6 +3320,73 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+{
+ /*
+ * Pioneer DJ / AlphaTheta DJM-S11
+ */
+ USB_DEVICE(0x2b73, 0x0037),
+ QUIRK_DRIVER_INFO {
+ QUIRK_DATA_COMPOSITE {
+ {
+ QUIRK_DATA_STANDARD_MIXER(0)
+ },
+ {
+ QUIRK_DATA_AUDIOFORMAT(1) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 14,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 48000 },
+ .clock = 1,
+ .fmt_type = UAC_FORMAT_TYPE_I
+ }
+ },
+ {
+ QUIRK_DATA_AUDIOFORMAT(2) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 10,
+ .iface = 2,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .endpoint = 0x82,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC |
+ USB_ENDPOINT_USAGE_IMPLICIT_FB,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) { 48000 },
+ .clock = 1,
+ .fmt_type = UAC_FORMAT_TYPE_I
+ }
+ },
+ {
+ /* Audio Control (unknown purpose) */
+ .ifnum = 3,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 4,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ /* HID */
+ .ifnum = 5,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ QUIRK_COMPOSITE_END
+ }
+ }
+},
/*
* MacroSilicon MS2100/MS2106 based AV capture cards
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 4d2957e62fbd..eb1750def067 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2145,7 +2145,7 @@ struct usb_string_match {
struct usb_audio_quirk_flags_table {
u32 id;
- u32 flags;
+ u64 flags;
const struct usb_string_match *usb_string_match;
};
@@ -2314,7 +2314,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
DEVICE_FLG(0x0661, 0x0883, /* iBasso DC04 Ultra */
QUIRK_FLAG_DSD_RAW),
DEVICE_FLG(0x0666, 0x0880, /* SPACETOUCH USB Audio */
- QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
+ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY |
+ QUIRK_FLAG_CTL_MSG_DELAY_5M),
DEVICE_FLG(0x06f8, 0xb000, /* Hercules DJ Console (Windows Edition) */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x06f8, 0xd002, /* Hercules DJ Console (Macintosh Edition) */
@@ -2337,6 +2338,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x0951, 0x16ad, /* Kingston HyperX */
QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x0a73, 0x003a, /* Mackie DLZ Creator XS */
+ QUIRK_FLAG_ALWAYS_SET_RATE),
DEVICE_FLG(0x0b05, 0x18a6, /* ASUSTek Computer, Inc. */
QUIRK_FLAG_MIXER_CAPTURE_MIN_MUTE),
DEVICE_FLG(0x0b0e, 0x0349, /* Jabra 550a */
@@ -2432,6 +2435,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
+ DEVICE_FLG(0x1e0b, 0xd01e, /* Generic USB Audio Device */
+ QUIRK_FLAG_PLAYBACK_URB_FIXUP),
DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
@@ -2528,6 +2533,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x84ef, 0x002a, /* Valeton GP-200 */
+ QUIRK_FLAG_GENERIC_IMPLICIT_FB),
DEVICE_FLG(0x84ef, 0x0082, /* Hotone Audio Pulze Mini */
QUIRK_FLAG_MIXER_PLAYBACK_LINEAR_VOL | QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL),
@@ -2641,18 +2648,12 @@ static const char *const snd_usb_audio_quirk_flag_names[] = {
QUIRK_STRING_ENTRY(MIXER_CAPTURE_LINEAR_VOL),
QUIRK_STRING_ENTRY(IFB_SILENCE_ON_EMPTY),
QUIRK_STRING_ENTRY(MIXER_GET_CUR_BROKEN),
+ QUIRK_STRING_ENTRY(PLAYBACK_URB_FIXUP),
+ QUIRK_STRING_ENTRY(ALWAYS_SET_RATE),
NULL
};
-const char *snd_usb_quirk_flag_find_name(unsigned long index)
-{
- if (index >= ARRAY_SIZE(snd_usb_audio_quirk_flag_names))
- return NULL;
-
- return snd_usb_audio_quirk_flag_names[index];
-}
-
-u32 snd_usb_quirk_flags_from_name(const char *name)
+static u64 snd_usb_quirk_flags_from_name(const char *name)
{
int i;
@@ -2661,7 +2662,7 @@ u32 snd_usb_quirk_flags_from_name(const char *name)
for (i = 0; snd_usb_audio_quirk_flag_names[i]; i++) {
if (strcasecmp(name, snd_usb_audio_quirk_flag_names[i]) == 0)
- return BIT_U32(i);
+ return BIT_U64(i);
}
return 0;
@@ -2719,7 +2720,7 @@ void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip,
{
u16 chip_vid = USB_ID_VENDOR(chip->usb_id);
u16 chip_pid = USB_ID_PRODUCT(chip->usb_id);
- u32 mask_flags, unmask_flags, bit;
+ u64 mask_flags, unmask_flags, bit;
char *p, *field, *flag;
bool is_unmask;
u16 vid, pid;
@@ -2773,7 +2774,7 @@ void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip,
is_unmask = false;
}
- if (!kstrtou32(flag, 16, &bit)) {
+ if (!kstrtou64(flag, 16, &bit)) {
if (is_unmask)
unmask_flags |= bit;
else
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index f24d6a5a197a..0a723c266bb4 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -56,7 +56,4 @@ void snd_usb_init_quirk_flags_table(struct snd_usb_audio *chip);
void snd_usb_init_quirk_flags_parse_string(struct snd_usb_audio *chip,
const char *str);
-const char *snd_usb_quirk_flag_find_name(unsigned long flag);
-u32 snd_usb_quirk_flags_from_name(const char *name);
-
#endif /* __USBAUDIO_QUIRKS_H */
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index e26f9092417e..c49709d7ad25 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -44,7 +44,7 @@ struct snd_usb_audio {
atomic_t active;
atomic_t shutdown;
struct snd_refcount usage_count;
- unsigned int quirk_flags;
+ u64 quirk_flags;
unsigned int need_delayed_register:1; /* warn for delayed registration */
int num_interfaces;
int last_iface;
@@ -254,6 +254,16 @@ extern bool snd_usb_skip_validation;
* check being non-fatal and only disabling GET_CUR instead of the whole mixer.
* The current volume will then be provided by the internal cache that stores
* the last set volume
+ * QUIRK_FLAG_PLAYBACK_URB_FIXUP
+ * Set URB_ISO_ASAP flag for isochronous URBs and force nurbs to MAX_URBS.
+ * This is needed for devices that exhibit boot-time audio stuttering due
+ * to insufficient buffer depth combined with xHCI scheduling variability.
+ * The larger buffer (MAX_URBS = 12, ~64ms) absorbs system scheduling
+ * jitter during boot, while URB_ISO_ASAP ensures consistent xHCI scheduling.
+ * QUIRK_FLAG_ALWAYS_SET_RATE:
+ * Issue SET_CUR for the sample rate even when the clock already reports the
+ * requested rate. A device advertising a single rate is otherwise never sent
+ * the request at all, and some require it before streaming will start.
*/
enum {
@@ -288,10 +298,12 @@ enum {
QUIRK_TYPE_MIXER_CAPTURE_LINEAR_VOL = 28,
QUIRK_TYPE_IFB_SILENCE_ON_EMPTY = 29,
QUIRK_TYPE_MIXER_GET_CUR_BROKEN = 30,
+ QUIRK_TYPE_PLAYBACK_URB_FIXUP = 31,
+ QUIRK_TYPE_ALWAYS_SET_RATE = 32,
/* Please also edit snd_usb_audio_quirk_flag_names */
};
-#define QUIRK_FLAG(x) BIT_U32(QUIRK_TYPE_ ## x)
+#define QUIRK_FLAG(x) BIT_U64(QUIRK_TYPE_ ## x)
#define QUIRK_FLAG_GET_SAMPLE_RATE QUIRK_FLAG(GET_SAMPLE_RATE)
#define QUIRK_FLAG_SHARE_MEDIA_DEVICE QUIRK_FLAG(SHARE_MEDIA_DEVICE)
@@ -324,5 +336,7 @@ enum {
#define QUIRK_FLAG_MIXER_CAPTURE_LINEAR_VOL QUIRK_FLAG(MIXER_CAPTURE_LINEAR_VOL)
#define QUIRK_FLAG_IFB_SILENCE_ON_EMPTY QUIRK_FLAG(IFB_SILENCE_ON_EMPTY)
#define QUIRK_FLAG_MIXER_GET_CUR_BROKEN QUIRK_FLAG(MIXER_GET_CUR_BROKEN)
+#define QUIRK_FLAG_PLAYBACK_URB_FIXUP QUIRK_FLAG(PLAYBACK_URB_FIXUP)
+#define QUIRK_FLAG_ALWAYS_SET_RATE QUIRK_FLAG(ALWAYS_SET_RATE)
#endif /* __USBAUDIO_H */
diff --git a/sound/usb/usx2y/us144mkii_pcm.h b/sound/usb/usx2y/us144mkii_pcm.h
index 74da8564431b..a130678405e3 100644
--- a/sound/usb/usx2y/us144mkii_pcm.h
+++ b/sound/usb/usx2y/us144mkii_pcm.h
@@ -7,7 +7,7 @@
#include "us144mkii.h"
/**
- * tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM.
+ * var tascam_pcm_hw - Hardware capabilities for TASCAM US-144MKII PCM.
*
* Defines the supported PCM formats, rates, channels, and buffer/period sizes
* for the TASCAM US-144MKII audio interface.
@@ -15,14 +15,14 @@
extern const struct snd_pcm_hardware tascam_pcm_hw;
/**
- * tascam_playback_ops - ALSA PCM operations for playback.
+ * var tascam_playback_ops - ALSA PCM operations for playback.
*
* This structure defines the callback functions for playback stream operations.
*/
extern const struct snd_pcm_ops tascam_playback_ops;
/**
- * tascam_capture_ops - ALSA PCM operations for capture.
+ * var tascam_capture_ops - ALSA PCM operations for capture.
*
* This structure defines the callback functions for capture stream operations.
*/
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 3808df54727d..a3a0bc13632b 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -167,7 +167,6 @@ static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, i
if (!urb)
return -ENODEV;
urb->start_frame = frame + NRURBS * nr_of_packs(); // let hcd do rollover sanity checks
- urb->hcpriv = NULL;
urb->dev = subs->usx2y->dev; /* we need to set this at each time */
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {