summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/ac97/bus.c9
-rw-r--r--sound/arm/aaci.c2
-rw-r--r--sound/atmel/ac97c.c9
-rw-r--r--sound/core/hrtimer.c3
-rw-r--r--sound/core/memory.c41
-rw-r--r--sound/core/pcm.c4
-rw-r--r--sound/core/pcm_drm_eld.c387
-rw-r--r--sound/core/pcm_misc.c4
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/core/rawmidi.c3
-rw-r--r--sound/core/seq/Kconfig4
-rw-r--r--sound/core/seq/oss/seq_oss_device.h5
-rw-r--r--sound/core/seq/oss/seq_oss_event.c8
-rw-r--r--sound/core/seq/oss/seq_oss_init.c8
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c84
-rw-r--r--sound/core/seq/seq_clientmgr.c84
-rw-r--r--sound/core/seq/seq_memory.c1
-rw-r--r--sound/core/seq/seq_system.c34
-rw-r--r--sound/core/seq/seq_system.h35
-rw-r--r--sound/core/seq/seq_ump_client.c42
-rw-r--r--sound/core/timer.c147
-rw-r--r--sound/core/ump.c112
-rw-r--r--sound/drivers/dummy.c3
-rw-r--r--sound/drivers/pcsp/pcsp.c3
-rw-r--r--sound/firewire/fireface/ff-protocol-former.c4
-rw-r--r--sound/hda/hdac_component.c7
-rw-r--r--sound/hda/hdac_stream.c63
-rw-r--r--sound/hda/intel-dsp-config.c9
-rw-r--r--sound/isa/es18xx.c8
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c2
-rw-r--r--sound/isa/sb/sb16_csp.c5
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ac97/ac97_proc.c8
-rw-r--r--sound/pci/ad1889.c8
-rw-r--r--sound/pci/cmipci.c2
-rw-r--r--sound/pci/ctxfi/ctdaio.c52
-rw-r--r--sound/pci/echoaudio/echoaudio.c6
-rw-r--r--sound/pci/emu10k1/emuproc.c15
-rw-r--r--sound/pci/emu10k1/memory.c2
-rw-r--r--sound/pci/ens1370.c6
-rw-r--r--sound/pci/hda/Kconfig16
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/cs35l56_hda.c6
-rw-r--r--sound/pci/hda/cs35l56_hda_spi.c3
-rw-r--r--sound/pci/hda/hda_auto_parser.c8
-rw-r--r--sound/pci/hda/hda_auto_parser.h1
-rw-r--r--sound/pci/hda/hda_beep.c15
-rw-r--r--sound/pci/hda/hda_bind.c2
-rw-r--r--sound/pci/hda/hda_codec.c7
-rw-r--r--sound/pci/hda/hda_eld.c385
-rw-r--r--sound/pci/hda/hda_hwdep.c2
-rw-r--r--sound/pci/hda/hda_intel.c64
-rw-r--r--sound/pci/hda/hda_local.h49
-rw-r--r--sound/pci/hda/hda_sysfs.c2
-rw-r--r--sound/pci/hda/hda_tegra.c16
-rw-r--r--sound/pci/hda/ideapad_hotkey_led_helper.c36
-rw-r--r--sound/pci/hda/patch_conexant.c14
-rw-r--r--sound/pci/hda/patch_cs8409-tables.c12
-rw-r--r--sound/pci/hda/patch_cs8409.c26
-rw-r--r--sound/pci/hda/patch_cs8409.h7
-rw-r--r--sound/pci/hda/patch_hdmi.c6
-rw-r--r--sound/pci/hda/patch_realtek.c292
-rw-r--r--sound/pci/hda/tas2781-spi.h157
-rw-r--r--sound/pci/hda/tas2781_hda_i2c.c13
-rw-r--r--sound/pci/hda/tas2781_hda_spi.c1263
-rw-r--r--sound/pci/hda/tas2781_spi_fwlib.c2006
-rw-r--r--sound/pci/lola/lola.h2
-rw-r--r--sound/pci/lola/lola_clock.c2
-rw-r--r--sound/pci/lola/lola_mixer.c43
-rw-r--r--sound/pci/nm256/nm256.c8
-rw-r--r--sound/pci/oxygen/oxygen.c4
-rw-r--r--sound/pci/oxygen/oxygen.h2
-rw-r--r--sound/pci/oxygen/oxygen_lib.c5
-rw-r--r--sound/pci/oxygen/se6x.c4
-rw-r--r--sound/pci/oxygen/virtuoso.c4
-rw-r--r--sound/pci/rme32.c13
-rw-r--r--sound/pci/rme96.c13
-rw-r--r--sound/pci/rme9652/hdsp.c10
-rw-r--r--sound/pci/rme9652/hdspm.c15
-rw-r--r--sound/pci/rme9652/rme9652.c5
-rw-r--r--sound/pci/sonicvibes.c8
-rw-r--r--sound/pci/trident/trident_main.c4
-rw-r--r--sound/pci/vx222/vx222.c9
-rw-r--r--sound/ppc/keywest.c7
-rw-r--r--sound/sh/sh_dac_audio.c3
-rw-r--r--sound/soc/Kconfig7
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/amd/Kconfig12
-rw-r--r--sound/soc/amd/acp/Kconfig12
-rw-r--r--sound/soc/amd/acp/Makefile4
-rw-r--r--sound/soc/amd/acp/acp-i2s.c184
-rw-r--r--sound/soc/amd/acp/acp-legacy-common.c308
-rw-r--r--sound/soc/amd/acp/acp-mach-common.c2
-rw-r--r--sound/soc/amd/acp/acp-pci.c220
-rw-r--r--sound/soc/amd/acp/acp-pdm.c53
-rw-r--r--sound/soc/amd/acp/acp-platform.c145
-rw-r--r--sound/soc/amd/acp/acp-rembrandt.c149
-rw-r--r--sound/soc/amd/acp/acp-renoir.c116
-rw-r--r--sound/soc/amd/acp/acp-sdw-legacy-mach.c45
-rw-r--r--sound/soc/amd/acp/acp-sdw-mach-common.c34
-rw-r--r--sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c5
-rw-r--r--sound/soc/amd/acp/acp63.c163
-rw-r--r--sound/soc/amd/acp/acp70.c132
-rw-r--r--sound/soc/amd/acp/amd-acp70-acpi-match.c160
-rw-r--r--sound/soc/amd/acp/amd-acpi-mach.c93
-rw-r--r--sound/soc/amd/acp/amd.h168
-rw-r--r--sound/soc/amd/acp/chip_offset_byte.h12
-rw-r--r--sound/soc/amd/acp/soc_amd_sdw_common.h12
-rw-r--r--sound/soc/amd/mach-config.h1
-rw-r--r--sound/soc/amd/ps/Makefile2
-rw-r--r--sound/soc/amd/ps/acp63.h246
-rw-r--r--sound/soc/amd/ps/pci-ps.c428
-rw-r--r--sound/soc/amd/ps/ps-common.c475
-rw-r--r--sound/soc/amd/ps/ps-pdm-dma.c18
-rw-r--r--sound/soc/amd/ps/ps-sdw-dma.c381
-rw-r--r--sound/soc/amd/rpl/rpl-pci-acp6x.c10
-rw-r--r--sound/soc/amd/vangogh/acp5x-pcm-dma.c11
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c49
-rw-r--r--sound/soc/amd/yc/acp6x-pdm-dma.c12
-rw-r--r--sound/soc/amd/yc/pci-acp6x.c10
-rw-r--r--sound/soc/atmel/atmel-classd.c3
-rw-r--r--sound/soc/atmel/tse850-pcm5142.c11
-rw-r--r--sound/soc/au1x/i2sc.c17
-rw-r--r--sound/soc/au1x/psc-ac97.c17
-rw-r--r--sound/soc/au1x/psc-i2s.c17
-rw-r--r--sound/soc/codecs/Kconfig15
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ad193x-i2c.c3
-rw-r--r--sound/soc/codecs/adau1701.c4
-rw-r--r--sound/soc/codecs/adau1761-i2c.c5
-rw-r--r--sound/soc/codecs/adau1781-i2c.c5
-rw-r--r--sound/soc/codecs/adau17x1.c2
-rw-r--r--sound/soc/codecs/adau1977-i2c.c5
-rw-r--r--sound/soc/codecs/ak4375.c11
-rw-r--r--sound/soc/codecs/ak4458.c13
-rw-r--r--sound/soc/codecs/ak5558.c11
-rw-r--r--sound/soc/codecs/alc5623.c10
-rw-r--r--sound/soc/codecs/alc5632.c6
-rw-r--r--sound/soc/codecs/arizona.c26
-rw-r--r--sound/soc/codecs/aw88081.c333
-rw-r--r--sound/soc/codecs/aw88081.h43
-rw-r--r--sound/soc/codecs/aw88166.c1933
-rw-r--r--sound/soc/codecs/aw88166.h534
-rw-r--r--sound/soc/codecs/aw88395/aw88395_device.c2
-rw-r--r--sound/soc/codecs/cpcap.c200
-rw-r--r--sound/soc/codecs/cros_ec_codec.c3
-rw-r--r--sound/soc/codecs/cs35l32.c11
-rw-r--r--sound/soc/codecs/cs35l33.c14
-rw-r--r--sound/soc/codecs/cs35l34.c14
-rw-r--r--sound/soc/codecs/cs35l41-spi.c5
-rw-r--r--sound/soc/codecs/cs35l41.c30
-rw-r--r--sound/soc/codecs/cs35l56-shared.c80
-rw-r--r--sound/soc/codecs/cs35l56-spi.c3
-rw-r--r--sound/soc/codecs/cs35l56.c9
-rw-r--r--sound/soc/codecs/cs4234.c12
-rw-r--r--sound/soc/codecs/cs4265.c4
-rw-r--r--sound/soc/codecs/cs4270.c4
-rw-r--r--sound/soc/codecs/cs4271.c4
-rw-r--r--sound/soc/codecs/cs42l42-i2c.c6
-rw-r--r--sound/soc/codecs/cs42l42-sdw.c16
-rw-r--r--sound/soc/codecs/cs42l42.c4
-rw-r--r--sound/soc/codecs/cs42l43-jack.c13
-rw-r--r--sound/soc/codecs/cs42l43.c19
-rw-r--r--sound/soc/codecs/cs42l43.h3
-rw-r--r--sound/soc/codecs/cs42l51-i2c.c8
-rw-r--r--sound/soc/codecs/cs42l51.c8
-rw-r--r--sound/soc/codecs/cs42l52.c4
-rw-r--r--sound/soc/codecs/cs42l56.c4
-rw-r--r--sound/soc/codecs/cs42l73.c4
-rw-r--r--sound/soc/codecs/cs42l83-i2c.c6
-rw-r--r--sound/soc/codecs/cs42l84.c2
-rw-r--r--sound/soc/codecs/cs42xx8-i2c.c2
-rw-r--r--sound/soc/codecs/cs42xx8.c14
-rw-r--r--sound/soc/codecs/cs43130.c33
-rw-r--r--sound/soc/codecs/cs4341.c2
-rw-r--r--sound/soc/codecs/cs4349.c7
-rw-r--r--sound/soc/codecs/cs530x.c4
-rw-r--r--sound/soc/codecs/cs53l30.c11
-rw-r--r--sound/soc/codecs/cx2072x.c12
-rw-r--r--sound/soc/codecs/da7210.c4
-rw-r--r--sound/soc/codecs/da7213.c12
-rw-r--r--sound/soc/codecs/da7218.c4
-rw-r--r--sound/soc/codecs/da7219.c4
-rw-r--r--sound/soc/codecs/da732x.c4
-rw-r--r--sound/soc/codecs/da9055.c4
-rw-r--r--sound/soc/codecs/dmic.c27
-rw-r--r--sound/soc/codecs/es8316.c2
-rw-r--r--sound/soc/codecs/es8323.c2
-rw-r--r--sound/soc/codecs/es8326.c4
-rw-r--r--sound/soc/codecs/es8328.c15
-rw-r--r--sound/soc/codecs/hdac_hdmi.c18
-rw-r--r--sound/soc/codecs/hdmi-codec.c72
-rw-r--r--sound/soc/codecs/jz4760.c32
-rw-r--r--sound/soc/codecs/jz4770.c40
-rw-r--r--sound/soc/codecs/lochnagar-sc.c4
-rw-r--r--sound/soc/codecs/lpass-rx-macro.c8
-rw-r--r--sound/soc/codecs/lpass-tx-macro.c8
-rw-r--r--sound/soc/codecs/lpass-va-macro.c8
-rw-r--r--sound/soc/codecs/lpass-wsa-macro.c8
-rw-r--r--sound/soc/codecs/madera.c29
-rw-r--r--sound/soc/codecs/max98088.c4
-rw-r--r--sound/soc/codecs/max98090.c29
-rw-r--r--sound/soc/codecs/max98095.c4
-rw-r--r--sound/soc/codecs/max98373-i2c.c6
-rw-r--r--sound/soc/codecs/max98373-sdw.c10
-rw-r--r--sound/soc/codecs/max98390.c6
-rw-r--r--sound/soc/codecs/max98396.c6
-rw-r--r--sound/soc/codecs/max98520.c8
-rw-r--r--sound/soc/codecs/max9860.c6
-rw-r--r--sound/soc/codecs/max98927.c6
-rw-r--r--sound/soc/codecs/mt6358.c104
-rw-r--r--sound/soc/codecs/mt6358.h4
-rw-r--r--sound/soc/codecs/mt6359-accdet.h9
-rw-r--r--sound/soc/codecs/mt6359.c9
-rw-r--r--sound/soc/codecs/mt6660.c9
-rw-r--r--sound/soc/codecs/nau8540.c4
-rw-r--r--sound/soc/codecs/nau8810.c4
-rw-r--r--sound/soc/codecs/nau8822.c4
-rw-r--r--sound/soc/codecs/nau8824.c12
-rw-r--r--sound/soc/codecs/nau8825.c4
-rw-r--r--sound/soc/codecs/ntp8835.c2
-rw-r--r--sound/soc/codecs/ntp8918.c3
-rw-r--r--sound/soc/codecs/pcm1681.c1
-rw-r--r--sound/soc/codecs/pcm186x-i2c.c3
-rw-r--r--sound/soc/codecs/pcm3008.c61
-rw-r--r--sound/soc/codecs/pcm3008.h19
-rw-r--r--sound/soc/codecs/pcm3168a-i2c.c11
-rw-r--r--sound/soc/codecs/pcm3168a-spi.c2
-rw-r--r--sound/soc/codecs/pcm3168a.c18
-rw-r--r--sound/soc/codecs/pcm512x-i2c.c2
-rw-r--r--sound/soc/codecs/pcm512x-spi.c2
-rw-r--r--sound/soc/codecs/pcm512x.c7
-rw-r--r--sound/soc/codecs/pcm6240.c31
-rw-r--r--sound/soc/codecs/pcm6240.h7
-rw-r--r--sound/soc/codecs/peb2466.c3
-rw-r--r--sound/soc/codecs/rk817_codec.c4
-rw-r--r--sound/soc/codecs/rt1011.c8
-rw-r--r--sound/soc/codecs/rt1015.c10
-rw-r--r--sound/soc/codecs/rt1016.c10
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c10
-rw-r--r--sound/soc/codecs/rt1019.c6
-rw-r--r--sound/soc/codecs/rt1305.c12
-rw-r--r--sound/soc/codecs/rt1308-sdw.c10
-rw-r--r--sound/soc/codecs/rt1308.c8
-rw-r--r--sound/soc/codecs/rt1316-sdw.c10
-rw-r--r--sound/soc/codecs/rt1318-sdw.c10
-rw-r--r--sound/soc/codecs/rt1318.c6
-rw-r--r--sound/soc/codecs/rt1320-sdw.c13
-rw-r--r--sound/soc/codecs/rt274.c12
-rw-r--r--sound/soc/codecs/rt286.c9
-rw-r--r--sound/soc/codecs/rt298.c9
-rw-r--r--sound/soc/codecs/rt5514-spi.c8
-rw-r--r--sound/soc/codecs/rt5514.c15
-rw-r--r--sound/soc/codecs/rt5616.c4
-rw-r--r--sound/soc/codecs/rt5631.c4
-rw-r--r--sound/soc/codecs/rt5640.c18
-rw-r--r--sound/soc/codecs/rt5645.c24
-rw-r--r--sound/soc/codecs/rt5651.c12
-rw-r--r--sound/soc/codecs/rt5659.c12
-rw-r--r--sound/soc/codecs/rt5660.c12
-rw-r--r--sound/soc/codecs/rt5663.c10
-rw-r--r--sound/soc/codecs/rt5665.c12
-rw-r--r--sound/soc/codecs/rt5668.c10
-rw-r--r--sound/soc/codecs/rt5670.c12
-rw-r--r--sound/soc/codecs/rt5677-spi.c3
-rw-r--r--sound/soc/codecs/rt5677.c5
-rw-r--r--sound/soc/codecs/rt5682-i2c.c12
-rw-r--r--sound/soc/codecs/rt5682-sdw.c12
-rw-r--r--sound/soc/codecs/rt5682.c16
-rw-r--r--sound/soc/codecs/rt5682.h2
-rw-r--r--sound/soc/codecs/rt5682s.c4
-rw-r--r--sound/soc/codecs/rt700-sdw.c12
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c12
-rw-r--r--sound/soc/codecs/rt711-sdw.c12
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c12
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c12
-rw-r--r--sound/soc/codecs/rt712-sdca.c80
-rw-r--r--sound/soc/codecs/rt712-sdca.h3
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c10
-rw-r--r--sound/soc/codecs/rt715-sdca.c8
-rw-r--r--sound/soc/codecs/rt715-sdw.c51
-rw-r--r--sound/soc/codecs/rt715.c8
-rw-r--r--sound/soc/codecs/rt715.h3
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c12
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c146
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.h99
-rw-r--r--sound/soc/codecs/rt722-sdca.c135
-rw-r--r--sound/soc/codecs/rt722-sdca.h4
-rw-r--r--sound/soc/codecs/rt9120.c8
-rw-r--r--sound/soc/codecs/rtq9128.c8
-rw-r--r--sound/soc/codecs/sgtl5000.c4
-rw-r--r--sound/soc/codecs/sma1307.c43
-rw-r--r--sound/soc/codecs/src4xxx.c4
-rw-r--r--sound/soc/codecs/ssm2602-i2c.c5
-rw-r--r--sound/soc/codecs/tas2552.c9
-rw-r--r--sound/soc/codecs/tas2562.c18
-rw-r--r--sound/soc/codecs/tas2764.c123
-rw-r--r--sound/soc/codecs/tas2764.h15
-rw-r--r--sound/soc/codecs/tas2770.c59
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c197
-rw-r--r--sound/soc/codecs/tas2781-i2c.c288
-rw-r--r--sound/soc/codecs/tas5720.c10
-rw-r--r--sound/soc/codecs/tlv320adc3xxx.c7
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c6
-rw-r--r--sound/soc/codecs/tlv320aic3x-i2c.c3
-rw-r--r--sound/soc/codecs/tlv320dac33.c6
-rw-r--r--sound/soc/codecs/tpa6130a2.c4
-rw-r--r--sound/soc/codecs/ts3a227e.c6
-rw-r--r--sound/soc/codecs/tscs454.c5
-rw-r--r--sound/soc/codecs/twl4030.c2
-rw-r--r--sound/soc/codecs/uda1342.c2
-rw-r--r--sound/soc/codecs/uda1380.c6
-rw-r--r--sound/soc/codecs/wcd9335.c2
-rw-r--r--sound/soc/codecs/wcd934x.c16
-rw-r--r--sound/soc/codecs/wcd937x-sdw.c49
-rw-r--r--sound/soc/codecs/wcd937x.c57
-rw-r--r--sound/soc/codecs/wcd937x.h7
-rw-r--r--sound/soc/codecs/wcd938x-sdw.c10
-rw-r--r--sound/soc/codecs/wcd938x.c11
-rw-r--r--sound/soc/codecs/wcd939x-sdw.c10
-rw-r--r--sound/soc/codecs/wcd939x.c2
-rw-r--r--sound/soc/codecs/wm0010.c13
-rw-r--r--sound/soc/codecs/wm2200.c15
-rw-r--r--sound/soc/codecs/wm5100.c15
-rw-r--r--sound/soc/codecs/wm5110.c12
-rw-r--r--sound/soc/codecs/wm8350.c4
-rw-r--r--sound/soc/codecs/wm8400.c4
-rw-r--r--sound/soc/codecs/wm8510.c4
-rw-r--r--sound/soc/codecs/wm8523.c4
-rw-r--r--sound/soc/codecs/wm8524.c2
-rw-r--r--sound/soc/codecs/wm8580.c4
-rw-r--r--sound/soc/codecs/wm8711.c4
-rw-r--r--sound/soc/codecs/wm8728.c2
-rw-r--r--sound/soc/codecs/wm8737.c4
-rw-r--r--sound/soc/codecs/wm8741.c2
-rw-r--r--sound/soc/codecs/wm8750.c4
-rw-r--r--sound/soc/codecs/wm8753.c12
-rw-r--r--sound/soc/codecs/wm8770.c4
-rw-r--r--sound/soc/codecs/wm8776.c4
-rw-r--r--sound/soc/codecs/wm8804-i2c.c2
-rw-r--r--sound/soc/codecs/wm8804-spi.c2
-rw-r--r--sound/soc/codecs/wm8804.c11
-rw-r--r--sound/soc/codecs/wm8900.c8
-rw-r--r--sound/soc/codecs/wm8903.c8
-rw-r--r--sound/soc/codecs/wm8904.c336
-rw-r--r--sound/soc/codecs/wm8940.c4
-rw-r--r--sound/soc/codecs/wm8955.c4
-rw-r--r--sound/soc/codecs/wm8960.c4
-rw-r--r--sound/soc/codecs/wm8961.c4
-rw-r--r--sound/soc/codecs/wm8962.c12
-rw-r--r--sound/soc/codecs/wm8971.c4
-rw-r--r--sound/soc/codecs/wm8974.c4
-rw-r--r--sound/soc/codecs/wm8978.c4
-rw-r--r--sound/soc/codecs/wm8983.c4
-rw-r--r--sound/soc/codecs/wm8985.c8
-rw-r--r--sound/soc/codecs/wm8988.c4
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8991.c4
-rw-r--r--sound/soc/codecs/wm8993.c8
-rw-r--r--sound/soc/codecs/wm8994.c10
-rw-r--r--sound/soc/codecs/wm8995.c4
-rw-r--r--sound/soc/codecs/wm8996.c8
-rw-r--r--sound/soc/codecs/wm9081.c8
-rw-r--r--sound/soc/codecs/wm9712.c10
-rw-r--r--sound/soc/codecs/wm9713.c18
-rw-r--r--sound/soc/codecs/wm_hubs.c3
-rw-r--r--sound/soc/codecs/wsa881x.c17
-rw-r--r--sound/soc/codecs/wsa883x.c202
-rw-r--r--sound/soc/codecs/wsa884x.c12
-rw-r--r--sound/soc/dwc/dwc-i2s.c6
-rw-r--r--sound/soc/fsl/Kconfig3
-rw-r--r--sound/soc/fsl/Makefile2
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c6
-rw-r--r--sound/soc/fsl/fsl_asrc.c179
-rw-r--r--sound/soc/fsl/fsl_asrc.h2
-rw-r--r--sound/soc/fsl/fsl_asrc_common.h70
-rw-r--r--sound/soc/fsl/fsl_asrc_m2m.c729
-rw-r--r--sound/soc/fsl/fsl_aud2htx.c3
-rw-r--r--sound/soc/fsl/fsl_audmix.c16
-rw-r--r--sound/soc/fsl/fsl_easrc.c261
-rw-r--r--sound/soc/fsl/fsl_easrc.h4
-rw-r--r--sound/soc/fsl/fsl_esai.c9
-rw-r--r--sound/soc/fsl/fsl_micfil.c189
-rw-r--r--sound/soc/fsl/fsl_micfil.h3
-rw-r--r--sound/soc/fsl/fsl_mqs.c28
-rw-r--r--sound/soc/fsl/fsl_qmc_audio.c4
-rw-r--r--sound/soc/fsl/fsl_sai.c21
-rw-r--r--sound/soc/fsl/fsl_sai.h3
-rw-r--r--sound/soc/fsl/fsl_utils.c45
-rw-r--r--sound/soc/fsl/fsl_utils.h5
-rw-r--r--sound/soc/fsl/fsl_xcvr.c407
-rw-r--r--sound/soc/fsl/fsl_xcvr.h13
-rw-r--r--sound/soc/fsl/imx-audmix.c35
-rw-r--r--sound/soc/fsl/imx-audmux.c2
-rw-r--r--sound/soc/fsl/imx-card.c7
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c3
-rw-r--r--sound/soc/fsl/imx-rpmsg.c2
-rw-r--r--sound/soc/generic/audio-graph-card.c141
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample.dtsi702
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample1.dtsi396
-rw-r--r--sound/soc/generic/audio-graph-card2-custom-sample2.dtsi382
-rw-r--r--sound/soc/generic/audio-graph-card2.c395
-rw-r--r--sound/soc/generic/simple-card-utils.c251
-rw-r--r--sound/soc/generic/simple-card.c186
-rw-r--r--sound/soc/img/img-i2s-in.c9
-rw-r--r--sound/soc/img/img-i2s-out.c9
-rw-r--r--sound/soc/img/img-parallel-out.c5
-rw-r--r--sound/soc/img/img-spdif-in.c9
-rw-r--r--sound/soc/img/img-spdif-out.c10
-rw-r--r--sound/soc/img/pistachio-internal-dac.c8
-rw-r--r--sound/soc/intel/avs/apl.c3
-rw-r--r--sound/soc/intel/avs/avs.h1
-rw-r--r--sound/soc/intel/avs/board_selection.c17
-rw-r--r--sound/soc/intel/avs/boards/Kconfig10
-rw-r--r--sound/soc/intel/avs/boards/Makefile2
-rw-r--r--sound/soc/intel/avs/boards/da7219.c5
-rw-r--r--sound/soc/intel/avs/boards/es8336.c3
-rw-r--r--sound/soc/intel/avs/boards/max98357a.c2
-rw-r--r--sound/soc/intel/avs/boards/max98373.c2
-rw-r--r--sound/soc/intel/avs/boards/max98927.c4
-rw-r--r--sound/soc/intel/avs/boards/nau8825.c5
-rw-r--r--sound/soc/intel/avs/boards/pcm3168a.c143
-rw-r--r--sound/soc/intel/avs/boards/rt274.c5
-rw-r--r--sound/soc/intel/avs/boards/rt286.c5
-rw-r--r--sound/soc/intel/avs/boards/rt298.c7
-rw-r--r--sound/soc/intel/avs/boards/rt5514.c2
-rw-r--r--sound/soc/intel/avs/boards/rt5663.c3
-rw-r--r--sound/soc/intel/avs/boards/rt5682.c3
-rw-r--r--sound/soc/intel/avs/boards/ssm4567.c4
-rw-r--r--sound/soc/intel/avs/cnl.c1
-rw-r--r--sound/soc/intel/avs/control.c182
-rw-r--r--sound/soc/intel/avs/control.h12
-rw-r--r--sound/soc/intel/avs/core.c48
-rw-r--r--sound/soc/intel/avs/debugfs.c1
-rw-r--r--sound/soc/intel/avs/dsp.c3
-rw-r--r--sound/soc/intel/avs/ipc.c25
-rw-r--r--sound/soc/intel/avs/loader.c100
-rw-r--r--sound/soc/intel/avs/messages.c171
-rw-r--r--sound/soc/intel/avs/messages.h49
-rw-r--r--sound/soc/intel/avs/path.c375
-rw-r--r--sound/soc/intel/avs/path.h5
-rw-r--r--sound/soc/intel/avs/pcm.c7
-rw-r--r--sound/soc/intel/avs/registers.h47
-rw-r--r--sound/soc/intel/avs/skl.c1
-rw-r--r--sound/soc/intel/avs/tgl.c33
-rw-r--r--sound/soc/intel/avs/topology.c93
-rw-r--r--sound/soc/intel/avs/topology.h16
-rw-r--r--sound/soc/intel/avs/trace.h38
-rw-r--r--sound/soc/intel/boards/bytcr_rt5640.c17
-rw-r--r--sound/soc/intel/boards/skl_hda_dsp_generic.c2
-rw-r--r--sound/soc/intel/boards/sof_sdw.c106
-rw-r--r--sound/soc/intel/catpt/device.c14
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-adl-match.c29
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-arl-match.c45
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-lnl-match.c207
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-mtl-match.c291
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-ptl-match.c432
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c42
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h1
-rw-r--r--sound/soc/intel/common/soc-acpi-intel-tgl-match.c194
-rw-r--r--sound/soc/intel/keembay/kmb_platform.c2
-rw-r--r--sound/soc/kirkwood/armada-370-db.c6
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.c20
-rw-r--r--sound/soc/mediatek/common/mtk-afe-fe-dai.h2
-rw-r--r--sound/soc/mediatek/common/mtk-soc-card.h1
-rw-r--r--sound/soc/mediatek/common/mtk-soundcard-driver.c23
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-cs42448.c8
-rw-r--r--sound/soc/mediatek/mt2701/mt2701-wm8960.c2
-rw-r--r--sound/soc/mediatek/mt6797/mt6797-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-dai-etdm.c4
-rw-r--r--sound/soc/mediatek/mt7986/mt7986-wm8960.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-max98090.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c2
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c4
-rw-r--r--sound/soc/mediatek/mt8173/mt8173-rt5650.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c2
-rw-r--r--sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c4
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-clk.c55
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-clk.h2
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt8186/mt8186-mt6366.c2
-rw-r--r--sound/soc/mediatek/mt8188/Makefile1
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-clk.c8
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-clk.h8
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-common.h1
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-afe-pcm.c34
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-audsys-clk.c4
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h4
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-dai-dmic.c683
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-mt6359.c57
-rw-r--r--sound/soc/mediatek/mt8188/mt8188-reg.h17
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-afe-pcm.c25
-rw-r--r--sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c2
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-afe-pcm.c6
-rw-r--r--sound/soc/mediatek/mt8195/mt8195-mt6359.c12
-rw-r--r--sound/soc/mediatek/mt8365/Makefile2
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-clk.c3
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-afe-pcm.c19
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-i2s.c12
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-dai-pcm.c4
-rw-r--r--sound/soc/mediatek/mt8365/mt8365-mt6357.c13
-rw-r--r--sound/soc/meson/axg-tdm-interface.c9
-rw-r--r--sound/soc/meson/meson-card-utils.c4
-rw-r--r--sound/soc/meson/t9015.c4
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c2
-rw-r--r--sound/soc/pxa/spitz.c2
-rw-r--r--sound/soc/qcom/common.c6
-rw-r--r--sound/soc/qcom/lpass-platform.c6
-rw-r--r--sound/soc/qcom/lpass-sc7180.c8
-rw-r--r--sound/soc/qcom/lpass-sc7280.c8
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c2
-rw-r--r--sound/soc/qcom/sc7180.c4
-rw-r--r--sound/soc/qcom/sc7280.c4
-rw-r--r--sound/soc/qcom/sdm845.c5
-rw-r--r--sound/soc/qcom/sdw.c34
-rw-r--r--sound/soc/qcom/sm8250.c3
-rw-r--r--sound/soc/renesas/Kconfig2
-rw-r--r--sound/soc/renesas/migor.c2
-rw-r--r--sound/soc/renesas/rcar/core.c22
-rw-r--r--sound/soc/renesas/rcar/rsnd.h1
-rw-r--r--sound/soc/renesas/rcar/src.c116
-rw-r--r--sound/soc/renesas/rcar/ssi.c3
-rw-r--r--sound/soc/renesas/rz-ssi.c228
-rw-r--r--sound/soc/rockchip/rk3288_hdmi_analog.c2
-rw-r--r--sound/soc/rockchip/rk3399_gru_sound.c10
-rw-r--r--sound/soc/rockchip/rockchip_i2s.c5
-rw-r--r--sound/soc/rockchip/rockchip_i2s_tdm.c79
-rw-r--r--sound/soc/rockchip/rockchip_max98090.c8
-rw-r--r--sound/soc/rockchip/rockchip_pdm.c10
-rw-r--r--sound/soc/rockchip/rockchip_rt5645.c2
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c9
-rw-r--r--sound/soc/samsung/aries_wm8994.c6
-rw-r--r--sound/soc/samsung/arndale.c4
-rw-r--r--sound/soc/samsung/bells.c21
-rw-r--r--sound/soc/samsung/i2s.c10
-rw-r--r--sound/soc/samsung/littlemill.c5
-rw-r--r--sound/soc/samsung/lowland.c7
-rw-r--r--sound/soc/samsung/midas_wm1811.c2
-rw-r--r--sound/soc/samsung/odroid.c2
-rw-r--r--sound/soc/samsung/smdk_wm8994.c4
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c2
-rw-r--r--sound/soc/samsung/snow.c2
-rw-r--r--sound/soc/samsung/speyside.c53
-rw-r--r--sound/soc/samsung/tm2_wm5110.c9
-rw-r--r--sound/soc/samsung/tobermory.c3
-rw-r--r--sound/soc/sdca/Makefile2
-rw-r--r--sound/soc/sdca/sdca_device.c5
-rw-r--r--sound/soc/sdca/sdca_functions.c1829
-rw-r--r--sound/soc/sdca/sdca_regmap.c321
-rw-r--r--sound/soc/sdw_utils/soc_sdw_cs_amp.c46
-rw-r--r--sound/soc/sdw_utils/soc_sdw_utils.c27
-rw-r--r--sound/soc/soc-card.c18
-rw-r--r--sound/soc/soc-component.c38
-rw-r--r--sound/soc/soc-compress.c2
-rw-r--r--sound/soc/soc-core.c108
-rw-r--r--sound/soc/soc-dai.c65
-rw-r--r--sound/soc/soc-dapm.c65
-rw-r--r--sound/soc/soc-link.c18
-rw-r--r--sound/soc/soc-ops-test.c541
-rw-r--r--sound/soc/soc-ops.c730
-rw-r--r--sound/soc/soc-pcm.c313
-rw-r--r--sound/soc/soc-topology.c69
-rw-r--r--sound/soc/soc-utils.c61
-rw-r--r--sound/soc/sof/amd/Kconfig5
-rw-r--r--sound/soc/sof/amd/acp-ipc.c25
-rw-r--r--sound/soc/sof/amd/acp.c57
-rw-r--r--sound/soc/sof/amd/acp.h3
-rw-r--r--sound/soc/sof/amd/pci-acp63.c3
-rw-r--r--sound/soc/sof/amd/pci-acp70.c3
-rw-r--r--sound/soc/sof/amd/pci-rmb.c1
-rw-r--r--sound/soc/sof/amd/pci-rn.c3
-rw-r--r--sound/soc/sof/amd/pci-vangogh.c5
-rw-r--r--sound/soc/sof/amd/vangogh.c22
-rw-r--r--sound/soc/sof/imx/Kconfig17
-rw-r--r--sound/soc/sof/imx/Makefile6
-rw-r--r--sound/soc/sof/imx/imx-common.c430
-rw-r--r--sound/soc/sof/imx/imx-common.h151
-rw-r--r--sound/soc/sof/imx/imx8.c773
-rw-r--r--sound/soc/sof/imx/imx8m.c519
-rw-r--r--sound/soc/sof/imx/imx8ulp.c521
-rw-r--r--sound/soc/sof/imx/imx9.c137
-rw-r--r--sound/soc/sof/intel/Makefile2
-rw-r--r--sound/soc/sof/intel/atom.c16
-rw-r--r--sound/soc/sof/intel/bdw.c22
-rw-r--r--sound/soc/sof/intel/byt.c6
-rw-r--r--sound/soc/sof/intel/hda-codec.c1
-rw-r--r--sound/soc/sof/intel/hda-dai.c14
-rw-r--r--sound/soc/sof/intel/hda-mlink.c127
-rw-r--r--sound/soc/sof/intel/hda-pcm.c15
-rw-r--r--sound/soc/sof/intel/hda.c57
-rw-r--r--sound/soc/sof/intel/hda.h4
-rw-r--r--sound/soc/sof/intel/lnl.c117
-rw-r--r--sound/soc/sof/intel/lnl.h6
-rw-r--r--sound/soc/sof/intel/mtl.c81
-rw-r--r--sound/soc/sof/intel/mtl.h15
-rw-r--r--sound/soc/sof/intel/pci-apl.c2
-rw-r--r--sound/soc/sof/intel/pci-cnl.c2
-rw-r--r--sound/soc/sof/intel/pci-icl.c2
-rw-r--r--sound/soc/sof/intel/pci-lnl.c14
-rw-r--r--sound/soc/sof/intel/pci-mtl.c10
-rw-r--r--sound/soc/sof/intel/pci-ptl.c20
-rw-r--r--sound/soc/sof/intel/pci-skl.c2
-rw-r--r--sound/soc/sof/intel/pci-tgl.c2
-rw-r--r--sound/soc/sof/intel/pci-tng.c3
-rw-r--r--sound/soc/sof/intel/ptl.c106
-rw-r--r--sound/soc/sof/intel/ptl.h19
-rw-r--r--sound/soc/sof/intel/shim.h2
-rw-r--r--sound/soc/sof/ipc3-pcm.c13
-rw-r--r--sound/soc/sof/ipc3-topology.c20
-rw-r--r--sound/soc/sof/ipc3.c12
-rw-r--r--sound/soc/sof/ipc4-loader.c176
-rw-r--r--sound/soc/sof/ipc4-pcm.c21
-rw-r--r--sound/soc/sof/ipc4-priv.h6
-rw-r--r--sound/soc/sof/ipc4-topology.c79
-rw-r--r--sound/soc/sof/ipc4.c26
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c109
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195-clk.c3
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.c113
-rw-r--r--sound/soc/sof/mediatek/mtk-adsp-common.c130
-rw-r--r--sound/soc/sof/mediatek/mtk-adsp-common.h10
-rw-r--r--sound/soc/sof/pcm.c171
-rw-r--r--sound/soc/sof/sof-acpi-dev.c9
-rw-r--r--sound/soc/sof/sof-audio.c49
-rw-r--r--sound/soc/sof/sof-audio.h18
-rw-r--r--sound/soc/sof/sof-client-ipc-flood-test.c39
-rw-r--r--sound/soc/sof/sof-of-dev.c8
-rw-r--r--sound/soc/sof/sof-pci-dev.c9
-rw-r--r--sound/soc/sof/sof-priv.h8
-rw-r--r--sound/soc/sof/stream-ipc.c6
-rw-r--r--sound/soc/sof/topology.c8
-rw-r--r--sound/soc/stm/stm32_i2s.c6
-rw-r--r--sound/soc/stm/stm32_sai.c6
-rw-r--r--sound/soc/stm/stm32_sai_sub.c6
-rw-r--r--sound/soc/stm/stm32_spdifrx.c6
-rw-r--r--sound/soc/sunxi/sun4i-codec.c466
-rw-r--r--sound/soc/sunxi/sun4i-spdif.c30
-rw-r--r--sound/soc/sunxi/sun50i-dmic.c6
-rw-r--r--sound/soc/sunxi/sun8i-codec.c6
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra186_asrc.c13
-rw-r--r--sound/soc/tegra/tegra186_dspk.c13
-rw-r--r--sound/soc/tegra/tegra20_i2s.c13
-rw-r--r--sound/soc/tegra/tegra20_spdif.c13
-rw-r--r--sound/soc/tegra/tegra210_admaif.c37
-rw-r--r--sound/soc/tegra/tegra210_admaif.h9
-rw-r--r--sound/soc/tegra/tegra210_adx.c23
-rw-r--r--sound/soc/tegra/tegra210_ahub.c13
-rw-r--r--sound/soc/tegra/tegra210_amx.c13
-rw-r--r--sound/soc/tegra/tegra210_dmic.c13
-rw-r--r--sound/soc/tegra/tegra210_i2s.c13
-rw-r--r--sound/soc/tegra/tegra210_mixer.c13
-rw-r--r--sound/soc/tegra/tegra210_mvc.c13
-rw-r--r--sound/soc/tegra/tegra210_ope.c13
-rw-r--r--sound/soc/tegra/tegra210_sfc.c13
-rw-r--r--sound/soc/tegra/tegra30_ahub.c13
-rw-r--r--sound/soc/tegra/tegra30_i2s.c13
-rw-r--r--sound/soc/tegra/tegra_asoc_machine.c18
-rw-r--r--sound/soc/tegra/tegra_isomgr_bw.c129
-rw-r--r--sound/soc/tegra/tegra_isomgr_bw.h31
-rw-r--r--sound/soc/tegra/tegra_wm8903.c2
-rw-r--r--sound/soc/ti/ams-delta.c2
-rw-r--r--sound/soc/ti/davinci-evm.c2
-rw-r--r--sound/soc/ti/davinci-i2s.c6
-rw-r--r--sound/soc/ti/j721e-evm.c9
-rw-r--r--sound/soc/ti/n810.c2
-rw-r--r--sound/soc/ti/omap-twl4030.c6
-rw-r--r--sound/soc/ti/omap3pandora.c4
-rw-r--r--sound/soc/ti/osk5912.c2
-rw-r--r--sound/soc/ti/rx51.c2
-rw-r--r--sound/soc/uniphier/aio-cpu.c8
-rw-r--r--sound/soc/ux500/mop500_ab8500.c4
-rw-r--r--sound/soc/xilinx/xlnx_spdif.c38
-rw-r--r--sound/soc/xtensa/xtfpga-i2s.c6
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/fcp.c1134
-rw-r--r--sound/usb/fcp.h7
-rw-r--r--sound/usb/format.c4
-rw-r--r--sound/usb/line6/toneport.c2
-rw-r--r--sound/usb/midi.c82
-rw-r--r--sound/usb/mixer_quirks.c68
-rw-r--r--sound/usb/mixer_scarlett2.c8
-rw-r--r--sound/usb/quirks.c9
-rw-r--r--sound/usb/usx2y/usbusx2y.c11
-rw-r--r--sound/usb/usx2y/usbusx2y.h26
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c27
-rw-r--r--sound/x86/intel_hdmi_audio.c8
690 files changed, 27131 insertions, 9806 deletions
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
index 8dfffdc101a2..47c6787158a7 100644
--- a/sound/ac97/bus.c
+++ b/sound/ac97/bus.c
@@ -387,7 +387,6 @@ void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl)
}
EXPORT_SYMBOL_GPL(snd_ac97_controller_unregister);
-#ifdef CONFIG_PM
static int ac97_pm_runtime_suspend(struct device *dev)
{
struct ac97_codec_device *codec = to_ac97_device(dev);
@@ -419,7 +418,6 @@ static int ac97_pm_runtime_resume(struct device *dev)
return pm_generic_runtime_resume(dev);
}
-#endif /* CONFIG_PM */
static const struct dev_pm_ops ac97_pm = {
.suspend = pm_generic_suspend,
@@ -428,10 +426,7 @@ static const struct dev_pm_ops ac97_pm = {
.thaw = pm_generic_thaw,
.poweroff = pm_generic_poweroff,
.restore = pm_generic_restore,
- SET_RUNTIME_PM_OPS(
- ac97_pm_runtime_suspend,
- ac97_pm_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(ac97_pm_runtime_suspend, ac97_pm_runtime_resume, NULL)
};
static int ac97_get_enable_clk(struct ac97_codec_device *adev)
@@ -535,7 +530,7 @@ const struct bus_type ac97_bus_type = {
.name = "ac97bus",
.dev_groups = ac97_dev_groups,
.match = ac97_bus_match,
- .pm = &ac97_pm,
+ .pm = pm_ptr(&ac97_pm),
.probe = ac97_bus_probe,
.remove = ac97_bus_remove,
};
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index c3340b8ff3da..243965615ef2 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -1061,7 +1061,7 @@ static void aaci_remove(struct amba_device *dev)
}
}
-static struct amba_id aaci_ids[] = {
+static const struct amba_id aaci_ids[] = {
{
.id = 0x00041041,
.mask = 0x000fffff,
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index d8f8e08f1bb7..84e264f335ca 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -817,7 +817,6 @@ err_prepare_enable:
return retval;
}
-#ifdef CONFIG_PM_SLEEP
static int atmel_ac97c_suspend(struct device *pdev)
{
struct snd_card *card = dev_get_drvdata(pdev);
@@ -836,11 +835,7 @@ static int atmel_ac97c_resume(struct device *pdev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume);
-#define ATMEL_AC97C_PM_OPS &atmel_ac97c_pm
-#else
-#define ATMEL_AC97C_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume);
static void atmel_ac97c_remove(struct platform_device *pdev)
{
@@ -864,7 +859,7 @@ static struct platform_driver atmel_ac97c_driver = {
.remove = atmel_ac97c_remove,
.driver = {
.name = "atmel_ac97c",
- .pm = ATMEL_AC97C_PM_OPS,
+ .pm = pm_ptr(&atmel_ac97c_pm),
.of_match_table = atmel_ac97c_dt_ids,
},
};
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index 147c1fea4708..e9c60dce59fb 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -66,9 +66,8 @@ static int snd_hrtimer_open(struct snd_timer *t)
stime = kzalloc(sizeof(*stime), GFP_KERNEL);
if (!stime)
return -ENOMEM;
- hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
stime->timer = t;
- stime->hrt.function = snd_hrtimer_callback;
+ hrtimer_setup(&stime->hrt, snd_hrtimer_callback, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
t->private_data = stime;
return 0;
}
diff --git a/sound/core/memory.c b/sound/core/memory.c
index 2d2d0094c897..d683442b4c97 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -27,38 +27,43 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size
if (import_ubuf(ITER_DEST, dst, count, &iter))
return -EFAULT;
- return copy_to_iter_fromio(&iter, (const void __iomem *)src, count);
+ if (copy_to_iter_fromio((const void __iomem *)src, count, &iter) != count)
+ return -EFAULT;
+ return 0;
}
EXPORT_SYMBOL(copy_to_user_fromio);
/**
* copy_to_iter_fromio - copy data from mmio-space to iov_iter
- * @dst: the destination iov_iter
* @src: the source pointer on mmio
* @count: the data size to copy in bytes
+ * @dst: the destination iov_iter
*
* Copies the data from mmio-space to iov_iter.
*
- * Return: Zero if successful, or non-zero on failure.
+ * Return: number of bytes to be copied
*/
-int copy_to_iter_fromio(struct iov_iter *dst, const void __iomem *src,
- size_t count)
+size_t copy_to_iter_fromio(const void __iomem *src, size_t count,
+ struct iov_iter *dst)
{
#if defined(__i386__) || defined(CONFIG_SPARC32)
- return copy_to_iter((const void __force *)src, count, dst) == count ? 0 : -EFAULT;
+ return copy_to_iter((const void __force *)src, count, dst);
#else
char buf[256];
+ size_t res = 0;
+
while (count) {
size_t c = count;
if (c > sizeof(buf))
c = sizeof(buf);
memcpy_fromio(buf, (void __iomem *)src, c);
if (copy_to_iter(buf, c, dst) != c)
- return -EFAULT;
+ return res;
count -= c;
src += c;
+ res += c;
}
- return 0;
+ return res;
#endif
}
EXPORT_SYMBOL(copy_to_iter_fromio);
@@ -79,37 +84,43 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
if (import_ubuf(ITER_SOURCE, (void __user *)src, count, &iter))
return -EFAULT;
- return copy_from_iter_toio((void __iomem *)dst, &iter, count);
+ if (copy_from_iter_toio((void __iomem *)dst, count, &iter) != count)
+ return -EFAULT;
+ return 0;
}
EXPORT_SYMBOL(copy_from_user_toio);
/**
* copy_from_iter_toio - copy data from iov_iter to mmio-space
* @dst: the destination pointer on mmio-space
- * @src: the source iov_iter
* @count: the data size to copy in bytes
+ * @src: the source iov_iter
*
* Copies the data from iov_iter to mmio-space.
*
- * Return: Zero if successful, or non-zero on failure.
+ * Return: number of bytes to be copied
*/
-int copy_from_iter_toio(void __iomem *dst, struct iov_iter *src, size_t count)
+size_t copy_from_iter_toio(void __iomem *dst, size_t count,
+ struct iov_iter *src)
{
#if defined(__i386__) || defined(CONFIG_SPARC32)
- return copy_from_iter((void __force *)dst, count, src) == count ? 0 : -EFAULT;
+ return copy_from_iter((void __force *)dst, count, src);
#else
char buf[256];
+ size_t res = 0;
+
while (count) {
size_t c = count;
if (c > sizeof(buf))
c = sizeof(buf);
if (copy_from_iter(buf, c, src) != c)
- return -EFAULT;
+ return res;
memcpy_toio(dst, buf, c);
count -= c;
dst += c;
+ res += c;
}
- return 0;
+ return res;
#endif
}
EXPORT_SYMBOL(copy_from_iter_toio);
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 290690fc2abc..283aac441fa0 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -592,7 +592,6 @@ static const struct attribute_group *pcm_dev_attr_groups[];
* PM callbacks: we need to deal only with suspend here, as the resume is
* triggered either from user-space or the driver's resume callback
*/
-#ifdef CONFIG_PM_SLEEP
static int do_pcm_suspend(struct device *dev)
{
struct snd_pcm_str *pstr = dev_get_drvdata(dev);
@@ -601,10 +600,9 @@ static int do_pcm_suspend(struct device *dev)
snd_pcm_suspend_all(pstr->pcm);
return 0;
}
-#endif
static const struct dev_pm_ops pcm_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL)
+ SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL)
};
/* device type for PCM -- basically only for passing PM callbacks */
diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c
index 1cdca4d4fc9c..688eefce82fa 100644
--- a/sound/core/pcm_drm_eld.c
+++ b/sound/core/pcm_drm_eld.c
@@ -5,8 +5,10 @@
#include <linux/bitfield.h>
#include <linux/export.h>
#include <linux/hdmi.h>
+#include <linux/unaligned.h>
#include <drm/drm_edid.h>
#include <drm/drm_eld.h>
+#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_drm_eld.h>
@@ -162,3 +164,388 @@ int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld)
return ret;
}
EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld);
+
+#define SND_PRINT_RATES_ADVISED_BUFSIZE 80
+#define SND_PRINT_BITS_ADVISED_BUFSIZE 16
+#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
+
+static const char * const eld_connection_type_names[4] = {
+ "HDMI",
+ "DisplayPort",
+ "2-reserved",
+ "3-reserved"
+};
+
+static const char * const cea_audio_coding_type_names[] = {
+ /* 0 */ "undefined",
+ /* 1 */ "LPCM",
+ /* 2 */ "AC-3",
+ /* 3 */ "MPEG1",
+ /* 4 */ "MP3",
+ /* 5 */ "MPEG2",
+ /* 6 */ "AAC-LC",
+ /* 7 */ "DTS",
+ /* 8 */ "ATRAC",
+ /* 9 */ "DSD (One Bit Audio)",
+ /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)",
+ /* 11 */ "DTS-HD",
+ /* 12 */ "MLP (Dolby TrueHD)",
+ /* 13 */ "DST",
+ /* 14 */ "WMAPro",
+ /* 15 */ "HE-AAC",
+ /* 16 */ "HE-AACv2",
+ /* 17 */ "MPEG Surround",
+};
+
+static const char * const cea_speaker_allocation_names[] = {
+ /* 0 */ "FL/FR",
+ /* 1 */ "LFE",
+ /* 2 */ "FC",
+ /* 3 */ "RL/RR",
+ /* 4 */ "RC",
+ /* 5 */ "FLC/FRC",
+ /* 6 */ "RLC/RRC",
+ /* 7 */ "FLW/FRW",
+ /* 8 */ "FLH/FRH",
+ /* 9 */ "TC",
+ /* 10 */ "FCH",
+};
+
+/*
+ * SS1:SS0 index => sample size
+ */
+static const int cea_sample_sizes[4] = {
+ 0, /* 0: Refer to Stream Header */
+ ELD_PCM_BITS_16, /* 1: 16 bits */
+ ELD_PCM_BITS_20, /* 2: 20 bits */
+ ELD_PCM_BITS_24, /* 3: 24 bits */
+};
+
+/*
+ * SF2:SF1:SF0 index => sampling frequency
+ */
+static const int cea_sampling_frequencies[8] = {
+ 0, /* 0: Refer to Stream Header */
+ SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
+ SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
+ SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
+ SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
+ SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
+ SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
+ SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
+};
+
+#define GRAB_BITS(buf, byte, lowbit, bits) \
+({ \
+ BUILD_BUG_ON(lowbit > 7); \
+ BUILD_BUG_ON(bits > 8); \
+ BUILD_BUG_ON(bits <= 0); \
+ \
+ (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \
+})
+
+static void hdmi_update_short_audio_desc(struct device *dev,
+ struct snd_cea_sad *a,
+ const unsigned char *buf)
+{
+ int i;
+ int val;
+
+ val = GRAB_BITS(buf, 1, 0, 7);
+ a->rates = 0;
+ for (i = 0; i < 7; i++)
+ if (val & (1 << i))
+ a->rates |= cea_sampling_frequencies[i + 1];
+
+ a->channels = GRAB_BITS(buf, 0, 0, 3);
+ a->channels++;
+
+ a->sample_bits = 0;
+ a->max_bitrate = 0;
+
+ a->format = GRAB_BITS(buf, 0, 3, 4);
+ switch (a->format) {
+ case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
+ dev_info(dev, "HDMI: audio coding type 0 not expected\n");
+ break;
+
+ case AUDIO_CODING_TYPE_LPCM:
+ val = GRAB_BITS(buf, 2, 0, 3);
+ for (i = 0; i < 3; i++)
+ if (val & (1 << i))
+ a->sample_bits |= cea_sample_sizes[i + 1];
+ break;
+
+ case AUDIO_CODING_TYPE_AC3:
+ case AUDIO_CODING_TYPE_MPEG1:
+ case AUDIO_CODING_TYPE_MP3:
+ case AUDIO_CODING_TYPE_MPEG2:
+ case AUDIO_CODING_TYPE_AACLC:
+ case AUDIO_CODING_TYPE_DTS:
+ case AUDIO_CODING_TYPE_ATRAC:
+ a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
+ a->max_bitrate *= 8000;
+ break;
+
+ case AUDIO_CODING_TYPE_SACD:
+ break;
+
+ case AUDIO_CODING_TYPE_EAC3:
+ break;
+
+ case AUDIO_CODING_TYPE_DTS_HD:
+ break;
+
+ case AUDIO_CODING_TYPE_MLP:
+ break;
+
+ case AUDIO_CODING_TYPE_DST:
+ break;
+
+ case AUDIO_CODING_TYPE_WMAPRO:
+ a->profile = GRAB_BITS(buf, 2, 0, 3);
+ break;
+
+ case AUDIO_CODING_TYPE_REF_CXT:
+ a->format = GRAB_BITS(buf, 2, 3, 5);
+ if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
+ a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
+ dev_info(dev,
+ "HDMI: audio coding xtype %d not expected\n",
+ a->format);
+ a->format = 0;
+ } else
+ a->format += AUDIO_CODING_TYPE_HE_AAC -
+ AUDIO_CODING_XTYPE_HE_AAC;
+ break;
+ }
+}
+
+/*
+ * Be careful, ELD buf could be totally rubbish!
+ */
+int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e,
+ const unsigned char *buf, int size)
+{
+ int mnl;
+ int i;
+
+ memset(e, 0, sizeof(*e));
+ e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
+ if (e->eld_ver != ELD_VER_CEA_861D &&
+ e->eld_ver != ELD_VER_PARTIAL) {
+ dev_info(dev, "HDMI: Unknown ELD version %d\n", e->eld_ver);
+ goto out_fail;
+ }
+
+ e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
+ mnl = GRAB_BITS(buf, 4, 0, 5);
+ e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
+
+ e->support_hdcp = GRAB_BITS(buf, 5, 0, 1);
+ e->support_ai = GRAB_BITS(buf, 5, 1, 1);
+ e->conn_type = GRAB_BITS(buf, 5, 2, 2);
+ e->sad_count = GRAB_BITS(buf, 5, 4, 4);
+
+ e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
+ e->spk_alloc = GRAB_BITS(buf, 7, 0, 7);
+
+ e->port_id = get_unaligned_le64(buf + 8);
+
+ /* not specified, but the spec's tendency is little endian */
+ e->manufacture_id = get_unaligned_le16(buf + 16);
+ e->product_id = get_unaligned_le16(buf + 18);
+
+ if (mnl > ELD_MAX_MNL) {
+ dev_info(dev, "HDMI: MNL is reserved value %d\n", mnl);
+ goto out_fail;
+ } else if (ELD_FIXED_BYTES + mnl > size) {
+ dev_info(dev, "HDMI: out of range MNL %d\n", mnl);
+ goto out_fail;
+ } else
+ strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1);
+
+ for (i = 0; i < e->sad_count; i++) {
+ if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
+ dev_info(dev, "HDMI: out of range SAD %d\n", i);
+ goto out_fail;
+ }
+ hdmi_update_short_audio_desc(dev, e->sad + i,
+ buf + ELD_FIXED_BYTES + mnl + 3 * i);
+ }
+
+ /*
+ * HDMI sink's ELD info cannot always be retrieved for now, e.g.
+ * in console or for audio devices. Assume the highest speakers
+ * configuration, to _not_ prohibit multi-channel audio playback.
+ */
+ if (!e->spk_alloc)
+ e->spk_alloc = 0xffff;
+
+ return 0;
+
+out_fail:
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(snd_parse_eld);
+
+/*
+ * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with
+ * hdmi-specific routine.
+ */
+static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen)
+{
+ static const unsigned int alsa_rates[] = {
+ 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+ 88200, 96000, 176400, 192000, 384000
+ };
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++)
+ if (pcm & (1 << i))
+ j += scnprintf(buf + j, buflen - j, " %d",
+ alsa_rates[i]);
+
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+static void eld_print_pcm_bits(int pcm, char *buf, int buflen)
+{
+ static const unsigned int bits[] = { 8, 16, 20, 24, 32 };
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++)
+ if (pcm & (ELD_PCM_BITS_8 << i))
+ j += scnprintf(buf + j, buflen - j, " %d", bits[i]);
+
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+static void hdmi_show_short_audio_desc(struct device *dev,
+ struct snd_cea_sad *a)
+{
+ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+ char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits =";
+
+ if (!a->format)
+ return;
+
+ hdmi_print_pcm_rates(a->rates, buf, sizeof(buf));
+
+ if (a->format == AUDIO_CODING_TYPE_LPCM)
+ eld_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8);
+ else if (a->max_bitrate)
+ snprintf(buf2, sizeof(buf2),
+ ", max bitrate = %d", a->max_bitrate);
+ else
+ buf2[0] = '\0';
+
+ dev_dbg(dev,
+ "HDMI: supports coding type %s: channels = %d, rates =%s%s\n",
+ cea_audio_coding_type_names[a->format],
+ a->channels, buf, buf2);
+}
+
+static void snd_eld_print_channel_allocation(int spk_alloc, char *buf, int buflen)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) {
+ if (spk_alloc & (1 << i))
+ j += scnprintf(buf + j, buflen - j, " %s",
+ cea_speaker_allocation_names[i]);
+ }
+ buf[j] = '\0'; /* necessary when j == 0 */
+}
+
+void snd_show_eld(struct device *dev, struct snd_parsed_hdmi_eld *e)
+{
+ int i;
+
+ dev_dbg(dev, "HDMI: detected monitor %s at connection type %s\n",
+ e->monitor_name,
+ eld_connection_type_names[e->conn_type]);
+
+ if (e->spk_alloc) {
+ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+
+ snd_eld_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+ dev_dbg(dev, "HDMI: available speakers:%s\n", buf);
+ }
+
+ for (i = 0; i < e->sad_count; i++)
+ hdmi_show_short_audio_desc(dev, e->sad + i);
+}
+EXPORT_SYMBOL_GPL(snd_show_eld);
+
+#ifdef CONFIG_SND_PROC_FS
+static void hdmi_print_sad_info(int i, struct snd_cea_sad *a,
+ struct snd_info_buffer *buffer)
+{
+ char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
+
+ snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n",
+ i, a->format, cea_audio_coding_type_names[a->format]);
+ snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
+
+ hdmi_print_pcm_rates(a->rates, buf, sizeof(buf));
+ snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
+
+ if (a->format == AUDIO_CODING_TYPE_LPCM) {
+ eld_print_pcm_bits(a->sample_bits, buf, sizeof(buf));
+ snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n",
+ i, a->sample_bits, buf);
+ }
+
+ if (a->max_bitrate)
+ snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
+ i, a->max_bitrate);
+
+ if (a->profile)
+ snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
+}
+
+void snd_print_eld_info(struct snd_parsed_hdmi_eld *e,
+ struct snd_info_buffer *buffer)
+{
+ char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
+ int i;
+ static const char * const eld_version_names[32] = {
+ "reserved",
+ "reserved",
+ "CEA-861D or below",
+ [3 ... 30] = "reserved",
+ [31] = "partial"
+ };
+ static const char * const cea_edid_version_names[8] = {
+ "no CEA EDID Timing Extension block present",
+ "CEA-861",
+ "CEA-861-A",
+ "CEA-861-B, C or D",
+ [4 ... 7] = "reserved"
+ };
+
+ snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
+ snd_iprintf(buffer, "connection_type\t\t%s\n",
+ eld_connection_type_names[e->conn_type]);
+ snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
+ eld_version_names[e->eld_ver]);
+ snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
+ cea_edid_version_names[e->cea_edid_ver]);
+ snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
+ snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
+ snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
+ snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
+ snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
+ snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
+
+ snd_eld_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
+ snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
+
+ snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
+
+ for (i = 0; i < e->sad_count; i++)
+ hdmi_print_sad_info(i, e->sad + i, buffer);
+}
+EXPORT_SYMBOL_GPL(snd_print_eld_info);
+#endif /* CONFIG_SND_PROC_FS */
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index 4f556211bb56..d3a08e292072 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -432,9 +432,9 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
if (samples == 0)
return 0;
width = pcm_formats[(INT)format].phys; /* physical width */
- pat = pcm_formats[(INT)format].silence;
- if (!width || !pat)
+ if (!width)
return -EINVAL;
+ pat = pcm_formats[(INT)format].silence;
/* signed or 1 byte data */
if (pcm_formats[(INT)format].signd == 1 || width <= 8) {
unsigned int bytes = samples * width / 8;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8a3384342e8d..6c2b6a62d9d2 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3245,7 +3245,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
return -EFAULT;
- bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
+ bufs = memdup_array_user(xfern.bufs, runtime->channels, sizeof(void *));
if (IS_ERR(bufs))
return PTR_ERR(bufs);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 348ce1b7725e..70a958ac1112 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -629,12 +629,15 @@ static int snd_rawmidi_info(struct snd_rawmidi_substream *substream,
info->subdevice = substream->number;
info->stream = substream->stream;
info->flags = rmidi->info_flags;
+ if (substream->inactive)
+ info->flags |= SNDRV_RAWMIDI_INFO_STREAM_INACTIVE;
strcpy(info->id, rmidi->id);
strcpy(info->name, rmidi->name);
strcpy(info->subname, substream->name);
info->subdevices_count = substream->pstr->substream_count;
info->subdevices_avail = (substream->pstr->substream_count -
substream->pstr->substream_opened);
+ info->tied_device = rmidi->tied_device;
return 0;
}
diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig
index 0374bbf51cd4..e4f58cb985d4 100644
--- a/sound/core/seq/Kconfig
+++ b/sound/core/seq/Kconfig
@@ -62,7 +62,7 @@ config SND_SEQ_VIRMIDI
config SND_SEQ_UMP
bool "Support for UMP events"
- default y if SND_SEQ_UMP_CLIENT
+ default SND_UMP
help
Say Y here to enable the support for handling UMP (Universal MIDI
Packet) events via ALSA sequencer infrastructure, which is an
@@ -71,6 +71,6 @@ config SND_SEQ_UMP
among legacy and UMP clients.
config SND_SEQ_UMP_CLIENT
- def_tristate SND_UMP
+ def_tristate SND_UMP && SND_SEQ_UMP
endif # SND_SEQUENCER
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
index 98dd20b42976..6163a00bc8de 100644
--- a/sound/core/seq/oss/seq_oss_device.h
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -55,7 +55,6 @@ struct seq_oss_chinfo {
struct seq_oss_synthinfo {
struct snd_seq_oss_arg arg;
struct seq_oss_chinfo *ch;
- struct seq_oss_synth_sysex *sysex;
int nr_voices;
int opened;
int is_midi;
@@ -157,8 +156,4 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev,
ev->dest.port = dest_port;
}
-
-/* misc. functions for proc interface */
-char *enabled_str(bool b);
-
#endif /* __SEQ_OSS_DEVICE_H */
diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c
index 7b7c925dd3aa..76fb81077eef 100644
--- a/sound/core/seq/oss/seq_oss_event.c
+++ b/sound/core/seq/oss/seq_oss_event.c
@@ -290,16 +290,14 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st
if (note == 255 && info->ch[ch].note >= 0) {
/* volume control */
int type;
- //if (! vel)
- /* set volume to zero -- note off */
- // type = SNDRV_SEQ_EVENT_NOTEOFF;
- //else
- if (info->ch[ch].vel)
+
+ if (info->ch[ch].vel)
/* sample already started -- volume change */
type = SNDRV_SEQ_EVENT_KEYPRESS;
else
/* sample not started -- start now */
type = SNDRV_SEQ_EVENT_NOTEON;
+
info->ch[ch].vel = vel;
return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev);
} else if (note >= 128)
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index 676246fa02f1..e6d7d83ed0e7 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -111,7 +111,7 @@ snd_seq_oss_create_client(void)
/*
- * receive annoucement from system port, and check the midi device
+ * receive announcement from system port, and check the midi device
*/
static int
receive_announce(struct snd_seq_event *ev, int direct, void *private, int atomic, int hop)
@@ -449,12 +449,6 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp)
/*
* misc. functions for proc interface
*/
-char *
-enabled_str(bool b)
-{
- return b ? "enabled" : "disabled";
-}
-
static const char *
filemode_str(int val)
{
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
index 51ee4c00a843..9de47e098b29 100644
--- a/sound/core/seq/oss/seq_oss_synth.c
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -26,13 +26,6 @@
* definition of synth info records
*/
-/* sysex buffer */
-struct seq_oss_synth_sysex {
- int len;
- int skip;
- unsigned char buf[MAX_SYSEX_BUFLEN];
-};
-
/* synth info */
struct seq_oss_synth {
int seq_device;
@@ -66,7 +59,6 @@ static struct seq_oss_synth midi_synth_dev = {
};
static DEFINE_SPINLOCK(register_lock);
-static DEFINE_MUTEX(sysex_mutex);
/*
* prototypes
@@ -319,8 +311,6 @@ snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp)
}
snd_use_lock_free(&rec->use_lock);
}
- kfree(info->sysex);
- info->sysex = NULL;
kfree(info->ch);
info->ch = NULL;
}
@@ -396,8 +386,6 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
info = get_synthinfo_nospec(dp, dev);
if (!info || !info->opened)
return;
- if (info->sysex)
- info->sysex->len = 0; /* reset sysex */
reset_channels(info);
if (info->is_midi) {
if (midi_synth_dev.opened <= 0)
@@ -409,8 +397,6 @@ snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev)
dp->file_mode) < 0) {
midi_synth_dev.opened--;
info->opened = 0;
- kfree(info->sysex);
- info->sysex = NULL;
kfree(info->ch);
info->ch = NULL;
}
@@ -483,64 +469,26 @@ snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev)
/*
* receive OSS 6 byte sysex packet:
- * the full sysex message will be sent if it reaches to the end of data
- * (0xff).
+ * the event is filled and prepared for sending immediately
+ * (i.e. sysex messages are fragmented)
*/
int
snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev)
{
- int i, send;
- unsigned char *dest;
- struct seq_oss_synth_sysex *sysex;
- struct seq_oss_synthinfo *info;
+ unsigned char *p;
+ int len = 6;
- info = snd_seq_oss_synth_info(dp, dev);
- if (!info)
- return -ENXIO;
+ p = memchr(buf, 0xff, 6);
+ if (p)
+ len = p - buf + 1;
- guard(mutex)(&sysex_mutex);
- sysex = info->sysex;
- if (sysex == NULL) {
- sysex = kzalloc(sizeof(*sysex), GFP_KERNEL);
- if (sysex == NULL)
- return -ENOMEM;
- info->sysex = sysex;
- }
-
- send = 0;
- dest = sysex->buf + sysex->len;
- /* copy 6 byte packet to the buffer */
- for (i = 0; i < 6; i++) {
- if (buf[i] == 0xff) {
- send = 1;
- break;
- }
- dest[i] = buf[i];
- sysex->len++;
- if (sysex->len >= MAX_SYSEX_BUFLEN) {
- sysex->len = 0;
- sysex->skip = 1;
- break;
- }
- }
-
- if (sysex->len && send) {
- if (sysex->skip) {
- sysex->skip = 0;
- sysex->len = 0;
- return -EINVAL; /* skip */
- }
- /* copy the data to event record and send it */
- ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
- if (snd_seq_oss_synth_addr(dp, dev, ev))
- return -EINVAL;
- ev->data.ext.len = sysex->len;
- ev->data.ext.ptr = sysex->buf;
- sysex->len = 0;
- return 0;
- }
-
- return -EINVAL; /* skip */
+ /* copy the data to event record and send it */
+ if (snd_seq_oss_synth_addr(dp, dev, ev))
+ return -EINVAL;
+ ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
+ ev->data.ext.len = len;
+ ev->data.ext.ptr = buf;
+ return 0;
}
/*
@@ -660,8 +608,8 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf)
rec->synth_type, rec->synth_subtype,
rec->nr_voices);
snd_iprintf(buf, " capabilities : ioctl %s / load_patch %s\n",
- enabled_str((long)rec->oper.ioctl),
- enabled_str((long)rec->oper.load_patch));
+ str_enabled_disabled((long)rec->oper.ioctl),
+ str_enabled_disabled((long)rec->oper.load_patch));
snd_use_lock_free(&rec->use_lock);
}
}
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 77b6ac9b5c11..198c598a5393 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -106,7 +106,7 @@ static struct snd_seq_client *clientptr(int clientid)
return clienttab[clientid];
}
-struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
+static struct snd_seq_client *client_use_ptr(int clientid, bool load_module)
{
unsigned long flags;
struct snd_seq_client *client;
@@ -126,7 +126,7 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
}
spin_unlock_irqrestore(&clients_lock, flags);
#ifdef CONFIG_MODULES
- if (!in_interrupt()) {
+ if (load_module) {
static DECLARE_BITMAP(client_requested, SNDRV_SEQ_GLOBAL_CLIENTS);
static DECLARE_BITMAP(card_requested, SNDRV_CARDS);
@@ -168,6 +168,20 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
return client;
}
+/* get snd_seq_client object for the given id quickly */
+struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
+{
+ return client_use_ptr(clientid, false);
+}
+
+/* get snd_seq_client object for the given id;
+ * if not found, retry after loading the modules
+ */
+static struct snd_seq_client *client_load_and_use_ptr(int clientid)
+{
+ return client_use_ptr(clientid, IS_ENABLED(CONFIG_MODULES));
+}
+
/* Take refcount and perform ioctl_mutex lock on the given client;
* used only for OSS sequencer
* Unlock via snd_seq_client_ioctl_unlock() below
@@ -176,7 +190,7 @@ bool snd_seq_client_ioctl_lock(int clientid)
{
struct snd_seq_client *client;
- client = snd_seq_client_use_ptr(clientid);
+ client = client_load_and_use_ptr(clientid);
if (!client)
return false;
mutex_lock(&client->ioctl_mutex);
@@ -678,12 +692,18 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
dest_port->time_real);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
- if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
- if (snd_seq_ev_is_ump(event)) {
+ if (snd_seq_ev_is_ump(event)) {
+ if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
result = snd_seq_deliver_from_ump(client, dest, dest_port,
event, atomic, hop);
goto __skip;
- } else if (snd_seq_client_is_ump(dest)) {
+ } else if (dest->type == USER_CLIENT &&
+ !snd_seq_client_is_ump(dest)) {
+ result = 0; // drop the event
+ goto __skip;
+ }
+ } else if (snd_seq_client_is_ump(dest)) {
+ if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
result = snd_seq_deliver_to_ump(client, dest, dest_port,
event, atomic, hop);
goto __skip;
@@ -1130,8 +1150,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait)
if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) {
/* check if data is available in the pool */
- if (!snd_seq_write_pool_allocated(client) ||
- snd_seq_pool_poll_wait(client->pool, file, wait))
+ if (snd_seq_pool_poll_wait(client->pool, file, wait))
mask |= EPOLLOUT | EPOLLWRNORM;
}
@@ -1189,7 +1208,7 @@ static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg)
int err = 0;
/* requested client number */
- cptr = snd_seq_client_use_ptr(info->client);
+ cptr = client_load_and_use_ptr(info->client);
if (cptr == NULL)
return -ENOENT; /* don't change !!! */
@@ -1251,7 +1270,7 @@ static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
struct snd_seq_client *cptr;
/* requested client number */
- cptr = snd_seq_client_use_ptr(client_info->client);
+ cptr = client_load_and_use_ptr(client_info->client);
if (cptr == NULL)
return -ENOENT; /* don't change !!! */
@@ -1296,6 +1315,10 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
client->midi_version = client_info->midi_version;
memcpy(client->event_filter, client_info->event_filter, 32);
client->group_filter = client_info->group_filter;
+
+ /* notify the change */
+ snd_seq_system_client_ev_client_change(client->number);
+
return 0;
}
@@ -1386,7 +1409,7 @@ static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
struct snd_seq_client *cptr;
struct snd_seq_client_port *port;
- cptr = snd_seq_client_use_ptr(info->addr.client);
+ cptr = client_load_and_use_ptr(info->addr.client);
if (cptr == NULL)
return -ENXIO;
@@ -1419,6 +1442,9 @@ static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg)
if (port) {
snd_seq_set_port_info(port, info);
snd_seq_port_unlock(port);
+ /* notify the change */
+ snd_seq_system_client_ev_port_change(info->addr.client,
+ info->addr.port);
}
return 0;
}
@@ -1475,7 +1501,7 @@ int snd_seq_client_notify_subscription(int client, int port,
event.data.connect.dest = info->dest;
event.data.connect.sender = info->sender;
- return snd_seq_system_notify(client, port, &event); /* non-atomic */
+ return snd_seq_system_notify(client, port, &event, false); /* non-atomic */
}
@@ -1490,10 +1516,10 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
struct snd_seq_client *receiver = NULL, *sender = NULL;
struct snd_seq_client_port *sport = NULL, *dport = NULL;
- receiver = snd_seq_client_use_ptr(subs->dest.client);
+ receiver = client_load_and_use_ptr(subs->dest.client);
if (!receiver)
goto __end;
- sender = snd_seq_client_use_ptr(subs->sender.client);
+ sender = client_load_and_use_ptr(subs->sender.client);
if (!sender)
goto __end;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
@@ -1858,7 +1884,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
struct snd_seq_client_pool *info = arg;
struct snd_seq_client *cptr;
- cptr = snd_seq_client_use_ptr(info->client);
+ cptr = client_load_and_use_ptr(info->client);
if (cptr == NULL)
return -ENOENT;
memset(info, 0, sizeof(*info));
@@ -1962,7 +1988,7 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
struct snd_seq_client_port *sport = NULL;
result = -EINVAL;
- sender = snd_seq_client_use_ptr(subs->sender.client);
+ sender = client_load_and_use_ptr(subs->sender.client);
if (!sender)
goto __end;
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
@@ -1993,7 +2019,7 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
struct list_head *p;
int i;
- cptr = snd_seq_client_use_ptr(subs->root.client);
+ cptr = client_load_and_use_ptr(subs->root.client);
if (!cptr)
goto __end;
port = snd_seq_port_use_ptr(cptr, subs->root.port);
@@ -2060,7 +2086,7 @@ static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
if (info->client < 0)
info->client = 0;
for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) {
- cptr = snd_seq_client_use_ptr(info->client);
+ cptr = client_load_and_use_ptr(info->client);
if (cptr)
break; /* found */
}
@@ -2083,7 +2109,7 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
struct snd_seq_client *cptr;
struct snd_seq_client_port *port = NULL;
- cptr = snd_seq_client_use_ptr(info->addr.client);
+ cptr = client_load_and_use_ptr(info->addr.client);
if (cptr == NULL)
return -ENXIO;
@@ -2180,7 +2206,7 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
size = sizeof(struct snd_ump_endpoint_info);
else
size = sizeof(struct snd_ump_block_info);
- cptr = snd_seq_client_use_ptr(client);
+ cptr = client_load_and_use_ptr(client);
if (!cptr)
return -ENOENT;
@@ -2229,6 +2255,16 @@ static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
error:
mutex_unlock(&cptr->ioctl_mutex);
snd_seq_client_unlock(cptr);
+ if (!err && cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO) {
+ if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
+ snd_seq_system_ump_notify(client, 0,
+ SNDRV_SEQ_EVENT_UMP_EP_CHANGE,
+ false);
+ else
+ snd_seq_system_ump_notify(client, type - 1,
+ SNDRV_SEQ_EVENT_UMP_BLOCK_CHANGE,
+ false);
+ }
return err;
}
#endif
@@ -2452,7 +2488,7 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
if (check_event_type_and_length(ev))
return -EINVAL;
- cptr = snd_seq_client_use_ptr(client);
+ cptr = client_load_and_use_ptr(client);
if (cptr == NULL)
return -EINVAL;
@@ -2549,8 +2585,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
if (client == NULL)
return -ENXIO;
- if (! snd_seq_write_pool_allocated(client))
- return 1;
if (snd_seq_pool_poll_wait(client->pool, file, wait))
return 1;
return 0;
@@ -2684,7 +2718,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
/* list the client table */
for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
- client = snd_seq_client_use_ptr(c);
+ client = client_load_and_use_ptr(c);
if (client == NULL)
continue;
if (client->type == NO_CLIENT) {
@@ -2692,6 +2726,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
continue;
}
+ mutex_lock(&client->ioctl_mutex);
snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n",
c, client->name,
client->type == USER_CLIENT ? "User" : "Kernel",
@@ -2709,6 +2744,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
snd_iprintf(buffer, " Input pool :\n");
snd_seq_info_pool(buffer, client->data.user.fifo->pool, " ");
}
+ mutex_unlock(&client->ioctl_mutex);
snd_seq_client_unlock(client);
}
}
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index 20155e3e87c6..ccde0ca3d208 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -427,6 +427,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file,
poll_table *wait)
{
poll_wait(file, &pool->output_sleep, wait);
+ guard(spinlock_irq)(&pool->lock);
return snd_seq_output_ok(pool);
}
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c
index 80267290190d..853920f79016 100644
--- a/sound/core/seq/seq_system.c
+++ b/sound/core/seq/seq_system.c
@@ -49,12 +49,14 @@ static int sysclient = -1;
/* port id numbers for this client */
static int announce_port = -1;
+/* number of subscriptions to announce port */
+static int announce_subscribed;
/* fill standard header data, source port & channel are filled in */
static int setheader(struct snd_seq_event * ev, int client, int port)
{
- if (announce_port < 0)
+ if (announce_port < 0 || !announce_subscribed)
return -ENODEV;
memset(ev, 0, sizeof(struct snd_seq_event));
@@ -76,26 +78,27 @@ static int setheader(struct snd_seq_event * ev, int client, int port)
/* entry points for broadcasting system events */
-void snd_seq_system_broadcast(int client, int port, int type)
+void snd_seq_system_broadcast(int client, int port, int type, bool atomic)
{
struct snd_seq_event ev;
if (setheader(&ev, client, port) < 0)
return;
ev.type = type;
- snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0);
+ snd_seq_kernel_client_dispatch(sysclient, &ev, atomic, 0);
}
EXPORT_SYMBOL_GPL(snd_seq_system_broadcast);
/* entry points for broadcasting system events */
-int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev)
+int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev,
+ bool atomic)
{
ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
ev->source.client = sysclient;
ev->source.port = announce_port;
ev->dest.client = client;
ev->dest.port = port;
- return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0);
+ return snd_seq_kernel_client_dispatch(sysclient, ev, atomic, 0);
}
/* call-back handler for timer events */
@@ -104,6 +107,22 @@ static int event_input_timer(struct snd_seq_event * ev, int direct, void *privat
return snd_seq_control_queue(ev, atomic, hop);
}
+static int sys_announce_subscribe(void *private_data,
+ struct snd_seq_port_subscribe *info)
+{
+ announce_subscribed++;
+ return 0;
+}
+
+static int sys_announce_unsubscribe(void *private_data,
+ struct snd_seq_port_subscribe *info)
+{
+ if (snd_BUG_ON(!announce_subscribed))
+ return 0;
+ announce_subscribed--;
+ return 0;
+}
+
/* register our internal client */
int __init snd_seq_system_client_init(void)
{
@@ -143,7 +162,10 @@ int __init snd_seq_system_client_init(void)
/* register announcement port */
strcpy(port->name, "Announce");
port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
- port->kernel = NULL;
+ pcallbacks.event_input = NULL;
+ pcallbacks.subscribe = sys_announce_subscribe;
+ pcallbacks.unsubscribe = sys_announce_unsubscribe;
+ port->kernel = &pcallbacks;
port->type = 0;
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
port->addr.client = sysclient;
diff --git a/sound/core/seq/seq_system.h b/sound/core/seq/seq_system.h
index 4fe88ad40346..62e513f74871 100644
--- a/sound/core/seq/seq_system.h
+++ b/sound/core/seq/seq_system.h
@@ -10,16 +10,31 @@
/* entry points for broadcasting system events */
-void snd_seq_system_broadcast(int client, int port, int type);
-
-#define snd_seq_system_client_ev_client_start(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_START)
-#define snd_seq_system_client_ev_client_exit(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_EXIT)
-#define snd_seq_system_client_ev_client_change(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_CHANGE)
-#define snd_seq_system_client_ev_port_start(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_START)
-#define snd_seq_system_client_ev_port_exit(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_EXIT)
-#define snd_seq_system_client_ev_port_change(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_CHANGE)
-
-int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev);
+void snd_seq_system_broadcast(int client, int port, int type, bool atomic);
+
+/* normal system notification event broadcast */
+#define notify_event(client, port, type) \
+ snd_seq_system_broadcast(client, port, type, false)
+
+/* notify UMP EP/FB change event */
+static inline void snd_seq_system_ump_notify(int client, int block, int type,
+ bool atomic)
+{
+ /* reuse the existing snd_seq_system_broadcast():
+ * struct snd_seq_ev_ump_notify is compatible with struct snd_seq_addr
+ */
+ snd_seq_system_broadcast(client, block, type, atomic);
+}
+
+#define snd_seq_system_client_ev_client_start(client) notify_event(client, 0, SNDRV_SEQ_EVENT_CLIENT_START)
+#define snd_seq_system_client_ev_client_exit(client) notify_event(client, 0, SNDRV_SEQ_EVENT_CLIENT_EXIT)
+#define snd_seq_system_client_ev_client_change(client) notify_event(client, 0, SNDRV_SEQ_EVENT_CLIENT_CHANGE)
+#define snd_seq_system_client_ev_port_start(client, port) notify_event(client, port, SNDRV_SEQ_EVENT_PORT_START)
+#define snd_seq_system_client_ev_port_exit(client, port) notify_event(client, port, SNDRV_SEQ_EVENT_PORT_EXIT)
+#define snd_seq_system_client_ev_port_change(client, port) notify_event(client, port, SNDRV_SEQ_EVENT_PORT_CHANGE)
+
+int snd_seq_system_notify(int client, int port, struct snd_seq_event *ev,
+ bool atomic);
/* register our internal client */
int snd_seq_system_client_init(void);
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
index e956f17f3792..1255351b59ce 100644
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -272,8 +272,6 @@ static void update_port_infos(struct seq_ump_client *client)
new);
if (err < 0)
continue;
- /* notify to system port */
- snd_seq_system_client_ev_port_change(client->seq_client, i);
}
}
@@ -390,6 +388,33 @@ static void handle_group_notify(struct work_struct *work)
setup_client_group_filter(client);
}
+/* UMP EP change notification */
+static int seq_ump_notify_ep_change(struct snd_ump_endpoint *ump)
+{
+ struct seq_ump_client *client = ump->seq_client;
+ struct snd_seq_client *cptr;
+ int client_id;
+
+ if (!client)
+ return -ENODEV;
+ client_id = client->seq_client;
+ cptr = snd_seq_kernel_client_get(client_id);
+ if (!cptr)
+ return -ENODEV;
+
+ snd_seq_system_ump_notify(client_id, 0, SNDRV_SEQ_EVENT_UMP_EP_CHANGE,
+ true);
+
+ /* update sequencer client name if needed */
+ if (*ump->core.name && strcmp(ump->core.name, cptr->name)) {
+ strscpy(cptr->name, ump->core.name, sizeof(cptr->name));
+ snd_seq_system_client_ev_client_change(client_id);
+ }
+
+ snd_seq_kernel_client_put(cptr);
+ return 0;
+}
+
/* UMP FB change notification */
static int seq_ump_notify_fb_change(struct snd_ump_endpoint *ump,
struct snd_ump_block *fb)
@@ -399,20 +424,29 @@ static int seq_ump_notify_fb_change(struct snd_ump_endpoint *ump,
if (!client)
return -ENODEV;
schedule_work(&client->group_notify_work);
+ snd_seq_system_ump_notify(client->seq_client, fb->info.block_id,
+ SNDRV_SEQ_EVENT_UMP_BLOCK_CHANGE,
+ true);
return 0;
}
/* UMP protocol change notification; just update the midi_version field */
static int seq_ump_switch_protocol(struct snd_ump_endpoint *ump)
{
- if (!ump->seq_client)
+ struct seq_ump_client *client = ump->seq_client;
+
+ if (!client)
return -ENODEV;
- setup_client_midi_version(ump->seq_client);
+ setup_client_midi_version(client);
+ snd_seq_system_ump_notify(client->seq_client, 0,
+ SNDRV_SEQ_EVENT_UMP_EP_CHANGE,
+ true);
return 0;
}
static const struct snd_seq_ump_ops seq_ump_ops = {
.input_receive = seq_ump_input_receive,
+ .notify_ep_change = seq_ump_notify_ep_change,
.notify_fb_change = seq_ump_notify_fb_change,
.switch_protocol = seq_ump_switch_protocol,
};
diff --git a/sound/core/timer.c b/sound/core/timer.c
index fbada79380f9..d774b9b71ce2 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1515,91 +1515,97 @@ static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *ti
id->subdevice = timer->tmr_subdevice;
}
-static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
+static void get_next_device(struct snd_timer_id *id)
{
- struct snd_timer_id id;
struct snd_timer *timer;
struct list_head *p;
- if (copy_from_user(&id, _tid, sizeof(id)))
- return -EFAULT;
- guard(mutex)(&register_mutex);
- if (id.dev_class < 0) { /* first item */
+ if (id->dev_class < 0) { /* first item */
if (list_empty(&snd_timer_list))
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
else {
timer = list_entry(snd_timer_list.next,
struct snd_timer, device_list);
- snd_timer_user_copy_id(&id, timer);
+ snd_timer_user_copy_id(id, timer);
}
} else {
- switch (id.dev_class) {
+ switch (id->dev_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
- id.device = id.device < 0 ? 0 : id.device + 1;
+ id->device = id->device < 0 ? 0 : id->device + 1;
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {
- snd_timer_user_copy_id(&id, timer);
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_device >= id.device) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_device >= id->device) {
+ snd_timer_user_copy_id(id, timer);
break;
}
}
if (p == &snd_timer_list)
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
break;
case SNDRV_TIMER_CLASS_CARD:
case SNDRV_TIMER_CLASS_PCM:
- if (id.card < 0) {
- id.card = 0;
+ if (id->card < 0) {
+ id->card = 0;
} else {
- if (id.device < 0) {
- id.device = 0;
+ if (id->device < 0) {
+ id->device = 0;
} else {
- if (id.subdevice < 0)
- id.subdevice = 0;
- else if (id.subdevice < INT_MAX)
- id.subdevice++;
+ if (id->subdevice < 0)
+ id->subdevice = 0;
+ else if (id->subdevice < INT_MAX)
+ id->subdevice++;
}
}
list_for_each(p, &snd_timer_list) {
timer = list_entry(p, struct snd_timer, device_list);
- if (timer->tmr_class > id.dev_class) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_class > id->dev_class) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_class < id.dev_class)
+ if (timer->tmr_class < id->dev_class)
continue;
- if (timer->card->number > id.card) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->card->number > id->card) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->card->number < id.card)
+ if (timer->card->number < id->card)
continue;
- if (timer->tmr_device > id.device) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_device > id->device) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_device < id.device)
+ if (timer->tmr_device < id->device)
continue;
- if (timer->tmr_subdevice > id.subdevice) {
- snd_timer_user_copy_id(&id, timer);
+ if (timer->tmr_subdevice > id->subdevice) {
+ snd_timer_user_copy_id(id, timer);
break;
}
- if (timer->tmr_subdevice < id.subdevice)
+ if (timer->tmr_subdevice < id->subdevice)
continue;
- snd_timer_user_copy_id(&id, timer);
+ snd_timer_user_copy_id(id, timer);
break;
}
if (p == &snd_timer_list)
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
break;
default:
- snd_timer_user_zero_id(&id);
+ snd_timer_user_zero_id(id);
}
}
+}
+
+static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
+{
+ struct snd_timer_id id;
+
+ if (copy_from_user(&id, _tid, sizeof(id)))
+ return -EFAULT;
+ scoped_guard(mutex, &register_mutex)
+ get_next_device(&id);
if (copy_to_user(_tid, &id, sizeof(*_tid)))
return -EFAULT;
return 0;
@@ -1620,23 +1626,24 @@ static int snd_timer_user_ginfo(struct file *file,
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
- guard(mutex)(&register_mutex);
- t = snd_timer_find(&tid);
- if (!t)
- return -ENODEV;
- ginfo->card = t->card ? t->card->number : -1;
- if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
- ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
- strscpy(ginfo->id, t->id, sizeof(ginfo->id));
- strscpy(ginfo->name, t->name, sizeof(ginfo->name));
- scoped_guard(spinlock_irq, &t->lock)
- ginfo->resolution = snd_timer_hw_resolution(t);
- if (t->hw.resolution_min > 0) {
- ginfo->resolution_min = t->hw.resolution_min;
- ginfo->resolution_max = t->hw.resolution_max;
- }
- list_for_each(p, &t->open_list_head) {
- ginfo->clients++;
+ scoped_guard(mutex, &register_mutex) {
+ t = snd_timer_find(&tid);
+ if (!t)
+ return -ENODEV;
+ ginfo->card = t->card ? t->card->number : -1;
+ if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
+ ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
+ strscpy(ginfo->id, t->id, sizeof(ginfo->id));
+ strscpy(ginfo->name, t->name, sizeof(ginfo->name));
+ scoped_guard(spinlock_irq, &t->lock)
+ ginfo->resolution = snd_timer_hw_resolution(t);
+ if (t->hw.resolution_min > 0) {
+ ginfo->resolution_min = t->hw.resolution_min;
+ ginfo->resolution_max = t->hw.resolution_max;
+ }
+ list_for_each(p, &t->open_list_head) {
+ ginfo->clients++;
+ }
}
if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
return -EFAULT;
@@ -1674,31 +1681,31 @@ static int snd_timer_user_gstatus(struct file *file,
struct snd_timer_gstatus gstatus;
struct snd_timer_id tid;
struct snd_timer *t;
- int err = 0;
if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
return -EFAULT;
tid = gstatus.tid;
memset(&gstatus, 0, sizeof(gstatus));
gstatus.tid = tid;
- guard(mutex)(&register_mutex);
- t = snd_timer_find(&tid);
- if (t != NULL) {
- guard(spinlock_irq)(&t->lock);
- gstatus.resolution = snd_timer_hw_resolution(t);
- if (t->hw.precise_resolution) {
- t->hw.precise_resolution(t, &gstatus.resolution_num,
- &gstatus.resolution_den);
+ scoped_guard(mutex, &register_mutex) {
+ t = snd_timer_find(&tid);
+ if (t != NULL) {
+ guard(spinlock_irq)(&t->lock);
+ gstatus.resolution = snd_timer_hw_resolution(t);
+ if (t->hw.precise_resolution) {
+ t->hw.precise_resolution(t, &gstatus.resolution_num,
+ &gstatus.resolution_den);
+ } else {
+ gstatus.resolution_num = gstatus.resolution;
+ gstatus.resolution_den = 1000000000uL;
+ }
} else {
- gstatus.resolution_num = gstatus.resolution;
- gstatus.resolution_den = 1000000000uL;
+ return -ENODEV;
}
- } else {
- err = -ENODEV;
}
- if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
- err = -EFAULT;
- return err;
+ if (copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
+ return -EFAULT;
+ return 0;
}
static int snd_timer_user_tselect(struct file *file,
diff --git a/sound/core/ump.c b/sound/core/ump.c
index 9198bff4768c..8d8681a42ca5 100644
--- a/sound/core/ump.c
+++ b/sound/core/ump.c
@@ -37,6 +37,7 @@ static int process_legacy_output(struct snd_ump_endpoint *ump,
u32 *buffer, int count);
static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src,
int words);
+static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump);
static void update_legacy_names(struct snd_ump_endpoint *ump);
#else
static inline int process_legacy_output(struct snd_ump_endpoint *ump,
@@ -48,11 +49,42 @@ static inline void process_legacy_input(struct snd_ump_endpoint *ump,
const u32 *src, int words)
{
}
+static inline void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump)
+{
+}
static inline void update_legacy_names(struct snd_ump_endpoint *ump)
{
}
#endif
+/* copy a string safely with stripping non-printable letters */
+static void safe_copy_string(void *dst, size_t max_dst_size,
+ const void *src, size_t max_src_size)
+{
+ const unsigned char *s = src;
+ unsigned char *d = dst;
+
+ if (!max_dst_size--)
+ return;
+ for (s = src; max_dst_size && *s && max_src_size--; s++) {
+ if (!isascii(*s) || !isprint(*s))
+ continue;
+ *d++ = *s;
+ max_dst_size--;
+ }
+ *d = 0;
+}
+
+/* append a string safely with stripping non-printable letters */
+static void safe_append_string(void *dst, size_t max_dst_size,
+ const void *src, size_t max_src_size)
+{
+ unsigned char *d = dst;
+ size_t len = strlen(d);
+
+ safe_copy_string(d + len, max_dst_size - len, src, max_src_size);
+}
+
static const struct snd_rawmidi_global_ops snd_ump_rawmidi_ops = {
.dev_register = snd_ump_dev_register,
.dev_unregister = snd_ump_dev_unregister,
@@ -565,16 +597,10 @@ void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
}
if (!*fb->info.name)
continue;
- if (!*group->name) {
- /* store the first matching name */
- strscpy(group->name, fb->info.name,
- sizeof(group->name));
- } else {
- /* when overlapping, concat names */
+ if (*group->name)
strlcat(group->name, ", ", sizeof(group->name));
- strlcat(group->name, fb->info.name,
- sizeof(group->name));
- }
+ safe_append_string(group->name, sizeof(group->name),
+ fb->info.name, sizeof(fb->info.name));
}
}
}
@@ -669,6 +695,15 @@ static void choose_default_protocol(struct snd_ump_endpoint *ump)
ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI1;
}
+/* notify the EP info/name change to sequencer */
+static void seq_notify_ep_change(struct snd_ump_endpoint *ump)
+{
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
+ if (ump->parsed && ump->seq_ops && ump->seq_ops->notify_ep_change)
+ ump->seq_ops->notify_ep_change(ump);
+#endif
+}
+
/* handle EP info stream message; update the UMP attributes */
static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
const union snd_ump_stream_msg *buf)
@@ -693,6 +728,7 @@ static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
ump->info.protocol &= ump->info.protocol_caps;
choose_default_protocol(ump);
+ seq_notify_ep_change(ump);
return 1; /* finished */
}
@@ -715,24 +751,46 @@ static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump,
ump->info.family_id,
ump->info.model_id,
ump->info.sw_revision);
+ seq_notify_ep_change(ump);
return 1; /* finished */
}
+/* set up the core rawmidi name from UMP EP name string */
+static void ump_set_rawmidi_name(struct snd_ump_endpoint *ump)
+{
+ safe_copy_string(ump->core.name, sizeof(ump->core.name),
+ ump->info.name, sizeof(ump->info.name));
+}
+
/* handle EP name stream message; update the UMP name string */
static int ump_handle_ep_name_msg(struct snd_ump_endpoint *ump,
const union snd_ump_stream_msg *buf)
{
- return ump_append_string(ump, ump->info.name, sizeof(ump->info.name),
- buf->raw, 2);
+ int ret;
+
+ ret = ump_append_string(ump, ump->info.name, sizeof(ump->info.name),
+ buf->raw, 2);
+ if (ret && ump->parsed) {
+ ump_set_rawmidi_name(ump);
+ ump_legacy_set_rawmidi_name(ump);
+ seq_notify_ep_change(ump);
+ }
+
+ return ret;
}
/* handle EP product id stream message; update the UMP product_id string */
static int ump_handle_product_id_msg(struct snd_ump_endpoint *ump,
const union snd_ump_stream_msg *buf)
{
- return ump_append_string(ump, ump->info.product_id,
- sizeof(ump->info.product_id),
- buf->raw, 2);
+ int ret;
+
+ ret = ump_append_string(ump, ump->info.product_id,
+ sizeof(ump->info.product_id),
+ buf->raw, 2);
+ if (ret)
+ seq_notify_ep_change(ump);
+ return ret;
}
/* notify the protocol change to sequencer */
@@ -1045,6 +1103,8 @@ int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
if (err < 0)
ump_dbg(ump, "Unable to get UMP EP name string\n");
+ ump_set_rawmidi_name(ump);
+
/* Request Endpoint Product ID */
err = ump_req_msg(ump, msg, UMP_STREAM_MSG_REQUEST_PRODUCT_ID,
UMP_STREAM_MSG_STATUS_PRODUCT_ID);
@@ -1250,8 +1310,8 @@ static int fill_legacy_mapping(struct snd_ump_endpoint *ump)
return num;
}
-static void fill_substream_names(struct snd_ump_endpoint *ump,
- struct snd_rawmidi *rmidi, int dir)
+static void update_legacy_substreams(struct snd_ump_endpoint *ump,
+ struct snd_rawmidi *rmidi, int dir)
{
struct snd_rawmidi_substream *s;
const char *name;
@@ -1261,10 +1321,11 @@ static void fill_substream_names(struct snd_ump_endpoint *ump,
idx = ump->legacy_mapping[s->number];
name = ump->groups[idx].name;
if (!*name)
- name = ump->info.name;
+ name = ump->core.name;
scnprintf(s->name, sizeof(s->name), "Group %d (%.16s)%s",
idx + 1, name,
ump->groups[idx].active ? "" : " [Inactive]");
+ s->inactive = !ump->groups[idx].active;
}
}
@@ -1272,8 +1333,16 @@ static void update_legacy_names(struct snd_ump_endpoint *ump)
{
struct snd_rawmidi *rmidi = ump->legacy_rmidi;
- fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT);
- fill_substream_names(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT);
+ update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_INPUT);
+ update_legacy_substreams(ump, rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT);
+}
+
+static void ump_legacy_set_rawmidi_name(struct snd_ump_endpoint *ump)
+{
+ struct snd_rawmidi *rmidi = ump->legacy_rmidi;
+
+ snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)",
+ ump->core.name);
}
int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
@@ -1306,14 +1375,15 @@ int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
if (output)
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
&snd_ump_legacy_output_ops);
- snprintf(rmidi->name, sizeof(rmidi->name), "%.68s (MIDI 1.0)",
- ump->info.name);
rmidi->info_flags = ump->core.info_flags & ~SNDRV_RAWMIDI_INFO_UMP;
rmidi->ops = &snd_ump_legacy_ops;
rmidi->private_data = ump;
ump->legacy_rmidi = rmidi;
+ ump_legacy_set_rawmidi_name(ump);
update_legacy_names(ump);
+ snd_rawmidi_tie_devices(rmidi, &ump->core);
+
ump_dbg(ump, "Created a legacy rawmidi #%d (%s)\n", device, id);
return 0;
}
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 8f5df9b3aaaa..c1a3efb633c5 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -457,8 +457,7 @@ static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
if (!dpcm)
return -ENOMEM;
substream->runtime->private_data = dpcm;
- hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
- dpcm->timer.function = dummy_hrtimer_callback;
+ hrtimer_setup(&dpcm->timer, dummy_hrtimer_callback, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
dpcm->substream = substream;
atomic_set(&dpcm->running, 0);
return 0;
diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c
index 78c9b1c7590f..e8482c2290c3 100644
--- a/sound/drivers/pcsp/pcsp.c
+++ b/sound/drivers/pcsp/pcsp.c
@@ -103,8 +103,7 @@ static int snd_card_pcsp_probe(int devnum, struct device *dev)
if (devnum != 0)
return -EINVAL;
- hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- pcsp_chip.timer.function = pcsp_do_timer;
+ hrtimer_setup(&pcsp_chip.timer, pcsp_do_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
err = snd_devm_card_new(dev, index, id, THIS_MODULE, 0, &card);
if (err < 0)
diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c
index efd59e9d9935..0907d0a2296f 100644
--- a/sound/firewire/fireface/ff-protocol-former.c
+++ b/sound/firewire/fireface/ff-protocol-former.c
@@ -135,13 +135,13 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
(data & 0x00000020) ? "Professional" : "Consumer",
- (data & 0x00000040) ? "on" : "off");
+ str_on_off(data & 0x00000040));
snd_iprintf(buffer, "Optical output interface format: %s\n",
(data & 0x00000100) ? "S/PDIF" : "ADAT");
snd_iprintf(buffer, "Word output single speed: %s\n",
- (data & 0x00002000) ? "on" : "off");
+ str_on_off(data & 0x00002000));
snd_iprintf(buffer, "S/PDIF input interface: %s\n",
(data & 0x00000200) ? "Optical" : "Coaxial");
diff --git a/sound/hda/hdac_component.c b/sound/hda/hdac_component.c
index bb37e7e0bd79..9c82a2864a2f 100644
--- a/sound/hda/hdac_component.c
+++ b/sound/hda/hdac_component.c
@@ -5,6 +5,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/component.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/hdaudio.h>
#include <sound/hda_component.h>
@@ -42,8 +43,7 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
if (!acomp->ops->codec_wake_override)
return 0;
- dev_dbg(bus->dev, "%s codec wakeup\n",
- enable ? "enable" : "disable");
+ dev_dbg(bus->dev, "%s codec wakeup\n", str_enable_disable(enable));
acomp->ops->codec_wake_override(acomp->dev, enable);
@@ -67,8 +67,7 @@ void snd_hdac_display_power(struct hdac_bus *bus, unsigned int idx, bool enable)
{
struct drm_audio_component *acomp = bus->audio_component;
- dev_dbg(bus->dev, "display power %s\n",
- enable ? "enable" : "disable");
+ dev_dbg(bus->dev, "display power %s\n", str_enable_disable(enable));
mutex_lock(&bus->lock);
if (enable)
diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c
index 2670792f43b4..4e85a838ad7e 100644
--- a/sound/hda/hdac_stream.c
+++ b/sound/hda/hdac_stream.c
@@ -492,32 +492,21 @@ static int setup_bdle(struct hdac_bus *bus,
}
/**
- * snd_hdac_stream_setup_periods - set up BDL entries
+ * snd_hdac_stream_setup_bdle - set up BDL entries
* @azx_dev: HD-audio core stream to set up
+ * @dmab: allocated DMA buffer
+ * @runtime: substream runtime, optional
*
* Set up the buffer descriptor table of the given stream based on the
* period and buffer sizes of the assigned PCM substream.
*/
-int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
+static int snd_hdac_stream_setup_bdle(struct hdac_stream *azx_dev, struct snd_dma_buffer *dmab,
+ struct snd_pcm_runtime *runtime)
{
struct hdac_bus *bus = azx_dev->bus;
- struct snd_pcm_substream *substream = azx_dev->substream;
- struct snd_compr_stream *cstream = azx_dev->cstream;
- struct snd_pcm_runtime *runtime = NULL;
- struct snd_dma_buffer *dmab;
- __le32 *bdl;
int i, ofs, periods, period_bytes;
int pos_adj, pos_align;
-
- if (substream) {
- runtime = substream->runtime;
- dmab = snd_pcm_get_dma_buf(substream);
- } else if (cstream) {
- dmab = snd_pcm_get_dma_buf(cstream);
- } else {
- WARN(1, "No substream or cstream assigned\n");
- return -EINVAL;
- }
+ __le32 *bdl;
/* reset BDL address */
snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
@@ -571,6 +560,33 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
azx_dev->bufsize, period_bytes);
return -EINVAL;
}
+
+/**
+ * snd_hdac_stream_setup_periods - set up BDL entries
+ * @azx_dev: HD-audio core stream to set up
+ *
+ * Set up the buffer descriptor table of the given stream based on the
+ * period and buffer sizes of the assigned PCM substream.
+ */
+int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev)
+{
+ struct snd_pcm_substream *substream = azx_dev->substream;
+ struct snd_compr_stream *cstream = azx_dev->cstream;
+ struct snd_pcm_runtime *runtime = NULL;
+ struct snd_dma_buffer *dmab;
+
+ if (substream) {
+ runtime = substream->runtime;
+ dmab = snd_pcm_get_dma_buf(substream);
+ } else if (cstream) {
+ dmab = snd_pcm_get_dma_buf(cstream);
+ } else {
+ WARN(1, "No substream or cstream assigned\n");
+ return -EINVAL;
+ }
+
+ return snd_hdac_stream_setup_bdle(azx_dev, dmab, runtime);
+}
EXPORT_SYMBOL_GPL(snd_hdac_stream_setup_periods);
/**
@@ -923,7 +939,6 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
unsigned int byte_size, struct snd_dma_buffer *bufp)
{
struct hdac_bus *bus = azx_dev->bus;
- __le32 *bdl;
int err;
snd_hdac_dsp_lock(azx_dev);
@@ -943,18 +958,14 @@ int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
azx_dev->substream = NULL;
azx_dev->bufsize = byte_size;
- azx_dev->period_bytes = byte_size;
+ /* It is recommended to transfer the firmware in two or more chunks. */
+ azx_dev->period_bytes = byte_size / 2;
azx_dev->format_val = format;
+ azx_dev->no_period_wakeup = 1;
snd_hdac_stream_reset(azx_dev);
- /* reset BDL address */
- snd_hdac_stream_writel(azx_dev, SD_BDLPL, 0);
- snd_hdac_stream_writel(azx_dev, SD_BDLPU, 0);
-
- azx_dev->frags = 0;
- bdl = (__le32 *)azx_dev->bdl.area;
- err = setup_bdle(bus, bufp, azx_dev, &bdl, 0, byte_size, 0);
+ err = snd_hdac_stream_setup_bdle(azx_dev, bufp, NULL);
if (err < 0)
goto error;
diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c
index f564ec7af194..5103e37be428 100644
--- a/sound/hda/intel-dsp-config.c
+++ b/sound/hda/intel-dsp-config.c
@@ -108,6 +108,10 @@ static const struct config_entry config_table[] = {
{}
}
},
+ {
+ .flags = FLAG_SST,
+ .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M,
+ },
#endif
#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE)
{
@@ -539,6 +543,11 @@ static const struct config_entry config_table[] = {
.flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
.device = PCI_DEVICE_ID_INTEL_HDA_PTL,
},
+ {
+ .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
+ .device = PCI_DEVICE_ID_INTEL_HDA_PTL_H,
+ },
+
#endif
};
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 59c784a70ac1..e35c727a52fa 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -1735,27 +1735,27 @@ static int snd_es18xx_new_device(struct snd_card *card,
chip->active = 0;
if (!devm_request_region(card->dev, port, 16, "ES18xx")) {
- dev_err(card->dev, "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1);
+ dev_err(card->dev, "unable to grab ports 0x%lx-0x%lx\n", port, port + 16 - 1);
return -EBUSY;
}
if (devm_request_irq(card->dev, irq, snd_es18xx_interrupt, 0, "ES18xx",
(void *) card)) {
- dev_err(card->dev, "unable to grap IRQ %d\n", irq);
+ dev_err(card->dev, "unable to grab IRQ %d\n", irq);
return -EBUSY;
}
chip->irq = irq;
card->sync_irq = chip->irq;
if (snd_devm_request_dma(card->dev, dma1, "ES18xx DMA 1")) {
- dev_err(card->dev, "unable to grap DMA1 %d\n", dma1);
+ dev_err(card->dev, "unable to grab DMA1 %d\n", dma1);
return -EBUSY;
}
chip->dma1 = dma1;
if (dma2 != dma1 &&
snd_devm_request_dma(card->dev, dma2, "ES18xx DMA 2")) {
- dev_err(card->dev, "unable to grap DMA2 %d\n", dma2);
+ dev_err(card->dev, "unable to grab DMA2 %d\n", dma2);
return -EBUSY;
}
chip->dma2 = dma2;
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 220ea1952c1e..a07a665d93dc 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -486,7 +486,7 @@ __skip_base:
#endif /* CS4231 || OPTi93X */
#ifndef OPTi93X
- outb(irq_bits << 3 | dma_bits, chip->wss_base);
+ outb(irq_bits << 3 | dma_bits, chip->wss_base);
#else /* OPTi93X */
snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
#endif /* OPTi93X */
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 071ba85f76bb..7034072c80d4 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
@@ -1157,8 +1158,8 @@ static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buff
((p->acc_rates & SNDRV_SB_CSP_RATE_44100) ? "44100Hz" : ""));
}
if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
- snd_iprintf(buffer, "QSound decoder %sabled\n",
- p->q_enabled ? "en" : "dis");
+ snd_iprintf(buffer, "QSound decoder %s\n",
+ str_enabled_disabled(p->q_enabled));
} else {
snd_iprintf(buffer, "PCM format ID: 0x%x (%s/%s) [%s/%s] [%s/%s]\n",
p->acc_format,
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 25f93e56cfc7..6e710dce5c60 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1864,7 +1864,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m
strcat(name, " ");
strcat(name, pid->name);
if (pid->mask != 0xffffffff)
- sprintf(name + strlen(name), " rev %d", id & ~pid->mask);
+ sprintf(name + strlen(name), " rev %u", id & ~pid->mask);
if (ac97 && pid->patch) {
if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||
(! modem && ! (pid->flags & AC97_MODEM_PATCH)))
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
index 5426f7bc9884..518834964b7b 100644
--- a/sound/pci/ac97/ac97_proc.c
+++ b/sound/pci/ac97/ac97_proc.c
@@ -161,12 +161,12 @@ static void snd_ac97_proc_read_main(struct snd_ac97 *ac97, struct snd_info_buffe
"Mic select : %s\n"
"ADC/DAC loopback : %s\n",
val & 0x8000 ? "post" : "pre",
- val & 0x4000 ? "on" : "off",
- val & 0x2000 ? "on" : "off",
- val & 0x1000 ? "on" : "off",
+ str_on_off(val & 0x4000),
+ str_on_off(val & 0x2000),
+ str_on_off(val & 0x1000),
val & 0x0200 ? "Mic" : "MIX",
val & 0x0100 ? "Mic2" : "Mic1",
- val & 0x0080 ? "on" : "off");
+ str_on_off(val & 0x0080));
if (ac97->ext_id & AC97_EI_DRA)
snd_iprintf(buffer, "Double rate slots: %s\n",
double_rate_slots[(val >> 10) & 3]);
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 50e30704bf6f..9ed778b6b03c 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -626,7 +626,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
reg = ad1889_readw(chip, AD_DS_WSMC);
snd_iprintf(buffer, "Wave output: %s\n",
- (reg & AD_DS_WSMC_WAEN) ? "enabled" : "disabled");
+ str_enabled_disabled(reg & AD_DS_WSMC_WAEN));
snd_iprintf(buffer, "Wave Channels: %s\n",
(reg & AD_DS_WSMC_WAST) ? "stereo" : "mono");
snd_iprintf(buffer, "Wave Quality: %d-bit linear\n",
@@ -642,7 +642,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
snd_iprintf(buffer, "Synthesis output: %s\n",
- reg & AD_DS_WSMC_SYEN ? "enabled" : "disabled");
+ str_enabled_disabled(reg & AD_DS_WSMC_SYEN));
/* SYRQ is at offset 4 */
tmp = (reg & AD_DS_WSMC_SYRQ) ?
@@ -654,7 +654,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
reg = ad1889_readw(chip, AD_DS_RAMC);
snd_iprintf(buffer, "ADC input: %s\n",
- (reg & AD_DS_RAMC_ADEN) ? "enabled" : "disabled");
+ str_enabled_disabled(reg & AD_DS_RAMC_ADEN));
snd_iprintf(buffer, "ADC Channels: %s\n",
(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");
snd_iprintf(buffer, "ADC Quality: %d-bit linear\n",
@@ -669,7 +669,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe
(reg & AD_DS_RAMC_ADST) ? "stereo" : "mono");
snd_iprintf(buffer, "Resampler input: %s\n",
- reg & AD_DS_RAMC_REEN ? "enabled" : "disabled");
+ str_enabled_disabled(reg & AD_DS_RAMC_REEN));
/* RERQ is at offset 12 */
tmp = (reg & AD_DS_RAMC_RERQ) ?
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index e3cac73517d6..cb8593c376ee 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -3084,7 +3084,7 @@ static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci,
}
}
}
- sprintf(card->shortname, "C-Media CMI%d", val);
+ sprintf(card->shortname, "C-Media CMI%u", val);
if (cm->chip_version < 68)
scnprintf(modelstr, sizeof(modelstr),
" (model %d)", cm->chip_version);
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 83aaf9441ef3..806c4d754387 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -159,7 +159,7 @@ static int dao_set_left_input(struct dao *dao, struct rsc *input)
struct daio *daio = &dao->daio;
int i;
- entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL);
+ entry = kcalloc(daio->rscl.msr, sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
@@ -188,7 +188,7 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input)
struct daio *daio = &dao->daio;
int i;
- entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL);
+ entry = kcalloc(daio->rscr.msr, sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
@@ -211,52 +211,30 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input)
return 0;
}
-static int dao_clear_left_input(struct dao *dao)
+static int dao_clear_input(struct dao *dao, unsigned int start, unsigned int end)
{
- struct imapper *entry;
- struct daio *daio = &dao->daio;
- int i;
+ unsigned int i;
- if (!dao->imappers[0])
+ if (!dao->imappers[start])
return 0;
-
- entry = dao->imappers[0];
- dao->mgr->imap_delete(dao->mgr, entry);
- /* Program conjugate resources */
- for (i = 1; i < daio->rscl.msr; i++) {
- entry = dao->imappers[i];
- dao->mgr->imap_delete(dao->mgr, entry);
+ for (i = start; i < end; i++) {
+ dao->mgr->imap_delete(dao->mgr, dao->imappers[i]);
dao->imappers[i] = NULL;
}
- kfree(dao->imappers[0]);
- dao->imappers[0] = NULL;
-
return 0;
}
-static int dao_clear_right_input(struct dao *dao)
-{
- struct imapper *entry;
- struct daio *daio = &dao->daio;
- int i;
- if (!dao->imappers[daio->rscl.msr])
- return 0;
-
- entry = dao->imappers[daio->rscl.msr];
- dao->mgr->imap_delete(dao->mgr, entry);
- /* Program conjugate resources */
- for (i = 1; i < daio->rscr.msr; i++) {
- entry = dao->imappers[daio->rscl.msr + i];
- dao->mgr->imap_delete(dao->mgr, entry);
- dao->imappers[daio->rscl.msr + i] = NULL;
- }
-
- kfree(dao->imappers[daio->rscl.msr]);
- dao->imappers[daio->rscl.msr] = NULL;
+static int dao_clear_left_input(struct dao *dao)
+{
+ return dao_clear_input(dao, 0, dao->daio.rscl.msr);
+}
- return 0;
+static int dao_clear_right_input(struct dao *dao)
+{
+ return dao_clear_input(dao, dao->daio.rscl.msr,
+ dao->daio.rscl.msr + dao->daio.rscr.msr);
}
static const struct dao_rsc_ops dao_ops = {
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 7484de255a3e..4effcc0090ac 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1966,7 +1966,6 @@ static int __snd_echo_probe(struct pci_dev *pci,
struct snd_card *card;
struct echoaudio *chip;
char *dsp;
- __maybe_unused int i;
int err;
if (dev >= SNDRV_CARDS)
@@ -1976,7 +1975,6 @@ static int __snd_echo_probe(struct pci_dev *pci,
return -ENOENT;
}
- i = 0;
err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
sizeof(*chip), &card);
if (err < 0)
@@ -2080,7 +2078,7 @@ static int __snd_echo_probe(struct pci_dev *pci,
#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH
/* Creates a list of available digital modes */
chip->num_digital_modes = 0;
- for (i = 0; i < 6; i++)
+ for (int i = 0; i < 6; i++)
if (chip->digital_modes & (1 << i))
chip->digital_mode_list[chip->num_digital_modes++] = i;
@@ -2092,7 +2090,7 @@ static int __snd_echo_probe(struct pci_dev *pci,
#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK
/* Creates a list of available clock sources */
chip->num_clock_sources = 0;
- for (i = 0; i < 10; i++)
+ for (int i = 0; i < 10; i++)
if (chip->input_clock_types & (1 << i))
chip->clock_source_list[chip->num_clock_sources++] = i;
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
index 737c28d31b41..bd4734dc04cd 100644
--- a/sound/pci/emu10k1/emuproc.c
+++ b/sound/pci/emu10k1/emuproc.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/emu10k1.h>
#include "p16v.h"
@@ -32,9 +33,9 @@ static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu,
snd_iprintf(buffer, "\n%s\n", title);
if (status != 0xffffffff) {
- snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no");
- snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no");
- snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no");
+ snd_iprintf(buffer, "Professional Mode : %s\n", str_yes_no(status & SPCS_PROFESSIONAL));
+ snd_iprintf(buffer, "Not Audio Data : %s\n", str_yes_no(status & SPCS_NOTAUDIODATA));
+ snd_iprintf(buffer, "Copyright : %s\n", str_yes_no(status & SPCS_COPYRIGHT));
snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]);
snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6);
snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8);
@@ -46,9 +47,9 @@ static void snd_emu10k1_proc_spdif_status(struct snd_emu10k1 * emu,
if (rate_reg > 0) {
rate = snd_emu10k1_ptr_read(emu, rate_reg, 0);
- snd_iprintf(buffer, "S/PDIF Valid : %s\n", rate & SRCS_SPDIFVALID ? "on" : "off");
- snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off");
- snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off");
+ snd_iprintf(buffer, "S/PDIF Valid : %s\n", str_on_off(rate & SRCS_SPDIFVALID));
+ snd_iprintf(buffer, "S/PDIF Locked : %s\n", str_on_off(rate & SRCS_SPDIFLOCKED));
+ snd_iprintf(buffer, "Rate Locked : %s\n", str_on_off(rate & SRCS_RATELOCKED));
/* From ((Rate * 48000 ) / 262144); */
snd_iprintf(buffer, "Estimated Sample Rate : %d\n", ((rate & 0xFFFFF ) * 375) >> 11);
}
@@ -208,7 +209,7 @@ static void snd_emu10k1_proc_spdif_read(struct snd_info_entry *entry,
#if 0
val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0);
snd_iprintf(buffer, "\nZoomed Video\n");
- snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off");
+ snd_iprintf(buffer, "Rate Locked : %s\n", str_on_off(val & SRCS_RATELOCKED));
snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE);
#endif
}
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index d29711777161..f6982bc6ff0d 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -441,7 +441,7 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk)
unmap_memblk(emu, blk);
spin_unlock_irqrestore(&emu->memblk_lock, flags);
synth_free_pages(emu, blk);
- __snd_util_mem_free(hdr, memblk);
+ __snd_util_mem_free(hdr, memblk);
mutex_unlock(&hdr->block_mutex);
return 0;
}
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 18928b905939..71c89e4e3090 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1850,12 +1850,12 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "Ensoniq AudioPCI " CHIP_NAME "\n\n");
snd_iprintf(buffer, "Joystick enable : %s\n",
- ensoniq->ctrl & ES_JYSTK_EN ? "on" : "off");
+ str_on_off(ensoniq->ctrl & ES_JYSTK_EN));
#ifdef CHIP1370
snd_iprintf(buffer, "MIC +5V bias : %s\n",
- ensoniq->ctrl & ES_1370_XCTL1 ? "on" : "off");
+ str_on_off(ensoniq->ctrl & ES_1370_XCTL1));
snd_iprintf(buffer, "Line In to AOUT : %s\n",
- ensoniq->ctrl & ES_1370_XCTL0 ? "on" : "off");
+ str_on_off(ensoniq->ctrl & ES_1370_XCTL0));
#else
snd_iprintf(buffer, "Joystick port : 0x%x\n",
(ES_1371_JOY_ASELI(ensoniq->ctrl) * 8) + 0x200);
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 68f1eee9e5c9..fb955a205d50 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -206,8 +206,23 @@ config SND_HDA_SCODEC_TAS2781_I2C
comment "Set to Y if you want auto-loading the side codec driver"
depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
+config SND_HDA_SCODEC_TAS2781_SPI
+ tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
+ depends on SPI_MASTER
+ depends on ACPI
+ depends on EFI
+ depends on SND_SOC
+ select CRC32
+ help
+ Say Y or M here to include TAS2781 SPI 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_TAS2781_SPI=m
+
config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
+ depends on INPUT
select SND_HDA_GENERIC
select SND_HDA_GENERIC_LEDS
select SND_HDA_SCODEC_COMPONENT
@@ -252,6 +267,7 @@ comment "Set to Y if you want auto-loading the codec driver"
config SND_HDA_CODEC_HDMI
tristate "Build HDMI/DisplayPort HD-audio codec support"
select SND_DYNAMIC_MINORS
+ select SND_PCM_ELD
help
Say Y or M here to include HDMI and DisplayPort HD-audio codec
support in snd-hda-intel driver. This includes all AMD/ATI,
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 80210f845df2..210c406dfbc5 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -40,6 +40,7 @@ snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o
snd-hda-cs-dsp-ctls-y := hda_cs_dsp_ctl.o
snd-hda-scodec-component-y := hda_component.o
snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o
+snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o tas2781_spi_fwlib.o
# common driver
obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
@@ -72,6 +73,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
# this must be the last entry after codec drivers;
# otherwise the codec patches won't be hooked before the PCI probe
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c
index 4ef7878e8fd4..235d22049aa9 100644
--- a/sound/pci/hda/cs35l56_hda.c
+++ b/sound/pci/hda/cs35l56_hda.c
@@ -546,12 +546,10 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw
const struct firmware *coeff_firmware,
char *coeff_filename)
{
- if (wmfw_firmware)
- release_firmware(wmfw_firmware);
+ release_firmware(wmfw_firmware);
kfree(wmfw_filename);
- if (coeff_firmware)
- release_firmware(coeff_firmware);
+ release_firmware(coeff_firmware);
kfree(coeff_filename);
}
diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c
index d4ee5bb7c486..903578466905 100644
--- a/sound/pci/hda/cs35l56_hda_spi.c
+++ b/sound/pci/hda/cs35l56_hda_spi.c
@@ -22,6 +22,9 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi)
return -ENOMEM;
cs35l56->base.dev = &spi->dev;
+ ret = cs35l56_init_config_for_spi(&cs35l56->base, spi);
+ if (ret)
+ return ret;
#ifdef CS35L56_WAKE_HOLD_TIME_US
cs35l56->base.can_hibernate = true;
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index 84393f4f429d..8923813ce424 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -80,7 +80,11 @@ static int compare_input_type(const void *ap, const void *bp)
/* In case one has boost and the other one has not,
pick the one with boost first. */
- return (int)(b->has_boost_on_pin - a->has_boost_on_pin);
+ if (a->has_boost_on_pin != b->has_boost_on_pin)
+ return (int)(b->has_boost_on_pin - a->has_boost_on_pin);
+
+ /* Keep the original order */
+ return a->order - b->order;
}
/* Reorder the surround channels
@@ -400,6 +404,8 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
/* sort inputs in the order of AUTO_PIN_* type */
+ for (i = 0; i < cfg->num_inputs; i++)
+ cfg->inputs[i].order = i;
sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]),
compare_input_type, NULL);
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
index 579b11beac71..87af3d8c02f7 100644
--- a/sound/pci/hda/hda_auto_parser.h
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -37,6 +37,7 @@ struct auto_pin_cfg_item {
unsigned int is_headset_mic:1;
unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */
unsigned int has_boost_on_pin:1;
+ int order;
};
struct auto_pin_cfg;
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index e51d47572557..13a7d92e8d8d 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone)
beep->power_hook(beep, true);
beep->playing = 1;
}
- snd_hda_codec_write(codec, beep->nid, 0,
- AC_VERB_SET_BEEP_CONTROL, tone);
+ if (!codec->beep_just_power_on)
+ snd_hda_codec_write(codec, beep->nid, 0,
+ AC_VERB_SET_BEEP_CONTROL, tone);
if (!tone && beep->playing) {
beep->playing = 0;
if (beep->power_hook)
@@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
struct hda_beep *beep;
int err;
- if (!snd_hda_get_bool_hint(codec, "beep"))
- return 0; /* disabled explicitly by hints */
- if (codec->beep_mode == HDA_BEEP_MODE_OFF)
- return 0; /* disabled by module option */
+ if (!codec->beep_just_power_on) {
+ if (!snd_hda_get_bool_hint(codec, "beep"))
+ return 0; /* disabled explicitly by hints */
+ if (codec->beep_mode == HDA_BEEP_MODE_OFF)
+ return 0; /* disabled by module option */
+ }
beep = kzalloc(sizeof(*beep), GFP_KERNEL);
if (beep == NULL)
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c
index b7ca2a83fbb0..9521e5e0e6e6 100644
--- a/sound/pci/hda/hda_bind.c
+++ b/sound/pci/hda/hda_bind.c
@@ -185,7 +185,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
drv->core.driver.probe = hda_codec_driver_probe;
drv->core.driver.remove = hda_codec_driver_remove;
drv->core.driver.shutdown = hda_codec_driver_shutdown;
- drv->core.driver.pm = &hda_codec_driver_pm;
+ drv->core.driver.pm = pm_ptr(&hda_codec_driver_pm);
drv->core.type = HDA_DEV_LEGACY;
drv->core.match = hda_codec_match;
drv->core.unsol_event = hda_codec_unsol_event;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 14763c0f31ad..b436d436831b 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2470,7 +2470,9 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
break;
id = kctl->id;
id.index = spdif_index;
- snd_ctl_rename_id(codec->card, &kctl->id, &id);
+ err = snd_ctl_rename_id(codec->card, &kctl->id, &id);
+ if (err < 0)
+ return err;
}
bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
}
@@ -3037,8 +3039,7 @@ const struct dev_pm_ops hda_codec_driver_pm = {
.thaw = pm_sleep_ptr(hda_codec_pm_thaw),
.poweroff = pm_sleep_ptr(hda_codec_pm_suspend),
.restore = pm_sleep_ptr(hda_codec_pm_restore),
- .runtime_suspend = pm_ptr(hda_codec_runtime_suspend),
- .runtime_resume = pm_ptr(hda_codec_runtime_resume),
+ RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, NULL)
};
/* suspend the codec at shutdown; called from driver's shutdown callback */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index 301730432375..d3e87b9c1a4f 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -17,11 +17,6 @@
#include <sound/hda_codec.h>
#include "hda_local.h"
-enum eld_versions {
- ELD_VER_CEA_861D = 2,
- ELD_VER_PARTIAL = 31,
-};
-
enum cea_edid_versions {
CEA_EDID_VER_NONE = 0,
CEA_EDID_VER_CEA861 = 1,
@@ -30,95 +25,12 @@ enum cea_edid_versions {
CEA_EDID_VER_RESERVED = 4,
};
-static const char * const eld_connection_type_names[4] = {
- "HDMI",
- "DisplayPort",
- "2-reserved",
- "3-reserved"
-};
-
-enum cea_audio_coding_types {
- AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0,
- AUDIO_CODING_TYPE_LPCM = 1,
- AUDIO_CODING_TYPE_AC3 = 2,
- AUDIO_CODING_TYPE_MPEG1 = 3,
- AUDIO_CODING_TYPE_MP3 = 4,
- AUDIO_CODING_TYPE_MPEG2 = 5,
- AUDIO_CODING_TYPE_AACLC = 6,
- AUDIO_CODING_TYPE_DTS = 7,
- AUDIO_CODING_TYPE_ATRAC = 8,
- AUDIO_CODING_TYPE_SACD = 9,
- AUDIO_CODING_TYPE_EAC3 = 10,
- AUDIO_CODING_TYPE_DTS_HD = 11,
- AUDIO_CODING_TYPE_MLP = 12,
- AUDIO_CODING_TYPE_DST = 13,
- AUDIO_CODING_TYPE_WMAPRO = 14,
- AUDIO_CODING_TYPE_REF_CXT = 15,
- /* also include valid xtypes below */
- AUDIO_CODING_TYPE_HE_AAC = 15,
- AUDIO_CODING_TYPE_HE_AAC2 = 16,
- AUDIO_CODING_TYPE_MPEG_SURROUND = 17,
-};
-
-enum cea_audio_coding_xtypes {
- AUDIO_CODING_XTYPE_HE_REF_CT = 0,
- AUDIO_CODING_XTYPE_HE_AAC = 1,
- AUDIO_CODING_XTYPE_HE_AAC2 = 2,
- AUDIO_CODING_XTYPE_MPEG_SURROUND = 3,
- AUDIO_CODING_XTYPE_FIRST_RESERVED = 4,
-};
-
-static const char * const cea_audio_coding_type_names[] = {
- /* 0 */ "undefined",
- /* 1 */ "LPCM",
- /* 2 */ "AC-3",
- /* 3 */ "MPEG1",
- /* 4 */ "MP3",
- /* 5 */ "MPEG2",
- /* 6 */ "AAC-LC",
- /* 7 */ "DTS",
- /* 8 */ "ATRAC",
- /* 9 */ "DSD (One Bit Audio)",
- /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)",
- /* 11 */ "DTS-HD",
- /* 12 */ "MLP (Dolby TrueHD)",
- /* 13 */ "DST",
- /* 14 */ "WMAPro",
- /* 15 */ "HE-AAC",
- /* 16 */ "HE-AACv2",
- /* 17 */ "MPEG Surround",
-};
-
/*
* The following two lists are shared between
* - HDMI audio InfoFrame (source to sink)
* - CEA E-EDID Extension (sink to source)
*/
-/*
- * SS1:SS0 index => sample size
- */
-static const int cea_sample_sizes[4] = {
- 0, /* 0: Refer to Stream Header */
- AC_SUPPCM_BITS_16, /* 1: 16 bits */
- AC_SUPPCM_BITS_20, /* 2: 20 bits */
- AC_SUPPCM_BITS_24, /* 3: 24 bits */
-};
-
-/*
- * SF2:SF1:SF0 index => sampling frequency
- */
-static const int cea_sampling_frequencies[8] = {
- 0, /* 0: Refer to Stream Header */
- SNDRV_PCM_RATE_32000, /* 1: 32000Hz */
- SNDRV_PCM_RATE_44100, /* 2: 44100Hz */
- SNDRV_PCM_RATE_48000, /* 3: 48000Hz */
- SNDRV_PCM_RATE_88200, /* 4: 88200Hz */
- SNDRV_PCM_RATE_96000, /* 5: 96000Hz */
- SNDRV_PCM_RATE_176400, /* 6: 176400Hz */
- SNDRV_PCM_RATE_192000, /* 7: 192000Hz */
-};
-
static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
int byte_index)
{
@@ -132,159 +44,6 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
return val;
}
-#define GRAB_BITS(buf, byte, lowbit, bits) \
-({ \
- BUILD_BUG_ON(lowbit > 7); \
- BUILD_BUG_ON(bits > 8); \
- BUILD_BUG_ON(bits <= 0); \
- \
- (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \
-})
-
-static void hdmi_update_short_audio_desc(struct hda_codec *codec,
- struct cea_sad *a,
- const unsigned char *buf)
-{
- int i;
- int val;
-
- val = GRAB_BITS(buf, 1, 0, 7);
- a->rates = 0;
- for (i = 0; i < 7; i++)
- if (val & (1 << i))
- a->rates |= cea_sampling_frequencies[i + 1];
-
- a->channels = GRAB_BITS(buf, 0, 0, 3);
- a->channels++;
-
- a->sample_bits = 0;
- a->max_bitrate = 0;
-
- a->format = GRAB_BITS(buf, 0, 3, 4);
- switch (a->format) {
- case AUDIO_CODING_TYPE_REF_STREAM_HEADER:
- codec_info(codec, "HDMI: audio coding type 0 not expected\n");
- break;
-
- case AUDIO_CODING_TYPE_LPCM:
- val = GRAB_BITS(buf, 2, 0, 3);
- for (i = 0; i < 3; i++)
- if (val & (1 << i))
- a->sample_bits |= cea_sample_sizes[i + 1];
- break;
-
- case AUDIO_CODING_TYPE_AC3:
- case AUDIO_CODING_TYPE_MPEG1:
- case AUDIO_CODING_TYPE_MP3:
- case AUDIO_CODING_TYPE_MPEG2:
- case AUDIO_CODING_TYPE_AACLC:
- case AUDIO_CODING_TYPE_DTS:
- case AUDIO_CODING_TYPE_ATRAC:
- a->max_bitrate = GRAB_BITS(buf, 2, 0, 8);
- a->max_bitrate *= 8000;
- break;
-
- case AUDIO_CODING_TYPE_SACD:
- break;
-
- case AUDIO_CODING_TYPE_EAC3:
- break;
-
- case AUDIO_CODING_TYPE_DTS_HD:
- break;
-
- case AUDIO_CODING_TYPE_MLP:
- break;
-
- case AUDIO_CODING_TYPE_DST:
- break;
-
- case AUDIO_CODING_TYPE_WMAPRO:
- a->profile = GRAB_BITS(buf, 2, 0, 3);
- break;
-
- case AUDIO_CODING_TYPE_REF_CXT:
- a->format = GRAB_BITS(buf, 2, 3, 5);
- if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT ||
- a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) {
- codec_info(codec,
- "HDMI: audio coding xtype %d not expected\n",
- a->format);
- a->format = 0;
- } else
- a->format += AUDIO_CODING_TYPE_HE_AAC -
- AUDIO_CODING_XTYPE_HE_AAC;
- break;
- }
-}
-
-/*
- * Be careful, ELD buf could be totally rubbish!
- */
-int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e,
- const unsigned char *buf, int size)
-{
- int mnl;
- int i;
-
- memset(e, 0, sizeof(*e));
- e->eld_ver = GRAB_BITS(buf, 0, 3, 5);
- if (e->eld_ver != ELD_VER_CEA_861D &&
- e->eld_ver != ELD_VER_PARTIAL) {
- codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver);
- goto out_fail;
- }
-
- e->baseline_len = GRAB_BITS(buf, 2, 0, 8);
- mnl = GRAB_BITS(buf, 4, 0, 5);
- e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3);
-
- e->support_hdcp = GRAB_BITS(buf, 5, 0, 1);
- e->support_ai = GRAB_BITS(buf, 5, 1, 1);
- e->conn_type = GRAB_BITS(buf, 5, 2, 2);
- e->sad_count = GRAB_BITS(buf, 5, 4, 4);
-
- e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2;
- e->spk_alloc = GRAB_BITS(buf, 7, 0, 7);
-
- e->port_id = get_unaligned_le64(buf + 8);
-
- /* not specified, but the spec's tendency is little endian */
- e->manufacture_id = get_unaligned_le16(buf + 16);
- e->product_id = get_unaligned_le16(buf + 18);
-
- if (mnl > ELD_MAX_MNL) {
- codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl);
- goto out_fail;
- } else if (ELD_FIXED_BYTES + mnl > size) {
- codec_info(codec, "HDMI: out of range MNL %d\n", mnl);
- goto out_fail;
- } else
- strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1);
-
- for (i = 0; i < e->sad_count; i++) {
- if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) {
- codec_info(codec, "HDMI: out of range SAD %d\n", i);
- goto out_fail;
- }
- hdmi_update_short_audio_desc(codec, e->sad + i,
- buf + ELD_FIXED_BYTES + mnl + 3 * i);
- }
-
- /*
- * HDMI sink's ELD info cannot always be retrieved for now, e.g.
- * in console or for audio devices. Assume the highest speakers
- * configuration, to _not_ prohibit multi-channel audio playback.
- */
- if (!e->spk_alloc)
- e->spk_alloc = 0xffff;
-
- return 0;
-
-out_fail:
- return -EINVAL;
-}
-
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
@@ -346,155 +105,27 @@ error:
return ret;
}
-/*
- * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with
- * hdmi-specific routine.
- */
-static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen)
-{
- static const unsigned int alsa_rates[] = {
- 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
- 88200, 96000, 176400, 192000, 384000
- };
- int i, j;
-
- for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++)
- if (pcm & (1 << i))
- j += scnprintf(buf + j, buflen - j, " %d",
- alsa_rates[i]);
-
- buf[j] = '\0'; /* necessary when j == 0 */
-}
-
-#define SND_PRINT_RATES_ADVISED_BUFSIZE 80
-
-static void hdmi_show_short_audio_desc(struct hda_codec *codec,
- struct cea_sad *a)
-{
- char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
- char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits =";
-
- if (!a->format)
- return;
-
- hdmi_print_pcm_rates(a->rates, buf, sizeof(buf));
-
- if (a->format == AUDIO_CODING_TYPE_LPCM)
- snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8);
- else if (a->max_bitrate)
- snprintf(buf2, sizeof(buf2),
- ", max bitrate = %d", a->max_bitrate);
- else
- buf2[0] = '\0';
-
- codec_dbg(codec,
- "HDMI: supports coding type %s: channels = %d, rates =%s%s\n",
- cea_audio_coding_type_names[a->format],
- a->channels, buf, buf2);
-}
-
-void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e)
-{
- int i;
-
- codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n",
- e->monitor_name,
- eld_connection_type_names[e->conn_type]);
-
- if (e->spk_alloc) {
- char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
- snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
- codec_dbg(codec, "HDMI: available speakers:%s\n", buf);
- }
-
- for (i = 0; i < e->sad_count; i++)
- hdmi_show_short_audio_desc(codec, e->sad + i);
-}
-
#ifdef CONFIG_SND_PROC_FS
-
-static void hdmi_print_sad_info(int i, struct cea_sad *a,
- struct snd_info_buffer *buffer)
-{
- char buf[SND_PRINT_RATES_ADVISED_BUFSIZE];
-
- snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n",
- i, a->format, cea_audio_coding_type_names[a->format]);
- snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels);
-
- hdmi_print_pcm_rates(a->rates, buf, sizeof(buf));
- snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf);
-
- if (a->format == AUDIO_CODING_TYPE_LPCM) {
- snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf));
- snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n",
- i, a->sample_bits, buf);
- }
-
- if (a->max_bitrate)
- snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n",
- i, a->max_bitrate);
-
- if (a->profile)
- snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile);
-}
-
void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
struct snd_info_buffer *buffer,
hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
{
- struct parsed_hdmi_eld *e = &eld->info;
- char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE];
- int i;
- static const char * const eld_version_names[32] = {
- "reserved",
- "reserved",
- "CEA-861D or below",
- [3 ... 30] = "reserved",
- [31] = "partial"
- };
- static const char * const cea_edid_version_names[8] = {
- "no CEA EDID Timing Extension block present",
- "CEA-861",
- "CEA-861-A",
- "CEA-861-B, C or D",
- [4 ... 7] = "reserved"
- };
-
snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid);
snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id);
snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid);
+
if (!eld->eld_valid)
return;
- snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name);
- snd_iprintf(buffer, "connection_type\t\t%s\n",
- eld_connection_type_names[e->conn_type]);
- snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver,
- eld_version_names[e->eld_ver]);
- snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver,
- cea_edid_version_names[e->cea_edid_ver]);
- snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id);
- snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id);
- snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id);
- snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp);
- snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai);
- snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay);
-
- snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf));
- snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf);
-
- snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count);
-
- for (i = 0; i < e->sad_count; i++)
- hdmi_print_sad_info(i, e->sad + i, buffer);
+
+ snd_print_eld_info(&eld->info, buffer);
}
void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
struct snd_info_buffer *buffer)
{
- struct parsed_hdmi_eld *e = &eld->info;
+ struct snd_parsed_hdmi_eld *e = &eld->info;
char line[64];
char name[64];
char *sname;
@@ -556,7 +187,7 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
#endif /* CONFIG_SND_PROC_FS */
/* update PCM info based on ELD */
-void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
+void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo)
{
u32 rates;
@@ -574,17 +205,17 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
maxbps = 16;
channels_max = 2;
for (i = 0; i < e->sad_count; i++) {
- struct cea_sad *a = &e->sad[i];
+ struct snd_cea_sad *a = &e->sad[i];
rates |= a->rates;
if (a->channels > channels_max)
channels_max = a->channels;
if (a->format == AUDIO_CODING_TYPE_LPCM) {
- if (a->sample_bits & AC_SUPPCM_BITS_20) {
+ if (a->sample_bits & ELD_PCM_BITS_20) {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
if (maxbps < 20)
maxbps = 20;
}
- if (a->sample_bits & AC_SUPPCM_BITS_24) {
+ if (a->sample_bits & ELD_PCM_BITS_24) {
formats |= SNDRV_PCM_FMTBIT_S32_LE;
if (maxbps < 24)
maxbps = 24;
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 727f39acedfc..9325e5c3cbe6 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -84,10 +84,8 @@ static int hda_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file)
{
-#ifndef CONFIG_SND_DEBUG_VERBOSE
if (!capable(CAP_SYS_RAWIO))
return -EACCES;
-#endif
return 0;
}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 4a62440adfaf..512fb22f5e5e 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -37,6 +37,7 @@
#include <linux/completion.h>
#include <linux/acpi.h>
#include <linux/pgtable.h>
+#include <linux/dmi.h>
#ifdef CONFIG_X86
/* for snoop control */
@@ -1050,7 +1051,7 @@ static int azx_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused azx_resume(struct device *dev)
+static int azx_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
@@ -1097,7 +1098,7 @@ static int azx_thaw_noirq(struct device *dev)
return 0;
}
-static int __maybe_unused azx_runtime_suspend(struct device *dev)
+static int azx_runtime_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
@@ -1114,7 +1115,7 @@ static int __maybe_unused azx_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused azx_runtime_resume(struct device *dev)
+static int azx_runtime_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
@@ -1131,7 +1132,7 @@ static int __maybe_unused azx_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused azx_runtime_idle(struct device *dev)
+static int azx_runtime_idle(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
@@ -1162,7 +1163,7 @@ static const struct dev_pm_ops azx_pm = {
.complete = pm_sleep_ptr(azx_complete),
.freeze_noirq = pm_sleep_ptr(azx_freeze_noirq),
.thaw_noirq = pm_sleep_ptr(azx_thaw_noirq),
- SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
+ RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
};
@@ -1352,8 +1353,21 @@ static void azx_free(struct azx *chip)
if (use_vga_switcheroo(hda)) {
if (chip->disabled && hda->probe_continued)
snd_hda_unlock_devices(&chip->bus);
- if (hda->vga_switcheroo_registered)
+ if (hda->vga_switcheroo_registered) {
vga_switcheroo_unregister_client(chip->pci);
+
+ /* Some GPUs don't have sound, and azx_first_init fails,
+ * leaving the device probed but non-functional. As long
+ * as it's probed, the PCI subsystem keeps its runtime
+ * PM status as active. Force it to suspended (as we
+ * actually stop the chip) to allow GPU to suspend via
+ * vga_switcheroo, and print a warning.
+ */
+ dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n");
+ pm_runtime_disable(&pci->dev);
+ pm_runtime_set_suspended(&pci->dev);
+ pm_runtime_enable(&pci->dev);
+ }
}
if (bus->chip_init) {
@@ -2061,6 +2075,27 @@ static const struct pci_device_id driver_denylist[] = {
{}
};
+static struct pci_device_id driver_denylist_ideapad_z570[] = {
+ { PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */
+ {}
+};
+
+/* DMI-based denylist, to be used when:
+ * - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards.
+ * - Different modifications of the same laptop use different GPU models.
+ */
+static const struct dmi_system_id driver_denylist_dmi[] = {
+ {
+ /* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
+ },
+ .driver_data = &driver_denylist_ideapad_z570,
+ },
+ {}
+};
+
static const struct hda_controller_ops pci_hda_ops = {
.disable_msi_reset_irq = disable_msi_reset_irq,
.position_check = azx_position_check,
@@ -2071,6 +2106,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS);
static int azx_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
+ const struct dmi_system_id *dmi;
struct snd_card *card;
struct hda_intel *hda;
struct azx *chip;
@@ -2083,6 +2119,12 @@ static int azx_probe(struct pci_dev *pci,
return -ENODEV;
}
+ dmi = dmi_first_match(driver_denylist_dmi);
+ if (dmi && pci_match_id(dmi->driver_data, pci)) {
+ dev_info(&pci->dev, "Skipping the device on the DMI denylist\n");
+ return -ENODEV;
+ }
+
dev = find_first_zero_bit(probed_devs, SNDRV_CARDS);
if (dev >= SNDRV_CARDS)
return -ENODEV;
@@ -2232,6 +2274,8 @@ static const struct snd_pci_quirk power_save_denylist[] = {
SND_PCI_QUIRK(0x1631, 0xe017, "Packard Bell NEC IMEDIA 5204", 0),
/* KONTRON SinglePC may cause a stall at runtime resume */
SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0),
+ /* Dell ALC3271 */
+ SND_PCI_QUIRK(0x1028, 0x0962, "Dell ALC3271", 0),
{}
};
@@ -2496,6 +2540,8 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_ARL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Panther Lake */
{ PCI_DEVICE_DATA(INTEL, HDA_PTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
+ /* Panther Lake-H */
+ { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
/* Apollolake (Broxton-P) */
{ PCI_DEVICE_DATA(INTEL, HDA_APL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_BROXTON) },
/* Gemini-Lake */
@@ -2738,9 +2784,9 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_VDEVICE(ZHAOXIN, 0x3288), .driver_data = AZX_DRIVER_ZHAOXIN },
/* Loongson HDAudio*/
{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDA),
- .driver_data = AZX_DRIVER_LOONGSON },
+ .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
{ PCI_VDEVICE(LOONGSON, PCI_DEVICE_ID_LOONGSON_HDMI),
- .driver_data = AZX_DRIVER_LOONGSON },
+ .driver_data = AZX_DRIVER_LOONGSON | AZX_DCAPS_NO_TCSEL },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
@@ -2753,7 +2799,7 @@ static struct pci_driver azx_driver = {
.remove = azx_remove,
.shutdown = azx_shutdown,
.driver = {
- .pm = &azx_pm,
+ .pm = pm_ptr(&azx_pm),
},
};
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 763f79f6f32e..4714057dba85 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -10,6 +10,8 @@
#ifndef __SOUND_HDA_LOCAL_H
#define __SOUND_HDA_LOCAL_H
+#include <sound/pcm_drm_eld.h>
+
/* We abuse kcontrol_new.subdev field to pass the NID corresponding to
* the given new control. If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG,
* snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID.
@@ -675,61 +677,18 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
#define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \
snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL)
-/*
- * CEA Short Audio Descriptor data
- */
-struct cea_sad {
- int channels;
- int format; /* (format == 0) indicates invalid SAD */
- int rates;
- int sample_bits; /* for LPCM */
- int max_bitrate; /* for AC3...ATRAC */
- int profile; /* for WMAPRO */
-};
-
-#define ELD_FIXED_BYTES 20
-#define ELD_MAX_SIZE 256
-#define ELD_MAX_MNL 16
-#define ELD_MAX_SAD 16
-
-/*
- * ELD: EDID Like Data
- */
-struct parsed_hdmi_eld {
- /*
- * all fields will be cleared before updating ELD
- */
- int baseline_len;
- int eld_ver;
- int cea_edid_ver;
- char monitor_name[ELD_MAX_MNL + 1];
- int manufacture_id;
- int product_id;
- u64 port_id;
- int support_hdcp;
- int support_ai;
- int conn_type;
- int aud_synch_delay;
- int spk_alloc;
- int sad_count;
- struct cea_sad sad[ELD_MAX_SAD];
-};
-
struct hdmi_eld {
bool monitor_present;
bool eld_valid;
int eld_size;
char eld_buffer[ELD_MAX_SIZE];
- struct parsed_hdmi_eld info;
+ struct snd_parsed_hdmi_eld info;
};
int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid);
int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
unsigned char *buf, int *eld_size);
-int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e,
- const unsigned char *buf, int size);
-void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e);
-void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e,
+void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
struct hda_pcm_stream *hinfo);
int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
index 265fd4737893..140e24bf4d7f 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/pci/hda/hda_sysfs.c
@@ -648,7 +648,7 @@ static const struct hda_patch_item patch_items[NUM_LINE_MODES] = {
},
};
-/* check the line starting with '[' -- change the parser mode accodingly */
+/* check the line starting with '[' -- change the parser mode accordingly */
static int parse_line_mode(char *buf, struct hda_bus *bus)
{
int i;
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index b1e30a83dfb0..a590d431c5ff 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -125,7 +125,7 @@ static void hda_tegra_init(struct hda_tegra *hda)
/*
* power management
*/
-static int __maybe_unused hda_tegra_suspend(struct device *dev)
+static int hda_tegra_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
int rc;
@@ -138,7 +138,7 @@ static int __maybe_unused hda_tegra_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hda_tegra_resume(struct device *dev)
+static int hda_tegra_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
int rc;
@@ -151,7 +151,7 @@ static int __maybe_unused hda_tegra_resume(struct device *dev)
return 0;
}
-static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
+static int hda_tegra_runtime_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
@@ -170,7 +170,7 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
+static int hda_tegra_runtime_resume(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
@@ -204,10 +204,8 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops hda_tegra_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume)
- SET_RUNTIME_PM_OPS(hda_tegra_runtime_suspend,
- hda_tegra_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume)
+ RUNTIME_PM_OPS(hda_tegra_runtime_suspend, hda_tegra_runtime_resume, NULL)
};
static int hda_tegra_dev_disconnect(struct snd_device *device)
@@ -602,7 +600,7 @@ static void hda_tegra_shutdown(struct platform_device *pdev)
static struct platform_driver tegra_platform_hda = {
.driver = {
.name = "tegra-hda",
- .pm = &hda_tegra_pm,
+ .pm = pm_ptr(&hda_tegra_pm),
.of_match_table = hda_tegra_match,
},
.probe = hda_tegra_probe,
diff --git a/sound/pci/hda/ideapad_hotkey_led_helper.c b/sound/pci/hda/ideapad_hotkey_led_helper.c
new file mode 100644
index 000000000000..c10d97964d49
--- /dev/null
+++ b/sound/pci/hda/ideapad_hotkey_led_helper.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ideapad helper functions for Lenovo Ideapad LED control,
+ * It should be included from codec driver.
+ */
+
+#if IS_ENABLED(CONFIG_IDEAPAD_LAPTOP)
+
+#include <linux/acpi.h>
+#include <linux/leds.h>
+
+static bool is_ideapad(struct hda_codec *codec)
+{
+ return (codec->core.subsystem_id >> 16 == 0x17aa) &&
+ (acpi_dev_found("LHK2019") || acpi_dev_found("VPC2004"));
+}
+
+static void hda_fixup_ideapad_acpi(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ if (!is_ideapad(codec))
+ return;
+ snd_hda_gen_add_mute_led_cdev(codec, NULL);
+ snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+ }
+}
+
+#else /* CONFIG_IDEAPAD_LAPTOP */
+
+static void hda_fixup_ideapad_acpi(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+}
+
+#endif /* CONFIG_IDEAPAD_LAPTOP */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 538c37a78a56..34874039ad45 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -291,6 +291,7 @@ enum {
CXT_FIXUP_GPIO1,
CXT_FIXUP_ASPIRE_DMIC,
CXT_FIXUP_THINKPAD_ACPI,
+ CXT_FIXUP_LENOVO_XPAD_ACPI,
CXT_FIXUP_OLPC_XO,
CXT_FIXUP_CAP_MIX_AMP,
CXT_FIXUP_TOSHIBA_P105,
@@ -313,6 +314,9 @@ enum {
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
+/* for hda_fixup_ideapad_acpi() */
+#include "ideapad_hotkey_led_helper.c"
+
static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -928,6 +932,12 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = hda_fixup_thinkpad_acpi,
},
+ [CXT_FIXUP_LENOVO_XPAD_ACPI] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = hda_fixup_ideapad_acpi,
+ .chained = true,
+ .chain_id = CXT_FIXUP_THINKPAD_ACPI,
+ },
[CXT_FIXUP_OLPC_XO] = {
.type = HDA_FIXUP_FUNC,
.v.func = cxt_fixup_olpc_xo,
@@ -1080,6 +1090,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
+ SND_PCI_QUIRK(0x103c, 0x8231, "HP ProBook 450 G4", CXT_FIXUP_MUTE_LED_GPIO),
SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
@@ -1119,7 +1130,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
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", CXT_FIXUP_THINKPAD_ACPI),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI),
SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER),
@@ -1133,6 +1144,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = {
{ .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
{ .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
{ .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
+ { .id = CXT_FIXUP_LENOVO_XPAD_ACPI, .name = "thinkpad-ideapad" },
{ .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
{ .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" },
{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c
index 759f48038273..09240138e087 100644
--- a/sound/pci/hda/patch_cs8409-tables.c
+++ b/sound/pci/hda/patch_cs8409-tables.c
@@ -121,7 +121,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ CS42L42_MIXER_CHA_VOL, 0x3F },
{ CS42L42_MIXER_CHB_VOL, 0x3F },
{ CS42L42_MIXER_ADC_VOL, 0x3f },
- { CS42L42_HP_CTL, 0x03 },
+ { CS42L42_HP_CTL, 0x0D },
{ CS42L42_MIC_DET_CTL1, 0xB6 },
{ CS42L42_TIPSENSE_CTL, 0xC2 },
{ CS42L42_HS_CLAMP_DISABLE, 0x01 },
@@ -131,7 +131,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
{ CS42L42_RSENSE_CTL3, 0x00 },
{ CS42L42_TSENSE_CTL, 0x80 },
{ CS42L42_HS_BIAS_CTL, 0xC0 },
- { CS42L42_PWR_CTL1, 0x02 },
+ { CS42L42_PWR_CTL1, 0x02, 10000 },
{ CS42L42_ADC_OVFL_INT_MASK, 0xff },
{ CS42L42_MIXER_INT_MASK, 0xff },
{ CS42L42_SRC_INT_MASK, 0xff },
@@ -315,7 +315,7 @@ static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = {
{ CS42L42_ASP_TX_SZ_EN, 0x01 },
{ CS42L42_PWR_CTL1, 0x0A },
{ CS42L42_PWR_CTL2, 0x84 },
- { CS42L42_HP_CTL, 0x03 },
+ { CS42L42_HP_CTL, 0x0D },
{ CS42L42_MIXER_CHA_VOL, 0x3F },
{ CS42L42_MIXER_CHB_VOL, 0x3F },
{ CS42L42_MIXER_ADC_VOL, 0x3f },
@@ -328,7 +328,7 @@ static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = {
{ CS42L42_RSENSE_CTL3, 0x00 },
{ CS42L42_TSENSE_CTL, 0x80 },
{ CS42L42_HS_BIAS_CTL, 0xC0 },
- { CS42L42_PWR_CTL1, 0x02 },
+ { CS42L42_PWR_CTL1, 0x02, 10000 },
{ CS42L42_ADC_OVFL_INT_MASK, 0xff },
{ CS42L42_MIXER_INT_MASK, 0xff },
{ CS42L42_SRC_INT_MASK, 0xff },
@@ -371,7 +371,7 @@ static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = {
{ CS42L42_ASP_TX_SZ_EN, 0x00 },
{ CS42L42_PWR_CTL1, 0x0E },
{ CS42L42_PWR_CTL2, 0x84 },
- { CS42L42_HP_CTL, 0x01 },
+ { CS42L42_HP_CTL, 0x0D },
{ CS42L42_MIXER_CHA_VOL, 0x3F },
{ CS42L42_MIXER_CHB_VOL, 0x3F },
{ CS42L42_MIXER_ADC_VOL, 0x3f },
@@ -384,7 +384,7 @@ static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = {
{ CS42L42_RSENSE_CTL3, 0x00 },
{ CS42L42_TSENSE_CTL, 0x80 },
{ CS42L42_HS_BIAS_CTL, 0xC0 },
- { CS42L42_PWR_CTL1, 0x06 },
+ { CS42L42_PWR_CTL1, 0x06, 10000 },
{ CS42L42_ADC_OVFL_INT_MASK, 0xff },
{ CS42L42_MIXER_INT_MASK, 0xff },
{ CS42L42_SRC_INT_MASK, 0xff },
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c
index 614327218634..e50006757a2c 100644
--- a/sound/pci/hda/patch_cs8409.c
+++ b/sound/pci/hda/patch_cs8409.c
@@ -346,6 +346,11 @@ static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i
if (cs8409_i2c_wait_complete(codec) < 0)
goto error;
+ /* Certain use cases may require a delay
+ * after a write operation before proceeding.
+ */
+ if (seq[i].delay)
+ fsleep(seq[i].delay);
}
mutex_unlock(&spec->i2c_mux);
@@ -876,7 +881,7 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
{ CS42L42_DET_INT_STATUS2, 0x00 },
{ CS42L42_TSRS_PLUG_STATUS, 0x00 },
};
- int fsv_old, fsv_new;
+ unsigned int fsv;
/* Bring CS42L42 out of Reset */
spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
@@ -888,18 +893,19 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
/* Initialize CS42L42 companion codec */
cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num);
- msleep(CS42L42_INIT_TIMEOUT_MS);
/* Clear interrupts, by reading interrupt status registers */
cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs));
- fsv_old = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL);
- if (cs42l42->full_scale_vol == CS42L42_FULL_SCALE_VOL_0DB)
- fsv_new = fsv_old & ~CS42L42_FULL_SCALE_VOL_MASK;
- else
- fsv_new = fsv_old & CS42L42_FULL_SCALE_VOL_MASK;
- if (fsv_new != fsv_old)
- cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv_new);
+ fsv = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL);
+ if (cs42l42->full_scale_vol) {
+ // Set the full scale volume bit
+ fsv |= CS42L42_FULL_SCALE_VOL_MASK;
+ cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
+ }
+ // Unmute analog channels A and B
+ fsv = (fsv & ~CS42L42_ANA_MUTE_AB);
+ cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
/* we have to explicitly allow unsol event handling even during the
* resume phase so that the jack event is processed properly
@@ -920,7 +926,7 @@ static void cs42l42_suspend(struct sub_codec *cs42l42)
{ CS42L42_MIXER_CHA_VOL, 0x3F },
{ CS42L42_MIXER_ADC_VOL, 0x3F },
{ CS42L42_MIXER_CHB_VOL, 0x3F },
- { CS42L42_HP_CTL, 0x0F },
+ { CS42L42_HP_CTL, 0x0D },
{ CS42L42_ASP_RX_DAI0_EN, 0x00 },
{ CS42L42_ASP_CLK_CFG, 0x00 },
{ CS42L42_PWR_CTL1, 0xFE },
diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h
index 5e48115caf09..e4bd2e12110b 100644
--- a/sound/pci/hda/patch_cs8409.h
+++ b/sound/pci/hda/patch_cs8409.h
@@ -229,10 +229,10 @@ enum cs8409_coefficient_index_registers {
#define CS42L42_I2C_SLEEP_US (2000)
#define CS42L42_PDN_TIMEOUT_US (250000)
#define CS42L42_PDN_SLEEP_US (2000)
-#define CS42L42_INIT_TIMEOUT_MS (45)
+#define CS42L42_ANA_MUTE_AB (0x0C)
#define CS42L42_FULL_SCALE_VOL_MASK (2)
-#define CS42L42_FULL_SCALE_VOL_0DB (1)
-#define CS42L42_FULL_SCALE_VOL_MINUS6DB (0)
+#define CS42L42_FULL_SCALE_VOL_0DB (0)
+#define CS42L42_FULL_SCALE_VOL_MINUS6DB (1)
/* Dell BULLSEYE / WARLOCK / CYBORG Specific Definitions */
@@ -290,6 +290,7 @@ enum {
struct cs8409_i2c_param {
unsigned int addr;
unsigned int value;
+ unsigned int delay;
};
struct cs8409_cir_param {
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 643e0496b093..7167989a8d86 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1511,8 +1511,8 @@ static void update_eld(struct hda_codec *codec,
if (eld->eld_valid) {
if (eld->eld_size <= 0 ||
- snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
- eld->eld_size) < 0) {
+ snd_parse_eld(hda_codec_dev(codec), &eld->info,
+ eld->eld_buffer, eld->eld_size) < 0) {
eld->eld_valid = false;
if (repoll) {
schedule_delayed_work(&per_pin->work,
@@ -1555,7 +1555,7 @@ static void update_eld(struct hda_codec *codec,
pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
if (eld->eld_valid)
- snd_hdmi_show_eld(codec, &eld->info);
+ snd_show_eld(hda_codec_dev(codec), &eld->info);
eld_changed = (pin_eld->eld_valid != eld->eld_valid);
eld_changed |= (pin_eld->monitor_present != eld->monitor_present);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index ad66378d7321..b4fe681ec3cb 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -28,6 +28,7 @@
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
+#include "hda_beep.h"
#include "hda_jack.h"
#include "hda_generic.h"
#include "hda_component.h"
@@ -586,6 +587,9 @@ static void alc_shutup_pins(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
+ if (spec->no_shutup_pins)
+ return;
+
switch (codec->core.vendor_id) {
case 0x10ec0236:
case 0x10ec0256:
@@ -601,8 +605,7 @@ static void alc_shutup_pins(struct hda_codec *codec)
alc_headset_mic_no_shutup(codec);
break;
default:
- if (!spec->no_shutup_pins)
- snd_hda_shutup_pins(codec);
+ snd_hda_shutup_pins(codec);
break;
}
}
@@ -890,9 +893,7 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
}
}
-/*
- */
-
+/* inverted digital-mic */
static void alc_fixup_inv_dmic(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3790,6 +3791,7 @@ static void alc225_init(struct hda_codec *codec)
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
msleep(75);
+ alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
}
}
@@ -3844,6 +3846,79 @@ static void alc225_shutup(struct hda_codec *codec)
}
}
+static void alc222_init(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ bool hp1_pin_sense, hp2_pin_sense;
+
+ if (!hp_pin)
+ return;
+
+ msleep(30);
+
+ hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+ hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
+
+ if (hp1_pin_sense || hp2_pin_sense) {
+ msleep(2);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ msleep(75);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+ msleep(75);
+ }
+}
+
+static void alc222_shutup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t hp_pin = alc_get_hp_pin(spec);
+ bool hp1_pin_sense, hp2_pin_sense;
+
+ if (!hp_pin)
+ hp_pin = 0x21;
+
+ hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+ hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
+
+ if (hp1_pin_sense || hp2_pin_sense) {
+ msleep(2);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+ msleep(75);
+
+ if (hp1_pin_sense)
+ snd_hda_codec_write(codec, hp_pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+ if (hp2_pin_sense)
+ snd_hda_codec_write(codec, 0x14, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+ msleep(75);
+ }
+ alc_auto_setup_eapd(codec, false);
+ alc_shutup_pins(codec);
+}
+
static void alc_default_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
@@ -4718,6 +4793,21 @@ static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
}
}
+static void alc295_fixup_hp_mute_led_coefbit11(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->mute_led_polarity = 0;
+ spec->mute_led_coef.idx = 0xb;
+ spec->mute_led_coef.mask = 3 << 3;
+ spec->mute_led_coef.on = 1 << 3;
+ spec->mute_led_coef.off = 1 << 4;
+ snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+ }
+}
+
static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4928,7 +5018,6 @@ static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec,
alc298_samsung_v2_init_amps(codec, 4);
}
-#if IS_REACHABLE(CONFIG_INPUT)
static void gpio2_mic_hotkey_event(struct hda_codec *codec,
struct hda_jack_callback *event)
{
@@ -5037,10 +5126,6 @@ static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
spec->kb_dev = NULL;
}
}
-#else /* INPUT */
-#define alc280_fixup_hp_gpio2_mic_hotkey NULL
-#define alc233_fixup_lenovo_line2_mic_hotkey NULL
-#endif /* INPUT */
static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -5054,6 +5139,16 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
}
}
+static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE)
+ spec->micmute_led_polarity = 1;
+ alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
+}
+
static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
{
if (delay <= 0)
@@ -5902,7 +5997,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
}
codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
- is_ctia ? "yes" : "no");
+ str_yes_no(is_ctia));
spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
}
@@ -6924,6 +7019,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
}
}
+static void alc285_fixup_hp_beep(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ codec->beep_just_power_on = true;
+ } else if (action == HDA_FIXUP_ACT_INIT) {
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+ /*
+ * Just enable loopback to internal speaker and headphone jack.
+ * Disable amplification to get about the same beep volume as
+ * was on pure BIOS setup before loading the driver.
+ */
+ alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13));
+
+ snd_hda_enable_beep_device(codec, 1);
+
+#if !IS_ENABLED(CONFIG_INPUT_PCSPKR)
+ dev_warn_once(hda_codec_dev(codec),
+ "enable CONFIG_INPUT_PCSPKR to get PC beeps\n");
+#endif
+#endif
+ }
+}
+
/* for hda_fixup_thinkpad_acpi() */
#include "thinkpad_helper.c"
@@ -6934,6 +7053,15 @@ static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
hda_fixup_thinkpad_acpi(codec, fix, action);
}
+/* for hda_fixup_ideapad_acpi() */
+#include "ideapad_hotkey_led_helper.c"
+
+static void alc_fixup_ideapad_acpi(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ hda_fixup_ideapad_acpi(codec, fix, action);
+}
+
/* Fixup for Lenovo Legion 15IMHg05 speaker output on headset removal. */
static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
const struct hda_fixup *fix,
@@ -7128,6 +7256,11 @@ static void tas2781_fixup_i2c(struct hda_codec *cdc,
comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
}
+static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
+}
+
static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
const struct hda_fixup *fix, int action)
{
@@ -7485,6 +7618,16 @@ static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
}
+/*
+ * Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
+ * at PM resume
+ */
+static void alc283_fixup_dell_hp_resume(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_INIT)
+ alc_write_coef_idx(codec, 0xd, 0x2800);
+}
enum {
ALC269_FIXUP_GPIO2,
@@ -7555,7 +7698,9 @@ enum {
ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
ALC290_FIXUP_SUBWOOFER,
ALC290_FIXUP_SUBWOOFER_HSJACK,
+ ALC295_FIXUP_HP_MUTE_LED_COEFBIT11,
ALC269_FIXUP_THINKPAD_ACPI,
+ ALC269_FIXUP_LENOVO_XPAD_ACPI,
ALC269_FIXUP_DMIC_THINKPAD_ACPI,
ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13,
ALC269VC_FIXUP_INFINIX_Y4_MAX,
@@ -7597,6 +7742,7 @@ enum {
ALC275_FIXUP_DELL_XPS,
ALC293_FIXUP_LENOVO_SPK_NOISE,
ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
+ ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED,
ALC255_FIXUP_DELL_SPK_NOISE,
ALC225_FIXUP_DISABLE_MIC_VREF,
ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -7666,7 +7812,6 @@ enum {
ALC285_FIXUP_THINKPAD_X1_GEN7,
ALC285_FIXUP_THINKPAD_HEADSET_JACK,
ALC294_FIXUP_ASUS_ALLY,
- ALC294_FIXUP_ASUS_ALLY_X,
ALC294_FIXUP_ASUS_ALLY_PINS,
ALC294_FIXUP_ASUS_ALLY_VERBS,
ALC294_FIXUP_ASUS_ALLY_SPEAKER,
@@ -7683,6 +7828,7 @@ enum {
ALC285_FIXUP_HP_GPIO_LED,
ALC285_FIXUP_HP_MUTE_LED,
ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
+ ALC285_FIXUP_HP_BEEP_MICMUTE_LED,
ALC236_FIXUP_HP_MUTE_LED_COEFBIT2,
ALC236_FIXUP_HP_GPIO_LED,
ALC236_FIXUP_HP_MUTE_LED,
@@ -7762,6 +7908,7 @@ enum {
ALC236_FIXUP_DELL_DUAL_CODECS,
ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
ALC287_FIXUP_TAS2781_I2C,
+ ALC245_FIXUP_TAS2781_SPI_2,
ALC287_FIXUP_YOGA7_14ARB7_I2C,
ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
ALC245_FIXUP_HP_X360_MUTE_LEDS,
@@ -7785,6 +7932,7 @@ enum {
ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
ALC233_FIXUP_MEDION_MTL_SPK,
ALC294_FIXUP_BASS_SPEAKER_15,
+ ALC283_FIXUP_DELL_HP_RESUME,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -8327,6 +8475,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_SKU_IGNORE,
},
+ [ALC269_FIXUP_LENOVO_XPAD_ACPI] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_ideapad_acpi,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+ },
[ALC269_FIXUP_DMIC_THINKPAD_ACPI] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic,
@@ -8584,6 +8738,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc233_fixup_lenovo_line2_mic_hotkey,
},
+ [ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_fixup_lenovo_low_en_micmute_led,
+ },
[ALC233_FIXUP_INTEL_NUC8_DMIC] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic,
@@ -9106,12 +9264,6 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
},
- [ALC294_FIXUP_ASUS_ALLY_X] = {
- .type = HDA_FIXUP_FUNC,
- .v.func = tas2781_fixup_i2c,
- .chained = true,
- .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
- },
[ALC294_FIXUP_ASUS_ALLY_PINS] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -9271,6 +9423,12 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc285_fixup_hp_spectre_x360_mute_led,
},
+ [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc285_fixup_hp_beep,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_HP_MUTE_LED,
+ },
[ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc236_fixup_hp_mute_led_coefbit2,
@@ -9293,6 +9451,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC283_FIXUP_INT_MIC,
},
+ [ALC295_FIXUP_HP_MUTE_LED_COEFBIT11] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc295_fixup_hp_mute_led_coefbit11,
+ },
[ALC298_FIXUP_SAMSUNG_AMP] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc298_fixup_samsung_amp,
@@ -9986,6 +10148,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
},
+ [ALC245_FIXUP_TAS2781_SPI_2] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = tas2781_fixup_spi,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+ },
[ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
.type = HDA_FIXUP_FUNC,
.v.func = yoga7_14arb7_fixup_i2c,
@@ -10117,6 +10285,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc294_fixup_bass_speaker_15,
},
+ [ALC283_FIXUP_DELL_HP_RESUME] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc283_fixup_dell_hp_resume,
+ },
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -10158,6 +10330,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x1360, "Acer Aspire A115", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x141f, "Acer Spin SP513-54N", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
@@ -10176,6 +10349,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x0604, "Dell Venue 11 Pro 7130", ALC283_FIXUP_DELL_HP_RESUME),
SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X),
@@ -10331,6 +10505,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ 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, 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),
@@ -10348,7 +10523,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
- SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED),
SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
@@ -10378,6 +10553,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x8812, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
SND_PCI_QUIRK(0x103c, 0x881d, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x881e, "HP Laptop 15s-du3xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
@@ -10388,6 +10564,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8870, "HP ZBook Fury 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x8873, "HP ZBook Studio 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
SND_PCI_QUIRK(0x103c, 0x887a, "HP Laptop 15s-eq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x887c, "HP Laptop 14s-fq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED),
@@ -10546,14 +10723,55 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite X360 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 13 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite X360 13 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da0, "HP 16 Clipper OmniBook 7(X360)", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da1, "HP 16 Clipper OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da7, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
+ SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
+ SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dee, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8df0, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED),
+ 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),
+ SND_PCI_QUIRK(0x103c, 0x8e14, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
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, 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),
+ SND_PCI_QUIRK(0x1043, 0x1074, "ASUS G614PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
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),
@@ -10561,21 +10779,25 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
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),
SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
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),
+ SND_PCI_QUIRK(0x1043, 0x1294, "ASUS B3405CVA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x12a3, "Asus N7691ZM", ALC269_FIXUP_ASUS_N7601ZM),
SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1460, "Asus VivoBook 15", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603VQ/VU/VV/VJ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
@@ -10597,7 +10819,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
- SND_PCI_QUIRK(0x1043, 0x1eb3, "ROG Ally X RC72LA", ALC294_FIXUP_ASUS_ALLY_X),
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),
@@ -10609,7 +10830,6 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
- SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
@@ -10635,6 +10855,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15),
+ 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, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
@@ -10652,14 +10873,28 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x1f63, "ASUS P5405CSA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1fb3, "ASUS ROG Flow Z13 GZ302EA", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3011, "ASUS B5605CVA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
+ SND_PCI_QUIRK(0x1043, 0x3061, "ASUS B3405CCA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x3071, "ASUS B5405CCA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30c1, "ASUS B3605CCA / P3605CCA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30d1, "ASUS B5405CCA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x30e1, "ASUS B5605CCA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27),
+ SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+ SND_PCI_QUIRK(0x1043, 0x3d78, "ASUS GA603KH", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3d88, "ASUS GA603KM", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3e00, "ASUS G814FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x1043, 0x3e20, "ASUS G814PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x3e30, "ASUS TP3607SA", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3ee0, "ASUS Strix G815_JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
@@ -10667,6 +10902,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2),
+ SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
@@ -10865,6 +11102,9 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x17aa, 0x3384, "ThinkCentre M90a PRO", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+ SND_PCI_QUIRK(0x17aa, 0x3386, "ThinkCentre M90a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+ SND_PCI_QUIRK(0x17aa, 0x3387, "ThinkCentre M70a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C),
@@ -10888,7 +11128,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, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
- HDA_CODEC_QUIRK(0x17aa, 0x386f, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C),
+ HDA_CODEC_QUIRK(0x17aa, 0x38a8, "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),
SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
@@ -10963,6 +11203,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1849, 0x0269, "Positivo Master C6400", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1854, 0x0440, "LG CQ6", ALC256_FIXUP_HEADPHONE_AMP_VOL),
@@ -10998,6 +11239,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
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(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),
@@ -11069,7 +11311,7 @@ static const struct hda_quirk alc269_fixup_vendor_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
- SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI),
+ SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI),
SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED),
{}
};
@@ -11134,6 +11376,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"},
{.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"},
{.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"},
+ {.id = ALC269_FIXUP_LENOVO_XPAD_ACPI, .name = "lenovo-xpad-led"},
{.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"},
{.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"},
{.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"},
@@ -11850,8 +12093,11 @@ static int patch_alc269(struct hda_codec *codec)
spec->codec_variant = ALC269_TYPE_ALC300;
spec->gen.mixer_nid = 0; /* no loopback on ALC300 */
break;
+ case 0x10ec0222:
case 0x10ec0623:
spec->codec_variant = ALC269_TYPE_ALC623;
+ spec->shutup = alc222_shutup;
+ spec->init_hook = alc222_init;
break;
case 0x10ec0700:
case 0x10ec0701:
diff --git a/sound/pci/hda/tas2781-spi.h b/sound/pci/hda/tas2781-spi.h
new file mode 100644
index 000000000000..7a0faceeb675
--- /dev/null
+++ b/sound/pci/hda/tas2781-spi.h
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+//
+// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
+//
+// Copyright (C) 2024 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The TAS2781 driver implements a flexible and configurable
+// algo coefficient setting for TAS2781 chips.
+//
+// Author: Baojun Xu <baojun.xu@ti.com>
+//
+
+#ifndef __TAS2781_SPI_H__
+#define __TAS2781_SPI_H__
+
+#define TASDEVICE_RATES \
+ (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
+
+#define TASDEVICE_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define TASDEVICE_MAX_BOOK_NUM 256
+#define TASDEVICE_MAX_PAGE 256
+
+#define TASDEVICE_MAX_SIZE (TASDEVICE_MAX_BOOK_NUM * TASDEVICE_MAX_PAGE)
+
+/* PAGE Control Register (available in page0 of each book) */
+#define TASDEVICE_PAGE_SELECT 0x00
+#define TASDEVICE_BOOKCTL_PAGE 0x00
+#define TASDEVICE_BOOKCTL_REG GENMASK(7, 1)
+#define TASDEVICE_BOOK_ID(reg) (((reg) & GENMASK(24, 16)) >> 16)
+#define TASDEVICE_PAGE_ID(reg) (((reg) & GENMASK(15, 8)) >> 8)
+#define TASDEVICE_REG_ID(reg) (((reg) & GENMASK(7, 1)) >> 1)
+#define TASDEVICE_PAGE_REG(reg) ((reg) & GENMASK(15, 1))
+#define TASDEVICE_REG(book, page, reg) \
+ (((book) << 16) | ((page) << 8) | ((reg) << 1))
+
+/* Software Reset */
+#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01)
+#define TAS2781_REG_SWRESET_RESET BIT(0)
+
+/* System Reset Check Register */
+#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
+#define TAS2781_REG_CLK_CONFIG_RESET (0x19)
+#define TAS2781_PRE_POST_RESET_CFG 3
+
+/* Block Checksum */
+#define TASDEVICE_CHECKSUM TASDEVICE_REG(0x0, 0x0, 0x7e)
+
+/* Volume control */
+#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1a)
+#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
+#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
+
+#define TASDEVICE_CMD_SING_W 0x1
+#define TASDEVICE_CMD_BURST 0x2
+#define TASDEVICE_CMD_DELAY 0x3
+#define TASDEVICE_CMD_FIELD_W 0x4
+
+#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ)
+
+#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
+#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20
+
+/* Flag of calibration registers address. */
+#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7)
+
+#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA"
+#define TASDEVICE_CALIBRATION_DATA_SIZE 256
+
+enum calib_data {
+ R0_VAL = 0,
+ INV_R0,
+ R0LOW,
+ POWER,
+ TLIM,
+ CALIB_MAX
+};
+
+struct tasdevice_priv {
+ struct tasdevice_fw *cali_data_fmw;
+ struct tasdevice_rca rcabin;
+ struct tasdevice_fw *fmw;
+ struct gpio_desc *reset;
+ struct mutex codec_lock;
+ struct regmap *regmap;
+ struct device *dev;
+
+ unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
+ unsigned char coef_binaryname[64];
+ unsigned char rca_binaryname[64];
+ unsigned char dev_name[32];
+
+ bool force_fwload_status;
+ bool playback_started;
+ bool is_loading;
+ bool is_loaderr;
+ unsigned int cali_reg_array[CALIB_MAX];
+ unsigned int cali_data[CALIB_MAX];
+ unsigned int err_code;
+ void *codec;
+ int cur_book;
+ int cur_prog;
+ int cur_conf;
+ int fw_state;
+ int index;
+ int irq;
+
+ int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
+ const struct firmware *fmw,
+ int offset);
+ int (*fw_parse_program_data)(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw,
+ const struct firmware *fmw, int offset);
+ int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw,
+ const struct firmware *fmw,
+ int offset);
+ int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block);
+
+ int (*save_calibration)(struct tasdevice_priv *tas_priv);
+ void (*apply_calibration)(struct tasdevice_priv *tas_priv);
+};
+
+int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
+ unsigned int reg, unsigned int *value);
+int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv,
+ unsigned int reg, unsigned int value);
+int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv,
+ unsigned int reg, unsigned char *p_data,
+ unsigned int n_length);
+int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
+ unsigned int reg, unsigned char *p_data,
+ unsigned int n_length);
+int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tasdevice,
+ unsigned int reg, unsigned int mask,
+ unsigned int value);
+
+void tasdevice_spi_select_cfg_blk(void *context, int conf_no,
+ unsigned char block_type);
+void tasdevice_spi_config_info_remove(void *context);
+int tasdevice_spi_dsp_parser(void *context);
+int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw);
+void tasdevice_spi_dsp_remove(void *context);
+void tasdevice_spi_calbin_remove(void *context);
+int tasdevice_spi_select_tuningprm_cfg(void *context, int prm, int cfg_no,
+ int rca_conf_no);
+int tasdevice_spi_prmg_load(void *context, int prm_no);
+int tasdevice_spi_prmg_calibdata_load(void *context, int prm_no);
+void tasdevice_spi_tuning_switch(void *context, int state);
+int tas2781_spi_load_calibration(void *context, char *file_name,
+ unsigned short i);
+#endif /* __TAS2781_SPI_H__ */
diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c
index 0e42b87dadb8..9ed49b0dbe6b 100644
--- a/sound/pci/hda/tas2781_hda_i2c.c
+++ b/sound/pci/hda/tas2781_hda_i2c.c
@@ -45,7 +45,7 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_range, \
+ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .rreg = xreg, .shift = xshift, \
@@ -594,7 +594,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d,
0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
static efi_char16_t efi_name[] = L"CALI_DATA";
- struct tm *tm = &tas_priv->tm;
unsigned int attr, crc;
unsigned int *tmp_val;
efi_status_t status;
@@ -629,10 +628,9 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
crc, tmp_val[21]);
if (crc == tmp_val[21]) {
- time64_to_tm(tmp_val[20], 0, tm);
- dev_dbg(tas_priv->dev, "%4ld-%2d-%2d, %2d:%2d:%2d\n",
- tm->tm_year, tm->tm_mon, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
+ time64_t seconds = tmp_val[20];
+
+ dev_dbg(tas_priv->dev, "%ptTsr\n", &seconds);
tasdevice_apply_calibration(tas_priv);
} else
tas_priv->cali_data.total_sz = 0;
@@ -755,8 +753,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
out:
mutex_unlock(&tas_hda->priv->codec_lock);
- if (fmw)
- release_firmware(fmw);
+ release_firmware(fmw);
pm_runtime_mark_last_busy(tas_hda->dev);
pm_runtime_put_autosuspend(tas_hda->dev);
}
diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c
new file mode 100644
index 000000000000..399f2e4c3b62
--- /dev/null
+++ b/sound/pci/hda/tas2781_hda_spi.c
@@ -0,0 +1,1263 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA SPI driver
+//
+// Copyright 2024 Texas Instruments, Inc.
+//
+// Author: Baojun Xu <baojun.xu@ti.com>
+
+#include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <sound/hda_codec.h>
+#include <sound/soc.h>
+#include <sound/tas2781-dsp.h>
+#include <sound/tlv.h>
+#include <sound/tas2781-tlv.h>
+
+#include "tas2781-spi.h"
+
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_component.h"
+#include "hda_jack.h"
+#include "hda_generic.h"
+
+/*
+ * No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD
+ * Define two controls, one is Volume control callbacks, the other is
+ * flag setting control callbacks.
+ */
+
+/* Volume control callbacks for tas2781 */
+#define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \
+ xhandler_get, xhandler_put, tlv_array) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) { \
+ .reg = xreg, .rreg = xreg, \
+ .shift = xshift, .rshift = xshift,\
+ .min = xmin, .max = xmax, .invert = xinvert, \
+ } \
+}
+
+/* Flag control callbacks for tas2781 */
+#define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
+ .name = xname, \
+ .info = snd_ctl_boolean_mono_info, \
+ .get = xhandler_get, \
+ .put = xhandler_put, \
+ .private_value = xdata, \
+}
+
+struct tas2781_hda {
+ struct tasdevice_priv *priv;
+ struct acpi_device *dacpi;
+ struct snd_kcontrol *dsp_prog_ctl;
+ struct snd_kcontrol *dsp_conf_ctl;
+ struct snd_kcontrol *snd_ctls[3];
+ struct snd_kcontrol *prof_ctl;
+};
+
+static const struct regmap_range_cfg tasdevice_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = TASDEVICE_MAX_SIZE,
+ .selector_reg = TASDEVICE_PAGE_SELECT,
+ .selector_mask = GENMASK(7, 0),
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = TASDEVICE_MAX_PAGE,
+ },
+};
+
+static const struct regmap_config tasdevice_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .zero_flag_mask = true,
+ .cache_type = REGCACHE_NONE,
+ .ranges = tasdevice_ranges,
+ .num_ranges = ARRAY_SIZE(tasdevice_ranges),
+ .max_register = TASDEVICE_MAX_SIZE,
+};
+
+static int tasdevice_spi_switch_book(struct tasdevice_priv *tas_priv, int reg)
+{
+ struct regmap *map = tas_priv->regmap;
+
+ if (tas_priv->cur_book != TASDEVICE_BOOK_ID(reg)) {
+ int ret = regmap_write(map, TASDEVICE_BOOKCTL_REG,
+ TASDEVICE_BOOK_ID(reg));
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "Switch Book E=%d\n", ret);
+ return ret;
+ }
+ tas_priv->cur_book = TASDEVICE_BOOK_ID(reg);
+ }
+ return 0;
+}
+
+int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
+ unsigned int reg,
+ unsigned int *val)
+{
+ struct regmap *map = tas_priv->regmap;
+ int ret;
+
+ ret = tasdevice_spi_switch_book(tas_priv, reg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * In our TAS2781 SPI mode, if read from other book (not book 0),
+ * or read from page number larger than 1 in book 0, one more byte
+ * read is needed, and first byte is a dummy byte, need to be ignored.
+ */
+ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+ unsigned char data[2];
+
+ ret = regmap_bulk_read(map, TASDEVICE_PAGE_REG(reg) | 1,
+ data, sizeof(data));
+ *val = data[1];
+ } else {
+ ret = regmap_read(map, TASDEVICE_PAGE_REG(reg) | 1, val);
+ }
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv,
+ unsigned int reg,
+ unsigned int value)
+{
+ struct regmap *map = tas_priv->regmap;
+ int ret;
+
+ ret = tasdevice_spi_switch_book(tas_priv, reg);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(map, TASDEVICE_PAGE_REG(reg), value);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv,
+ unsigned int reg,
+ unsigned char *data,
+ unsigned int len)
+{
+ struct regmap *map = tas_priv->regmap;
+ int ret;
+
+ ret = tasdevice_spi_switch_book(tas_priv, reg);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_bulk_write(map, TASDEVICE_PAGE_REG(reg), data, len);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
+ unsigned int reg,
+ unsigned char *data,
+ unsigned int len)
+{
+ struct regmap *map = tas_priv->regmap;
+ int ret;
+
+ ret = tasdevice_spi_switch_book(tas_priv, reg);
+ if (ret < 0)
+ return ret;
+
+ if (len > TASDEVICE_MAX_PAGE)
+ len = TASDEVICE_MAX_PAGE;
+ /*
+ * In our TAS2781 SPI mode, if read from other book (not book 0),
+ * or read from page number larger than 1 in book 0, one more byte
+ * read is needed, and first byte is a dummy byte, need to be ignored.
+ */
+ if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+ unsigned char buf[TASDEVICE_MAX_PAGE+1];
+
+ ret = regmap_bulk_read(map, TASDEVICE_PAGE_REG(reg) | 1, buf,
+ len + 1);
+ memcpy(data, buf + 1, len);
+ } else {
+ ret = regmap_bulk_read(map, TASDEVICE_PAGE_REG(reg) | 1, data,
+ len);
+ }
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
+ unsigned int reg,
+ unsigned int mask,
+ unsigned int value)
+{
+ struct regmap *map = tas_priv->regmap;
+ int ret, val;
+
+ /*
+ * In our TAS2781 SPI mode, read/write was masked in last bit of
+ * address, it cause regmap_update_bits() not work as expected.
+ */
+ ret = tasdevice_spi_dev_read(tas_priv, reg, &val);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+ return ret;
+ }
+ ret = regmap_write(map, TASDEVICE_PAGE_REG(reg),
+ (val & ~mask) | (mask & value));
+ if (ret < 0)
+ dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static void tas2781_spi_reset(struct tasdevice_priv *tas_dev)
+{
+ int ret;
+
+ if (tas_dev->reset) {
+ gpiod_set_value_cansleep(tas_dev->reset, 0);
+ fsleep(800);
+ gpiod_set_value_cansleep(tas_dev->reset, 1);
+ }
+ ret = tasdevice_spi_dev_write(tas_dev, TAS2781_REG_SWRESET,
+ TAS2781_REG_SWRESET_RESET);
+ if (ret < 0)
+ dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret);
+ fsleep(1000);
+}
+
+static int tascodec_spi_init(struct tasdevice_priv *tas_priv,
+ void *codec, struct module *module,
+ void (*cont)(const struct firmware *fw, void *context))
+{
+ int ret;
+
+ /*
+ * Codec Lock Hold to ensure that codec_probe and firmware parsing and
+ * loading do not simultaneously execute.
+ */
+ guard(mutex)(&tas_priv->codec_lock);
+
+ scnprintf(tas_priv->rca_binaryname,
+ sizeof(tas_priv->rca_binaryname), "%sRCA%d.bin",
+ tas_priv->dev_name, tas_priv->index);
+ crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
+ tas_priv->codec = codec;
+ ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
+ tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
+ cont);
+ if (ret)
+ dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
+ ret);
+
+ return ret;
+}
+
+static void tasdevice_spi_init(struct tasdevice_priv *tas_priv)
+{
+ tas_priv->cur_prog = -1;
+ tas_priv->cur_conf = -1;
+
+ tas_priv->cur_book = -1;
+ tas_priv->cur_prog = -1;
+ tas_priv->cur_conf = -1;
+
+ /* Store default registers address for calibration data. */
+ tas_priv->cali_reg_array[0] = TASDEVICE_REG(0, 0x17, 0x74);
+ tas_priv->cali_reg_array[1] = TASDEVICE_REG(0, 0x18, 0x0c);
+ tas_priv->cali_reg_array[2] = TASDEVICE_REG(0, 0x18, 0x14);
+ tas_priv->cali_reg_array[3] = TASDEVICE_REG(0, 0x13, 0x70);
+ tas_priv->cali_reg_array[4] = TASDEVICE_REG(0, 0x18, 0x7c);
+
+ mutex_init(&tas_priv->codec_lock);
+}
+
+static int tasdevice_spi_amp_putvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ unsigned char mask;
+ int max = mc->max;
+ int val, ret;
+
+ mask = rounddown_pow_of_two(max);
+ mask <<= mc->shift;
+ val = clamp(invert ? max - ucontrol->value.integer.value[0] :
+ ucontrol->value.integer.value[0], 0, max);
+ ret = tasdevice_spi_dev_update_bits(tas_priv,
+ mc->reg, mask, (unsigned int)(val << mc->shift));
+ if (ret)
+ dev_err(tas_priv->dev, "set AMP vol error in dev %d\n",
+ tas_priv->index);
+
+ return ret;
+}
+
+static int tasdevice_spi_amp_getvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ unsigned char mask = 0;
+ int max = mc->max;
+ int ret, val;
+
+ /* Read the primary device */
+ ret = tasdevice_spi_dev_read(tas_priv, mc->reg, &val);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__);
+ return ret;
+ }
+
+ mask = rounddown_pow_of_two(max);
+ mask <<= mc->shift;
+ val = (val & mask) >> mc->shift;
+ val = clamp(invert ? max - val : val, 0, max);
+ ucontrol->value.integer.value[0] = val;
+
+ return ret;
+}
+
+static int tasdevice_spi_digital_putvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ int max = mc->max;
+ int val, ret;
+
+ val = clamp(invert ? max - ucontrol->value.integer.value[0] :
+ ucontrol->value.integer.value[0], 0, max);
+ ret = tasdevice_spi_dev_write(tas_priv, mc->reg, (unsigned int)val);
+ if (ret)
+ dev_err(tas_priv->dev, "set digital vol err in dev %d\n",
+ tas_priv->index);
+
+ return ret;
+}
+
+static int tasdevice_spi_digital_getvol(struct tasdevice_priv *tas_priv,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc)
+{
+ unsigned int invert = mc->invert;
+ int max = mc->max;
+ int ret, val;
+
+ /* Read the primary device as the whole */
+ ret = tasdevice_spi_dev_read(tas_priv, mc->reg, &val);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s, get digital vol err\n", __func__);
+ return ret;
+ }
+
+ val = clamp(invert ? max - val : val, 0, max);
+ ucontrol->value.integer.value[0] = val;
+
+ return ret;
+}
+
+static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
+ const char *hid,
+ int id)
+{
+ 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;
+ int ret, i;
+
+ adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+ if (!adev) {
+ dev_err(p->dev, "Failed to find ACPI device: %s\n", hid);
+ return -ENODEV;
+ }
+
+ strscpy(p->dev_name, hid, sizeof(p->dev_name));
+ tas_hda->dacpi = adev;
+ physdev = get_device(acpi_get_first_physical_node(adev));
+ acpi_dev_put(adev);
+
+ property = "ti,dev-index";
+ ret = device_property_count_u32(physdev, property);
+ if (ret <= 0 || ret > ARRAY_SIZE(values)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ nval = ret;
+
+ ret = device_property_read_u32_array(physdev, property, values, nval);
+ if (ret)
+ goto err;
+
+ p->index = U8_MAX;
+ for (i = 0; i < nval; i++) {
+ if (values[i] == id) {
+ p->index = i;
+ break;
+ }
+ }
+ if (p->index == U8_MAX) {
+ dev_dbg(p->dev, "No index found in %s\n", property);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (p->index == 0) {
+ /* All of amps share same RESET pin. */
+ p->reset = devm_gpiod_get_index_optional(physdev, "reset",
+ p->index, GPIOD_OUT_LOW);
+ if (IS_ERR(p->reset)) {
+ ret = PTR_ERR(p->reset);
+ dev_err_probe(p->dev, ret, "Failed on reset GPIO\n");
+ goto err;
+ }
+ }
+ put_device(physdev);
+
+ return 0;
+err:
+ dev_err(p->dev, "read acpi error, ret: %d\n", ret);
+ put_device(physdev);
+ acpi_dev_put(adev);
+
+ return ret;
+}
+
+static void tas2781_hda_playback_hook(struct device *dev, int action)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ if (action == HDA_GEN_PCM_ACT_OPEN) {
+ pm_runtime_get_sync(dev);
+ guard(mutex)(&tas_hda->priv->codec_lock);
+ tasdevice_spi_tuning_switch(tas_hda->priv, 0);
+ } else if (action == HDA_GEN_PCM_ACT_CLOSE) {
+ guard(mutex)(&tas_hda->priv->codec_lock);
+ tasdevice_spi_tuning_switch(tas_hda->priv, 1);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
+}
+
+static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
+
+ return 0;
+}
+
+static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
+
+ return 0;
+}
+
+static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ int max = tas_priv->rcabin.ncfgs - 1;
+ int val;
+
+ val = clamp(ucontrol->value.integer.value[0], 0, max);
+ if (tas_priv->rcabin.profile_cfg_id != val) {
+ tas_priv->rcabin.profile_cfg_id = val;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
+
+ return 0;
+}
+
+static int tasdevice_info_config(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = tas_priv->fmw->nr_configurations - 1;
+
+ return 0;
+}
+
+static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = tas_priv->cur_prog;
+
+ return 0;
+}
+
+static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ int nr_program = ucontrol->value.integer.value[0];
+ int max = tas_priv->fmw->nr_programs - 1;
+ int val;
+
+ val = clamp(nr_program, 0, max);
+
+ if (tas_priv->cur_prog != val) {
+ tas_priv->cur_prog = val;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = tas_priv->cur_conf;
+
+ return 0;
+}
+
+static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ int max = tas_priv->fmw->nr_configurations - 1;
+ int val;
+
+ val = clamp(ucontrol->value.integer.value[0], 0, max);
+
+ if (tas_priv->cur_conf != val) {
+ tas_priv->cur_conf = val;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * tas2781_digital_getvol - get the volum control
+ * @kcontrol: control pointer
+ * @ucontrol: User data
+ *
+ * Customer Kcontrol for tas2781 is primarily for regmap booking, paging
+ * depends on internal regmap mechanism.
+ * tas2781 contains book and page two-level register map, especially
+ * book switching will set the register BXXP00R7F, after switching to the
+ * correct book, then leverage the mechanism for paging to access the
+ * register.
+ *
+ * Return 0 if succeeded.
+ */
+static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_spi_digital_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ return tasdevice_spi_amp_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* The check of the given value is in tasdevice_digital_putvol. */
+ return tasdevice_spi_digital_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ /* The check of the given value is in tasdevice_amp_putvol. */
+ return tasdevice_spi_amp_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
+ dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+ str_on_off(tas_priv->force_fwload_status));
+
+ return 0;
+}
+
+static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+ bool change, val = (bool)ucontrol->value.integer.value[0];
+
+ if (tas_priv->force_fwload_status == val) {
+ change = false;
+ } else {
+ change = true;
+ tas_priv->force_fwload_status = val;
+ }
+ dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+ str_on_off(tas_priv->force_fwload_status));
+
+ return change;
+}
+
+static const struct snd_kcontrol_new tas2781_snd_controls[] = {
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 0", TAS2781_AMP_LEVEL,
+ 1, 0, 20, 0, tas2781_amp_getvol,
+ tas2781_amp_putvol, amp_vol_tlv),
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 0", TAS2781_DVC_LVL,
+ 0, 0, 200, 1, tas2781_digital_getvol,
+ tas2781_digital_putvol, dvc_tlv),
+ ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 0", 0,
+ tas2781_force_fwload_get, tas2781_force_fwload_put),
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 1", TAS2781_AMP_LEVEL,
+ 1, 0, 20, 0, tas2781_amp_getvol,
+ tas2781_amp_putvol, amp_vol_tlv),
+ ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 1", TAS2781_DVC_LVL,
+ 0, 0, 200, 1, tas2781_digital_getvol,
+ tas2781_digital_putvol, dvc_tlv),
+ ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 1", 0,
+ tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas2781_prof_ctrl[] = {
+{
+ .name = "Speaker Profile Id - 0",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_profile,
+ .get = tasdevice_get_profile_id,
+ .put = tasdevice_set_profile_id,
+},
+{
+ .name = "Speaker Profile Id - 1",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_profile,
+ .get = tasdevice_get_profile_id,
+ .put = tasdevice_set_profile_id,
+},
+};
+static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl[] = {
+{
+ .name = "Speaker Program Id 0",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_programs,
+ .get = tasdevice_program_get,
+ .put = tasdevice_program_put,
+},
+{
+ .name = "Speaker Program Id 1",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_programs,
+ .get = tasdevice_program_get,
+ .put = tasdevice_program_put,
+},
+};
+
+static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl[] = {
+{
+ .name = "Speaker Config Id 0",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_config,
+ .get = tasdevice_config_get,
+ .put = tasdevice_config_put,
+},
+{
+ .name = "Speaker Config Id 1",
+ .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+ .info = tasdevice_info_config,
+ .get = tasdevice_config_get,
+ .put = tasdevice_config_put,
+},
+};
+
+static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
+{
+ int i, rc;
+
+ /*
+ * If no calibration data exist in tasdevice_priv *tas_priv,
+ * calibration apply will be ignored, and use default values
+ * in firmware binary, which was loaded during firmware download.
+ */
+ if (tas_priv->cali_data[0] == 0)
+ return;
+ /*
+ * Calibration data was saved in tasdevice_priv *tas_priv as:
+ * unsigned int cali_data[CALIB_MAX];
+ * and every data (in 4 bytes) will be saved in register which in
+ * book 0, and page number in page_array[], offset was saved in
+ * rgno_array[].
+ */
+ for (i = 0; i < CALIB_MAX; i++) {
+ rc = tasdevice_spi_dev_bulk_write(tas_priv,
+ tas_priv->cali_reg_array[i],
+ (unsigned char *)&tas_priv->cali_data[i], 4);
+ if (rc < 0)
+ dev_err(tas_priv->dev,
+ "chn %d calib %d bulk_wr err = %d\n",
+ tas_priv->index, i, rc);
+ }
+}
+
+/*
+ * Update the calibration data, including speaker impedance, f0, etc,
+ * into algo. Calibrate data is done by manufacturer in the factory.
+ * These data are used by Algo for calculating the speaker temperature,
+ * speaker membrane excursion and f0 in real time during playback.
+ * Calibration data format in EFI is V2, since 2024.
+ */
+static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
+{
+ /*
+ * GUID was used for data access in BIOS, it was provided by board
+ * manufactory, like HP: "{02f9af02-7734-4233-b43d-93fe5aa35db3}"
+ */
+ efi_guid_t efi_guid =
+ EFI_GUID(0x02f9af02, 0x7734, 0x4233,
+ 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3);
+ static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME;
+ unsigned char data[TASDEVICE_CALIBRATION_DATA_SIZE], *buf;
+ unsigned int attr, crc, offset, *tmp_val;
+ unsigned long total_sz = 0;
+ efi_status_t status;
+
+ tas_priv->cali_data[0] = 0;
+ status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, data);
+ if (status == EFI_BUFFER_TOO_SMALL) {
+ if (total_sz > TASDEVICE_CALIBRATION_DATA_SIZE)
+ return -ENOMEM;
+ /* Get variable contents into buffer */
+ status = efi.get_variable(efi_name, &efi_guid, &attr,
+ &total_sz, data);
+ }
+ if (status != EFI_SUCCESS)
+ return status;
+
+ tmp_val = (unsigned int *)data;
+ if (tmp_val[0] == 2781) {
+ /*
+ * New features were added in calibrated Data V3:
+ * 1. Added calibration registers address define in
+ * a node, marked as Device id == 0x80.
+ * New features were added in calibrated Data V2:
+ * 1. Added some the fields to store the link_id and
+ * uniqie_id for multi-link solutions
+ * 2. Support flexible number of devices instead of
+ * fixed one in V1.
+ * Layout of calibrated data V2 in UEFI(total 256 bytes):
+ * ChipID (2781, 4 bytes)
+ * Device-Sum (4 bytes)
+ * TimeStamp of Calibration (4 bytes)
+ * for (i = 0; i < Device-Sum; i++) {
+ * Device #i index_info () {
+ * SDW link id (2bytes)
+ * SDW unique_id (2bytes)
+ * } // if Device number is 0x80, mean it's
+ * calibration registers address.
+ * Calibrated Data of Device #i (20 bytes)
+ * }
+ * CRC (4 bytes)
+ * Reserved (the rest)
+ */
+ crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0;
+
+ if (crc != tmp_val[3 + tmp_val[1] * 6])
+ return 0;
+
+ for (int j = 0; j < tmp_val[1]; j++) {
+ offset = j * 6 + 3;
+ if (tmp_val[offset] == tas_priv->index) {
+ for (int i = 0; i < CALIB_MAX; i++)
+ tas_priv->cali_data[i] =
+ tmp_val[offset + i + 1];
+ } else if (tmp_val[offset] ==
+ TASDEVICE_CALIBRATION_REG_ADDRESS) {
+ for (int i = 0; i < CALIB_MAX; i++) {
+ buf = &data[(offset + i + 1) * 4];
+ tas_priv->cali_reg_array[i] =
+ TASDEVICE_REG(buf[1], buf[2],
+ buf[3]);
+ }
+ }
+ tas_priv->apply_calibration(tas_priv);
+ }
+ } else {
+ /*
+ * Calibration data is in V1 format.
+ * struct cali_data {
+ * char cali_data[20];
+ * }
+ *
+ * struct {
+ * struct cali_data cali_data[4];
+ * int TimeStamp of Calibration (4 bytes)
+ * int CRC (4 bytes)
+ * } ueft;
+ */
+ crc = crc32(~0, data, 84) ^ ~0;
+ if (crc == tmp_val[21]) {
+ for (int i = 0; i < CALIB_MAX; i++)
+ tas_priv->cali_data[i] =
+ tmp_val[tas_priv->index * 5 + i];
+ tas_priv->apply_calibration(tas_priv);
+ }
+ }
+
+ return 0;
+}
+
+static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
+{
+ struct hda_codec *codec = tas_hda->priv->codec;
+
+ snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
+
+ snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
+
+ for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
+ snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
+
+ snd_ctl_remove(codec->card, tas_hda->prof_ctl);
+}
+
+static void tasdev_fw_ready(const struct firmware *fmw, void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
+ struct hda_codec *codec = tas_priv->codec;
+ int i, j, ret, val;
+
+ pm_runtime_get_sync(tas_priv->dev);
+ guard(mutex)(&tas_priv->codec_lock);
+
+ ret = tasdevice_spi_rca_parser(tas_priv, fmw);
+ if (ret)
+ goto out;
+
+ /* Add control one time only. */
+ tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl[tas_priv->index],
+ tas_priv);
+ ret = snd_ctl_add(codec->card, tas_hda->prof_ctl);
+ if (ret) {
+ dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n",
+ tas2781_prof_ctrl[tas_priv->index].name, ret);
+ goto out;
+ }
+ j = tas_priv->index * ARRAY_SIZE(tas2781_snd_controls) / 2;
+ for (i = 0; i < 3; i++) {
+ tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i+j],
+ tas_priv);
+ ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]);
+ if (ret) {
+ dev_err(tas_priv->dev,
+ "Failed to add KControl %s = %d\n",
+ tas2781_snd_controls[i+tas_priv->index*3].name,
+ ret);
+ goto out;
+ }
+ }
+
+ tasdevice_spi_dsp_remove(tas_priv);
+
+ tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+ scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%08X-%01d.bin",
+ codec->core.subsystem_id, tas_priv->index);
+ ret = tasdevice_spi_dsp_parser(tas_priv);
+ if (ret) {
+ dev_err(tas_priv->dev, "dspfw load %s error\n",
+ tas_priv->coef_binaryname);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ goto out;
+ }
+
+ /* Add control one time only. */
+ tas_hda->dsp_prog_ctl =
+ snd_ctl_new1(&tas2781_dsp_prog_ctrl[tas_priv->index],
+ tas_priv);
+ ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl);
+ if (ret) {
+ dev_err(tas_priv->dev,
+ "Failed to add KControl %s = %d\n",
+ tas2781_dsp_prog_ctrl[tas_priv->index].name, ret);
+ goto out;
+ }
+
+ tas_hda->dsp_conf_ctl =
+ snd_ctl_new1(&tas2781_dsp_conf_ctrl[tas_priv->index],
+ tas_priv);
+ ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl);
+ if (ret) {
+ dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n",
+ tas2781_dsp_conf_ctrl[tas_priv->index].name, ret);
+ goto out;
+ }
+
+ /* Perform AMP reset before firmware download. */
+ tas_priv->rcabin.profile_cfg_id = TAS2781_PRE_POST_RESET_CFG;
+ tas2781_spi_reset(tas_priv);
+ tas_priv->rcabin.profile_cfg_id = 0;
+
+ tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+ ret = tasdevice_spi_dev_read(tas_priv, TAS2781_REG_CLK_CONFIG, &val);
+ if (ret < 0)
+ goto out;
+
+ if (val == TAS2781_REG_CLK_CONFIG_RESET)
+ ret = tasdevice_spi_prmg_load(tas_priv, 0);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "FW download failed = %d\n", ret);
+ goto out;
+ }
+ if (tas_priv->fmw->nr_programs > 0)
+ tas_priv->cur_prog = 0;
+ if (tas_priv->fmw->nr_configurations > 0)
+ tas_priv->cur_conf = 0;
+
+ /*
+ * If calibrated data occurs error, dsp will still works with default
+ * calibrated data inside algo.
+ */
+
+out:
+ if (fmw)
+ release_firmware(fmw);
+ pm_runtime_mark_last_busy(tas_hda->priv->dev);
+ pm_runtime_put_autosuspend(tas_hda->priv->dev);
+}
+
+static int tas2781_hda_bind(struct device *dev, struct device *master,
+ void *master_data)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+ struct hda_codec *codec;
+ int ret;
+
+ comp = hda_component_from_index(parent, tas_hda->priv->index);
+ if (!comp)
+ return -EINVAL;
+
+ if (comp->dev)
+ return -EBUSY;
+
+ codec = parent->codec;
+
+ pm_runtime_get_sync(dev);
+
+ comp->dev = dev;
+
+ strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+ ret = tascodec_spi_init(tas_hda->priv, codec, THIS_MODULE,
+ tasdev_fw_ready);
+ if (!ret)
+ comp->playback_hook = tas2781_hda_playback_hook;
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+static void tas2781_hda_unbind(struct device *dev, struct device *master,
+ void *master_data)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ struct hda_component_parent *parent = master_data;
+ struct hda_component *comp;
+
+ comp = hda_component_from_index(parent, tas_hda->priv->index);
+ if (comp && (comp->dev == dev)) {
+ comp->dev = NULL;
+ memset(comp->name, 0, sizeof(comp->name));
+ comp->playback_hook = NULL;
+ }
+
+ tas2781_hda_remove_controls(tas_hda);
+
+ tasdevice_spi_config_info_remove(tas_hda->priv);
+ tasdevice_spi_dsp_remove(tas_hda->priv);
+
+ tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+}
+
+static const struct component_ops tas2781_hda_comp_ops = {
+ .bind = tas2781_hda_bind,
+ .unbind = tas2781_hda_unbind,
+};
+
+static void tas2781_hda_remove(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ component_del(tas_hda->priv->dev, &tas2781_hda_comp_ops);
+
+ pm_runtime_get_sync(tas_hda->priv->dev);
+ pm_runtime_disable(tas_hda->priv->dev);
+
+ pm_runtime_put_noidle(tas_hda->priv->dev);
+
+ mutex_destroy(&tas_hda->priv->codec_lock);
+}
+
+static int tas2781_hda_spi_probe(struct spi_device *spi)
+{
+ struct tasdevice_priv *tas_priv;
+ struct tas2781_hda *tas_hda;
+ const char *device_name;
+ int ret = 0;
+
+ tas_hda = devm_kzalloc(&spi->dev, sizeof(*tas_hda), GFP_KERNEL);
+ if (!tas_hda)
+ return -ENOMEM;
+
+ spi->max_speed_hz = TAS2781_SPI_MAX_FREQ;
+
+ tas_priv = devm_kzalloc(&spi->dev, sizeof(*tas_priv), GFP_KERNEL);
+ if (!tas_priv)
+ return -ENOMEM;
+ tas_priv->dev = &spi->dev;
+ tas_hda->priv = tas_priv;
+ tas_priv->regmap = devm_regmap_init_spi(spi, &tasdevice_regmap);
+ if (IS_ERR(tas_priv->regmap)) {
+ ret = PTR_ERR(tas_priv->regmap);
+ dev_err(tas_priv->dev, "Failed to allocate regmap: %d\n",
+ ret);
+ return ret;
+ }
+ if (strstr(dev_name(&spi->dev), "TXNW2781")) {
+ device_name = "TXNW2781";
+ tas_priv->save_calibration = tas2781_save_calibration;
+ tas_priv->apply_calibration = tas2781_apply_calib;
+ } else {
+ dev_err(tas_priv->dev, "Unmatched spi dev %s\n",
+ dev_name(&spi->dev));
+ return -ENODEV;
+ }
+
+ tas_priv->irq = spi->irq;
+ dev_set_drvdata(&spi->dev, tas_hda);
+ ret = tas2781_read_acpi(tas_hda, device_name,
+ spi_get_chipselect(spi, 0));
+ if (ret)
+ return dev_err_probe(tas_priv->dev, ret,
+ "Platform not supported\n");
+
+ tasdevice_spi_init(tas_priv);
+
+ ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
+ if (ret) {
+ dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
+ pm_runtime_use_autosuspend(tas_priv->dev);
+ pm_runtime_mark_last_busy(tas_priv->dev);
+ pm_runtime_set_active(tas_priv->dev);
+ pm_runtime_get_noresume(tas_priv->dev);
+ pm_runtime_enable(tas_priv->dev);
+
+ pm_runtime_put_autosuspend(tas_priv->dev);
+
+ return 0;
+}
+
+static void tas2781_hda_spi_remove(struct spi_device *spi)
+{
+ tas2781_hda_remove(&spi->dev);
+}
+
+static int tas2781_runtime_suspend(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+
+ if (tas_hda->priv->playback_started)
+ tasdevice_spi_tuning_switch(tas_hda->priv, 1);
+
+ tas_hda->priv->cur_book = -1;
+ tas_hda->priv->cur_conf = -1;
+
+ return 0;
+}
+
+static int tas2781_runtime_resume(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+
+ if (tas_hda->priv->playback_started)
+ tasdevice_spi_tuning_switch(tas_hda->priv, 0);
+
+ return 0;
+}
+
+static int tas2781_system_suspend(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret)
+ return ret;
+
+ /* Shutdown chip before system suspend */
+ if (tas_hda->priv->playback_started)
+ tasdevice_spi_tuning_switch(tas_hda->priv, 1);
+
+ return 0;
+}
+
+static int tas2781_system_resume(struct device *dev)
+{
+ struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+ int ret, val;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&tas_hda->priv->codec_lock);
+ ret = tasdevice_spi_dev_read(tas_hda->priv, TAS2781_REG_CLK_CONFIG,
+ &val);
+ if (ret < 0)
+ return ret;
+
+ if (val == TAS2781_REG_CLK_CONFIG_RESET) {
+ tas_hda->priv->cur_book = -1;
+ tas_hda->priv->cur_conf = -1;
+ tas_hda->priv->cur_prog = -1;
+
+ ret = tasdevice_spi_prmg_load(tas_hda->priv, 0);
+ if (ret < 0) {
+ dev_err(tas_hda->priv->dev,
+ "FW download failed = %d\n", ret);
+ return ret;
+ }
+
+ if (tas_hda->priv->playback_started)
+ tasdevice_spi_tuning_switch(tas_hda->priv, 0);
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops tas2781_hda_pm_ops = {
+ RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume)
+};
+
+static const struct spi_device_id tas2781_hda_spi_id[] = {
+ { "tas2781-hda", },
+ {}
+};
+
+static const struct acpi_device_id tas2781_acpi_hda_match[] = {
+ {"TXNW2781", },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
+
+static struct spi_driver tas2781_hda_spi_driver = {
+ .driver = {
+ .name = "tas2781-hda",
+ .acpi_match_table = tas2781_acpi_hda_match,
+ .pm = &tas2781_hda_pm_ops,
+ },
+ .id_table = tas2781_hda_spi_id,
+ .probe = tas2781_hda_spi_probe,
+ .remove = tas2781_hda_spi_remove,
+};
+module_spi_driver(tas2781_hda_spi_driver);
+
+MODULE_DESCRIPTION("TAS2781 HDA SPI Driver");
+MODULE_AUTHOR("Baojun, Xu, <baojun.xug@ti.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/tas2781_spi_fwlib.c b/sound/pci/hda/tas2781_spi_fwlib.c
new file mode 100644
index 000000000000..d90d022d8449
--- /dev/null
+++ b/sound/pci/hda/tas2781_spi_fwlib.c
@@ -0,0 +1,2006 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA SPI driver
+//
+// Copyright 2024 - 2025 Texas Instruments, Inc.
+//
+// Author: Baojun Xu <baojun.xu@ti.com>
+
+#include <linux/crc8.h>
+#include <linux/firmware.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tas2781-dsp.h>
+#include <sound/tlv.h>
+
+#include "tas2781-spi.h"
+
+#define OFFSET_ERROR_BIT BIT(31)
+
+#define ERROR_PRAM_CRCCHK 0x0000000
+#define ERROR_YRAM_CRCCHK 0x0000001
+#define PPC_DRIVER_CRCCHK 0x00000200
+
+#define TAS2781_SA_COEFF_SWAP_REG TASDEVICE_REG(0, 0x35, 0x2c)
+#define TAS2781_YRAM_BOOK1 140
+#define TAS2781_YRAM1_PAGE 42
+#define TAS2781_YRAM1_START_REG 88
+
+#define TAS2781_YRAM2_START_PAGE 43
+#define TAS2781_YRAM2_END_PAGE 49
+#define TAS2781_YRAM2_START_REG 8
+#define TAS2781_YRAM2_END_REG 127
+
+#define TAS2781_YRAM3_PAGE 50
+#define TAS2781_YRAM3_START_REG 8
+#define TAS2781_YRAM3_END_REG 27
+
+/* should not include B0_P53_R44-R47 */
+#define TAS2781_YRAM_BOOK2 0
+#define TAS2781_YRAM4_START_PAGE 50
+#define TAS2781_YRAM4_END_PAGE 60
+
+#define TAS2781_YRAM5_PAGE 61
+#define TAS2781_YRAM5_START_REG TAS2781_YRAM3_START_REG
+#define TAS2781_YRAM5_END_REG TAS2781_YRAM3_END_REG
+
+#define TASDEVICE_MAXPROGRAM_NUM_KERNEL 5
+#define TASDEVICE_MAXCONFIG_NUM_KERNEL_MULTIPLE_AMPS 64
+#define TASDEVICE_MAXCONFIG_NUM_KERNEL 10
+#define MAIN_ALL_DEVICES_1X 0x01
+#define MAIN_DEVICE_A_1X 0x02
+#define MAIN_DEVICE_B_1X 0x03
+#define MAIN_DEVICE_C_1X 0x04
+#define MAIN_DEVICE_D_1X 0x05
+#define COEFF_DEVICE_A_1X 0x12
+#define COEFF_DEVICE_B_1X 0x13
+#define COEFF_DEVICE_C_1X 0x14
+#define COEFF_DEVICE_D_1X 0x15
+#define PRE_DEVICE_A_1X 0x22
+#define PRE_DEVICE_B_1X 0x23
+#define PRE_DEVICE_C_1X 0x24
+#define PRE_DEVICE_D_1X 0x25
+#define PRE_SOFTWARE_RESET_DEVICE_A 0x41
+#define PRE_SOFTWARE_RESET_DEVICE_B 0x42
+#define PRE_SOFTWARE_RESET_DEVICE_C 0x43
+#define PRE_SOFTWARE_RESET_DEVICE_D 0x44
+#define POST_SOFTWARE_RESET_DEVICE_A 0x45
+#define POST_SOFTWARE_RESET_DEVICE_B 0x46
+#define POST_SOFTWARE_RESET_DEVICE_C 0x47
+#define POST_SOFTWARE_RESET_DEVICE_D 0x48
+
+struct tas_crc {
+ unsigned char offset;
+ unsigned char len;
+};
+
+struct blktyp_devidx_map {
+ unsigned char blktyp;
+ unsigned char dev_idx;
+};
+
+/* fixed m68k compiling issue: mapping table can save code field */
+static const struct blktyp_devidx_map ppc3_tas2781_mapping_table[] = {
+ { MAIN_ALL_DEVICES_1X, 0x80 },
+ { MAIN_DEVICE_A_1X, 0x81 },
+ { COEFF_DEVICE_A_1X, 0x81 },
+ { PRE_DEVICE_A_1X, 0x81 },
+ { PRE_SOFTWARE_RESET_DEVICE_A, 0xC1 },
+ { POST_SOFTWARE_RESET_DEVICE_A, 0xC1 },
+ { MAIN_DEVICE_B_1X, 0x82 },
+ { COEFF_DEVICE_B_1X, 0x82 },
+ { PRE_DEVICE_B_1X, 0x82 },
+ { PRE_SOFTWARE_RESET_DEVICE_B, 0xC2 },
+ { POST_SOFTWARE_RESET_DEVICE_B, 0xC2 },
+ { MAIN_DEVICE_C_1X, 0x83 },
+ { COEFF_DEVICE_C_1X, 0x83 },
+ { PRE_DEVICE_C_1X, 0x83 },
+ { PRE_SOFTWARE_RESET_DEVICE_C, 0xC3 },
+ { POST_SOFTWARE_RESET_DEVICE_C, 0xC3 },
+ { MAIN_DEVICE_D_1X, 0x84 },
+ { COEFF_DEVICE_D_1X, 0x84 },
+ { PRE_DEVICE_D_1X, 0x84 },
+ { PRE_SOFTWARE_RESET_DEVICE_D, 0xC4 },
+ { POST_SOFTWARE_RESET_DEVICE_D, 0xC4 },
+};
+
+static const struct blktyp_devidx_map ppc3_mapping_table[] = {
+ { MAIN_ALL_DEVICES_1X, 0x80 },
+ { MAIN_DEVICE_A_1X, 0x81 },
+ { COEFF_DEVICE_A_1X, 0xC1 },
+ { PRE_DEVICE_A_1X, 0xC1 },
+ { MAIN_DEVICE_B_1X, 0x82 },
+ { COEFF_DEVICE_B_1X, 0xC2 },
+ { PRE_DEVICE_B_1X, 0xC2 },
+ { MAIN_DEVICE_C_1X, 0x83 },
+ { COEFF_DEVICE_C_1X, 0xC3 },
+ { PRE_DEVICE_C_1X, 0xC3 },
+ { MAIN_DEVICE_D_1X, 0x84 },
+ { COEFF_DEVICE_D_1X, 0xC4 },
+ { PRE_DEVICE_D_1X, 0xC4 },
+};
+
+static const struct blktyp_devidx_map non_ppc3_mapping_table[] = {
+ { MAIN_ALL_DEVICES, 0x80 },
+ { MAIN_DEVICE_A, 0x81 },
+ { COEFF_DEVICE_A, 0xC1 },
+ { PRE_DEVICE_A, 0xC1 },
+ { MAIN_DEVICE_B, 0x82 },
+ { COEFF_DEVICE_B, 0xC2 },
+ { PRE_DEVICE_B, 0xC2 },
+ { MAIN_DEVICE_C, 0x83 },
+ { COEFF_DEVICE_C, 0xC3 },
+ { PRE_DEVICE_C, 0xC3 },
+ { MAIN_DEVICE_D, 0x84 },
+ { COEFF_DEVICE_D, 0xC4 },
+ { PRE_DEVICE_D, 0xC4 },
+};
+
+/*
+ * Device support different configurations for different scene,
+ * like voice, music, calibration, was write in regbin file.
+ * Will be stored into tas_priv after regbin was loaded.
+ */
+static struct tasdevice_config_info *tasdevice_add_config(
+ struct tasdevice_priv *tas_priv, unsigned char *config_data,
+ unsigned int config_size, int *status)
+{
+ struct tasdevice_config_info *cfg_info;
+ struct tasdev_blk_data **bk_da;
+ unsigned int config_offset = 0;
+ unsigned int i;
+
+ /*
+ * In most projects are many audio cases, such as music, handfree,
+ * receiver, games, audio-to-haptics, PMIC record, bypass mode,
+ * portrait, landscape, etc. Even in multiple audios, one or
+ * two of the chips will work for the special case, such as
+ * ultrasonic application. In order to support these variable-numbers
+ * of audio cases, flexible configs have been introduced in the
+ * DSP firmware.
+ */
+ cfg_info = kzalloc(sizeof(*cfg_info), GFP_KERNEL);
+ if (!cfg_info) {
+ *status = -ENOMEM;
+ return NULL;
+ }
+
+ if (tas_priv->rcabin.fw_hdr.binary_version_num >= 0x105) {
+ if ((config_offset + 64) > config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev, "add conf: Out of boundary\n");
+ goto config_err;
+ }
+ config_offset += 64;
+ }
+
+ if ((config_offset + 4) > config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev, "add config: Out of boundary\n");
+ goto config_err;
+ }
+
+ /*
+ * convert data[offset], data[offset + 1], data[offset + 2] and
+ * data[offset + 3] into host
+ */
+ cfg_info->nblocks = get_unaligned_be32(&config_data[config_offset]);
+ config_offset += 4;
+
+ /*
+ * Several kinds of dsp/algorithm firmwares can run on tas2781,
+ * the number and size of blk are not fixed and different among
+ * these firmwares.
+ */
+ bk_da = cfg_info->blk_data = kcalloc(cfg_info->nblocks,
+ sizeof(*bk_da), GFP_KERNEL);
+ if (!bk_da) {
+ *status = -ENOMEM;
+ goto config_err;
+ }
+ cfg_info->real_nblocks = 0;
+ for (i = 0; i < cfg_info->nblocks; i++) {
+ if (config_offset + 12 > config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev,
+ "%s: Out of boundary: i = %d nblocks = %u!\n",
+ __func__, i, cfg_info->nblocks);
+ goto block_err;
+ }
+ bk_da[i] = kzalloc(sizeof(*bk_da[i]), GFP_KERNEL);
+ if (!bk_da[i]) {
+ *status = -ENOMEM;
+ goto block_err;
+ }
+
+ bk_da[i]->dev_idx = config_data[config_offset];
+ config_offset++;
+
+ bk_da[i]->block_type = config_data[config_offset];
+ config_offset++;
+
+ bk_da[i]->yram_checksum =
+ get_unaligned_be16(&config_data[config_offset]);
+ config_offset += 2;
+ bk_da[i]->block_size =
+ get_unaligned_be32(&config_data[config_offset]);
+ config_offset += 4;
+
+ bk_da[i]->n_subblks =
+ get_unaligned_be32(&config_data[config_offset]);
+
+ config_offset += 4;
+
+ if (config_offset + bk_da[i]->block_size > config_size) {
+ *status = -EINVAL;
+ dev_err(tas_priv->dev,
+ "%s: Out of boundary: i = %d blks = %u!\n",
+ __func__, i, cfg_info->nblocks);
+ goto block_err;
+ }
+ /* instead of kzalloc+memcpy */
+ bk_da[i]->regdata = kmemdup(&config_data[config_offset],
+ bk_da[i]->block_size, GFP_KERNEL);
+ if (!bk_da[i]->regdata) {
+ *status = -ENOMEM;
+ i++;
+ goto block_err;
+ }
+
+ config_offset += bk_da[i]->block_size;
+ cfg_info->real_nblocks += 1;
+ }
+
+ return cfg_info;
+block_err:
+ for (int j = 0; j < i; j++)
+ kfree(bk_da[j]);
+ kfree(bk_da);
+config_err:
+ kfree(cfg_info);
+ return NULL;
+}
+
+/* Regbin file parser function. */
+int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tasdevice_config_info **cfg_info;
+ struct tasdevice_rca_hdr *fw_hdr;
+ struct tasdevice_rca *rca;
+ unsigned int total_config_sz = 0;
+ int offset = 0, ret = 0, i;
+ unsigned char *buf;
+
+ rca = &tas_priv->rcabin;
+ fw_hdr = &rca->fw_hdr;
+ if (!fmw || !fmw->data) {
+ dev_err(tas_priv->dev, "Failed to read %s\n",
+ tas_priv->rca_binaryname);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return -EINVAL;
+ }
+ buf = (unsigned char *)fmw->data;
+ fw_hdr->img_sz = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ if (fw_hdr->img_sz != fmw->size) {
+ dev_err(tas_priv->dev,
+ "File size not match, %d %u", (int)fmw->size,
+ fw_hdr->img_sz);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return -EINVAL;
+ }
+
+ fw_hdr->checksum = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ fw_hdr->binary_version_num = get_unaligned_be32(&buf[offset]);
+ if (fw_hdr->binary_version_num < 0x103) {
+ dev_err(tas_priv->dev, "File version 0x%04x is too low",
+ fw_hdr->binary_version_num);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return -EINVAL;
+ }
+ offset += 4;
+ fw_hdr->drv_fw_version = get_unaligned_be32(&buf[offset]);
+ offset += 8;
+ fw_hdr->plat_type = buf[offset++];
+ fw_hdr->dev_family = buf[offset++];
+ fw_hdr->reserve = buf[offset++];
+ fw_hdr->ndev = buf[offset++];
+ if (offset + TASDEVICE_DEVICE_SUM > fw_hdr->img_sz) {
+ dev_err(tas_priv->dev, "rca_ready: Out of boundary!\n");
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TASDEVICE_DEVICE_SUM; i++, offset++)
+ fw_hdr->devs[i] = buf[offset];
+
+ fw_hdr->nconfig = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+
+ for (i = 0; i < TASDEVICE_CONFIG_SUM; i++) {
+ fw_hdr->config_size[i] = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ total_config_sz += fw_hdr->config_size[i];
+ }
+
+ if (fw_hdr->img_sz - total_config_sz != (unsigned int)offset) {
+ dev_err(tas_priv->dev, "Bin file err %d - %d != %d!\n",
+ fw_hdr->img_sz, total_config_sz, (int)offset);
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return -EINVAL;
+ }
+
+ cfg_info = kcalloc(fw_hdr->nconfig, sizeof(*cfg_info), GFP_KERNEL);
+ if (!cfg_info) {
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return -ENOMEM;
+ }
+ rca->cfg_info = cfg_info;
+ rca->ncfgs = 0;
+ for (i = 0; i < (int)fw_hdr->nconfig; i++) {
+ rca->ncfgs += 1;
+ cfg_info[i] = tasdevice_add_config(tas_priv, &buf[offset],
+ fw_hdr->config_size[i], &ret);
+ if (ret) {
+ tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+ return ret;
+ }
+ offset += (int)fw_hdr->config_size[i];
+ }
+
+ return ret;
+}
+
+/* fixed m68k compiling issue: mapping table can save code field */
+static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw,
+ struct tasdev_blk *block)
+{
+ struct blktyp_devidx_map *p =
+ (struct blktyp_devidx_map *)non_ppc3_mapping_table;
+ struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr;
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &fw_hdr->fixed_hdr;
+ int i, n = ARRAY_SIZE(non_ppc3_mapping_table);
+ unsigned char dev_idx = 0;
+
+ if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) {
+ p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table;
+ n = ARRAY_SIZE(ppc3_tas2781_mapping_table);
+ } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) {
+ p = (struct blktyp_devidx_map *)ppc3_mapping_table;
+ n = ARRAY_SIZE(ppc3_mapping_table);
+ }
+
+ for (i = 0; i < n; i++) {
+ if (block->type == p[i].blktyp) {
+ dev_idx = p[i].dev_idx;
+ break;
+ }
+ }
+
+ return dev_idx;
+}
+
+/* Block parser function. */
+static int fw_parse_block_data_kernel(struct tasdevice_fw *tas_fmw,
+ struct tasdev_blk *block, const struct firmware *fmw, int offset)
+{
+ const unsigned char *data = fmw->data;
+
+ if (offset + 16 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Convert data[offset], data[offset + 1], data[offset + 2] and
+ * data[offset + 3] into host.
+ */
+ block->type = get_unaligned_be32(&data[offset]);
+ offset += 4;
+
+ block->is_pchksum_present = data[offset++];
+ block->pchksum = data[offset++];
+ block->is_ychksum_present = data[offset++];
+ block->ychksum = data[offset++];
+ block->blk_size = get_unaligned_be32(&data[offset]);
+ offset += 4;
+ block->nr_subblocks = get_unaligned_be32(&data[offset]);
+ offset += 4;
+
+ /*
+ * Fixed m68k compiling issue:
+ * 1. mapping table can save code field.
+ * 2. storing the dev_idx as a member of block can reduce unnecessary
+ * time and system resource comsumption of dev_idx mapping every
+ * time the block data writing to the dsp.
+ */
+ block->dev_idx = map_dev_idx(tas_fmw, block);
+
+ if (offset + block->blk_size > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: nSublocks error\n", __func__);
+ return -EINVAL;
+ }
+ /* instead of kzalloc+memcpy */
+ block->data = kmemdup(&data[offset], block->blk_size, GFP_KERNEL);
+ if (!block->data)
+ return -ENOMEM;
+
+ offset += block->blk_size;
+
+ return offset;
+}
+
+/* Data of block parser function. */
+static int fw_parse_data_kernel(struct tasdevice_fw *tas_fmw,
+ struct tasdevice_data *img_data, const struct firmware *fmw,
+ int offset)
+{
+ const unsigned char *data = fmw->data;
+ struct tasdev_blk *blk;
+ unsigned int i;
+
+ if (offset + 4 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+ img_data->nr_blk = get_unaligned_be32(&data[offset]);
+ offset += 4;
+
+ img_data->dev_blks = kcalloc(img_data->nr_blk,
+ sizeof(struct tasdev_blk), GFP_KERNEL);
+ if (!img_data->dev_blks)
+ return -ENOMEM;
+
+ for (i = 0; i < img_data->nr_blk; i++) {
+ blk = &img_data->dev_blks[i];
+ offset = fw_parse_block_data_kernel(
+ tas_fmw, blk, fmw, offset);
+ if (offset < 0) {
+ kfree(img_data->dev_blks);
+ return -EINVAL;
+ }
+ }
+
+ return offset;
+}
+
+/* Data of DSP program parser function. */
+static int fw_parse_program_data_kernel(
+ struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
+ const struct firmware *fmw, int offset)
+{
+ struct tasdevice_prog *program;
+ unsigned int i;
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ program = &tas_fmw->programs[i];
+ if (offset + 72 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+ return -EINVAL;
+ }
+ /* skip 72 unused byts */
+ offset += 72;
+
+ offset = fw_parse_data_kernel(tas_fmw, &program->dev_data,
+ fmw, offset);
+ if (offset < 0)
+ break;
+ }
+
+ return offset;
+}
+
+/* Data of DSP configurations parser function. */
+static int fw_parse_configuration_data_kernel(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ const unsigned char *data = fmw->data;
+ struct tasdevice_config *config;
+ unsigned int i;
+
+ for (i = 0; i < tas_fmw->nr_configurations; i++) {
+ config = &tas_fmw->configs[i];
+ if (offset + 80 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+ return -EINVAL;
+ }
+ memcpy(config->name, &data[offset], 64);
+ /* skip extra 16 bytes */
+ offset += 80;
+
+ offset = fw_parse_data_kernel(tas_fmw, &config->dev_data,
+ fmw, offset);
+ if (offset < 0)
+ break;
+ }
+
+ return offset;
+}
+
+/* DSP firmware file header parser function for early PPC3 firmware binary. */
+static int fw_parse_variable_header_kernel(struct tasdevice_priv *tas_priv,
+ const struct firmware *fmw, int offset)
+{
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr;
+ struct tasdevice_config *config;
+ struct tasdevice_prog *program;
+ const unsigned char *buf = fmw->data;
+ unsigned short max_confs;
+ unsigned int i;
+
+ if (offset + 12 + 4 * TASDEVICE_MAXPROGRAM_NUM_KERNEL > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+ fw_hdr->device_family = get_unaligned_be16(&buf[offset]);
+ if (fw_hdr->device_family != 0) {
+ dev_err(tas_priv->dev, "%s:not TAS device\n", __func__);
+ return -EINVAL;
+ }
+ offset += 2;
+ fw_hdr->device = get_unaligned_be16(&buf[offset]);
+ if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
+ fw_hdr->device == 6) {
+ dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
+ return -EINVAL;
+ }
+ offset += 2;
+
+ tas_fmw->nr_programs = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+
+ if (tas_fmw->nr_programs == 0 ||
+ tas_fmw->nr_programs > TASDEVICE_MAXPROGRAM_NUM_KERNEL) {
+ dev_err(tas_priv->dev, "mnPrograms is invalid\n");
+ return -EINVAL;
+ }
+
+ tas_fmw->programs = kcalloc(tas_fmw->nr_programs,
+ sizeof(*tas_fmw->programs), GFP_KERNEL);
+ if (!tas_fmw->programs)
+ return -ENOMEM;
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ program = &tas_fmw->programs[i];
+ program->prog_size = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ }
+
+ /* Skip the unused prog_size */
+ offset += 4 * (TASDEVICE_MAXPROGRAM_NUM_KERNEL - tas_fmw->nr_programs);
+
+ tas_fmw->nr_configurations = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+
+ /*
+ * The max number of config in firmware greater than 4 pieces of
+ * tas2781s is different from the one lower than 4 pieces of
+ * tas2781s.
+ */
+ max_confs = TASDEVICE_MAXCONFIG_NUM_KERNEL;
+ if (tas_fmw->nr_configurations == 0 ||
+ tas_fmw->nr_configurations > max_confs) {
+ dev_err(tas_priv->dev, "%s: Conf is invalid\n", __func__);
+ kfree(tas_fmw->programs);
+ return -EINVAL;
+ }
+
+ if (offset + 4 * max_confs > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpConfigurations err\n", __func__);
+ kfree(tas_fmw->programs);
+ return -EINVAL;
+ }
+
+ tas_fmw->configs = kcalloc(tas_fmw->nr_configurations,
+ sizeof(*tas_fmw->configs), GFP_KERNEL);
+ if (!tas_fmw->configs) {
+ kfree(tas_fmw->programs);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ config = &tas_fmw->configs[i];
+ config->cfg_size = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ }
+
+ /* Skip the unused configs */
+ offset += 4 * (max_confs - tas_fmw->nr_programs);
+
+ return offset;
+}
+
+/*
+ * In sub-block data, have three type sub-block:
+ * 1. Single byte write.
+ * 2. Multi-byte write.
+ * 3. Delay.
+ * 4. Bits update.
+ * This function perform single byte write to device.
+ */
+static int tasdevice_single_byte_wr(void *context, int dev_idx,
+ unsigned char *data, int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = context;
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int i, subblk_offset, rc;
+
+ subblk_offset = 4;
+ if (subblk_offset + 4 * len > sublocksize) {
+ dev_err(tas_priv->dev, "process_block: Out of boundary\n");
+ return 0;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) {
+ rc = tasdevice_spi_dev_write(tas_priv,
+ TASDEVICE_REG(data[subblk_offset],
+ data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ data[subblk_offset + 3]);
+ if (rc < 0) {
+ dev_err(tas_priv->dev,
+ "process_block: single write error\n");
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+ }
+ subblk_offset += 4;
+ }
+
+ return subblk_offset;
+}
+
+/*
+ * In sub-block data, have three type sub-block:
+ * 1. Single byte write.
+ * 2. Multi-byte write.
+ * 3. Delay.
+ * 4. Bits update.
+ * This function perform multi-write to device.
+ */
+static int tasdevice_burst_wr(void *context, int dev_idx, unsigned char *data,
+ int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = context;
+ unsigned short len = get_unaligned_be16(&data[2]);
+ int subblk_offset, rc;
+
+ subblk_offset = 4;
+ if (subblk_offset + 4 + len > sublocksize) {
+ dev_err(tas_priv->dev, "%s: BST Out of boundary\n", __func__);
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+ if (len % 4) {
+ dev_err(tas_priv->dev, "%s:Bst-len(%u)not div by 4\n",
+ __func__, len);
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+
+ if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) {
+ rc = tasdevice_spi_dev_bulk_write(tas_priv,
+ TASDEVICE_REG(data[subblk_offset],
+ data[subblk_offset + 1],
+ data[subblk_offset + 2]),
+ &data[subblk_offset + 4], len);
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: bulk_write error = %d\n",
+ __func__, rc);
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+ }
+ subblk_offset += (len + 4);
+
+ return subblk_offset;
+}
+
+/* Just delay for ms.*/
+static int tasdevice_delay(void *context, int dev_idx, unsigned char *data,
+ int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = context;
+ unsigned int sleep_time, subblk_offset = 2;
+
+ if (subblk_offset + 2 > sublocksize) {
+ dev_err(tas_priv->dev, "%s: delay Out of boundary\n",
+ __func__);
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+ if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) {
+ sleep_time = get_unaligned_be16(&data[2]) * 1000;
+ fsleep(sleep_time);
+ }
+ subblk_offset += 2;
+
+ return subblk_offset;
+}
+
+/*
+ * In sub-block data, have three type sub-block:
+ * 1. Single byte write.
+ * 2. Multi-byte write.
+ * 3. Delay.
+ * 4. Bits update.
+ * This function perform bits update.
+ */
+static int tasdevice_field_wr(void *context, int dev_idx, unsigned char *data,
+ int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = context;
+ int rc, subblk_offset = 2;
+
+ if (subblk_offset + 6 > sublocksize) {
+ dev_err(tas_priv->dev, "%s: bit write Out of boundary\n",
+ __func__);
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+ if (dev_idx == (tas_priv->index + 1) || dev_idx == 0) {
+ rc = tasdevice_spi_dev_update_bits(tas_priv,
+ TASDEVICE_REG(data[subblk_offset + 2],
+ data[subblk_offset + 3],
+ data[subblk_offset + 4]),
+ data[subblk_offset + 1],
+ data[subblk_offset + 5]);
+ if (rc < 0) {
+ dev_err(tas_priv->dev, "%s: update_bits error = %d\n",
+ __func__, rc);
+ subblk_offset |= OFFSET_ERROR_BIT;
+ }
+ }
+ subblk_offset += 6;
+
+ return subblk_offset;
+}
+
+/* Data block process function. */
+static int tasdevice_process_block(void *context, unsigned char *data,
+ unsigned char dev_idx, int sublocksize)
+{
+ struct tasdevice_priv *tas_priv = context;
+ int blktyp = dev_idx & 0xC0, subblk_offset;
+ unsigned char subblk_typ = data[1];
+
+ switch (subblk_typ) {
+ case TASDEVICE_CMD_SING_W:
+ subblk_offset = tasdevice_single_byte_wr(tas_priv,
+ dev_idx & 0x3f, data, sublocksize);
+ break;
+ case TASDEVICE_CMD_BURST:
+ subblk_offset = tasdevice_burst_wr(tas_priv,
+ dev_idx & 0x3f, data, sublocksize);
+ break;
+ case TASDEVICE_CMD_DELAY:
+ subblk_offset = tasdevice_delay(tas_priv,
+ dev_idx & 0x3f, data, sublocksize);
+ break;
+ case TASDEVICE_CMD_FIELD_W:
+ subblk_offset = tasdevice_field_wr(tas_priv,
+ dev_idx & 0x3f, data, sublocksize);
+ break;
+ default:
+ subblk_offset = 2;
+ break;
+ }
+ if (((subblk_offset & OFFSET_ERROR_BIT) != 0) && blktyp != 0) {
+ if (blktyp == 0x80) {
+ tas_priv->cur_prog = -1;
+ tas_priv->cur_conf = -1;
+ } else
+ tas_priv->cur_conf = -1;
+ }
+ subblk_offset &= ~OFFSET_ERROR_BIT;
+
+ return subblk_offset;
+}
+
+/*
+ * Device support different configurations for different scene,
+ * this function was used for choose different config.
+ */
+void tasdevice_spi_select_cfg_blk(void *pContext, int conf_no,
+ unsigned char block_type)
+{
+ struct tasdevice_priv *tas_priv = pContext;
+ struct tasdevice_rca *rca = &tas_priv->rcabin;
+ struct tasdevice_config_info **cfg_info = rca->cfg_info;
+ struct tasdev_blk_data **blk_data;
+ unsigned int j, k;
+
+ if (conf_no >= rca->ncfgs || conf_no < 0 || !cfg_info) {
+ dev_err(tas_priv->dev, "conf_no should be not more than %u\n",
+ rca->ncfgs);
+ return;
+ }
+ blk_data = cfg_info[conf_no]->blk_data;
+
+ for (j = 0; j < cfg_info[conf_no]->real_nblocks; j++) {
+ unsigned int length = 0, rc = 0;
+
+ if (block_type > 5 || block_type < 2) {
+ dev_err(tas_priv->dev,
+ "block_type should be in range from 2 to 5\n");
+ break;
+ }
+ if (block_type != blk_data[j]->block_type)
+ continue;
+
+ for (k = 0; k < blk_data[j]->n_subblks; k++) {
+ tas_priv->is_loading = true;
+
+ rc = tasdevice_process_block(tas_priv,
+ blk_data[j]->regdata + length,
+ blk_data[j]->dev_idx,
+ blk_data[j]->block_size - length);
+ length += rc;
+ if (blk_data[j]->block_size < length) {
+ dev_err(tas_priv->dev,
+ "%s: %u %u out of boundary\n",
+ __func__, length,
+ blk_data[j]->block_size);
+ break;
+ }
+ }
+ if (length != blk_data[j]->block_size)
+ dev_err(tas_priv->dev, "%s: %u %u size is not same\n",
+ __func__, length, blk_data[j]->block_size);
+ }
+}
+
+/* Block process function. */
+static int tasdevice_load_block_kernel(
+ struct tasdevice_priv *tasdevice, struct tasdev_blk *block)
+{
+ const unsigned int blk_size = block->blk_size;
+ unsigned char *data = block->data;
+ unsigned int i, length;
+
+ for (i = 0, length = 0; i < block->nr_subblocks; i++) {
+ int rc = tasdevice_process_block(tasdevice, data + length,
+ block->dev_idx, blk_size - length);
+ if (rc < 0) {
+ dev_err(tasdevice->dev,
+ "%s: %u %u sublock write error\n",
+ __func__, length, blk_size);
+ return rc;
+ }
+ length += rc;
+ if (blk_size < length) {
+ dev_err(tasdevice->dev, "%s: %u %u out of boundary\n",
+ __func__, length, blk_size);
+ rc = -ENOMEM;
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+/* DSP firmware file header parser function. */
+static int fw_parse_variable_hdr(struct tasdevice_priv *tas_priv,
+ struct tasdevice_dspfw_hdr *fw_hdr,
+ const struct firmware *fmw, int offset)
+{
+ const unsigned char *buf = fmw->data;
+ int len = strlen((char *)&buf[offset]);
+
+ len++;
+
+ if (offset + len + 8 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+
+ offset += len;
+
+ fw_hdr->device_family = get_unaligned_be32(&buf[offset]);
+ if (fw_hdr->device_family != 0) {
+ dev_err(tas_priv->dev, "%s: not TAS device\n", __func__);
+ return -EINVAL;
+ }
+ offset += 4;
+
+ fw_hdr->device = get_unaligned_be32(&buf[offset]);
+ if (fw_hdr->device >= TASDEVICE_DSP_TAS_MAX_DEVICE ||
+ fw_hdr->device == 6) {
+ dev_err(tas_priv->dev, "Unsupported dev %d\n", fw_hdr->device);
+ return -EINVAL;
+ }
+ offset += 4;
+ fw_hdr->ndev = 1;
+
+ return offset;
+}
+
+/* DSP firmware file header parser function for size variabled header. */
+static int fw_parse_variable_header_git(struct tasdevice_priv
+ *tas_priv, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr;
+
+ offset = fw_parse_variable_hdr(tas_priv, fw_hdr, fmw, offset);
+
+ return offset;
+}
+
+/* DSP firmware file block parser function. */
+static int fw_parse_block_data(struct tasdevice_fw *tas_fmw,
+ struct tasdev_blk *block, const struct firmware *fmw, int offset)
+{
+ unsigned char *data = (unsigned char *)fmw->data;
+ int n;
+
+ if (offset + 8 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Type error\n", __func__);
+ return -EINVAL;
+ }
+ block->type = get_unaligned_be32(&data[offset]);
+ offset += 4;
+
+ if (tas_fmw->fw_hdr.fixed_hdr.drv_ver >= PPC_DRIVER_CRCCHK) {
+ if (offset + 8 > fmw->size) {
+ dev_err(tas_fmw->dev, "PChkSumPresent error\n");
+ return -EINVAL;
+ }
+ block->is_pchksum_present = data[offset];
+ offset++;
+
+ block->pchksum = data[offset];
+ offset++;
+
+ block->is_ychksum_present = data[offset];
+ offset++;
+
+ block->ychksum = data[offset];
+ offset++;
+ } else {
+ block->is_pchksum_present = 0;
+ block->is_ychksum_present = 0;
+ }
+
+ block->nr_cmds = get_unaligned_be32(&data[offset]);
+ offset += 4;
+
+ n = block->nr_cmds * 4;
+ if (offset + n > fmw->size) {
+ dev_err(tas_fmw->dev,
+ "%s: File Size(%lu) error offset = %d n = %d\n",
+ __func__, (unsigned long)fmw->size, offset, n);
+ return -EINVAL;
+ }
+ /* instead of kzalloc+memcpy */
+ block->data = kmemdup(&data[offset], n, GFP_KERNEL);
+ if (!block->data)
+ return -ENOMEM;
+
+ offset += n;
+
+ return offset;
+}
+
+/*
+ * When parsing error occurs, all the memory resource will be released
+ * in the end of tasdevice_rca_ready.
+ */
+static int fw_parse_data(struct tasdevice_fw *tas_fmw,
+ struct tasdevice_data *img_data, const struct firmware *fmw,
+ int offset)
+{
+ const unsigned char *data = (unsigned char *)fmw->data;
+ struct tasdev_blk *blk;
+ unsigned int i, n;
+
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Name error\n", __func__);
+ return -EINVAL;
+ }
+ memcpy(img_data->name, &data[offset], 64);
+ offset += 64;
+
+ n = strlen((char *)&data[offset]);
+ n++;
+ if (offset + n + 2 > fmw->size) {
+ dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
+ return -EINVAL;
+ }
+ offset += n;
+ img_data->nr_blk = get_unaligned_be16(&data[offset]);
+ offset += 2;
+
+ img_data->dev_blks = kcalloc(img_data->nr_blk,
+ sizeof(*img_data->dev_blks), GFP_KERNEL);
+ if (!img_data->dev_blks)
+ return -ENOMEM;
+
+ for (i = 0; i < img_data->nr_blk; i++) {
+ blk = &img_data->dev_blks[i];
+ offset = fw_parse_block_data(tas_fmw, blk, fmw, offset);
+ if (offset < 0)
+ return -EINVAL;
+ }
+
+ return offset;
+}
+
+/*
+ * When parsing error occurs, all the memory resource will be released
+ * in the end of tasdevice_rca_ready.
+ */
+static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ unsigned char *buf = (unsigned char *)fmw->data;
+ struct tasdevice_prog *program;
+ int i;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+ tas_fmw->nr_programs = get_unaligned_be16(&buf[offset]);
+ offset += 2;
+
+ if (tas_fmw->nr_programs == 0) {
+ /* Not error in calibration Data file, return directly */
+ dev_dbg(tas_priv->dev, "%s: No Programs data, maybe calbin\n",
+ __func__);
+ return offset;
+ }
+
+ tas_fmw->programs =
+ kcalloc(tas_fmw->nr_programs, sizeof(*tas_fmw->programs),
+ GFP_KERNEL);
+ if (!tas_fmw->programs)
+ return -ENOMEM;
+
+ for (i = 0; i < tas_fmw->nr_programs; i++) {
+ int n = 0;
+
+ program = &tas_fmw->programs[i];
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+ return -EINVAL;
+ }
+ offset += 64;
+
+ n = strlen((char *)&buf[offset]);
+ /* skip '\0' and 5 unused bytes */
+ n += 6;
+ if (offset + n > fmw->size) {
+ dev_err(tas_priv->dev, "Description err\n");
+ return -EINVAL;
+ }
+
+ offset += n;
+
+ offset = fw_parse_data(tas_fmw, &program->dev_data, fmw,
+ offset);
+ if (offset < 0)
+ return offset;
+ }
+
+ return offset;
+}
+
+/*
+ * When parsing error occurs, all the memory resource will be released
+ * in the end of tasdevice_rca_ready.
+ */
+static int fw_parse_configuration_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ unsigned char *data = (unsigned char *)fmw->data;
+ struct tasdevice_config *config;
+ unsigned int i, n;
+
+ if (offset + 2 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+ tas_fmw->nr_configurations = get_unaligned_be16(&data[offset]);
+ offset += 2;
+
+ if (tas_fmw->nr_configurations == 0) {
+ dev_err(tas_priv->dev, "%s: Conf is zero\n", __func__);
+ /* Not error for calibration Data file, return directly */
+ return offset;
+ }
+ tas_fmw->configs = kcalloc(tas_fmw->nr_configurations,
+ sizeof(*tas_fmw->configs), GFP_KERNEL);
+ if (!tas_fmw->configs)
+ return -ENOMEM;
+ for (i = 0; i < tas_fmw->nr_configurations; i++) {
+ config = &tas_fmw->configs[i];
+ if (offset + 64 > fmw->size) {
+ dev_err(tas_priv->dev, "File Size err\n");
+ return -EINVAL;
+ }
+ memcpy(config->name, &data[offset], 64);
+ offset += 64;
+
+ n = strlen((char *)&data[offset]);
+ n += 15;
+ if (offset + n > fmw->size) {
+ dev_err(tas_priv->dev, "Description err\n");
+ return -EINVAL;
+ }
+ offset += n;
+ offset = fw_parse_data(tas_fmw, &config->dev_data,
+ fmw, offset);
+ if (offset < 0)
+ break;
+ }
+
+ return offset;
+}
+
+/* yram5 page check. */
+static bool check_inpage_yram_rg(struct tas_crc *cd,
+ unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (reg <= TAS2781_YRAM5_END_REG &&
+ reg >= TAS2781_YRAM5_START_REG) {
+ if (reg + len > TAS2781_YRAM5_END_REG)
+ cd->len = TAS2781_YRAM5_END_REG - reg + 1;
+ else
+ cd->len = len;
+ cd->offset = reg;
+ in = true;
+ } else if (reg < TAS2781_YRAM5_START_REG) {
+ if (reg + len > TAS2781_YRAM5_START_REG) {
+ cd->offset = TAS2781_YRAM5_START_REG;
+ cd->len = len - TAS2781_YRAM5_START_REG + reg;
+ in = true;
+ }
+ }
+
+ return in;
+}
+
+/* DSP firmware yram block check. */
+static bool check_inpage_yram_bk1(struct tas_crc *cd,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (page == TAS2781_YRAM1_PAGE) {
+ if (reg >= TAS2781_YRAM1_START_REG) {
+ cd->offset = reg;
+ cd->len = len;
+ in = true;
+ } else if (reg + len > TAS2781_YRAM1_START_REG) {
+ cd->offset = TAS2781_YRAM1_START_REG;
+ cd->len = len - TAS2781_YRAM1_START_REG + reg;
+ in = true;
+ }
+ } else if (page == TAS2781_YRAM3_PAGE) {
+ in = check_inpage_yram_rg(cd, reg, len);
+ }
+
+ return in;
+}
+
+/*
+ * Return Code:
+ * true -- the registers are in the inpage yram
+ * false -- the registers are NOT in the inpage yram
+ */
+static bool check_inpage_yram(struct tas_crc *cd, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (book == TAS2781_YRAM_BOOK1)
+ in = check_inpage_yram_bk1(cd, page, reg, len);
+ else if (book == TAS2781_YRAM_BOOK2 && page == TAS2781_YRAM5_PAGE)
+ in = check_inpage_yram_rg(cd, reg, len);
+
+ return in;
+}
+
+/* yram4 page check. */
+static bool check_inblock_yram_bk(struct tas_crc *cd,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if ((page >= TAS2781_YRAM4_START_PAGE &&
+ page <= TAS2781_YRAM4_END_PAGE) ||
+ (page >= TAS2781_YRAM2_START_PAGE &&
+ page <= TAS2781_YRAM2_END_PAGE)) {
+ if (reg <= TAS2781_YRAM2_END_REG &&
+ reg >= TAS2781_YRAM2_START_REG) {
+ cd->offset = reg;
+ cd->len = len;
+ in = true;
+ } else if (reg < TAS2781_YRAM2_START_REG) {
+ if (reg + len - 1 >= TAS2781_YRAM2_START_REG) {
+ cd->offset = TAS2781_YRAM2_START_REG;
+ cd->len = reg + len - TAS2781_YRAM2_START_REG;
+ in = true;
+ }
+ }
+ }
+
+ return in;
+}
+
+/*
+ * Return Code:
+ * true -- the registers are in the inblock yram
+ * false -- the registers are NOT in the inblock yram
+ */
+static bool check_inblock_yram(struct tas_crc *cd, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in = false;
+
+ if (book == TAS2781_YRAM_BOOK1 || book == TAS2781_YRAM_BOOK2)
+ in = check_inblock_yram_bk(cd, page, reg, len);
+
+ return in;
+}
+
+/* yram page check. */
+static bool check_yram(struct tas_crc *cd, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char len)
+{
+ bool in;
+
+ in = check_inpage_yram(cd, book, page, reg, len);
+ if (!in)
+ in = check_inblock_yram(cd, book, page, reg, len);
+
+ return in;
+}
+
+/* Checksum for data block. */
+static int tasdev_multibytes_chksum(struct tasdevice_priv *tasdevice,
+ unsigned char book, unsigned char page,
+ unsigned char reg, unsigned int len)
+{
+ struct tas_crc crc_data;
+ unsigned char crc_chksum = 0;
+ unsigned char nBuf1[128];
+ int ret = 0, i;
+ bool in;
+
+ if ((reg + len - 1) > 127) {
+ ret = -EINVAL;
+ dev_err(tasdevice->dev, "firmware error\n");
+ goto end;
+ }
+
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (reg == TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (len == 4)) {
+ /* DSP swap command, pass */
+ ret = 0;
+ goto end;
+ }
+
+ in = check_yram(&crc_data, book, page, reg, len);
+ if (!in)
+ goto end;
+
+ if (len == 1) {
+ dev_err(tasdevice->dev, "firmware error\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ ret = tasdevice_spi_dev_bulk_read(tasdevice,
+ TASDEVICE_REG(book, page, crc_data.offset),
+ nBuf1, crc_data.len);
+ if (ret < 0)
+ goto end;
+
+ for (i = 0; i < crc_data.len; i++) {
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ ((i + crc_data.offset) >=
+ TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ ((i + crc_data.offset) <=
+ (TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG) + 4)))
+ /* DSP swap command, bypass */
+ continue;
+ else
+ crc_chksum += crc8(tasdevice->crc8_lkp_tbl, &nBuf1[i],
+ 1, 0);
+ }
+
+ ret = crc_chksum;
+
+end:
+ return ret;
+}
+
+/* Checksum for single register. */
+static int do_singlereg_checksum(struct tasdevice_priv *tasdevice,
+ unsigned char book, unsigned char page,
+ unsigned char reg, unsigned char val)
+{
+ struct tas_crc crc_data;
+ unsigned int nData1;
+ int ret = 0;
+ bool in;
+
+ /* DSP swap command, pass */
+ if ((book == TASDEVICE_BOOK_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (page == TASDEVICE_PAGE_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (reg >= TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG)) &&
+ (reg <= (TASDEVICE_REG_ID(TAS2781_SA_COEFF_SWAP_REG) + 4)))
+ return 0;
+
+ in = check_yram(&crc_data, book, page, reg, 1);
+ if (!in)
+ return 0;
+ ret = tasdevice_spi_dev_read(tasdevice,
+ TASDEVICE_REG(book, page, reg), &nData1);
+ if (ret < 0)
+ return ret;
+
+ if (nData1 != val) {
+ dev_err(tasdevice->dev,
+ "B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n",
+ book, page, reg, val, nData1);
+ tasdevice->err_code |= ERROR_YRAM_CRCCHK;
+ return -EAGAIN;
+ }
+
+ ret = crc8(tasdevice->crc8_lkp_tbl, &val, 1, 0);
+
+ return ret;
+}
+
+/* Block type check. */
+static void set_err_prg_cfg(unsigned int type, struct tasdevice_priv *p)
+{
+ if ((type == MAIN_ALL_DEVICES) || (type == MAIN_DEVICE_A) ||
+ (type == MAIN_DEVICE_B) || (type == MAIN_DEVICE_C) ||
+ (type == MAIN_DEVICE_D))
+ p->cur_prog = -1;
+ else
+ p->cur_conf = -1;
+}
+
+/* Checksum for data bytes. */
+static int tasdev_bytes_chksum(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned int len,
+ unsigned char val, unsigned char *crc_chksum)
+{
+ int ret;
+
+ if (len > 1)
+ ret = tasdev_multibytes_chksum(tas_priv, book, page, reg,
+ len);
+ else
+ ret = do_singlereg_checksum(tas_priv, book, page, reg, val);
+
+ if (ret > 0) {
+ *crc_chksum += ret;
+ goto end;
+ }
+
+ if (ret != -EAGAIN)
+ goto end;
+
+ block->nr_retry--;
+ if (block->nr_retry > 0)
+ goto end;
+
+ set_err_prg_cfg(block->type, tas_priv);
+
+end:
+ return ret;
+}
+
+/* Multi-data byte write. */
+static int tasdev_multibytes_wr(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block, unsigned char book,
+ unsigned char page, unsigned char reg, unsigned char *data,
+ unsigned int len, unsigned int *nr_cmds,
+ unsigned char *crc_chksum)
+{
+ int ret;
+
+ if (len > 1) {
+ ret = tasdevice_spi_dev_bulk_write(tas_priv,
+ TASDEVICE_REG(book, page, reg), data + 3, len);
+ if (ret < 0)
+ return ret;
+ if (block->is_ychksum_present)
+ ret = tasdev_bytes_chksum(tas_priv, block,
+ book, page, reg, len, 0, crc_chksum);
+ } else {
+ ret = tasdevice_spi_dev_write(tas_priv,
+ TASDEVICE_REG(book, page, reg), data[3]);
+ if (ret < 0)
+ return ret;
+ if (block->is_ychksum_present)
+ ret = tasdev_bytes_chksum(tas_priv, block, book,
+ page, reg, 1, data[3], crc_chksum);
+ }
+
+ if (!block->is_ychksum_present || ret >= 0) {
+ *nr_cmds += 1;
+ if (len >= 2)
+ *nr_cmds += ((len - 2) / 4) + 1;
+ }
+
+ return ret;
+}
+
+/* Checksum for block. */
+static int tasdev_block_chksum(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block)
+{
+ unsigned int nr_value;
+ int ret;
+
+ ret = tasdevice_spi_dev_read(tas_priv, TASDEVICE_CHECKSUM, &nr_value);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "%s: read error %d.\n", __func__, ret);
+ set_err_prg_cfg(block->type, tas_priv);
+ return ret;
+ }
+
+ if ((nr_value & 0xff) != block->pchksum) {
+ dev_err(tas_priv->dev, "%s: PChkSum err %d ", __func__, ret);
+ dev_err(tas_priv->dev, "PChkSum = 0x%x, Reg = 0x%x\n",
+ block->pchksum, (nr_value & 0xff));
+ tas_priv->err_code |= ERROR_PRAM_CRCCHK;
+ ret = -EAGAIN;
+ block->nr_retry--;
+
+ if (block->nr_retry <= 0)
+ set_err_prg_cfg(block->type, tas_priv);
+ } else {
+ tas_priv->err_code &= ~ERROR_PRAM_CRCCHK;
+ }
+
+ return ret;
+}
+
+/* Firmware block load function. */
+static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block)
+{
+ unsigned int sleep_time, len, nr_cmds;
+ unsigned char offset, book, page, val;
+ unsigned char *data = block->data;
+ unsigned char crc_chksum = 0;
+ int ret = 0;
+
+ while (block->nr_retry > 0) {
+ if (block->is_pchksum_present) {
+ ret = tasdevice_spi_dev_write(tas_priv,
+ TASDEVICE_CHECKSUM, 0);
+ if (ret < 0)
+ break;
+ }
+
+ if (block->is_ychksum_present)
+ crc_chksum = 0;
+
+ nr_cmds = 0;
+
+ while (nr_cmds < block->nr_cmds) {
+ data = block->data + nr_cmds * 4;
+
+ book = data[0];
+ page = data[1];
+ offset = data[2];
+ val = data[3];
+
+ nr_cmds++;
+ /* Single byte write */
+ if (offset <= 0x7F) {
+ ret = tasdevice_spi_dev_write(tas_priv,
+ TASDEVICE_REG(book, page, offset),
+ val);
+ if (ret < 0)
+ break;
+ if (block->is_ychksum_present) {
+ ret = tasdev_bytes_chksum(tas_priv,
+ block, book, page, offset,
+ 1, val, &crc_chksum);
+ if (ret < 0)
+ break;
+ }
+ continue;
+ }
+ /* sleep command */
+ if (offset == 0x81) {
+ /* book -- data[0] page -- data[1] */
+ sleep_time = ((book << 8) + page)*1000;
+ fsleep(sleep_time);
+ continue;
+ }
+ /* Multiple bytes write */
+ if (offset == 0x85) {
+ data += 4;
+ len = (book << 8) + page;
+ book = data[0];
+ page = data[1];
+ offset = data[2];
+ ret = tasdev_multibytes_wr(tas_priv,
+ block, book, page, offset, data,
+ len, &nr_cmds, &crc_chksum);
+ if (ret < 0)
+ break;
+ }
+ }
+ if (ret == -EAGAIN) {
+ if (block->nr_retry > 0)
+ continue;
+ } else if (ret < 0) {
+ /* err in current device, skip it */
+ break;
+ }
+
+ if (block->is_pchksum_present) {
+ ret = tasdev_block_chksum(tas_priv, block);
+ if (ret == -EAGAIN) {
+ if (block->nr_retry > 0)
+ continue;
+ } else if (ret < 0) {
+ /* err in current device, skip it */
+ break;
+ }
+ }
+
+ if (block->is_ychksum_present) {
+ /* TBD, open it when FW ready */
+ dev_err(tas_priv->dev,
+ "Blk YChkSum: FW = 0x%x, YCRC = 0x%x\n",
+ block->ychksum, crc_chksum);
+
+ tas_priv->err_code &=
+ ~ERROR_YRAM_CRCCHK;
+ ret = 0;
+ }
+ /* skip current blk */
+ break;
+ }
+
+ return ret;
+}
+
+/* Firmware block load function. */
+static int tasdevice_load_block(struct tasdevice_priv *tas_priv,
+ struct tasdev_blk *block)
+{
+ int ret = 0;
+
+ block->nr_retry = 6;
+ if (tas_priv->is_loading == false)
+ return 0;
+ ret = tasdev_load_blk(tas_priv, block);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "Blk (%d) load error\n", block->type);
+
+ return ret;
+}
+
+/*
+ * Select firmware binary parser & load callback functions by ppc3 version
+ * and firmware binary version.
+ */
+static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
+ unsigned int drv_ver, unsigned int ppcver)
+{
+ int rc = 0;
+
+ if (drv_ver == 0x100) {
+ if (ppcver >= PPC3_VERSION_BASE) {
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_kernel;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data_kernel;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data_kernel;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block_kernel;
+ } else if (ppcver == 0x00) {
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_git;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block;
+ } else {
+ dev_err(tas_priv->dev,
+ "Wrong PPCVer :0x%08x\n", ppcver);
+ rc = -EINVAL;
+ }
+ } else {
+ dev_err(tas_priv->dev, "Wrong DrvVer : 0x%02x\n", drv_ver);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/* DSP firmware binary file header parser function. */
+static int fw_parse_header(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ struct tasdevice_dspfw_hdr *fw_hdr = &tas_fmw->fw_hdr;
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr = &fw_hdr->fixed_hdr;
+ static const unsigned char magic_number[] = {0x35, 0x35, 0x35, 0x32, };
+ const unsigned char *buf = (unsigned char *)fmw->data;
+
+ if (offset + 92 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ if (memcmp(&buf[offset], magic_number, 4)) {
+ dev_err(tas_priv->dev, "%s: Magic num NOT match\n", __func__);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+
+ /*
+ * Convert data[offset], data[offset + 1], data[offset + 2] and
+ * data[offset + 3] into host
+ */
+ fw_fixed_hdr->fwsize = get_unaligned_be32(&buf[offset]);
+ offset += 4;
+ if (fw_fixed_hdr->fwsize != fmw->size) {
+ dev_err(tas_priv->dev, "File size not match, %lu %u",
+ (unsigned long)fmw->size, fw_fixed_hdr->fwsize);
+ offset = -EINVAL;
+ goto out;
+ }
+ offset += 4;
+ fw_fixed_hdr->ppcver = get_unaligned_be32(&buf[offset]);
+ offset += 8;
+ fw_fixed_hdr->drv_ver = get_unaligned_be32(&buf[offset]);
+ offset += 72;
+
+out:
+ return offset;
+}
+
+/* DSP firmware binary file parser function. */
+static int tasdevice_dspfw_ready(const struct firmware *fmw, void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tasdevice_fw_fixed_hdr *fw_fixed_hdr;
+ struct tasdevice_fw *tas_fmw;
+ int offset = 0, ret = 0;
+
+ if (!fmw || !fmw->data) {
+ dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n",
+ __func__, tas_priv->coef_binaryname);
+ return -EINVAL;
+ }
+
+ tas_priv->fmw = kzalloc(sizeof(*tas_priv->fmw), GFP_KERNEL);
+ if (!tas_priv->fmw)
+ return -ENOMEM;
+ tas_fmw = tas_priv->fmw;
+ tas_fmw->dev = tas_priv->dev;
+ offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset);
+
+ if (offset == -EINVAL)
+ return -EINVAL;
+
+ fw_fixed_hdr = &tas_fmw->fw_hdr.fixed_hdr;
+ /* Support different versions of firmware */
+ switch (fw_fixed_hdr->drv_ver) {
+ case 0x301:
+ case 0x302:
+ case 0x502:
+ case 0x503:
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_kernel;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data_kernel;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data_kernel;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block_kernel;
+ break;
+ case 0x202:
+ case 0x400:
+ tas_priv->fw_parse_variable_header =
+ fw_parse_variable_header_git;
+ tas_priv->fw_parse_program_data =
+ fw_parse_program_data;
+ tas_priv->fw_parse_configuration_data =
+ fw_parse_configuration_data;
+ tas_priv->tasdevice_load_block =
+ tasdevice_load_block;
+ break;
+ default:
+ ret = dspfw_default_callback(tas_priv,
+ fw_fixed_hdr->drv_ver, fw_fixed_hdr->ppcver);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset);
+ if (offset < 0)
+ return offset;
+
+ offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw,
+ offset);
+ if (offset < 0)
+ return offset;
+
+ offset = tas_priv->fw_parse_configuration_data(tas_priv,
+ tas_fmw, fmw, offset);
+ if (offset < 0)
+ ret = offset;
+
+ return ret;
+}
+
+/* DSP firmware binary file parser function. */
+int tasdevice_spi_dsp_parser(void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+ const struct firmware *fw_entry;
+ int ret;
+
+ ret = request_firmware(&fw_entry, tas_priv->coef_binaryname,
+ tas_priv->dev);
+ if (ret) {
+ dev_err(tas_priv->dev, "%s: load %s error\n", __func__,
+ tas_priv->coef_binaryname);
+ return ret;
+ }
+
+ ret = tasdevice_dspfw_ready(fw_entry, tas_priv);
+ release_firmware(fw_entry);
+ fw_entry = NULL;
+
+ return ret;
+}
+
+/* DSP firmware program block data remove function. */
+static void tasdev_dsp_prog_blk_remove(struct tasdevice_prog *prog)
+{
+ struct tasdevice_data *tas_dt;
+ struct tasdev_blk *blk;
+ unsigned int i;
+
+ if (!prog)
+ return;
+
+ tas_dt = &prog->dev_data;
+
+ if (!tas_dt->dev_blks)
+ return;
+
+ for (i = 0; i < tas_dt->nr_blk; i++) {
+ blk = &tas_dt->dev_blks[i];
+ kfree(blk->data);
+ }
+ kfree(tas_dt->dev_blks);
+}
+
+/* DSP firmware program block data remove function. */
+static void tasdev_dsp_prog_remove(struct tasdevice_prog *prog,
+ unsigned short nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ tasdev_dsp_prog_blk_remove(&prog[i]);
+ kfree(prog);
+}
+
+/* DSP firmware config block data remove function. */
+static void tasdev_dsp_cfg_blk_remove(struct tasdevice_config *cfg)
+{
+ struct tasdevice_data *tas_dt;
+ struct tasdev_blk *blk;
+ unsigned int i;
+
+ if (cfg) {
+ tas_dt = &cfg->dev_data;
+
+ if (!tas_dt->dev_blks)
+ return;
+
+ for (i = 0; i < tas_dt->nr_blk; i++) {
+ blk = &tas_dt->dev_blks[i];
+ kfree(blk->data);
+ }
+ kfree(tas_dt->dev_blks);
+ }
+}
+
+/* DSP firmware config remove function. */
+static void tasdev_dsp_cfg_remove(struct tasdevice_config *config,
+ unsigned short nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ tasdev_dsp_cfg_blk_remove(&config[i]);
+ kfree(config);
+}
+
+/* DSP firmware remove function. */
+void tasdevice_spi_dsp_remove(void *context)
+{
+ struct tasdevice_priv *tas_dev = context;
+
+ if (!tas_dev->fmw)
+ return;
+
+ if (tas_dev->fmw->programs)
+ tasdev_dsp_prog_remove(tas_dev->fmw->programs,
+ tas_dev->fmw->nr_programs);
+ if (tas_dev->fmw->configs)
+ tasdev_dsp_cfg_remove(tas_dev->fmw->configs,
+ tas_dev->fmw->nr_configurations);
+ kfree(tas_dev->fmw);
+ tas_dev->fmw = NULL;
+}
+
+/* DSP firmware calibration data remove function. */
+static void tas2781_clear_calfirmware(struct tasdevice_fw *tas_fmw)
+{
+ struct tasdevice_calibration *calibration;
+ struct tasdev_blk *block;
+ unsigned int blks;
+ int i;
+
+ if (!tas_fmw->calibrations)
+ goto out;
+
+ for (i = 0; i < tas_fmw->nr_calibrations; i++) {
+ calibration = &tas_fmw->calibrations[i];
+ if (!calibration)
+ continue;
+
+ if (!calibration->dev_data.dev_blks)
+ continue;
+
+ for (blks = 0; blks < calibration->dev_data.nr_blk; blks++) {
+ block = &calibration->dev_data.dev_blks[blks];
+ if (!block)
+ continue;
+ kfree(block->data);
+ }
+ kfree(calibration->dev_data.dev_blks);
+ }
+ kfree(tas_fmw->calibrations);
+out:
+ kfree(tas_fmw);
+}
+
+/* Calibration data from firmware remove function. */
+void tasdevice_spi_calbin_remove(void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+
+ if (tas_priv->cali_data_fmw) {
+ tas2781_clear_calfirmware(tas_priv->cali_data_fmw);
+ tas_priv->cali_data_fmw = NULL;
+ }
+}
+
+/* Configuration remove function. */
+void tasdevice_spi_config_info_remove(void *context)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tasdevice_rca *rca = &tas_priv->rcabin;
+ struct tasdevice_config_info **ci = rca->cfg_info;
+ unsigned int i, j;
+
+ if (!ci)
+ return;
+ for (i = 0; i < rca->ncfgs; i++) {
+ if (!ci[i])
+ continue;
+ if (ci[i]->blk_data) {
+ for (j = 0; j < ci[i]->real_nblocks; j++) {
+ if (!ci[i]->blk_data[j])
+ continue;
+ kfree(ci[i]->blk_data[j]->regdata);
+ kfree(ci[i]->blk_data[j]);
+ }
+ kfree(ci[i]->blk_data);
+ }
+ kfree(ci[i]);
+ }
+ kfree(ci);
+}
+
+/* DSP firmware program block data load function. */
+static int tasdevice_load_data(struct tasdevice_priv *tas_priv,
+ struct tasdevice_data *dev_data)
+{
+ struct tasdev_blk *block;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < dev_data->nr_blk; i++) {
+ block = &dev_data->dev_blks[i];
+ ret = tas_priv->tasdevice_load_block(tas_priv, block);
+ if (ret < 0)
+ break;
+ }
+
+ return ret;
+}
+
+/* DSP firmware program load interface function. */
+int tasdevice_spi_prmg_load(void *context, int prm_no)
+{
+ struct tasdevice_priv *tas_priv = context;
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct tasdevice_prog *program;
+ struct tasdevice_config *conf;
+ int ret = 0;
+
+ if (!tas_fmw) {
+ dev_err(tas_priv->dev, "%s: Firmware is NULL\n", __func__);
+ return -EINVAL;
+ }
+ if (prm_no >= 0 && prm_no <= tas_fmw->nr_programs) {
+ tas_priv->cur_conf = 0;
+ tas_priv->is_loading = true;
+ program = &tas_fmw->programs[prm_no];
+ ret = tasdevice_load_data(tas_priv, &program->dev_data);
+ if (ret < 0) {
+ dev_err(tas_priv->dev, "Program failed %d.\n", ret);
+ return ret;
+ }
+ tas_priv->cur_prog = prm_no;
+
+ conf = &tas_fmw->configs[tas_priv->cur_conf];
+ ret = tasdevice_load_data(tas_priv, &conf->dev_data);
+ if (ret < 0)
+ dev_err(tas_priv->dev, "Config failed %d.\n", ret);
+ } else {
+ dev_err(tas_priv->dev,
+ "%s: prm(%d) is not in range of Programs %u\n",
+ __func__, prm_no, tas_fmw->nr_programs);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/* RCABIN configuration switch interface function. */
+void tasdevice_spi_tuning_switch(void *context, int state)
+{
+ struct tasdevice_priv *tas_priv = context;
+ int profile_cfg_id = tas_priv->rcabin.profile_cfg_id;
+
+ if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
+ dev_err(tas_priv->dev, "DSP bin file not loaded\n");
+ return;
+ }
+
+ if (state == 0)
+ tasdevice_spi_select_cfg_blk(tas_priv, profile_cfg_id,
+ TASDEVICE_BIN_BLK_PRE_POWER_UP);
+ else
+ tasdevice_spi_select_cfg_blk(tas_priv, profile_cfg_id,
+ TASDEVICE_BIN_BLK_PRE_SHUTDOWN);
+}
diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h
index 0ff772cf66e6..25f72f9e3f9b 100644
--- a/sound/pci/lola/lola.h
+++ b/sound/pci/lola/lola.h
@@ -499,8 +499,6 @@ int lola_init_mixer_widget(struct lola *chip, int nid);
void lola_free_mixer(struct lola *chip);
int lola_create_mixer(struct lola *chip);
int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute);
-void lola_save_mixer(struct lola *chip);
-void lola_restore_mixer(struct lola *chip);
int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update);
/* proc */
diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c
index cafd30e30913..2e73fbf335ed 100644
--- a/sound/pci/lola/lola_clock.c
+++ b/sound/pci/lola/lola_clock.c
@@ -35,7 +35,7 @@ unsigned int lola_sample_rate_convert(unsigned int coded)
default: return 0; /* error */
}
- /* ajustement */
+ /* adjustement */
switch (coded & 0x60) {
case (0 << 5): break;
case (1 << 5): freq = (freq * 999) / 1000; break;
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
index 6b162489cb5f..9cb26a8a4e1a 100644
--- a/sound/pci/lola/lola_mixer.c
+++ b/sound/pci/lola/lola_mixer.c
@@ -336,49 +336,6 @@ int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute)
return lola_codec_flush(chip);
}
-void lola_save_mixer(struct lola *chip)
-{
- /* mute analog output */
- if (chip->mixer.array_saved) {
- /* store contents of mixer array */
- memcpy_fromio(chip->mixer.array_saved, chip->mixer.array,
- sizeof(*chip->mixer.array));
- }
- lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */
-}
-
-void lola_restore_mixer(struct lola *chip)
-{
- int i;
-
- /*lola_reset_setups(chip);*/
- if (chip->mixer.array_saved) {
- /* restore contents of mixer array */
- memcpy_toio(chip->mixer.array, chip->mixer.array_saved,
- sizeof(*chip->mixer.array));
- /* inform micro-controller about all restored values
- * and ignore return values
- */
- for (i = 0; i < chip->mixer.src_phys_ins; i++)
- lola_codec_write(chip, chip->mixer.nid,
- LOLA_VERB_SET_SOURCE_GAIN,
- i, 0);
- for (i = 0; i < chip->mixer.src_stream_outs; i++)
- lola_codec_write(chip, chip->mixer.nid,
- LOLA_VERB_SET_SOURCE_GAIN,
- chip->mixer.src_stream_out_ofs + i, 0);
- for (i = 0; i < chip->mixer.dest_stream_ins; i++)
- lola_codec_write(chip, chip->mixer.nid,
- LOLA_VERB_SET_DESTINATION_GAIN,
- i, 0);
- for (i = 0; i < chip->mixer.dest_phys_outs; i++)
- lola_codec_write(chip, chip->mixer.nid,
- LOLA_VERB_SET_DESTINATION_GAIN,
- chip->mixer.dest_phys_out_ofs + i, 0);
- lola_codec_flush(chip);
- }
-}
-
/*
*/
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 11ba7d4eac2a..44085237fb44 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -696,7 +696,9 @@ snd_nm256_playback_copy(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct nm256_stream *s = runtime->private_data;
- return copy_from_iter_toio(s->bufptr + pos, src, count);
+ if (copy_from_iter_toio(s->bufptr + pos, count, src) != count)
+ return -EFAULT;
+ return 0;
}
/*
@@ -710,7 +712,9 @@ snd_nm256_capture_copy(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct nm256_stream *s = runtime->private_data;
- return copy_to_iter_fromio(dst, s->bufptr + pos, count);
+ if (copy_to_iter_fromio(s->bufptr + pos, count, dst) != count)
+ return -EFAULT;
+ return 0;
}
#endif /* !__i386__ */
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index c346f42befc2..ff7439634d76 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -854,11 +854,9 @@ static struct pci_driver oxygen_driver = {
.name = KBUILD_MODNAME,
.id_table = oxygen_ids,
.probe = generic_oxygen_probe,
-#ifdef CONFIG_PM_SLEEP
.driver = {
- .pm = &oxygen_pci_pm,
+ .pm = pm_sleep_ptr(&oxygen_pci_pm),
},
-#endif
};
module_pci_driver(oxygen_driver);
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h
index 0cae640708f3..820026daf838 100644
--- a/sound/pci/oxygen/oxygen.h
+++ b/sound/pci/oxygen/oxygen.h
@@ -161,9 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
const struct pci_device_id *id
)
);
-#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops oxygen_pci_pm;
-#endif
void oxygen_pci_shutdown(struct pci_dev *pci);
/* oxygen_mixer.c */
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c
index 92ffe9dc20c5..9340d3c9ffd6 100644
--- a/sound/pci/oxygen/oxygen_lib.c
+++ b/sound/pci/oxygen/oxygen_lib.c
@@ -713,7 +713,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
}
EXPORT_SYMBOL(oxygen_pci_probe);
-#ifdef CONFIG_PM_SLEEP
static int oxygen_pci_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -789,9 +788,7 @@ static int oxygen_pci_resume(struct device *dev)
return 0;
}
-SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
-EXPORT_SYMBOL(oxygen_pci_pm);
-#endif /* CONFIG_PM_SLEEP */
+EXPORT_SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
void oxygen_pci_shutdown(struct pci_dev *pci)
{
diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c
index 17650a5b1bfa..9d009015d97e 100644
--- a/sound/pci/oxygen/se6x.c
+++ b/sound/pci/oxygen/se6x.c
@@ -137,11 +137,9 @@ static struct pci_driver se6x_driver = {
.name = KBUILD_MODNAME,
.id_table = se6x_ids,
.probe = se6x_probe,
-#ifdef CONFIG_PM_SLEEP
.driver = {
- .pm = &oxygen_pci_pm,
+ .pm = pm_sleep_ptr(&oxygen_pci_pm),
},
-#endif
.shutdown = oxygen_pci_shutdown,
};
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 2e405133371f..ded62199da7f 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -82,11 +82,9 @@ static struct pci_driver xonar_driver = {
.name = KBUILD_MODNAME,
.id_table = xonar_ids,
.probe = xonar_probe,
-#ifdef CONFIG_PM_SLEEP
.driver = {
- .pm = &oxygen_pci_pm,
+ .pm = pm_sleep_ptr(&oxygen_pci_pm),
},
-#endif
.shutdown = oxygen_pci_shutdown,
};
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 02144bbee6d5..a8c2ceaadef5 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -256,8 +256,10 @@ static int snd_rme32_playback_copy(struct snd_pcm_substream *substream,
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- return copy_from_iter_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos,
- src, count);
+ if (copy_from_iter_toio(rme32->iobase + RME32_IO_DATA_BUFFER + pos,
+ count, src) != count)
+ return -EFAULT;
+ return 0;
}
/* copy callback for halfduplex mode */
@@ -267,9 +269,10 @@ static int snd_rme32_capture_copy(struct snd_pcm_substream *substream,
{
struct rme32 *rme32 = snd_pcm_substream_chip(substream);
- return copy_to_iter_fromio(dst,
- rme32->iobase + RME32_IO_DATA_BUFFER + pos,
- count);
+ if (copy_to_iter_fromio(rme32->iobase + RME32_IO_DATA_BUFFER + pos,
+ count, dst) != count)
+ return -EFAULT;
+ return 0;
}
/*
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index d50ad25574ad..1265a7efac60 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -322,8 +322,10 @@ snd_rme96_playback_copy(struct snd_pcm_substream *substream,
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- return copy_from_iter_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos,
- src, count);
+ if (copy_from_iter_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos,
+ count, src) != count)
+ return -EFAULT;
+ return 0;
}
static int
@@ -333,9 +335,10 @@ snd_rme96_capture_copy(struct snd_pcm_substream *substream,
{
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
- return copy_to_iter_fromio(dst,
- rme96->iobase + RME96_IO_REC_BUFFER + pos,
- count);
+ if (copy_to_iter_fromio(rme96->iobase + RME96_IO_REC_BUFFER + pos,
+ count, dst) != count)
+ return -EFAULT;
+ return 0;
}
/*
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 1c504a591948..fd3dfbad397a 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -3444,7 +3444,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
snd_iprintf(buffer, "MIDI1 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn0));
snd_iprintf(buffer, "MIDI2 Output status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusOut1));
snd_iprintf(buffer, "MIDI2 Input status: 0x%x\n", hdsp_read(hdsp, HDSP_midiStatusIn1));
- snd_iprintf(buffer, "Use Midi Tasklet: %s\n", hdsp->use_midi_work ? "on" : "off");
+ snd_iprintf(buffer, "Use Midi Tasklet: %s\n", str_on_off(hdsp->use_midi_work));
snd_iprintf(buffer, "\n");
@@ -3452,8 +3452,8 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
snd_iprintf(buffer, "Buffer Size (Latency): %d samples (2 periods of %lu bytes)\n", x, (unsigned long) hdsp->period_bytes);
snd_iprintf(buffer, "Hardware pointer (frames): %ld\n", hdsp_hw_pointer(hdsp));
- snd_iprintf(buffer, "Precise pointer: %s\n", hdsp->precise_ptr ? "on" : "off");
- snd_iprintf(buffer, "Line out: %s\n", (hdsp->control_register & HDSP_LineOut) ? "on" : "off");
+ snd_iprintf(buffer, "Precise pointer: %s\n", str_on_off(hdsp->precise_ptr));
+ snd_iprintf(buffer, "Line out: %s\n", str_on_off(hdsp->control_register & HDSP_LineOut));
snd_iprintf(buffer, "Firmware version: %d\n", (status2&HDSP_version0)|(status2&HDSP_version1)<<1|(status2&HDSP_version2)<<2);
@@ -3750,8 +3750,8 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
snd_iprintf(buffer, "Phones Gain : %s\n", tmp);
snd_iprintf(buffer, "XLR Breakout Cable : %s\n",
- hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ?
- "yes" : "no");
+ str_yes_no(hdsp_toggle_setting(hdsp,
+ HDSP_XLRBreakoutCable)));
if (hdsp->control_register & HDSP_AnalogExtensionBoard)
snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n");
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index d7290463d654..f89718b19d23 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -4927,14 +4927,14 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
x, (unsigned long) hdspm->period_bytes);
snd_iprintf(buffer, "Line out: %s\n",
- (hdspm->control_register & HDSPM_LineOut) ? "on " : "off");
+ str_on_off(hdspm->control_register & HDSPM_LineOut));
snd_iprintf(buffer,
"ClearTrackMarker = %s, Transmit in %s Channel Mode, "
"Auto Input %s\n",
- (hdspm->control_register & HDSPM_clr_tms) ? "on" : "off",
+ str_on_off(hdspm->control_register & HDSPM_clr_tms),
(hdspm->control_register & HDSPM_TX_64ch) ? "64" : "56",
- (hdspm->control_register & HDSPM_AutoInp) ? "on" : "off");
+ str_on_off(hdspm->control_register & HDSPM_AutoInp));
if (!(hdspm->control_register & HDSPM_ClockModeMaster))
@@ -5088,12 +5088,9 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry,
snd_iprintf(buffer,
"ClearTrackMarker %s, Emphasis %s, Dolby %s\n",
- (hdspm->
- control_register & HDSPM_clr_tms) ? "on" : "off",
- (hdspm->
- control_register & HDSPM_Emphasis) ? "on" : "off",
- (hdspm->
- control_register & HDSPM_Dolby) ? "on" : "off");
+ str_on_off(hdspm->control_register & HDSPM_clr_tms),
+ str_on_off(hdspm->control_register & HDSPM_Emphasis),
+ str_on_off(hdspm->control_register & HDSPM_Dolby));
pref_syncref = hdspm_pref_sync_ref(hdspm);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index d066c70ae160..5b8dd7b0a02c 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -1561,8 +1561,7 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff
x, (unsigned long) rme9652->period_bytes);
snd_iprintf(buffer, "Hardware pointer (frames): %ld\n",
rme9652_hw_pointer(rme9652));
- snd_iprintf(buffer, "Passthru: %s\n",
- rme9652->passthru ? "yes" : "no");
+ snd_iprintf(buffer, "Passthru: %s\n", str_yes_no(rme9652->passthru));
if ((rme9652->control_register & (RME9652_Master | RME9652_wsel)) == 0) {
snd_iprintf(buffer, "Clock mode: autosync\n");
@@ -1685,7 +1684,7 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff
snd_iprintf(buffer, "\n");
snd_iprintf(buffer, "Timecode signal: %s\n",
- (status & RME9652_tc_valid) ? "yes" : "no");
+ str_yes_no(status & RME9652_tc_valid));
/* thru modes */
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index f91cbf6eeca0..c30eaf1038e7 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1118,7 +1118,7 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry,
tmp = sonic->srs_space & 0x0f;
snd_iprintf(buffer, "SRS 3D : %s\n",
- sonic->srs_space & 0x80 ? "off" : "on");
+ str_off_on(sonic->srs_space & 0x80));
snd_iprintf(buffer, "SRS Space : %s\n",
tmp == 0x00 ? "100%" :
tmp == 0x01 ? "75%" :
@@ -1135,9 +1135,9 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry,
tmp == 0x00 ? "on-board ROM" :
tmp == 0x01 ? "PCI bus" : "on-board ROM + PCI bus");
tmp = sonic->mpu_switch;
- snd_iprintf(buffer, "Onboard synth : %s\n", tmp & 0x01 ? "on" : "off");
- snd_iprintf(buffer, "Ext. Rx to synth : %s\n", tmp & 0x02 ? "on" : "off");
- snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", tmp & 0x04 ? "on" : "off");
+ snd_iprintf(buffer, "Onboard synth : %s\n", str_on_off(tmp & 0x01));
+ snd_iprintf(buffer, "Ext. Rx to synth : %s\n", str_on_off(tmp & 0x02));
+ snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", str_on_off(tmp & 0x04));
}
static void snd_sonicvibes_proc_init(struct sonicvibes *sonic)
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index e98eea1e6d81..8039f445bee2 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3278,9 +3278,9 @@ static void snd_trident_proc_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "Spurious IRQs : %d\n", trident->spurious_irq_count);
snd_iprintf(buffer, "Spurious IRQ dlta: %d\n", trident->spurious_irq_max_delta);
if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018)
- snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", trident->spdif_ctrl == 0x28 ? "on" : "off");
+ snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", str_on_off(trident->spdif_ctrl == 0x28));
if (trident->device == TRIDENT_DEVICE_ID_NX) {
- snd_iprintf(buffer, "Rear Speakers : %s\n", trident->ac97_ctrl & 0x00000010 ? "on" : "off");
+ snd_iprintf(buffer, "Rear Speakers : %s\n", str_on_off(trident->ac97_ctrl & 0x00000010));
if (trident->tlb.entries) {
snd_iprintf(buffer,"\nVirtual Memory\n");
snd_iprintf(buffer, "Memory Maximum : %d\n", trident->tlb.memhdr->size);
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 468a6a20dc1e..fdb039896205 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -204,7 +204,6 @@ static int snd_vx222_probe(struct pci_dev *pci,
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int snd_vx222_suspend(struct device *dev)
{
struct snd_card *card = dev_get_drvdata(dev);
@@ -221,18 +220,14 @@ static int snd_vx222_resume(struct device *dev)
return snd_vx_resume(&vx->core);
}
-static SIMPLE_DEV_PM_OPS(snd_vx222_pm, snd_vx222_suspend, snd_vx222_resume);
-#define SND_VX222_PM_OPS &snd_vx222_pm
-#else
-#define SND_VX222_PM_OPS NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(snd_vx222_pm, snd_vx222_suspend, snd_vx222_resume);
static struct pci_driver vx222_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_vx222_ids,
.probe = snd_vx222_probe,
.driver = {
- .pm = SND_VX222_PM_OPS,
+ .pm = pm_ptr(&snd_vx222_pm),
},
};
diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c
index 3d3513d9def5..4ce81ac7f700 100644
--- a/sound/ppc/keywest.c
+++ b/sound/ppc/keywest.c
@@ -61,12 +61,6 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
return -ENODEV;
}
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&keywest_ctx->client->detected,
- &to_i2c_driver(keywest_ctx->client->dev.driver)->clients);
return 0;
}
@@ -99,6 +93,7 @@ static struct i2c_driver keywest_driver = {
void snd_pmac_keywest_cleanup(struct pmac_keywest *i2c)
{
if (keywest_ctx && keywest_ctx == i2c) {
+ i2c_unregister_device(keywest_ctx->client);
i2c_del_driver(&keywest_driver);
keywest_ctx = NULL;
}
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index 3f5422145c5e..84a4b17a0cc2 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -312,8 +312,7 @@ static int snd_sh_dac_create(struct snd_card *card,
chip->card = card;
- hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- chip->hrtimer.function = sh_dac_audio_timer;
+ hrtimer_setup(&chip->hrtimer, sh_dac_audio_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
dac_audio_reset(chip);
chip->rate = 8000;
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 5efba76abb31..8b7d51266f81 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -81,6 +81,13 @@ config SND_SOC_UTILS_KUNIT_TEST
help
If you want to perform tests on ALSA SoC utils library say Y here.
+config SND_SOC_OPS_KUNIT_TEST
+ tristate "KUnit tests for SoC ops"
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ If you want to perform tests on ALSA SoC ops library say Y here.
+
config SND_SOC_ACPI
tristate
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 08baaa11d813..358e227c5ab6 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -21,6 +21,10 @@ ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),)
obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o
endif
+ifneq ($(CONFIG_SND_SOC_OPS_KUNIT_TEST),)
+obj-$(CONFIG_SND_SOC_OPS_KUNIT_TEST) += soc-ops-test.o
+endif
+
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-y += soc-generic-dmaengine-pcm.o
endif
diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig
index c7590d4989bb..c7daae392d74 100644
--- a/sound/soc/amd/Kconfig
+++ b/sound/soc/amd/Kconfig
@@ -105,7 +105,7 @@ config SND_SOC_AMD_ACP6x
config SND_SOC_AMD_YC_MACH
tristate "AMD YC support for DMIC"
select SND_SOC_DMIC
- depends on SND_SOC_AMD_ACP6x
+ depends on SND_SOC_AMD_ACP6x && ACPI
help
This option enables machine driver for Yellow Carp platform
using dmic. ACP IP has PDM Decoder block with DMA controller.
@@ -161,15 +161,15 @@ config SND_SOC_AMD_SOUNDWIRE
If unsure select "N".
config SND_SOC_AMD_PS
- tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support"
+ tristate "AMD Audio Coprocessor-v6.3/v7.0/v7.1 support"
select SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE
select SND_SOC_ACPI_AMD_MATCH
depends on X86 && PCI && ACPI
help
- This option enables Audio Coprocessor i.e ACP v6.3 support on
- AMD Pink sardine platform. By enabling this flag build will be
- triggered for ACP PCI driver, ACP PDM DMA driver, ACP SoundWire
- DMA driver.
+ This option enables Audio Coprocessor i.e ACP6.3/ACP7.0/ACP7.1
+ variants support. By enabling this flag build will be triggered
+ for ACP PCI driver, ACP PDM DMA driver, ACP SoundWire DMA
+ driver.
Say m if you have such a device.
If unsure select "N".
diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig
index 03f3fcbba5af..b9432052c638 100644
--- a/sound/soc/amd/acp/Kconfig
+++ b/sound/soc/amd/acp/Kconfig
@@ -28,6 +28,9 @@ config SND_SOC_AMD_ACP_LEGACY_COMMON
config SND_SOC_AMD_ACP_I2S
tristate
+config SND_SOC_AMD_ACPI_MACH
+ tristate
+
config SND_SOC_AMD_ACP_PCM
tristate
select SND_SOC_ACPI if ACPI
@@ -37,6 +40,7 @@ config SND_SOC_AMD_ACP_PCI
depends on X86 && PCI
depends on ACPI
select SND_SOC_AMD_ACP_LEGACY_COMMON
+ select SND_SOC_AMD_ACPI_MACH
help
This options enables generic PCI driver for ACP device.
@@ -47,6 +51,7 @@ config SND_AMD_ASOC_RENOIR
select SND_SOC_AMD_ACP_I2S
select SND_SOC_AMD_ACP_PDM
select SND_SOC_AMD_ACP_LEGACY_COMMON
+ select SND_SOC_AMD_ACPI_MACH
depends on X86 && PCI
help
This option enables Renoir I2S support on AMD platform.
@@ -58,6 +63,8 @@ config SND_AMD_ASOC_REMBRANDT
select SND_SOC_AMD_ACP_I2S
select SND_SOC_AMD_ACP_PDM
select SND_SOC_AMD_ACP_LEGACY_COMMON
+ select SND_SOC_AMD_ACPI_MACH
+ depends on AMD_NODE
depends on X86 && PCI
help
This option enables Rembrandt I2S support on AMD platform.
@@ -68,10 +75,12 @@ config SND_AMD_ASOC_ACP63
tristate "AMD ACP ASOC ACP6.3 Support"
depends on X86 && PCI
depends on ACPI
+ depends on AMD_NODE
select SND_SOC_AMD_ACP_PCM
select SND_SOC_AMD_ACP_I2S
select SND_SOC_AMD_ACP_PDM
select SND_SOC_AMD_ACP_LEGACY_COMMON
+ select SND_SOC_AMD_ACPI_MACH
help
This option enables Acp6.3 I2S support on AMD platform.
Say Y if you want to enable AUDIO on ACP6.3
@@ -81,10 +90,12 @@ config SND_AMD_ASOC_ACP70
tristate "AMD ACP ASOC Acp7.0 Support"
depends on X86 && PCI
depends on ACPI
+ depends on AMD_NODE
select SND_SOC_AMD_ACP_PCM
select SND_SOC_AMD_ACP_I2S
select SND_SOC_AMD_ACP_PDM
select SND_SOC_AMD_ACP_LEGACY_COMMON
+ select SND_SOC_AMD_ACPI_MACH
help
This option enables Acp7.0 PDM support on AMD platform.
Say Y if you want to enable AUDIO on ACP7.0
@@ -156,6 +167,7 @@ config SND_SOC_AMD_LEGACY_SDW_MACH
select SND_SOC_RT712_SDCA_SDW
select SND_SOC_RT712_SDCA_DMIC_SDW
select SND_SOC_RT1316_SDW
+ select SND_SOC_RT1320_SDW
select SND_SOC_RT715_SDW
select SND_SOC_RT715_SDCA_SDW
select SND_SOC_RT722_SDCA_SDW
diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile
index bb2702036338..08220b9a3802 100644
--- a/sound/soc/amd/acp/Makefile
+++ b/sound/soc/amd/acp/Makefile
@@ -11,6 +11,7 @@ snd-acp-pdm-y := acp-pdm.o
snd-acp-legacy-common-y := acp-legacy-common.o
snd-acp-pci-y := acp-pci.o
snd-amd-sdw-acpi-y := amd-sdw-acpi.o
+snd-amd-acpi-mach-y := amd-acpi-mach.o
#platform specific driver
snd-acp-renoir-y := acp-renoir.o
@@ -22,7 +23,7 @@ snd-acp70-y := acp70.o
snd-acp-mach-y := acp-mach-common.o
snd-acp-legacy-mach-y := acp-legacy-mach.o acp3x-es83xx/acp3x-es83xx.o
snd-acp-sof-mach-y := acp-sof-mach.o
-snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o
+snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o amd-acp70-acpi-match.o
snd-acp-sdw-mach-y := acp-sdw-mach-common.o
snd-acp-sdw-sof-mach-y += acp-sdw-sof-mach.o
snd-acp-sdw-legacy-mach-y += acp-sdw-legacy-mach.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o
obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o
obj-$(CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON) += snd-acp-legacy-common.o
obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o
+obj-$(CONFIG_SND_SOC_AMD_ACPI_MACH) += snd-amd-acpi-mach.o
obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o
diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
index 1f59ee248771..a38409dd1d34 100644
--- a/sound/soc/amd/acp/acp-i2s.c
+++ b/sound/soc/amd/acp/acp-i2s.c
@@ -31,14 +31,10 @@
#define ACP63_LRCLK_DIV_FIELD GENMASK(12, 2)
#define ACP63_BCLK_DIV_FIELD GENMASK(23, 13)
-static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
+static inline void acp_set_i2s_clk(struct acp_chip_info *chip, int dai_id)
{
u32 i2s_clk_reg, val;
- struct acp_chip_info *chip;
- struct device *dev;
- dev = adata->dev;
- chip = dev_get_platdata(dev);
switch (dai_id) {
case I2S_SP_INSTANCE:
i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN;
@@ -55,36 +51,37 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
}
val = I2S_MASTER_MODE_ENABLE;
- if (adata->tdm_mode)
+ if (chip->tdm_mode)
val |= BIT(1);
switch (chip->acp_rev) {
case ACP63_PCI_ID:
case ACP70_PCI_ID:
case ACP71_PCI_ID:
- val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div);
- val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div);
+ val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, chip->lrclk_div);
+ val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, chip->bclk_div);
break;
default:
- val |= FIELD_PREP(LRCLK_DIV_FIELD, adata->lrclk_div);
- val |= FIELD_PREP(BCLK_DIV_FIELD, adata->bclk_div);
+ val |= FIELD_PREP(LRCLK_DIV_FIELD, chip->lrclk_div);
+ val |= FIELD_PREP(BCLK_DIV_FIELD, chip->bclk_div);
}
- writel(val, adata->acp_base + i2s_clk_reg);
+ writel(val, chip->base + i2s_clk_reg);
}
static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
- struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
+ struct device *dev = cpu_dai->component->dev;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
int mode;
mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
switch (mode) {
case SND_SOC_DAIFMT_I2S:
- adata->tdm_mode = TDM_DISABLE;
+ chip->tdm_mode = TDM_DISABLE;
break;
case SND_SOC_DAIFMT_DSP_A:
- adata->tdm_mode = TDM_ENABLE;
+ chip->tdm_mode = TDM_ENABLE;
break;
default:
return -EINVAL;
@@ -96,7 +93,6 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
int slots, int slot_width)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
struct acp_chip_info *chip;
struct acp_stream *stream;
int slot_len, no_of_slots;
@@ -157,34 +153,35 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas
slots = no_of_slots;
- spin_lock_irq(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
+ spin_lock_irq(&chip->acp_lock);
+ list_for_each_entry(stream, &chip->stream_list, list) {
switch (chip->acp_rev) {
case ACP_RN_PCI_ID:
case ACP_RMB_PCI_ID:
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
- adata->tdm_tx_fmt[stream->dai_id - 1] =
+ chip->tdm_tx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 15) | (slot_len << 18);
else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
- adata->tdm_rx_fmt[stream->dai_id - 1] =
+ chip->tdm_rx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 15) | (slot_len << 18);
break;
case ACP63_PCI_ID:
case ACP70_PCI_ID:
case ACP71_PCI_ID:
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
- adata->tdm_tx_fmt[stream->dai_id - 1] =
+ chip->tdm_tx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 13) | (slot_len << 18);
else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
- adata->tdm_rx_fmt[stream->dai_id - 1] =
+ chip->tdm_rx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 13) | (slot_len << 18);
break;
default:
dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev);
+ spin_unlock_irq(&chip->acp_lock);
return -EINVAL;
}
}
- spin_unlock_irq(&adata->acp_lock);
+ spin_unlock_irq(&chip->acp_lock);
return 0;
}
@@ -192,15 +189,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata;
+ struct acp_chip_info *chip;
struct acp_resource *rsrc;
u32 val;
u32 xfer_resolution;
u32 reg_val, fmt_reg, tdm_fmt;
u32 lrclk_div_val, bclk_div_val;
- adata = snd_soc_dai_get_drvdata(dai);
- rsrc = adata->rsrc;
+ chip = dev_get_platdata(dev);
+ rsrc = chip->rsrc;
/* These values are as per Hardware Spec */
switch (params_format(params)) {
@@ -239,7 +236,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
return -EINVAL;
}
- adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
+ chip->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution;
} else {
switch (dai->driver->id) {
case I2S_BT_INSTANCE:
@@ -258,22 +255,22 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
return -EINVAL;
}
- adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;
+ chip->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution;
}
- val = readl(adata->acp_base + reg_val);
+ val = readl(chip->base + reg_val);
val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK;
val = val | (xfer_resolution << 3);
- writel(val, adata->acp_base + reg_val);
+ writel(val, chip->base + reg_val);
- if (adata->tdm_mode) {
- val = readl(adata->acp_base + reg_val);
- writel(val | BIT(1), adata->acp_base + reg_val);
+ if (chip->tdm_mode) {
+ val = readl(chip->base + reg_val);
+ writel(val | BIT(1), chip->base + reg_val);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1];
+ tdm_fmt = chip->tdm_tx_fmt[dai->driver->id - 1];
else
- tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1];
- writel(tdm_fmt, adata->acp_base + fmt_reg);
+ tdm_fmt = chip->tdm_rx_fmt[dai->driver->id - 1];
+ writel(tdm_fmt, chip->base + fmt_reg);
}
if (rsrc->soc_mclk) {
@@ -376,8 +373,8 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
default:
break;
}
- adata->lrclk_div = lrclk_div_val;
- adata->bclk_div = bclk_div_val;
+ chip->lrclk_div = lrclk_div_val;
+ chip->bclk_div = bclk_div_val;
}
return 0;
}
@@ -386,8 +383,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
{
struct acp_stream *stream = substream->runtime->private_data;
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ struct acp_resource *rsrc = chip->rsrc;
u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
@@ -397,20 +394,20 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
+ stream->bytescount = acp_get_byte_count(chip, stream->dai_id, substream->stream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (dai->driver->id) {
case I2S_BT_INSTANCE:
- water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(adata);
+ water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(chip);
reg_val = ACP_BTTDM_ITER;
ier_val = ACP_BTTDM_IER;
- buf_reg = ACP_BT_TX_RINGBUFSIZE(adata);
+ buf_reg = ACP_BT_TX_RINGBUFSIZE(chip);
break;
case I2S_SP_INSTANCE:
- water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(adata);
+ water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(chip);
reg_val = ACP_I2STDM_ITER;
ier_val = ACP_I2STDM_IER;
- buf_reg = ACP_I2S_TX_RINGBUFSIZE(adata);
+ buf_reg = ACP_I2S_TX_RINGBUFSIZE(chip);
break;
case I2S_HS_INSTANCE:
water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
@@ -425,16 +422,16 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
} else {
switch (dai->driver->id) {
case I2S_BT_INSTANCE:
- water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(adata);
+ water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(chip);
reg_val = ACP_BTTDM_IRER;
ier_val = ACP_BTTDM_IER;
- buf_reg = ACP_BT_RX_RINGBUFSIZE(adata);
+ buf_reg = ACP_BT_RX_RINGBUFSIZE(chip);
break;
case I2S_SP_INSTANCE:
- water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(adata);
+ water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(chip);
reg_val = ACP_I2STDM_IRER;
ier_val = ACP_I2STDM_IER;
- buf_reg = ACP_I2S_RX_RINGBUFSIZE(adata);
+ buf_reg = ACP_I2S_RX_RINGBUFSIZE(chip);
break;
case I2S_HS_INSTANCE:
water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
@@ -448,14 +445,14 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
}
}
- writel(period_bytes, adata->acp_base + water_val);
- writel(buf_size, adata->acp_base + buf_reg);
+ writel(period_bytes, chip->base + water_val);
+ writel(buf_size, chip->base + buf_reg);
if (rsrc->soc_mclk)
- acp_set_i2s_clk(adata, dai->driver->id);
- val = readl(adata->acp_base + reg_val);
+ acp_set_i2s_clk(chip, dai->driver->id);
+ val = readl(chip->base + reg_val);
val = val | BIT(0);
- writel(val, adata->acp_base + reg_val);
- writel(1, adata->acp_base + ier_val);
+ writel(val, chip->base + reg_val);
+ writel(1, chip->base + ier_val);
return 0;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -492,19 +489,19 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
return -EINVAL;
}
}
- val = readl(adata->acp_base + reg_val);
+ val = readl(chip->base + reg_val);
val = val & ~BIT(0);
- writel(val, adata->acp_base + reg_val);
-
- if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) &&
- !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0)))
- writel(0, adata->acp_base + ACP_BTTDM_IER);
- if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
- !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
- writel(0, adata->acp_base + ACP_I2STDM_IER);
- if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
- !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
- writel(0, adata->acp_base + ACP_HSTDM_IER);
+ writel(val, chip->base + reg_val);
+
+ if (!(readl(chip->base + ACP_BTTDM_ITER) & BIT(0)) &&
+ !(readl(chip->base + ACP_BTTDM_IRER) & BIT(0)))
+ writel(0, chip->base + ACP_BTTDM_IER);
+ if (!(readl(chip->base + ACP_I2STDM_ITER) & BIT(0)) &&
+ !(readl(chip->base + ACP_I2STDM_IRER) & BIT(0)))
+ writel(0, chip->base + ACP_I2STDM_IER);
+ if (!(readl(chip->base + ACP_HSTDM_ITER) & BIT(0)) &&
+ !(readl(chip->base + ACP_HSTDM_IRER) & BIT(0)))
+ writel(0, chip->base + ACP_HSTDM_IER);
return 0;
default:
return -EINVAL;
@@ -516,9 +513,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
- struct acp_chip_info *chip;
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ struct acp_resource *rsrc = chip->rsrc;
struct acp_stream *stream = substream->runtime->private_data;
u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0;
u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl;
@@ -528,56 +524,56 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
switch (dai->driver->id) {
case I2S_SP_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);
+ reg_dma_size = ACP_I2S_TX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_PB_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);
- reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip);
+ reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip);
if (chip->acp_rev >= ACP70_PCI_ID)
phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START;
else
phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
} else {
- reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);
+ reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_CAPT_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);
- reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip);
+ reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip);
if (chip->acp_rev >= ACP70_PCI_ID)
phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START;
else
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip));
}
break;
case I2S_BT_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);
+ reg_dma_size = ACP_BT_TX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_PB_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);
- reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip);
+ reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip);
if (chip->acp_rev >= ACP70_PCI_ID)
phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START;
else
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
} else {
- reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);
+ reg_dma_size = ACP_BT_RX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_CAPT_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);
- reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip);
+ reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip);
if (chip->acp_rev >= ACP70_PCI_ID)
phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START;
else
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
}
break;
case I2S_HS_INSTANCE:
@@ -592,7 +588,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START;
else
phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
+ writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR);
} else {
reg_dma_size = ACP_HS_RX_DMA_SIZE;
acp_fifo_addr = rsrc->sram_pte_offset +
@@ -604,7 +600,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START;
else
phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
+ writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR);
}
break;
default:
@@ -612,11 +608,11 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
return -EINVAL;
}
- writel(DMA_SIZE, adata->acp_base + reg_dma_size);
- writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
- writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
+ writel(DMA_SIZE, chip->base + reg_dma_size);
+ writel(acp_fifo_addr, chip->base + reg_fifo_addr);
+ writel(FIFO_SIZE, chip->base + reg_fifo_size);
- ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+ ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
BIT(BT_RX_THRESHOLD(rsrc->offset)) |
BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
@@ -624,7 +620,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
BIT(HS_RX_THRESHOLD(rsrc->offset)) |
BIT(HS_TX_THRESHOLD(rsrc->offset));
- writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+ writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
return 0;
}
@@ -633,8 +629,8 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
{
struct acp_stream *stream = substream->runtime->private_data;
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ struct acp_resource *rsrc = chip->rsrc;
unsigned int dir = substream->stream;
unsigned int irq_bit = 0;
diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c
index 7acc7ed2e8cc..b4d68484e06d 100644
--- a/sound/soc/amd/acp/acp-legacy-common.c
+++ b/sound/soc/amd/acp/acp-legacy-common.c
@@ -13,32 +13,132 @@
*/
#include "amd.h"
+#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/export.h>
+#include "../mach-config.h"
+
#define ACP_RENOIR_PDM_ADDR 0x02
#define ACP_REMBRANDT_PDM_ADDR 0x03
#define ACP63_PDM_ADDR 0x02
#define ACP70_PDM_ADDR 0x02
-void acp_enable_interrupts(struct acp_dev_data *adata)
+struct acp_resource rn_rsrc = {
+ .offset = 20,
+ .no_of_ctrls = 1,
+ .irqp_used = 0,
+ .irq_reg_offset = 0x1800,
+ .scratch_reg_offset = 0x12800,
+ .sram_pte_offset = 0x02052800,
+};
+EXPORT_SYMBOL_NS_GPL(rn_rsrc, "SND_SOC_ACP_COMMON");
+
+struct acp_resource rmb_rsrc = {
+ .offset = 0,
+ .no_of_ctrls = 2,
+ .irqp_used = 1,
+ .soc_mclk = true,
+ .irq_reg_offset = 0x1a00,
+ .scratch_reg_offset = 0x12800,
+ .sram_pte_offset = 0x03802800,
+};
+EXPORT_SYMBOL_NS_GPL(rmb_rsrc, "SND_SOC_ACP_COMMON");
+
+struct acp_resource acp63_rsrc = {
+ .offset = 0,
+ .no_of_ctrls = 2,
+ .irqp_used = 1,
+ .soc_mclk = true,
+ .irq_reg_offset = 0x1a00,
+ .scratch_reg_offset = 0x12800,
+ .sram_pte_offset = 0x03802800,
+};
+EXPORT_SYMBOL_NS_GPL(acp63_rsrc, "SND_SOC_ACP_COMMON");
+
+struct acp_resource acp70_rsrc = {
+ .offset = 0,
+ .no_of_ctrls = 2,
+ .irqp_used = 1,
+ .soc_mclk = true,
+ .irq_reg_offset = 0x1a00,
+ .scratch_reg_offset = 0x10000,
+ .sram_pte_offset = 0x03800000,
+};
+EXPORT_SYMBOL_NS_GPL(acp70_rsrc, "SND_SOC_ACP_COMMON");
+
+static const struct snd_acp_hw_ops acp_common_hw_ops = {
+ /* ACP hardware initilizations */
+ .acp_init = acp_init,
+ .acp_deinit = acp_deinit,
+
+ /* ACP Interrupts*/
+ .irq = acp_irq_handler,
+ .en_interrupts = acp_enable_interrupts,
+ .dis_interrupts = acp_disable_interrupts,
+};
+
+irqreturn_t acp_irq_handler(int irq, void *data)
{
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_chip_info *chip = data;
+ struct acp_resource *rsrc = chip->rsrc;
+ struct acp_stream *stream;
+ u16 i2s_flag = 0;
+ u32 ext_intr_stat, ext_intr_stat1;
+
+ if (rsrc->no_of_ctrls == 2)
+ ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(chip, (rsrc->irqp_used - 1)));
+
+ ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used));
+
+ spin_lock(&chip->acp_lock);
+ list_for_each_entry(stream, &chip->stream_list, list) {
+ if (ext_intr_stat & stream->irq_bit) {
+ writel(stream->irq_bit,
+ ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used));
+ snd_pcm_period_elapsed(stream->substream);
+ i2s_flag = 1;
+ }
+ if (chip->rsrc->no_of_ctrls == 2) {
+ if (ext_intr_stat1 & stream->irq_bit) {
+ writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(chip,
+ (rsrc->irqp_used - 1)));
+ snd_pcm_period_elapsed(stream->substream);
+ i2s_flag = 1;
+ }
+ }
+ }
+ spin_unlock(&chip->acp_lock);
+ if (i2s_flag)
+ return IRQ_HANDLED;
+
+ return IRQ_NONE;
+}
+
+int acp_enable_interrupts(struct acp_chip_info *chip)
+{
+ struct acp_resource *rsrc;
u32 ext_intr_ctrl;
- writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));
- ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+ rsrc = chip->rsrc;
+ writel(0x01, ACP_EXTERNAL_INTR_ENB(chip));
+ ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
ext_intr_ctrl |= ACP_ERROR_MASK;
- writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+ writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
+
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, "SND_SOC_ACP_COMMON");
-void acp_disable_interrupts(struct acp_dev_data *adata)
+int acp_disable_interrupts(struct acp_chip_info *chip)
{
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_resource *rsrc;
+
+ rsrc = chip->rsrc;
+ writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used));
+ writel(0x00, ACP_EXTERNAL_INTR_ENB(chip));
- writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
- writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));
+ return 0;
}
EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, "SND_SOC_ACP_COMMON");
@@ -48,7 +148,7 @@ static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
struct acp_stream *stream = runtime->private_data;
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
u32 physical_addr, pdm_size, period_bytes;
@@ -57,29 +157,29 @@ static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream,
physical_addr = stream->reg_offset + MEM_WINDOW_START;
/* Init ACP PDM Ring buffer */
- writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR);
- writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE);
- writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
- writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
+ writel(physical_addr, chip->base + ACP_WOV_RX_RINGBUFADDR);
+ writel(pdm_size, chip->base + ACP_WOV_RX_RINGBUFSIZE);
+ writel(period_bytes, chip->base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
+ writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL);
}
static void set_acp_pdm_clk(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
unsigned int pdm_ctrl;
/* Enable default ACP PDM clk */
- writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL);
- pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL);
+ writel(PDM_CLK_FREQ_MASK, chip->base + ACP_WOV_CLK_CTRL);
+ pdm_ctrl = readl(chip->base + ACP_WOV_MISC_CTRL);
pdm_ctrl |= PDM_MISC_CTRL_MASK;
- writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL);
+ writel(pdm_ctrl, chip->base + ACP_WOV_MISC_CTRL);
set_acp_pdm_ring_buffer(substream, dai);
}
void restore_acp_pdm_params(struct snd_pcm_substream *substream,
- struct acp_dev_data *adata)
+ struct acp_chip_info *chip)
{
struct snd_soc_dai *dai;
struct snd_soc_pcm_runtime *soc_runtime;
@@ -87,14 +187,15 @@ void restore_acp_pdm_params(struct snd_pcm_substream *substream,
soc_runtime = snd_soc_substream_to_rtd(substream);
dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+
/* Programming channel mask and sampling rate */
- writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);
- writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR);
+ writel(chip->ch_mask, chip->base + ACP_WOV_PDM_NO_OF_CHANNELS);
+ writel(PDM_DEC_64, chip->base + ACP_WOV_PDM_DECIMATION_FACTOR);
/* Enabling ACP Pdm interuppts */
- ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));
+ ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0));
ext_int_ctrl |= PDM_DMA_INTR_MASK;
- writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));
+ writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0));
set_acp_pdm_clk(substream, dai);
}
EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, "SND_SOC_ACP_COMMON");
@@ -103,8 +204,8 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ struct acp_resource *rsrc = chip->rsrc;
struct acp_stream *stream = substream->runtime->private_data;
u32 reg_dma_size, reg_fifo_size, reg_fifo_addr;
u32 phy_addr, acp_fifo_addr, ext_int_ctrl;
@@ -113,40 +214,40 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
switch (dai->driver->id) {
case I2S_SP_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata);
+ reg_dma_size = ACP_I2S_TX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_PB_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata);
- reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip);
+ reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip);
phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip));
} else {
- reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata);
+ reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
SP_CAPT_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata);
- reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip);
+ reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip);
phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip));
}
break;
case I2S_BT_INSTANCE:
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
- reg_dma_size = ACP_BT_TX_DMA_SIZE(adata);
+ reg_dma_size = ACP_BT_TX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_PB_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata);
- reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip);
+ reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip);
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip));
} else {
- reg_dma_size = ACP_BT_RX_DMA_SIZE(adata);
+ reg_dma_size = ACP_BT_RX_DMA_SIZE(chip);
acp_fifo_addr = rsrc->sram_pte_offset +
BT_CAPT_FIFO_ADDR_OFFSET;
- reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata);
- reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata);
+ reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip);
+ reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip);
phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata));
+ writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip));
}
break;
case I2S_HS_INSTANCE:
@@ -157,7 +258,7 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
reg_fifo_addr = ACP_HS_TX_FIFOADDR;
reg_fifo_size = ACP_HS_TX_FIFOSIZE;
phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
+ writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR);
} else {
reg_dma_size = ACP_HS_RX_DMA_SIZE;
acp_fifo_addr = rsrc->sram_pte_offset +
@@ -165,7 +266,7 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
reg_fifo_addr = ACP_HS_RX_FIFOADDR;
reg_fifo_size = ACP_HS_RX_FIFOSIZE;
phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
- writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
+ writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR);
}
break;
default:
@@ -173,11 +274,11 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
return -EINVAL;
}
- writel(DMA_SIZE, adata->acp_base + reg_dma_size);
- writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr);
- writel(FIFO_SIZE, adata->acp_base + reg_fifo_size);
+ writel(DMA_SIZE, chip->base + reg_dma_size);
+ writel(acp_fifo_addr, chip->base + reg_fifo_addr);
+ writel(FIFO_SIZE, chip->base + reg_fifo_size);
- ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+ ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
BIT(BT_RX_THRESHOLD(rsrc->offset)) |
BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
@@ -185,12 +286,12 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream,
BIT(HS_RX_THRESHOLD(rsrc->offset)) |
BIT(HS_TX_THRESHOLD(rsrc->offset));
- writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+ writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used));
return 0;
}
int restore_acp_i2s_params(struct snd_pcm_substream *substream,
- struct acp_dev_data *adata,
+ struct acp_chip_info *chip,
struct acp_stream *stream)
{
struct snd_soc_dai *dai;
@@ -200,7 +301,7 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream,
soc_runtime = snd_soc_substream_to_rtd(substream);
dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1];
+ tdm_fmt = chip->tdm_tx_fmt[stream->dai_id - 1];
switch (stream->dai_id) {
case I2S_BT_INSTANCE:
reg_val = ACP_BTTDM_ITER;
@@ -218,9 +319,9 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream,
pr_err("Invalid dai id %x\n", stream->dai_id);
return -EINVAL;
}
- val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3;
+ val = chip->xfer_tx_resolution[stream->dai_id - 1] << 3;
} else {
- tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1];
+ tdm_fmt = chip->tdm_rx_fmt[stream->dai_id - 1];
switch (stream->dai_id) {
case I2S_BT_INSTANCE:
reg_val = ACP_BTTDM_IRER;
@@ -238,13 +339,13 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream,
pr_err("Invalid dai id %x\n", stream->dai_id);
return -EINVAL;
}
- val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3;
+ val = chip->xfer_rx_resolution[stream->dai_id - 1] << 3;
}
- writel(val, adata->acp_base + reg_val);
- if (adata->tdm_mode == TDM_ENABLE) {
- writel(tdm_fmt, adata->acp_base + fmt_reg);
- val = readl(adata->acp_base + reg_val);
- writel(val | 0x2, adata->acp_base + reg_val);
+ writel(val, chip->base + reg_val);
+ if (chip->tdm_mode == TDM_ENABLE) {
+ writel(tdm_fmt, chip->base + fmt_reg);
+ val = readl(chip->base + reg_val);
+ writel(val | 0x2, chip->base + reg_val);
}
return set_acp_i2s_dma_fifo(substream, dai);
}
@@ -344,24 +445,32 @@ int acp_deinit(struct acp_chip_info *chip)
return 0;
}
EXPORT_SYMBOL_NS_GPL(acp_deinit, "SND_SOC_ACP_COMMON");
-
-int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
+int acp_machine_select(struct acp_chip_info *chip)
{
- pci_write_config_dword(dev, 0x60, smn_addr);
- pci_write_config_dword(dev, 0x64, data);
+ struct snd_soc_acpi_mach *mach;
+ int size, platform;
+
+ if (chip->flag == FLAG_AMD_LEGACY_ONLY_DMIC) {
+ platform = chip->acp_rev;
+ chip->mach_dev = platform_device_register_data(chip->dev, "acp-pdm-mach",
+ PLATFORM_DEVID_NONE, &platform,
+ sizeof(platform));
+ } else {
+ size = sizeof(*chip->machines);
+ mach = snd_soc_acpi_find_machine(chip->machines);
+ if (!mach) {
+ dev_err(chip->dev, "warning: No matching ASoC machine driver found\n");
+ return -EINVAL;
+ }
+ mach->mach_params.subsystem_rev = chip->acp_rev;
+ chip->mach_dev = platform_device_register_data(chip->dev, mach->drv_name,
+ PLATFORM_DEVID_NONE, mach, size);
+ }
+ if (IS_ERR(chip->mach_dev))
+ dev_warn(chip->dev, "Unable to register Machine device\n");
return 0;
}
-EXPORT_SYMBOL_NS_GPL(smn_write, "SND_SOC_ACP_COMMON");
-
-int smn_read(struct pci_dev *dev, u32 smn_addr)
-{
- u32 data;
-
- pci_write_config_dword(dev, 0x60, smn_addr);
- pci_read_config_dword(dev, 0x64, &data);
- return data;
-}
-EXPORT_SYMBOL_NS_GPL(smn_read, "SND_SOC_ACP_COMMON");
+EXPORT_SYMBOL_NS_GPL(acp_machine_select, "SND_SOC_ACP_COMMON");
static void check_acp3x_config(struct acp_chip_info *chip)
{
@@ -445,7 +554,9 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
{
struct acpi_device *pdm_dev;
const union acpi_object *obj;
- u32 pdm_addr;
+ acpi_handle handle;
+ acpi_integer dmic_status;
+ u32 pdm_addr, ret;
switch (chip->acp_rev) {
case ACP_RN_PCI_ID:
@@ -477,9 +588,58 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip)
obj->integer.value == pdm_addr)
chip->is_pdm_dev = true;
}
+
+ handle = ACPI_HANDLE(&pci->dev);
+ ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status);
+ if (!ACPI_FAILURE(ret))
+ chip->is_pdm_dev = dmic_status;
}
}
EXPORT_SYMBOL_NS_GPL(check_acp_config, "SND_SOC_ACP_COMMON");
+struct snd_acp_hw_ops acp31_common_hw_ops;
+EXPORT_SYMBOL_NS_GPL(acp31_common_hw_ops, "SND_SOC_ACP_COMMON");
+int acp31_hw_ops_init(struct acp_chip_info *chip)
+{
+ memcpy(&acp31_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
+ chip->acp_hw_ops = &acp31_common_hw_ops;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp31_hw_ops_init, "SND_SOC_ACP_COMMON");
+
+struct snd_acp_hw_ops acp6x_common_hw_ops;
+EXPORT_SYMBOL_NS_GPL(acp6x_common_hw_ops, "SND_SOC_ACP_COMMON");
+int acp6x_hw_ops_init(struct acp_chip_info *chip)
+{
+ memcpy(&acp6x_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
+ chip->acp_hw_ops = &acp6x_common_hw_ops;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp6x_hw_ops_init, "SND_SOC_ACP_COMMON");
+
+struct snd_acp_hw_ops acp63_common_hw_ops;
+EXPORT_SYMBOL_NS_GPL(acp63_common_hw_ops, "SND_SOC_ACP_COMMON");
+int acp63_hw_ops_init(struct acp_chip_info *chip)
+{
+ memcpy(&acp63_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
+ chip->acp_hw_ops = &acp63_common_hw_ops;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp63_hw_ops_init, "SND_SOC_ACP_COMMON");
+
+struct snd_acp_hw_ops acp70_common_hw_ops;
+EXPORT_SYMBOL_NS_GPL(acp70_common_hw_ops, "SND_SOC_ACP_COMMON");
+int acp70_hw_ops_init(struct acp_chip_info *chip)
+{
+ memcpy(&acp70_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops));
+ chip->acp_hw_ops = &acp70_common_hw_ops;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acp70_hw_ops_init, "SND_SOC_ACP_COMMON");
+
MODULE_DESCRIPTION("AMD ACP legacy common features");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index f7602c1769bf..a0dab85088ec 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -919,7 +919,7 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream,
int ret;
ret = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF);
if (ret < 0)
return ret;
diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c
index e0fc42d939d3..0b2aa33cc426 100644
--- a/sound/soc/amd/acp/acp-pci.c
+++ b/sound/soc/amd/acp/acp-pci.c
@@ -26,32 +26,88 @@
#define ACP3x_REG_START 0x1240000
#define ACP3x_REG_END 0x125C000
-static struct platform_device *dmic_dev;
-static struct platform_device *pdev;
-
-static const struct resource acp_res[] = {
- {
- .start = 0,
- .end = ACP3x_REG_END - ACP3x_REG_START,
- .name = "acp_mem",
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 0,
- .end = 0,
- .name = "acp_dai_irq",
- .flags = IORESOURCE_IRQ,
- },
-};
+static irqreturn_t irq_handler(int irq, void *data)
+{
+ struct acp_chip_info *chip = data;
-static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+ if (chip && chip->acp_hw_ops && chip->acp_hw_ops->irq)
+ return chip->acp_hw_ops->irq(irq, chip);
+
+ return IRQ_NONE;
+}
+static void acp_fill_platform_dev_info(struct platform_device_info *pdevinfo,
+ struct device *parent,
+ struct fwnode_handle *fw_node,
+ char *name, unsigned int id,
+ const struct resource *res,
+ unsigned int num_res,
+ const void *data,
+ size_t size_data)
+{
+ pdevinfo->name = name;
+ pdevinfo->id = id;
+ pdevinfo->parent = parent;
+ pdevinfo->num_res = num_res;
+ pdevinfo->res = res;
+ pdevinfo->data = data;
+ pdevinfo->size_data = size_data;
+ pdevinfo->fwnode = fw_node;
+}
+
+static int create_acp_platform_devs(struct pci_dev *pci, struct acp_chip_info *chip, u32 addr)
{
struct platform_device_info pdevinfo;
+ struct device *parent;
+ int ret;
+
+ parent = &pci->dev;
+
+ if (chip->is_i2s_config || chip->is_pdm_dev) {
+ chip->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL);
+ if (!chip->res) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ chip->res->flags = IORESOURCE_MEM;
+ chip->res->start = addr;
+ chip->res->end = addr + (ACP3x_REG_END - ACP3x_REG_START);
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ }
+
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ acp_fill_platform_dev_info(&pdevinfo, parent, NULL, chip->name,
+ 0, chip->res, 1, chip, sizeof(*chip));
+
+ chip->acp_plat_dev = platform_device_register_full(&pdevinfo);
+ if (IS_ERR(chip->acp_plat_dev)) {
+ dev_err(&pci->dev,
+ "cannot register %s device\n", pdevinfo.name);
+ ret = PTR_ERR(chip->acp_plat_dev);
+ goto err;
+ }
+ if (chip->is_pdm_dev && chip->is_pdm_config) {
+ chip->dmic_codec_dev = platform_device_register_data(&pci->dev,
+ "dmic-codec",
+ PLATFORM_DEVID_NONE,
+ NULL, 0);
+ if (IS_ERR(chip->dmic_codec_dev)) {
+ dev_err(&pci->dev, "failed to create DMIC device\n");
+ ret = PTR_ERR(chip->dmic_codec_dev);
+ goto unregister_acp_plat_dev;
+ }
+ }
+ return 0;
+unregister_acp_plat_dev:
+ platform_device_unregister(chip->acp_plat_dev);
+err:
+ return ret;
+}
+
+static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
+{
struct device *dev = &pci->dev;
- const struct resource *res_acp;
struct acp_chip_info *chip;
- struct resource *res;
- unsigned int flag, addr, num_res, i;
+ unsigned int flag, addr;
int ret;
flag = snd_amd_acp_find_config(pci);
@@ -75,24 +131,32 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
pci_set_master(pci);
- res_acp = acp_res;
- num_res = ARRAY_SIZE(acp_res);
chip->acp_rev = pci->revision;
switch (pci->revision) {
case 0x01:
chip->name = "acp_asoc_renoir";
+ chip->rsrc = &rn_rsrc;
+ chip->acp_hw_ops_init = acp31_hw_ops_init;
+ chip->machines = &snd_soc_acpi_amd_acp_machines;
break;
case 0x6f:
chip->name = "acp_asoc_rembrandt";
+ chip->rsrc = &rmb_rsrc;
+ chip->acp_hw_ops_init = acp6x_hw_ops_init;
+ chip->machines = &snd_soc_acpi_amd_rmb_acp_machines;
break;
case 0x63:
chip->name = "acp_asoc_acp63";
+ chip->rsrc = &acp63_rsrc;
+ chip->acp_hw_ops_init = acp63_hw_ops_init;
+ chip->machines = &snd_soc_acpi_amd_acp63_acp_machines;
break;
case 0x70:
- chip->name = "acp_asoc_acp70";
- break;
case 0x71:
chip->name = "acp_asoc_acp70";
+ chip->rsrc = &acp70_rsrc;
+ chip->acp_hw_ops_init = acp70_hw_ops_init;
+ chip->machines = &snd_soc_acpi_amd_acp70_acp_machines;
break;
default:
dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
@@ -100,64 +164,46 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
goto release_regions;
}
chip->flag = flag;
- dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
- if (IS_ERR(dmic_dev)) {
- dev_err(dev, "failed to create DMIC device\n");
- ret = PTR_ERR(dmic_dev);
- goto release_regions;
- }
addr = pci_resource_start(pci, 0);
chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0));
if (!chip->base) {
ret = -ENOMEM;
- goto unregister_dmic_dev;
+ goto release_regions;
}
- ret = acp_init(chip);
+ chip->addr = addr;
+
+ chip->acp_hw_ops_init(chip);
+ ret = acp_hw_init(chip);
if (ret)
- goto unregister_dmic_dev;
+ goto release_regions;
+
+ ret = devm_request_irq(dev, pci->irq, irq_handler,
+ IRQF_SHARED, "ACP_I2S_IRQ", chip);
+ if (ret) {
+ dev_err(&pci->dev, "ACP I2S IRQ request failed %d\n", ret);
+ goto de_init;
+ }
check_acp_config(pci, chip);
if (!chip->is_pdm_dev && !chip->is_i2s_config)
goto skip_pdev_creation;
- res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL);
- if (!res) {
- ret = -ENOMEM;
- goto unregister_dmic_dev;
+ ret = create_acp_platform_devs(pci, chip, addr);
+ if (ret < 0) {
+ dev_err(&pci->dev, "ACP platform devices creation failed\n");
+ goto de_init;
}
- for (i = 0; i < num_res; i++, res_acp++) {
- res[i].name = res_acp->name;
- res[i].flags = res_acp->flags;
- res[i].start = addr + res_acp->start;
- res[i].end = addr + res_acp->end;
- if (res_acp->flags == IORESOURCE_IRQ) {
- res[i].start = pci->irq;
- res[i].end = res[i].start;
- }
- }
+ chip->chip_pdev = chip->acp_plat_dev;
+ chip->dev = &chip->acp_plat_dev->dev;
- memset(&pdevinfo, 0, sizeof(pdevinfo));
-
- pdevinfo.name = chip->name;
- pdevinfo.id = 0;
- pdevinfo.parent = &pci->dev;
- pdevinfo.num_res = num_res;
- pdevinfo.res = &res[0];
- pdevinfo.data = chip;
- pdevinfo.size_data = sizeof(*chip);
-
- pdev = platform_device_register_full(&pdevinfo);
- if (IS_ERR(pdev)) {
- dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name);
- ret = PTR_ERR(pdev);
- goto unregister_dmic_dev;
- }
+ acp_machine_select(chip);
+ INIT_LIST_HEAD(&chip->stream_list);
+ spin_lock_init(&chip->acp_lock);
skip_pdev_creation:
- chip->chip_pdev = pdev;
dev_set_drvdata(&pci->dev, chip);
pm_runtime_set_autosuspend_delay(&pci->dev, 2000);
pm_runtime_use_autosuspend(&pci->dev);
@@ -165,8 +211,8 @@ skip_pdev_creation:
pm_runtime_allow(&pci->dev);
return ret;
-unregister_dmic_dev:
- platform_device_unregister(dmic_dev);
+de_init:
+ acp_hw_deinit(chip);
release_regions:
pci_release_regions(pci);
disable_pci:
@@ -175,41 +221,38 @@ disable_pci:
return ret;
};
-static int __maybe_unused snd_acp_suspend(struct device *dev)
+static int snd_acp_suspend(struct device *dev)
{
struct acp_chip_info *chip;
int ret;
chip = dev_get_drvdata(dev);
- ret = acp_deinit(chip);
+ ret = acp_hw_deinit(chip);
if (ret)
dev_err(dev, "ACP de-init failed\n");
return ret;
}
-static int __maybe_unused snd_acp_resume(struct device *dev)
+static int snd_acp_resume(struct device *dev)
{
struct acp_chip_info *chip;
- struct acp_dev_data *adata;
- struct device child;
int ret;
chip = dev_get_drvdata(dev);
- ret = acp_init(chip);
+ ret = acp_hw_init(chip);
if (ret)
dev_err(dev, "ACP init failed\n");
- if (chip->chip_pdev) {
- child = chip->chip_pdev->dev;
- adata = dev_get_drvdata(&child);
- if (adata)
- acp_enable_interrupts(adata);
- }
+
+ ret = acp_hw_en_interrupts(chip);
+ if (ret)
+ dev_err(dev, "ACP en-interrupts failed\n");
+
return ret;
}
static const struct dev_pm_ops acp_pm_ops = {
- SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume)
+ RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume)
};
static void acp_pci_remove(struct pci_dev *pci)
@@ -220,11 +263,14 @@ static void acp_pci_remove(struct pci_dev *pci)
chip = pci_get_drvdata(pci);
pm_runtime_forbid(&pci->dev);
pm_runtime_get_noresume(&pci->dev);
- if (dmic_dev)
- platform_device_unregister(dmic_dev);
- if (pdev)
- platform_device_unregister(pdev);
- ret = acp_deinit(chip);
+ if (chip->dmic_codec_dev)
+ platform_device_unregister(chip->dmic_codec_dev);
+ if (chip->acp_plat_dev)
+ platform_device_unregister(chip->acp_plat_dev);
+ if (chip->mach_dev)
+ platform_device_unregister(chip->mach_dev);
+
+ ret = acp_hw_deinit(chip);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
}
@@ -243,7 +289,7 @@ static struct pci_driver snd_amd_acp_pci_driver = {
.probe = acp_pci_probe,
.remove = acp_pci_remove,
.driver = {
- .pm = &acp_pm_ops,
+ .pm = pm_ptr(&acp_pm_ops),
},
};
module_pci_driver(snd_amd_acp_pci_driver);
diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c
index d4855da05b6a..1bfc34c2aa53 100644
--- a/sound/soc/amd/acp/acp-pdm.c
+++ b/sound/soc/amd/acp/acp-pdm.c
@@ -30,17 +30,16 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream,
{
struct acp_stream *stream = substream->runtime->private_data;
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
struct acp_chip_info *chip;
u32 physical_addr, size_dmic, period_bytes;
unsigned int dmic_ctrl;
chip = dev_get_platdata(dev);
/* Enable default DMIC clk */
- writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL);
- dmic_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL);
+ writel(PDM_CLK_FREQ_MASK, chip->base + ACP_WOV_CLK_CTRL);
+ dmic_ctrl = readl(chip->base + ACP_WOV_MISC_CTRL);
dmic_ctrl |= PDM_MISC_CTRL_MASK;
- writel(dmic_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL);
+ writel(dmic_ctrl, chip->base + ACP_WOV_MISC_CTRL);
period_bytes = frames_to_bytes(substream->runtime,
substream->runtime->period_size);
@@ -53,10 +52,10 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream,
physical_addr = stream->reg_offset + MEM_WINDOW_START;
/* Init DMIC Ring buffer */
- writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR);
- writel(size_dmic, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE);
- writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
- writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
+ writel(physical_addr, chip->base + ACP_WOV_RX_RINGBUFADDR);
+ writel(size_dmic, chip->base + ACP_WOV_RX_RINGBUFSIZE);
+ writel(period_bytes, chip->base + ACP_WOV_RX_INTR_WATERMARK_SIZE);
+ writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL);
return 0;
}
@@ -65,7 +64,7 @@ static int acp_dmic_dai_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
unsigned int dma_enable;
int ret = 0;
@@ -73,27 +72,27 @@ static int acp_dmic_dai_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- dma_enable = readl(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ dma_enable = readl(chip->base + ACP_WOV_PDM_DMA_ENABLE);
if (!(dma_enable & DMA_EN_MASK)) {
- writel(PDM_ENABLE, adata->acp_base + ACP_WOV_PDM_ENABLE);
- writel(PDM_ENABLE, adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ writel(PDM_ENABLE, chip->base + ACP_WOV_PDM_ENABLE);
+ writel(PDM_ENABLE, chip->base + ACP_WOV_PDM_DMA_ENABLE);
}
- ret = readl_poll_timeout_atomic(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE,
+ ret = readl_poll_timeout_atomic(chip->base + ACP_WOV_PDM_DMA_ENABLE,
dma_enable, (dma_enable & DMA_EN_MASK),
DELAY_US, PDM_TIMEOUT);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- dma_enable = readl(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ dma_enable = readl(chip->base + ACP_WOV_PDM_DMA_ENABLE);
if ((dma_enable & DMA_EN_MASK)) {
- writel(PDM_DISABLE, adata->acp_base + ACP_WOV_PDM_ENABLE);
- writel(PDM_DISABLE, adata->acp_base + ACP_WOV_PDM_DMA_ENABLE);
+ writel(PDM_DISABLE, chip->base + ACP_WOV_PDM_ENABLE);
+ writel(PDM_DISABLE, chip->base + ACP_WOV_PDM_DMA_ENABLE);
}
- ret = readl_poll_timeout_atomic(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE,
+ ret = readl_poll_timeout_atomic(chip->base + ACP_WOV_PDM_DMA_ENABLE,
dma_enable, !(dma_enable & DMA_EN_MASK),
DELAY_US, PDM_TIMEOUT);
break;
@@ -109,7 +108,7 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hwparams, struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
unsigned int channels, ch_mask;
channels = params_channels(hwparams);
@@ -128,14 +127,14 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream,
return -EINVAL;
}
- adata->ch_mask = ch_mask;
+ chip->ch_mask = ch_mask;
if (params_format(hwparams) != SNDRV_PCM_FORMAT_S32_LE) {
dev_err(dai->dev, "Invalid format:%d\n", params_format(hwparams));
return -EINVAL;
}
- writel(ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS);
- writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR);
+ writel(ch_mask, chip->base + ACP_WOV_PDM_NO_OF_CHANNELS);
+ writel(PDM_DEC_64, chip->base + ACP_WOV_PDM_DECIMATION_FACTOR);
return 0;
}
@@ -145,7 +144,7 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream,
{
struct acp_stream *stream = substream->runtime->private_data;
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
u32 ext_int_ctrl;
stream->dai_id = DMIC_INSTANCE;
@@ -154,9 +153,9 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream,
stream->reg_offset = ACP_REGION2_OFFSET;
/* Enable DMIC Interrupts */
- ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));
+ ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0));
ext_int_ctrl |= PDM_DMA_INTR_MASK;
- writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));
+ writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0));
return 0;
}
@@ -165,13 +164,13 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct device *dev = dai->component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
u32 ext_int_ctrl;
/* Disable DMIC interrupts */
- ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0));
+ ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0));
ext_int_ctrl &= ~PDM_DMA_INTR_MASK;
- writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0));
+ writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0));
}
const struct snd_soc_dai_ops acp_dmic_dai_ops = {
diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c
index aa330aeeb301..b3eddf76aaa4 100644
--- a/sound/soc/amd/acp/acp-platform.c
+++ b/sound/soc/amd/acp/acp-platform.c
@@ -21,7 +21,6 @@
#include <linux/dma-mapping.h>
#include "amd.h"
-#include "../mach-config.h"
#include "acp-mach.h"
#define DRV_NAME "acp_i2s_dma"
@@ -108,101 +107,37 @@ static const struct snd_pcm_hardware acp6x_pcm_hardware_capture = {
.periods_max = CAPTURE_MAX_NUM_PERIODS,
};
-int acp_machine_select(struct acp_dev_data *adata)
+void config_pte_for_stream(struct acp_chip_info *chip, struct acp_stream *stream)
{
- struct snd_soc_acpi_mach *mach;
- int size, platform;
-
- if (adata->flag == FLAG_AMD_LEGACY_ONLY_DMIC) {
- platform = adata->acp_rev;
- adata->mach_dev = platform_device_register_data(adata->dev, "acp-pdm-mach",
- PLATFORM_DEVID_NONE, &platform,
- sizeof(platform));
- } else {
- size = sizeof(*adata->machines);
- mach = snd_soc_acpi_find_machine(adata->machines);
- if (!mach) {
- dev_err(adata->dev, "warning: No matching ASoC machine driver found\n");
- return -EINVAL;
- }
- mach->mach_params.subsystem_rev = adata->acp_rev;
- adata->mach_dev = platform_device_register_data(adata->dev, mach->drv_name,
- PLATFORM_DEVID_NONE, mach, size);
- }
- if (IS_ERR(adata->mach_dev))
- dev_warn(adata->dev, "Unable to register Machine device\n");
- return 0;
-}
-EXPORT_SYMBOL_NS_GPL(acp_machine_select, "SND_SOC_ACP_COMMON");
-
-static irqreturn_t i2s_irq_handler(int irq, void *data)
-{
- struct acp_dev_data *adata = data;
- struct acp_resource *rsrc = adata->rsrc;
- struct acp_stream *stream;
- u16 i2s_flag = 0;
- u32 ext_intr_stat, ext_intr_stat1;
-
- if (adata->rsrc->no_of_ctrls == 2)
- ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1)));
-
- ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
-
- spin_lock(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
- if (ext_intr_stat & stream->irq_bit) {
- writel(stream->irq_bit,
- ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
- snd_pcm_period_elapsed(stream->substream);
- i2s_flag = 1;
- }
- if (adata->rsrc->no_of_ctrls == 2) {
- if (ext_intr_stat1 & stream->irq_bit) {
- writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata,
- (rsrc->irqp_used - 1)));
- snd_pcm_period_elapsed(stream->substream);
- i2s_flag = 1;
- }
- }
- }
- spin_unlock(&adata->acp_lock);
- if (i2s_flag)
- return IRQ_HANDLED;
-
- return IRQ_NONE;
-}
-
-void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream)
-{
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_resource *rsrc = chip->rsrc;
u32 reg_val;
reg_val = rsrc->sram_pte_offset;
stream->reg_offset = 0x02000000;
- writel((reg_val + GRP1_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
- writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
+ writel((reg_val + GRP1_OFFSET) | BIT(31), chip->base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1);
+ writel(PAGE_SIZE_4K_ENABLE, chip->base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1);
- writel((reg_val + GRP2_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2);
- writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2);
+ writel((reg_val + GRP2_OFFSET) | BIT(31), chip->base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2);
+ writel(PAGE_SIZE_4K_ENABLE, chip->base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2);
- writel(reg_val | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5);
- writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5);
+ writel(reg_val | BIT(31), chip->base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5);
+ writel(PAGE_SIZE_4K_ENABLE, chip->base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5);
- writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
+ writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL);
}
EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, "SND_SOC_ACP_COMMON");
-void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size)
+void config_acp_dma(struct acp_chip_info *chip, struct acp_stream *stream, int size)
{
struct snd_pcm_substream *substream = stream->substream;
- struct acp_resource *rsrc = adata->rsrc;
+ struct acp_resource *rsrc = chip->rsrc;
dma_addr_t addr = substream->dma_buffer.addr;
int num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
u32 low, high, val;
u16 page_idx;
- switch (adata->acp_rev) {
+ switch (chip->acp_rev) {
case ACP70_PCI_ID:
case ACP71_PCI_ID:
switch (stream->dai_id) {
@@ -228,7 +163,7 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s
val = 0x6000;
break;
default:
- dev_err(adata->dev, "Invalid dai id %x\n", stream->dai_id);
+ dev_err(chip->dev, "Invalid dai id %x\n", stream->dai_id);
return;
}
break;
@@ -241,9 +176,9 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s
/* Load the low address of page int ACP SRAM through SRBM */
low = lower_32_bits(addr);
high = upper_32_bits(addr);
- writel(low, adata->acp_base + rsrc->scratch_reg_offset + val);
+ writel(low, chip->base + rsrc->scratch_reg_offset + val);
high |= BIT(31);
- writel(high, adata->acp_base + rsrc->scratch_reg_offset + val + 4);
+ writel(high, chip->base + rsrc->scratch_reg_offset + val + 4);
/* Move to next physically contiguous page */
val += 8;
@@ -256,7 +191,6 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct device *dev = component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
struct acp_chip_info *chip;
struct acp_stream *stream;
int ret;
@@ -266,7 +200,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
return -ENOMEM;
stream->substream = substream;
- chip = dev_get_platdata(dev);
+ chip = dev_get_drvdata(dev->parent);
switch (chip->acp_rev) {
case ACP63_PCI_ID:
case ACP70_PCI_ID:
@@ -306,11 +240,11 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs
}
runtime->private_data = stream;
- writel(1, ACP_EXTERNAL_INTR_ENB(adata));
+ writel(1, ACP_EXTERNAL_INTR_ENB(chip));
- spin_lock_irq(&adata->acp_lock);
- list_add_tail(&stream->list, &adata->stream_list);
- spin_unlock_irq(&adata->acp_lock);
+ spin_lock_irq(&chip->acp_lock);
+ list_add_tail(&stream->list, &chip->stream_list);
+ spin_unlock_irq(&chip->acp_lock);
return ret;
}
@@ -319,13 +253,14 @@ static int acp_dma_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct acp_dev_data *adata = snd_soc_component_get_drvdata(component);
+ struct device *dev = component->dev;
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
struct acp_stream *stream = substream->runtime->private_data;
u64 size = params_buffer_bytes(params);
/* Configure ACP DMA block with params */
- config_pte_for_stream(adata, stream);
- config_acp_dma(adata, stream, size);
+ config_pte_for_stream(chip, stream);
+ config_acp_dma(chip, stream, size);
return 0;
}
@@ -334,7 +269,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct device *dev = component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
struct acp_stream *stream = substream->runtime->private_data;
u32 pos, buffersize;
u64 bytescount;
@@ -342,7 +277,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component,
buffersize = frames_to_bytes(substream->runtime,
substream->runtime->buffer_size);
- bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream);
+ bytescount = acp_get_byte_count(chip, stream->dai_id, substream->stream);
if (bytescount > stream->bytescount)
bytescount -= stream->bytescount;
@@ -366,13 +301,13 @@ static int acp_dma_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct device *dev = component->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_drvdata(dev->parent);
struct acp_stream *stream = substream->runtime->private_data;
/* Remove entry from list */
- spin_lock_irq(&adata->acp_lock);
+ spin_lock_irq(&chip->acp_lock);
list_del(&stream->list);
- spin_unlock_irq(&adata->acp_lock);
+ spin_unlock_irq(&chip->acp_lock);
kfree(stream);
return 0;
@@ -390,38 +325,30 @@ static const struct snd_soc_component_driver acp_pcm_component = {
int acp_platform_register(struct device *dev)
{
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip;
struct snd_soc_dai_driver;
unsigned int status;
- status = devm_request_irq(dev, adata->i2s_irq, i2s_irq_handler,
- IRQF_SHARED, "ACP_I2S_IRQ", adata);
- if (status) {
- dev_err(dev, "ACP I2S IRQ request failed\n");
- return status;
+ chip = dev_get_platdata(dev);
+ if (!chip || !chip->base) {
+ dev_err(dev, "ACP chip data is NULL\n");
+ return -ENODEV;
}
status = devm_snd_soc_register_component(dev, &acp_pcm_component,
- adata->dai_driver,
- adata->num_dai);
+ chip->dai_driver,
+ chip->num_dai);
if (status) {
dev_err(dev, "Fail to register acp i2s component\n");
return status;
}
- INIT_LIST_HEAD(&adata->stream_list);
- spin_lock_init(&adata->acp_lock);
-
return 0;
}
EXPORT_SYMBOL_NS_GPL(acp_platform_register, "SND_SOC_ACP_COMMON");
int acp_platform_unregister(struct device *dev)
{
- struct acp_dev_data *adata = dev_get_drvdata(dev);
-
- if (adata->mach_dev)
- platform_device_unregister(adata->mach_dev);
return 0;
}
EXPORT_SYMBOL_NS_GPL(acp_platform_unregister, "SND_SOC_ACP_COMMON");
diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c
index 2648256fa129..746b6ed72029 100644
--- a/sound/soc/amd/acp/acp-rembrandt.c
+++ b/sound/soc/amd/acp/acp-rembrandt.c
@@ -22,6 +22,8 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <asm/amd_node.h>
+
#include "amd.h"
#include "../mach-config.h"
#include "acp-mach.h"
@@ -31,47 +33,6 @@
#define MP1_C2PMSG_69 0x3B10A14
#define MP1_C2PMSG_85 0x3B10A54
#define MP1_C2PMSG_93 0x3B10A74
-#define HOST_BRIDGE_ID 0x14B5
-
-static struct acp_resource rsrc = {
- .offset = 0,
- .no_of_ctrls = 2,
- .irqp_used = 1,
- .soc_mclk = true,
- .irq_reg_offset = 0x1a00,
- .scratch_reg_offset = 0x12800,
- .sram_pte_offset = 0x03802800,
-};
-
-static struct snd_soc_acpi_codecs amp_rt1019 = {
- .num_codecs = 1,
- .codecs = {"10EC1019"}
-};
-
-static struct snd_soc_acpi_codecs amp_max = {
- .num_codecs = 1,
- .codecs = {"MX98360A"}
-};
-
-static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = {
- {
- .id = "10508825",
- .drv_name = "rmb-nau8825-max",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &amp_max,
- },
- {
- .id = "AMDI0007",
- .drv_name = "rembrandt-acp",
- },
- {
- .id = "RTL5682",
- .drv_name = "rmb-rt5682s-rt1019",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &amp_rt1019,
- },
- {},
-};
static struct snd_soc_dai_driver acp_rmb_dai[] = {
{
@@ -166,29 +127,26 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = {
static int acp6x_master_clock_generate(struct device *dev)
{
- int data = 0;
- struct pci_dev *smn_dev;
-
- smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL);
- if (!smn_dev) {
- dev_err(dev, "Failed to get host bridge device\n");
- return -ENODEV;
- }
-
- smn_write(smn_dev, MP1_C2PMSG_93, 0);
- smn_write(smn_dev, MP1_C2PMSG_85, 0xC4);
- smn_write(smn_dev, MP1_C2PMSG_69, 0x4);
- read_poll_timeout(smn_read, data, data, DELAY_US,
- ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93);
- return 0;
+ int data, rc;
+
+ rc = amd_smn_write(0, MP1_C2PMSG_93, 0);
+ if (rc)
+ return rc;
+ rc = amd_smn_write(0, MP1_C2PMSG_85, 0xC4);
+ if (rc)
+ return rc;
+ rc = amd_smn_write(0, MP1_C2PMSG_69, 0x4);
+ if (rc)
+ return rc;
+
+ return read_poll_timeout(smn_read_register, data, data > 0, DELAY_US,
+ ACP_TIMEOUT, false, MP1_C2PMSG_93);
}
static int rembrandt_audio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acp_chip_info *chip;
- struct acp_dev_data *adata;
- struct resource *res;
u32 ret;
chip = dev_get_platdata(&pdev->dev);
@@ -202,45 +160,20 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
return -ENODEV;
}
- adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
- if (!adata)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
- return -ENODEV;
- }
-
- adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!adata->acp_base)
- return -ENOMEM;
+ chip->dev = dev;
+ chip->dai_driver = acp_rmb_dai;
+ chip->num_dai = ARRAY_SIZE(acp_rmb_dai);
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
-
- adata->i2s_irq = res->start;
- adata->dev = dev;
- adata->dai_driver = acp_rmb_dai;
- adata->num_dai = ARRAY_SIZE(acp_rmb_dai);
- adata->rsrc = &rsrc;
- adata->acp_rev = chip->acp_rev;
- adata->flag = chip->flag;
- adata->is_i2s_config = chip->is_i2s_config;
- adata->machines = snd_soc_acpi_amd_rmb_acp_machines;
- acp_machine_select(adata);
-
- dev_set_drvdata(dev, adata);
-
- if (chip->is_i2s_config && rsrc.soc_mclk) {
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk) {
ret = acp6x_master_clock_generate(dev);
if (ret)
return ret;
}
- acp_enable_interrupts(adata);
+ ret = acp_hw_en_interrupts(chip);
+ if (ret) {
+ dev_err(dev, "ACP en-interrupts failed\n");
+ return ret;
+ }
acp_platform_register(dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -253,44 +186,48 @@ static int rembrandt_audio_probe(struct platform_device *pdev)
static void rembrandt_audio_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ int ret;
+
+ ret = acp_hw_dis_interrupts(chip);
+ if (ret)
+ dev_err(dev, "ACP dis-interrupts failed\n");
- acp_disable_interrupts(adata);
acp_platform_unregister(dev);
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused rmb_pcm_resume(struct device *dev)
+static int rmb_pcm_resume(struct device *dev)
{
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
struct acp_stream *stream;
struct snd_pcm_substream *substream;
snd_pcm_uframes_t buf_in_frames;
u64 buf_size;
- if (adata->is_i2s_config && adata->rsrc->soc_mclk)
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk)
acp6x_master_clock_generate(dev);
- spin_lock(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
+ spin_lock(&chip->acp_lock);
+ list_for_each_entry(stream, &chip->stream_list, list) {
substream = stream->substream;
if (substream && substream->runtime) {
buf_in_frames = (substream->runtime->buffer_size);
buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
- config_pte_for_stream(adata, stream);
- config_acp_dma(adata, stream, buf_size);
+ config_pte_for_stream(chip, stream);
+ config_acp_dma(chip, stream, buf_size);
if (stream->dai_id)
- restore_acp_i2s_params(substream, adata, stream);
+ restore_acp_i2s_params(substream, chip, stream);
else
- restore_acp_pdm_params(substream, adata);
+ restore_acp_pdm_params(substream, chip);
}
}
- spin_unlock(&adata->acp_lock);
+ spin_unlock(&chip->acp_lock);
return 0;
}
static const struct dev_pm_ops rmb_dma_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume)
+ SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume)
};
static struct platform_driver rembrandt_driver = {
@@ -298,7 +235,7 @@ static struct platform_driver rembrandt_driver = {
.remove = rembrandt_audio_remove,
.driver = {
.name = "acp_asoc_rembrandt",
- .pm = &rmb_dma_pm_ops,
+ .pm = pm_ptr(&rmb_dma_pm_ops),
},
};
diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c
index ca2b74283d8f..ebf0106fc737 100644
--- a/sound/soc/amd/acp/acp-renoir.c
+++ b/sound/soc/amd/acp/acp-renoir.c
@@ -27,55 +27,6 @@
#define DRV_NAME "acp_asoc_renoir"
-static struct acp_resource rsrc = {
- .offset = 20,
- .no_of_ctrls = 1,
- .irqp_used = 0,
- .irq_reg_offset = 0x1800,
- .scratch_reg_offset = 0x12800,
- .sram_pte_offset = 0x02052800,
-};
-
-static struct snd_soc_acpi_codecs amp_rt1019 = {
- .num_codecs = 1,
- .codecs = {"10EC1019"}
-};
-
-static struct snd_soc_acpi_codecs amp_max = {
- .num_codecs = 1,
- .codecs = {"MX98360A"}
-};
-
-static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = {
- {
- .id = "10EC5682",
- .drv_name = "acp3xalc56821019",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &amp_rt1019,
- },
- {
- .id = "RTL5682",
- .drv_name = "acp3xalc5682sm98360",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &amp_max,
- },
- {
- .id = "RTL5682",
- .drv_name = "acp3xalc5682s1019",
- .machine_quirk = snd_soc_acpi_codec_list,
- .quirk_data = &amp_rt1019,
- },
- {
- .id = "AMDI1019",
- .drv_name = "renoir-acp",
- },
- {
- .id = "ESSX8336",
- .drv_name = "acp3x-es83xx",
- },
- {},
-};
-
static struct snd_soc_dai_driver acp_renoir_dai[] = {
{
.name = "acp-i2s-sp",
@@ -147,8 +98,6 @@ static int renoir_audio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acp_chip_info *chip;
- struct acp_dev_data *adata;
- struct resource *res;
int ret;
chip = dev_get_platdata(&pdev->dev);
@@ -162,37 +111,16 @@ static int renoir_audio_probe(struct platform_device *pdev)
return -ENODEV;
}
- adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
- if (!adata)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
- return -ENODEV;
- }
-
- adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!adata->acp_base)
- return -ENOMEM;
+ chip->dev = dev;
+ chip->dai_driver = acp_renoir_dai;
+ chip->num_dai = ARRAY_SIZE(acp_renoir_dai);
- ret = platform_get_irq_byname(pdev, "acp_dai_irq");
- if (ret < 0)
+ ret = acp_hw_en_interrupts(chip);
+ if (ret) {
+ dev_err(dev, "ACP en-interrupts failed\n");
return ret;
- adata->i2s_irq = ret;
-
- adata->dev = dev;
- adata->dai_driver = acp_renoir_dai;
- adata->num_dai = ARRAY_SIZE(acp_renoir_dai);
- adata->rsrc = &rsrc;
- adata->acp_rev = chip->acp_rev;
- adata->flag = chip->flag;
-
- adata->machines = snd_soc_acpi_amd_acp_machines;
- acp_machine_select(adata);
+ }
- dev_set_drvdata(dev, adata);
- acp_enable_interrupts(adata);
acp_platform_register(dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
@@ -206,40 +134,44 @@ static int renoir_audio_probe(struct platform_device *pdev)
static void renoir_audio_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ int ret;
+
+ ret = acp_hw_dis_interrupts(chip);
+ if (ret)
+ dev_err(dev, "ACP dis-interrupts failed\n");
- acp_disable_interrupts(adata);
acp_platform_unregister(dev);
}
-static int __maybe_unused rn_pcm_resume(struct device *dev)
+static int rn_pcm_resume(struct device *dev)
{
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
struct acp_stream *stream;
struct snd_pcm_substream *substream;
snd_pcm_uframes_t buf_in_frames;
u64 buf_size;
- spin_lock(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
+ spin_lock(&chip->acp_lock);
+ list_for_each_entry(stream, &chip->stream_list, list) {
substream = stream->substream;
if (substream && substream->runtime) {
buf_in_frames = (substream->runtime->buffer_size);
buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
- config_pte_for_stream(adata, stream);
- config_acp_dma(adata, stream, buf_size);
+ config_pte_for_stream(chip, stream);
+ config_acp_dma(chip, stream, buf_size);
if (stream->dai_id)
- restore_acp_i2s_params(substream, adata, stream);
+ restore_acp_i2s_params(substream, chip, stream);
else
- restore_acp_pdm_params(substream, adata);
+ restore_acp_pdm_params(substream, chip);
}
}
- spin_unlock(&adata->acp_lock);
+ spin_unlock(&chip->acp_lock);
return 0;
}
static const struct dev_pm_ops rn_dma_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, rn_pcm_resume)
+ SYSTEM_SLEEP_PM_OPS(NULL, rn_pcm_resume)
};
static struct platform_driver renoir_driver = {
@@ -247,7 +179,7 @@ static struct platform_driver renoir_driver = {
.remove = renoir_audio_remove,
.driver = {
.name = "acp_asoc_renoir",
- .pm = &rn_dma_pm_ops,
+ .pm = pm_ptr(&rn_dma_pm_ops),
},
};
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index 9280cd30d19c..2020c5cfb3d5 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -28,6 +28,8 @@ static void log_quirks(struct device *dev)
SOC_JACK_JDSRC(soc_sdw_quirk));
if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC)
dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n");
+ if (soc_sdw_quirk & ASOC_SDW_CODEC_SPKR)
+ dev_dbg(dev, "quirk ASOC_SDW_CODEC_SPKR enabled\n");
}
static int soc_sdw_quirk_cb(const struct dmi_system_id *id)
@@ -45,6 +47,38 @@ static const struct dmi_system_id soc_sdw_quirk_table[] = {
},
.driver_data = (void *)RT711_JD2,
},
+ {
+ .callback = soc_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D80"),
+ },
+ .driver_data = (void *)(ASOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = soc_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D81"),
+ },
+ .driver_data = (void *)(ASOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = soc_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D82"),
+ },
+ .driver_data = (void *)(ASOC_SDW_CODEC_SPKR),
+ },
+ {
+ .callback = soc_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D83"),
+ },
+ .driver_data = (void *)(ASOC_SDW_CODEC_SPKR),
+ },
{}
};
@@ -122,6 +156,13 @@ static int create_sdw_dailink(struct snd_soc_card *card,
if (ret)
return ret;
break;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ ret = get_acp70_cpu_pin_id(ffs(soc_end->link_mask - 1),
+ *be_id, &cpu_pin_id, dev);
+ if (ret)
+ return ret;
+ break;
default:
return -EINVAL;
}
@@ -221,6 +262,8 @@ static int create_sdw_dailinks(struct snd_soc_card *card,
switch (amd_ctx->acp_rev) {
case ACP63_PCI_REV:
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
sdw_platform_component->name = "amd_ps_sdw_dma.0";
break;
default:
@@ -266,6 +309,8 @@ static int create_dmic_dailinks(struct snd_soc_card *card,
switch (amd_ctx->acp_rev) {
case ACP63_PCI_REV:
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
pdm_cpu->name = "acp_ps_pdm_dma.0";
pdm_platform->name = "acp_ps_pdm_dma.0";
break;
diff --git a/sound/soc/amd/acp/acp-sdw-mach-common.c b/sound/soc/amd/acp/acp-sdw-mach-common.c
index 6f5c39ed1a18..e5f394dc2f4c 100644
--- a/sound/soc/amd/acp/acp-sdw-mach-common.c
+++ b/sound/soc/amd/acp/acp-sdw-mach-common.c
@@ -59,6 +59,40 @@ int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct dev
}
EXPORT_SYMBOL_NS_GPL(get_acp63_cpu_pin_id, "SND_SOC_AMD_SDW_MACH");
+int get_acp70_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev)
+{
+ switch (sdw_link_id) {
+ case AMD_SDW0:
+ case AMD_SDW1:
+ switch (be_id) {
+ case SOC_SDW_JACK_OUT_DAI_ID:
+ *cpu_pin_id = ACP70_SW_AUDIO0_TX;
+ break;
+ case SOC_SDW_JACK_IN_DAI_ID:
+ *cpu_pin_id = ACP70_SW_AUDIO0_RX;
+ break;
+ case SOC_SDW_AMP_OUT_DAI_ID:
+ *cpu_pin_id = ACP70_SW_AUDIO1_TX;
+ break;
+ case SOC_SDW_AMP_IN_DAI_ID:
+ *cpu_pin_id = ACP70_SW_AUDIO1_RX;
+ break;
+ case SOC_SDW_DMIC_DAI_ID:
+ *cpu_pin_id = ACP70_SW_AUDIO2_RX;
+ break;
+ default:
+ dev_err(dev, "Invalid be id:%d\n", be_id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ dev_dbg(dev, "sdw_link_id:%d, be_id:%d, cpu_pin_id:%d\n", sdw_link_id, be_id, *cpu_pin_id);
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(get_acp70_cpu_pin_id, "SND_SOC_AMD_SDW_MACH");
+
MODULE_DESCRIPTION("AMD SoundWire Common Machine driver");
MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
index 2b0aa270a3e9..eb5d4a5baef2 100644
--- a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
+++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
+#include <linux/string_choices.h>
#include "../acp-mach.h"
#include "acp3x-es83xx.h"
@@ -241,9 +242,9 @@ static int acp3x_es83xx_configure_gpios(struct acp3x_es83xx_private *priv)
dev_info(priv->codec_dev, "speaker gpio %d active %s, headphone gpio %d active %s\n",
priv->enable_spk_gpio.crs_entry_index,
- priv->enable_spk_gpio.active_low ? "low" : "high",
+ str_low_high(priv->enable_spk_gpio.active_low),
priv->enable_hp_gpio.crs_entry_index,
- priv->enable_hp_gpio.active_low ? "low" : "high");
+ str_low_high(priv->enable_hp_gpio.active_low));
return 0;
}
diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c
index 81496e713440..52d895e624c7 100644
--- a/sound/soc/amd/acp/acp63.c
+++ b/sound/soc/amd/acp/acp63.c
@@ -20,6 +20,9 @@
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/pci.h>
+
+#include <asm/amd_node.h>
+
#include "amd.h"
#include "acp-mach.h"
#include "../mach-config.h"
@@ -49,24 +52,6 @@ union clk_pll_req_no {
u32 clk_pll_req_no_reg;
};
-static struct acp_resource rsrc = {
- .offset = 0,
- .no_of_ctrls = 2,
- .irqp_used = 1,
- .soc_mclk = true,
- .irq_reg_offset = 0x1a00,
- .scratch_reg_offset = 0x12800,
- .sram_pte_offset = 0x03802800,
-};
-
-static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[] = {
- {
- .id = "AMDI0052",
- .drv_name = "acp63-acp",
- },
- {},
-};
-
static struct snd_soc_dai_driver acp63_dai[] = {
{
.name = "acp-i2s-sp",
@@ -158,47 +143,61 @@ static struct snd_soc_dai_driver acp63_dai[] = {
},
};
-static int acp63_i2s_master_clock_generate(struct acp_dev_data *adata)
+static int acp63_i2s_master_clock_generate(struct acp_chip_info *chip)
{
+ int rc;
u32 data;
union clk_pll_req_no clk_pll;
- struct pci_dev *smn_dev;
-
- smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x14E8, NULL);
- if (!smn_dev)
- return -ENODEV;
/* Clk5 pll register values to get mclk as 196.6MHz*/
clk_pll.bits.fb_mult_int = 0x31;
clk_pll.bits.pll_spine_div = 0;
clk_pll.bits.gb_mult_frac = 0x26E9;
- data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0);
- smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ);
-
- data = smn_read(smn_dev, CLK_SPLL_FIELD_2_N0);
- if (data & PLL_FRANCE_EN)
- smn_write(smn_dev, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN);
-
- smn_write(smn_dev, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg);
-
- data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0);
- smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ);
-
- data = smn_read(smn_dev, CLK_DFSBYPASS_CONTR);
- smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0);
- smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1);
+ rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data);
+ if (rc)
+ return rc;
+ rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ);
+ if (rc)
+ return rc;
+
+ rc = amd_smn_read(0, CLK_SPLL_FIELD_2_N0, &data);
+ if (rc)
+ return rc;
+ if (data & PLL_FRANCE_EN) {
+ rc = amd_smn_write(0, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN);
+ if (rc)
+ return rc;
+ }
- smn_write(smn_dev, CLK_DFS_CNTL_N0, CLK0_DIVIDER);
- return 0;
+ rc = amd_smn_write(0, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg);
+ if (rc)
+ return rc;
+
+ rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data);
+ if (rc)
+ return rc;
+ rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ);
+ if (rc)
+ return rc;
+
+ rc = amd_smn_read(0, CLK_DFSBYPASS_CONTR, &data);
+ if (rc)
+ return rc;
+ rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0);
+ if (rc)
+ return rc;
+ rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1);
+ if (rc)
+ return rc;
+
+ return amd_smn_write(0, CLK_DFS_CNTL_N0, CLK0_DIVIDER);
}
static int acp63_audio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acp_chip_info *chip;
- struct acp_dev_data *adata;
- struct resource *res;
int ret;
chip = dev_get_platdata(&pdev->dev);
@@ -212,44 +211,20 @@ static int acp63_audio_probe(struct platform_device *pdev)
return -ENODEV;
}
- adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
- if (!adata)
- return -ENOMEM;
+ chip->dev = dev;
+ chip->dai_driver = acp63_dai;
+ chip->num_dai = ARRAY_SIZE(acp63_dai);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
- return -ENODEV;
- }
-
- adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!adata->acp_base)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
-
- adata->i2s_irq = res->start;
- adata->dev = dev;
- adata->dai_driver = acp63_dai;
- adata->num_dai = ARRAY_SIZE(acp63_dai);
- adata->rsrc = &rsrc;
- adata->acp_rev = chip->acp_rev;
- adata->flag = chip->flag;
- adata->is_i2s_config = chip->is_i2s_config;
- adata->machines = snd_soc_acpi_amd_acp63_acp_machines;
- acp_machine_select(adata);
- dev_set_drvdata(dev, adata);
-
- if (chip->is_i2s_config && rsrc.soc_mclk) {
- ret = acp63_i2s_master_clock_generate(adata);
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk) {
+ ret = acp63_i2s_master_clock_generate(chip);
if (ret)
return ret;
}
- acp_enable_interrupts(adata);
+ ret = acp_hw_en_interrupts(chip);
+ if (ret) {
+ dev_err(dev, "ACP en-interrupts failed\n");
+ return ret;
+ }
acp_platform_register(dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -262,44 +237,48 @@ static int acp63_audio_probe(struct platform_device *pdev)
static void acp63_audio_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ int ret;
+
+ ret = acp_hw_dis_interrupts(chip);
+ if (ret)
+ dev_err(dev, "ACP dis-interrupts failed\n");
- acp_disable_interrupts(adata);
acp_platform_unregister(dev);
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused acp63_pcm_resume(struct device *dev)
+static int acp63_pcm_resume(struct device *dev)
{
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
struct acp_stream *stream;
struct snd_pcm_substream *substream;
snd_pcm_uframes_t buf_in_frames;
u64 buf_size;
- if (adata->is_i2s_config && adata->rsrc->soc_mclk)
- acp63_i2s_master_clock_generate(adata);
+ if (chip->is_i2s_config && chip->rsrc->soc_mclk)
+ acp63_i2s_master_clock_generate(chip);
- spin_lock(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
+ spin_lock(&chip->acp_lock);
+ list_for_each_entry(stream, &chip->stream_list, list) {
substream = stream->substream;
if (substream && substream->runtime) {
buf_in_frames = (substream->runtime->buffer_size);
buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
- config_pte_for_stream(adata, stream);
- config_acp_dma(adata, stream, buf_size);
+ config_pte_for_stream(chip, stream);
+ config_acp_dma(chip, stream, buf_size);
if (stream->dai_id)
- restore_acp_i2s_params(substream, adata, stream);
+ restore_acp_i2s_params(substream, chip, stream);
else
- restore_acp_pdm_params(substream, adata);
+ restore_acp_pdm_params(substream, chip);
}
}
- spin_unlock(&adata->acp_lock);
+ spin_unlock(&chip->acp_lock);
return 0;
}
static const struct dev_pm_ops acp63_dma_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume)
+ SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume)
};
static struct platform_driver acp63_driver = {
@@ -307,7 +286,7 @@ static struct platform_driver acp63_driver = {
.remove = acp63_audio_remove,
.driver = {
.name = "acp_asoc_acp63",
- .pm = &acp63_dma_pm_ops,
+ .pm = pm_ptr(&acp63_dma_pm_ops),
},
};
diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c
index 9e23729fd1a7..6d5f5ade075c 100644
--- a/sound/soc/amd/acp/acp70.c
+++ b/sound/soc/amd/acp/acp70.c
@@ -23,29 +23,13 @@
#include "amd.h"
#include "acp-mach.h"
+#include <asm/amd_node.h>
+
#define DRV_NAME "acp_asoc_acp70"
#define CLK7_CLK0_DFS_CNTL_N1 0X0006C1A4
#define CLK0_DIVIDER 0X19
-static struct acp_resource rsrc = {
- .offset = 0,
- .no_of_ctrls = 2,
- .irqp_used = 1,
- .soc_mclk = true,
- .irq_reg_offset = 0x1a00,
- .scratch_reg_offset = 0x10000,
- .sram_pte_offset = 0x03800000,
-};
-
-static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[] = {
- {
- .id = "AMDI0029",
- .drv_name = "acp70-acp",
- },
- {},
-};
-
static struct snd_soc_dai_driver acp70_dai[] = {
{
.name = "acp-i2s-sp",
@@ -137,35 +121,10 @@ static struct snd_soc_dai_driver acp70_dai[] = {
},
};
-static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata)
-{
- struct pci_dev *smn_dev;
- u32 device_id;
-
- if (adata->acp_rev == ACP70_PCI_ID)
- device_id = 0x1507;
- else if (adata->acp_rev == ACP71_PCI_ID)
- device_id = 0x1122;
- else
- return -ENODEV;
-
- smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, device_id, NULL);
-
- if (!smn_dev)
- return -ENODEV;
-
- /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/
- smn_write(smn_dev, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER);
-
- return 0;
-}
-
static int acp_acp70_audio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct acp_chip_info *chip;
- struct acp_dev_data *adata;
- struct resource *res;
int ret;
chip = dev_get_platdata(&pdev->dev);
@@ -183,44 +142,21 @@ static int acp_acp70_audio_probe(struct platform_device *pdev)
return -ENODEV;
}
- adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
- if (!adata)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
- return -ENODEV;
- }
-
- adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!adata->acp_base)
- return -ENOMEM;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
- if (!res) {
- dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
- return -ENODEV;
- }
-
- adata->i2s_irq = res->start;
- adata->dev = dev;
- adata->dai_driver = acp70_dai;
- adata->num_dai = ARRAY_SIZE(acp70_dai);
- adata->rsrc = &rsrc;
- adata->machines = snd_soc_acpi_amd_acp70_acp_machines;
- adata->acp_rev = chip->acp_rev;
- adata->flag = chip->flag;
- acp_machine_select(adata);
-
- dev_set_drvdata(dev, adata);
+ chip->dev = dev;
+ chip->dai_driver = acp70_dai;
+ chip->num_dai = ARRAY_SIZE(acp70_dai);
- ret = acp70_i2s_master_clock_generate(adata);
+ /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/
+ ret = amd_smn_write(0, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER);
if (ret) {
dev_err(&pdev->dev, "Failed to set I2S master clock as 196.608MHz\n");
return ret;
}
- acp_enable_interrupts(adata);
+ ret = acp_hw_en_interrupts(chip);
+ if (ret) {
+ dev_err(dev, "ACP en-interrupts failed\n");
+ return ret;
+ }
acp_platform_register(dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -233,43 +169,45 @@ static int acp_acp70_audio_probe(struct platform_device *pdev)
static void acp_acp70_audio_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
+ int ret;
+
+ ret = acp_hw_dis_interrupts(chip);
+ if (ret)
+ dev_err(dev, "ACP dis-interrupts failed\n");
- acp_disable_interrupts(adata);
acp_platform_unregister(dev);
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused acp70_pcm_resume(struct device *dev)
+static int acp70_pcm_resume(struct device *dev)
{
- struct acp_dev_data *adata = dev_get_drvdata(dev);
+ struct acp_chip_info *chip = dev_get_platdata(dev);
struct acp_stream *stream;
struct snd_pcm_substream *substream;
snd_pcm_uframes_t buf_in_frames;
u64 buf_size;
- spin_lock(&adata->acp_lock);
- list_for_each_entry(stream, &adata->stream_list, list) {
- if (stream) {
- substream = stream->substream;
- if (substream && substream->runtime) {
- buf_in_frames = (substream->runtime->buffer_size);
- buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
- config_pte_for_stream(adata, stream);
- config_acp_dma(adata, stream, buf_size);
- if (stream->dai_id)
- restore_acp_i2s_params(substream, adata, stream);
- else
- restore_acp_pdm_params(substream, adata);
- }
+ spin_lock(&chip->acp_lock);
+ list_for_each_entry(stream, &chip->stream_list, list) {
+ substream = stream->substream;
+ if (substream && substream->runtime) {
+ buf_in_frames = (substream->runtime->buffer_size);
+ buf_size = frames_to_bytes(substream->runtime, buf_in_frames);
+ config_pte_for_stream(chip, stream);
+ config_acp_dma(chip, stream, buf_size);
+ if (stream->dai_id)
+ restore_acp_i2s_params(substream, chip, stream);
+ else
+ restore_acp_pdm_params(substream, chip);
}
}
- spin_unlock(&adata->acp_lock);
+ spin_unlock(&chip->acp_lock);
return 0;
}
static const struct dev_pm_ops acp70_dma_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, acp70_pcm_resume)
+ SYSTEM_SLEEP_PM_OPS(NULL, acp70_pcm_resume)
};
static struct platform_driver acp70_driver = {
@@ -277,7 +215,7 @@ static struct platform_driver acp70_driver = {
.remove = acp_acp70_audio_remove,
.driver = {
.name = "acp_asoc_acp70",
- .pm = &acp70_dma_pm_ops,
+ .pm = pm_ptr(&acp70_dma_pm_ops),
},
};
diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c
new file mode 100644
index 000000000000..e87ccfeee5bd
--- /dev/null
+++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * amd-acp70-acpi-match.c - tables and support for ACP 7.0 & ACP7.1
+ * ACPI enumeration.
+ *
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <sound/soc-acpi.h>
+#include "../mach-config.h"
+
+static const struct snd_soc_acpi_endpoint single_endpoint = {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0
+};
+
+static const struct snd_soc_acpi_endpoint spk_l_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1
+};
+
+static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1
+};
+
+static const struct snd_soc_acpi_adr_device rt711_rt1316_group_adr[] = {
+ {
+ .adr = 0x000030025D071101ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt711"
+ },
+ {
+ .adr = 0x000030025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1316-1"
+ },
+ {
+ .adr = 0x000032025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device rt714_adr[] = {
+ {
+ .adr = 0x130025d071401ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt714"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr acp70_4_in_1_sdca[] = {
+ { .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt711_rt1316_group_adr),
+ .adr_d = rt711_rt1316_group_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt714_adr),
+ .adr_d = rt714_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_endpoint rt722_endpoints[] = {
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ {
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ {
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
+static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = {
+ {
+ .adr = 0x000030025d072201ull,
+ .num_endpoints = ARRAY_SIZE(rt722_endpoints),
+ .endpoints = rt722_endpoints,
+ .name_prefix = "rt722"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_1_single_adr[] = {
+ {
+ .adr = 0x000130025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &single_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr acp70_rt722_only[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt722_0_single_adr),
+ .adr_d = rt722_0_single_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp70_rt722_l0_rt1320_l1[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt722_0_single_adr),
+ .adr_d = rt722_0_single_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1320_1_single_adr),
+ .adr_d = rt1320_1_single_adr,
+ },
+ {}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = {
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp70_rt722_l0_rt1320_l1,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = acp70_rt722_only,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp70_4_in_1_sdca,
+ .drv_name = "amd_sdw",
+ },
+ {},
+};
+EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sdw_machines);
+
+MODULE_DESCRIPTION("AMD ACP7.0 & ACP7.1 tables and support for ACPI enumeration");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
diff --git a/sound/soc/amd/acp/amd-acpi-mach.c b/sound/soc/amd/acp/amd-acpi-mach.c
new file mode 100644
index 000000000000..d95047d2ee94
--- /dev/null
+++ b/sound/soc/amd/acp/amd-acpi-mach.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * amd-acpi-match.c - tables and support for ACP platforms
+ * ACPI enumeration.
+ *
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ */
+
+#include <sound/soc-acpi.h>
+
+struct snd_soc_acpi_codecs amp_rt1019 = {
+ .num_codecs = 1,
+ .codecs = {"10EC1019"}
+};
+
+struct snd_soc_acpi_codecs amp_max = {
+ .num_codecs = 1,
+ .codecs = {"MX98360A"}
+};
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = {
+ {
+ .id = "10EC5682",
+ .drv_name = "acp3xalc56821019",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_rt1019,
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "acp3xalc5682sm98360",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_max,
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "acp3xalc5682s1019",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_rt1019,
+ },
+ {
+ .id = "AMDI1019",
+ .drv_name = "renoir-acp",
+ },
+ {
+ .id = "ESSX8336",
+ .drv_name = "acp3x-es83xx",
+ },
+ {},
+};
+EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_acp_machines, "SND_SOC_ACP_COMMON");
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = {
+ {
+ .id = "10508825",
+ .drv_name = "rmb-nau8825-max",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_max,
+ },
+ {
+ .id = "AMDI0007",
+ .drv_name = "rembrandt-acp",
+ },
+ {
+ .id = "RTL5682",
+ .drv_name = "rmb-rt5682s-rt1019",
+ .machine_quirk = snd_soc_acpi_codec_list,
+ .quirk_data = &amp_rt1019,
+ },
+ {},
+};
+EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_rmb_acp_machines, "SND_SOC_ACP_COMMON");
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[] = {
+ {
+ .id = "AMDI0052",
+ .drv_name = "acp63-acp",
+ },
+ {},
+};
+EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_acp63_acp_machines, "SND_SOC_ACP_COMMON");
+
+struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[] = {
+ {
+ .id = "AMDI0029",
+ .drv_name = "acp70-acp",
+ },
+ {},
+};
+EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_acp70_acp_machines, "SND_SOC_ACP_COMMON");
+
+MODULE_DESCRIPTION("AMD ACP tables and support for ACPI enumeration");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Venkataprasad.potturu@amd.com");
diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h
index ee69dfb10cb8..863e74fcee43 100644
--- a/sound/soc/amd/acp/amd.h
+++ b/sound/soc/amd/acp/amd.h
@@ -140,13 +140,36 @@
struct acp_chip_info {
char *name; /* Platform name */
+ struct resource *res;
+ struct device *dev;
+ struct snd_soc_dai_driver *dai_driver;
+
unsigned int acp_rev; /* ACP Revision id */
void __iomem *base; /* ACP memory PCI base */
+ struct snd_acp_hw_ops *acp_hw_ops;
+ int (*acp_hw_ops_init)(struct acp_chip_info *chip);
struct platform_device *chip_pdev;
+ struct acp_resource *rsrc; /* Platform specific resources*/
+ struct list_head stream_list;
+ spinlock_t acp_lock; /* Used to protect stream_list */
+ struct platform_device *dmic_codec_dev;
+ struct platform_device *acp_plat_dev;
+ struct platform_device *mach_dev;
+ struct snd_soc_acpi_mach *machines;
+ int num_dai;
+ u32 addr;
+ u32 bclk_div;
+ u32 lrclk_div;
+ u32 ch_mask;
+ u32 tdm_tx_fmt[3];
+ u32 tdm_rx_fmt[3];
+ u32 xfer_tx_resolution[3];
+ u32 xfer_rx_resolution[3];
unsigned int flag; /* Distinguish b/w Legacy or Only PDM */
bool is_pdm_dev; /* flag set to true when ACP PDM controller exists */
bool is_pdm_config; /* flag set to true when PDM configuration is selected from BIOS */
bool is_i2s_config; /* flag set to true when I2S configuration is selected from BIOS */
+ bool tdm_mode;
};
struct acp_stream {
@@ -172,35 +195,23 @@ struct acp_resource {
u64 sram_pte_offset;
};
-struct acp_dev_data {
- char *name;
- struct device *dev;
- void __iomem *acp_base;
- unsigned int i2s_irq;
- unsigned int acp_rev; /* ACP Revision id */
-
- bool tdm_mode;
- bool is_i2s_config;
- /* SOC specific dais */
- struct snd_soc_dai_driver *dai_driver;
- int num_dai;
-
- struct list_head stream_list;
- spinlock_t acp_lock;
-
- struct snd_soc_acpi_mach *machines;
- struct platform_device *mach_dev;
-
- u32 bclk_div;
- u32 lrclk_div;
-
- struct acp_resource *rsrc;
- u32 ch_mask;
- u32 tdm_tx_fmt[3];
- u32 tdm_rx_fmt[3];
- u32 xfer_tx_resolution[3];
- u32 xfer_rx_resolution[3];
- unsigned int flag;
+/**
+ * struct snd_acp_hw_ops - ACP PCI driver platform specific ops
+ * @acp_init: ACP initialization
+ * @acp_deinit: ACP de-initialization
+ * @irq: ACP irq handler
+ * @en_interrupts: ACP enable interrupts
+ * @dis_interrupts: ACP disable interrupts
+ */
+struct snd_acp_hw_ops {
+ /* ACP hardware initilizations */
+ int (*acp_init)(struct acp_chip_info *chip);
+ int (*acp_deinit)(struct acp_chip_info *chip);
+
+ /* ACP Interrupts*/
+ irqreturn_t (*irq)(int irq, void *data);
+ int (*en_interrupts)(struct acp_chip_info *chip);
+ int (*dis_interrupts)(struct acp_chip_info *chip);
};
enum acp_config {
@@ -227,76 +238,121 @@ enum acp_config {
ACP_CONFIG_20,
};
+extern struct acp_resource rn_rsrc;
+extern struct acp_resource rmb_rsrc;
+extern struct acp_resource acp63_rsrc;
+extern struct acp_resource acp70_rsrc;
+
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines;
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines;
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines;
+extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines;
+
extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
extern const struct snd_soc_dai_ops acp_dmic_dai_ops;
int acp_platform_register(struct device *dev);
int acp_platform_unregister(struct device *dev);
-int acp_machine_select(struct acp_dev_data *adata);
-
-int smn_read(struct pci_dev *dev, u32 smn_addr);
-int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data);
+int acp_machine_select(struct acp_chip_info *chip);
int acp_init(struct acp_chip_info *chip);
int acp_deinit(struct acp_chip_info *chip);
-void acp_enable_interrupts(struct acp_dev_data *adata);
-void acp_disable_interrupts(struct acp_dev_data *adata);
+int acp_enable_interrupts(struct acp_chip_info *chip);
+int acp_disable_interrupts(struct acp_chip_info *chip);
+irqreturn_t acp_irq_handler(int irq, void *data);
+
+extern struct snd_acp_hw_ops acp31_common_hw_ops;
+extern struct snd_acp_hw_ops acp6x_common_hw_ops;
+extern struct snd_acp_hw_ops acp63_common_hw_ops;
+extern struct snd_acp_hw_ops acp70_common_hw_ops;
+extern int acp31_hw_ops_init(struct acp_chip_info *chip);
+extern int acp6x_hw_ops_init(struct acp_chip_info *chip);
+extern int acp63_hw_ops_init(struct acp_chip_info *chip);
+extern int acp70_hw_ops_init(struct acp_chip_info *chip);
/* Machine configuration */
int snd_amd_acp_find_config(struct pci_dev *pci);
-void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream);
-void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size);
+void config_pte_for_stream(struct acp_chip_info *chip, struct acp_stream *stream);
+void config_acp_dma(struct acp_chip_info *chip, struct acp_stream *stream, int size);
void restore_acp_pdm_params(struct snd_pcm_substream *substream,
- struct acp_dev_data *adata);
+ struct acp_chip_info *chip);
int restore_acp_i2s_params(struct snd_pcm_substream *substream,
- struct acp_dev_data *adata, struct acp_stream *stream);
+ struct acp_chip_info *chip, struct acp_stream *stream);
void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip);
-static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction)
+static inline int acp_hw_init(struct acp_chip_info *chip)
+{
+ if (chip && chip->acp_hw_ops && chip->acp_hw_ops->acp_init)
+ return chip->acp_hw_ops->acp_init(chip);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_deinit(struct acp_chip_info *chip)
+{
+ if (chip && chip->acp_hw_ops && chip->acp_hw_ops->acp_deinit)
+ return chip->acp_hw_ops->acp_deinit(chip);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_en_interrupts(struct acp_chip_info *chip)
+{
+ if (chip && chip->acp_hw_ops && chip->acp_hw_ops->en_interrupts)
+ return chip->acp_hw_ops->en_interrupts(chip);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_dis_interrupts(struct acp_chip_info *chip)
+{
+ if (chip && chip->acp_hw_ops && chip->acp_hw_ops->dis_interrupts)
+ chip->acp_hw_ops->dis_interrupts(chip);
+ return -EOPNOTSUPP;
+}
+
+static inline u64 acp_get_byte_count(struct acp_chip_info *chip, int dai_id, int direction)
{
u64 byte_count = 0, low = 0, high = 0;
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
switch (dai_id) {
case I2S_BT_INSTANCE:
- high = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(adata));
- low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW(adata));
+ high = readl(chip->base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(chip));
+ low = readl(chip->base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW(chip));
break;
case I2S_SP_INSTANCE:
- high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(adata));
- low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(adata));
+ high = readl(chip->base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(chip));
+ low = readl(chip->base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(chip));
break;
case I2S_HS_INSTANCE:
- high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH);
- low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW);
+ high = readl(chip->base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH);
+ low = readl(chip->base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW);
break;
default:
- dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
+ dev_err(chip->dev, "Invalid dai id %x\n", dai_id);
goto POINTER_RETURN_BYTES;
}
} else {
switch (dai_id) {
case I2S_BT_INSTANCE:
- high = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(adata));
- low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW(adata));
+ high = readl(chip->base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(chip));
+ low = readl(chip->base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW(chip));
break;
case I2S_SP_INSTANCE:
- high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(adata));
- low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(adata));
+ high = readl(chip->base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(chip));
+ low = readl(chip->base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(chip));
break;
case I2S_HS_INSTANCE:
- high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH);
- low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW);
+ high = readl(chip->base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH);
+ low = readl(chip->base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW);
break;
case DMIC_INSTANCE:
- high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
- low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
+ high = readl(chip->base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
+ low = readl(chip->base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
break;
default:
- dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
+ dev_err(chip->dev, "Invalid dai id %x\n", dai_id);
goto POINTER_RETURN_BYTES;
}
}
diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h
index 117ea63e85c6..82275c9de53a 100644
--- a/sound/soc/amd/acp/chip_offset_byte.h
+++ b/sound/soc/amd/acp/chip_offset_byte.h
@@ -29,13 +29,13 @@
#define ACP_PIN_CONFIG 0x1440
#define ACP3X_PIN_CONFIG 0x1400
-#define ACP_EXTERNAL_INTR_REG_ADDR(adata, offset, ctrl) \
- (adata->acp_base + adata->rsrc->irq_reg_offset + offset + (ctrl * 0x04))
+#define ACP_EXTERNAL_INTR_REG_ADDR(chip, offset, ctrl) \
+ (chip->base + chip->rsrc->irq_reg_offset + offset + (ctrl * 0x04))
-#define ACP_EXTERNAL_INTR_ENB(adata) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x0, 0x0)
-#define ACP_EXTERNAL_INTR_CNTL(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x4, ctrl)
-#define ACP_EXTERNAL_INTR_STAT(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, \
- (0x4 + (adata->rsrc->no_of_ctrls * 0x04)), ctrl)
+#define ACP_EXTERNAL_INTR_ENB(chip) ACP_EXTERNAL_INTR_REG_ADDR(chip, 0x0, 0x0)
+#define ACP_EXTERNAL_INTR_CNTL(chip, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(chip, 0x4, ctrl)
+#define ACP_EXTERNAL_INTR_STAT(chip, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(chip, \
+ (0x4 + (chip->rsrc->no_of_ctrls * 0x04)), ctrl)
/* Registers from ACP_AUDIO_BUFFERS block */
diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h
index b7bae107c13e..1f24e0e06487 100644
--- a/sound/soc/amd/acp/soc_amd_sdw_common.h
+++ b/sound/soc/amd/acp/soc_amd_sdw_common.h
@@ -19,9 +19,12 @@
#define AMD_SDW_MAX_GROUPS 9
#define ACP63_PCI_REV 0x63
+#define ACP70_PCI_REV 0x70
+#define ACP71_PCI_REV 0x71
#define SOC_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0))
#define ASOC_SDW_FOUR_SPK BIT(4)
#define ASOC_SDW_ACP_DMIC BIT(5)
+#define ASOC_SDW_CODEC_SPKR BIT(15)
#define AMD_SDW0 0
#define AMD_SDW1 1
@@ -38,11 +41,20 @@
#define ACP_DMIC_BE_ID 4
+#define ACP70_SW_AUDIO0_TX 0
+#define ACP70_SW_AUDIO1_TX 1
+#define ACP70_SW_AUDIO2_TX 2
+
+#define ACP70_SW_AUDIO0_RX 3
+#define ACP70_SW_AUDIO1_RX 4
+#define ACP70_SW_AUDIO2_RX 5
+
struct amd_mc_ctx {
unsigned int acp_rev;
unsigned int max_sdw_links;
};
int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev);
+int get_acp70_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev);
#endif
diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h
index a86c76f781f9..fdf016a64bbf 100644
--- a/sound/soc/amd/mach-config.h
+++ b/sound/soc/amd/mach-config.h
@@ -26,6 +26,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[];
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[];
struct config_entry {
u32 flags;
diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile
index b5efb1c5382c..778ee4726389 100644
--- a/sound/soc/amd/ps/Makefile
+++ b/sound/soc/amd/ps/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
# Pink Sardine platform Support
-snd-pci-ps-y := pci-ps.o
+snd-pci-ps-y := pci-ps.o ps-common.o
snd-ps-pdm-dma-y := ps-pdm-dma.o
snd-soc-ps-mach-y := ps-mach.o
snd-ps-sdw-dma-y := ps-sdw-dma.o
diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h
index e54eabaa4d3e..85feae45c44c 100644
--- a/sound/soc/amd/ps/acp63.h
+++ b/sound/soc/amd/ps/acp63.h
@@ -1,8 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * AMD ALSA SoC PDM Driver
+ * AMD Common ACP header file for ACP6.3, ACP7.0 & ACP7.1 platforms
*
- * Copyright (C) 2022, 2023 Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (C) 2022, 2023, 2025 Advanced Micro Devices, Inc. All rights reserved.
*/
#include <linux/soundwire/sdw_amd.h>
@@ -11,15 +11,18 @@
#define ACP_DEVICE_ID 0x15E2
#define ACP63_REG_START 0x1240000
#define ACP63_REG_END 0x125C000
+#define ACP63_PCI_REV 0x63
+#define ACP70_PCI_REV 0x70
+#define ACP71_PCI_REV 0x71
#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001
-#define ACP_PGFSM_CNTL_POWER_ON_MASK 1
-#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0
-#define ACP_PGFSM_STATUS_MASK 3
-#define ACP_POWERED_ON 0
-#define ACP_POWER_ON_IN_PROGRESS 1
-#define ACP_POWERED_OFF 2
-#define ACP_POWER_OFF_IN_PROGRESS 3
+#define ACP63_PGFSM_CNTL_POWER_ON_MASK 1
+#define ACP63_PGFSM_CNTL_POWER_OFF_MASK 0
+#define ACP63_PGFSM_STATUS_MASK 3
+#define ACP63_POWERED_ON 0
+#define ACP63_POWER_ON_IN_PROGRESS 1
+#define ACP63_POWERED_OFF 2
+#define ACP63_POWER_OFF_IN_PROGRESS 3
#define ACP_ERROR_MASK 0x20000000
#define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF
@@ -60,7 +63,7 @@
#define AMD_SDW_MAX_MANAGERS 2
/* time in ms for acp timeout */
-#define ACP_TIMEOUT 500
+#define ACP63_TIMEOUT 500
#define ACP_SDW0_STAT BIT(21)
#define ACP_SDW1_STAT BIT(2)
@@ -72,13 +75,13 @@
#define ACP_AUDIO0_RX_THRESHOLD 0x1b
#define ACP_AUDIO1_RX_THRESHOLD 0x19
#define ACP_AUDIO2_RX_THRESHOLD 0x17
-#define ACP_P1_AUDIO1_TX_THRESHOLD BIT(6)
-#define ACP_P1_AUDIO1_RX_THRESHOLD BIT(5)
-#define ACP_SDW_DMA_IRQ_MASK 0x1F800000
-#define ACP_P1_SDW_DMA_IRQ_MASK 0x60
+#define ACP63_P1_AUDIO1_TX_THRESHOLD BIT(6)
+#define ACP63_P1_AUDIO1_RX_THRESHOLD BIT(5)
+#define ACP63_SDW_DMA_IRQ_MASK 0x1F800000
+#define ACP63_P1_SDW_DMA_IRQ_MASK 0x60
#define ACP63_SDW0_DMA_MAX_STREAMS 6
#define ACP63_SDW1_DMA_MAX_STREAMS 2
-#define ACP_P1_AUDIO_TX_THRESHOLD 6
+#define ACP63_P1_AUDIO_TX_THRESHOLD 6
/*
* Below entries describes SDW0 instance DMA stream id and DMA irq bit mapping
@@ -91,8 +94,8 @@
* 4 (SDW0_AUDIO1_RX) 25
* 5 (SDW0_AUDIO2_RX) 23
*/
-#define SDW0_DMA_TX_IRQ_MASK(i) (ACP_AUDIO0_TX_THRESHOLD - (2 * (i)))
-#define SDW0_DMA_RX_IRQ_MASK(i) (ACP_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3)))
+#define ACP63_SDW0_DMA_TX_IRQ_MASK(i) (ACP_AUDIO0_TX_THRESHOLD - (2 * (i)))
+#define ACP63_SDW0_DMA_RX_IRQ_MASK(i) (ACP_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3)))
/*
* Below entries describes SDW1 instance DMA stream id and DMA irq bit mapping
@@ -101,7 +104,7 @@
* 0 (SDW1_AUDIO1_TX) 6
* 1 (SDW1_AUDIO1_RX) 5
*/
-#define SDW1_DMA_IRQ_MASK(i) (ACP_P1_AUDIO_TX_THRESHOLD - (i))
+#define ACP63_SDW1_DMA_IRQ_MASK(i) (ACP63_P1_AUDIO_TX_THRESHOLD - (i))
#define ACP_DELAY_US 5
#define ACP_SDW_RING_BUFF_ADDR_OFFSET (128 * 1024)
@@ -129,6 +132,61 @@
#define SDW_MAX_BUFFER (SDW_PLAYBACK_MAX_PERIOD_SIZE * SDW_PLAYBACK_MAX_NUM_PERIODS)
#define SDW_MIN_BUFFER SDW_MAX_BUFFER
+#define ACP_HW_OPS(acp_data, cb) ((acp_data)->hw_ops->cb)
+
+#define ACP70_PGFSM_CNTL_POWER_ON_MASK 0x1F
+#define ACP70_PGFSM_CNTL_POWER_OFF_MASK 0
+#define ACP70_PGFSM_STATUS_MASK 0xFF
+#define ACP70_TIMEOUT 2000
+#define ACP70_SDW_HOST_WAKE_MASK 0x0C00000
+#define ACP70_SDW0_HOST_WAKE_STAT BIT(24)
+#define ACP70_SDW1_HOST_WAKE_STAT BIT(25)
+#define ACP70_SDW0_PME_STAT BIT(26)
+#define ACP70_SDW1_PME_STAT BIT(27)
+
+#define ACP70_SDW0_DMA_MAX_STREAMS 6
+#define ACP70_SDW1_DMA_MAX_STREAMS ACP70_SDW0_DMA_MAX_STREAMS
+#define ACP70_SDW_DMA_IRQ_MASK 0x1F800000
+#define ACP70_P1_SDW_DMA_IRQ_MASK 0x1F8
+
+#define ACP70_P1_AUDIO0_TX_THRESHOLD 0x8
+#define ACP70_P1_AUDIO1_TX_THRESHOLD 0x6
+#define ACP70_P1_AUDIO2_TX_THRESHOLD 0x4
+#define ACP70_P1_AUDIO0_RX_THRESHOLD 0x7
+#define ACP70_P1_AUDIO1_RX_THRESHOLD 0x5
+#define ACP70_P1_AUDIO2_RX_THRESHOLD 0x3
+
+#define ACP70_SDW0_DMA_TX_IRQ_MASK(i) (ACP_AUDIO0_TX_THRESHOLD - (2 * (i)))
+#define ACP70_SDW0_DMA_RX_IRQ_MASK(i) (ACP_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3)))
+
+/*
+ * Below entries describes SDW1 instance DMA stream id and DMA irq bit mapping
+ * in ACP_EXTENAL_INTR_CNTL1 register for ACP70/ACP71 platforms
+ * Stream id IRQ Bit
+ * 0 (SDW1_AUDIO0_TX) 8
+ * 1 (SDW1_AUDIO1_TX) 6
+ * 2 (SDW1_AUDIO2_TX) 4
+ * 3 (SDW1_AUDIO0_RX) 7
+ * 4 (SDW1_AUDIO1_RX) 5
+ * 5 (SDW1_AUDIO2_RX) 3
+ */
+#define ACP70_SDW1_DMA_TX_IRQ_MASK(i) (ACP70_P1_AUDIO0_TX_THRESHOLD - (2 * (i)))
+#define ACP70_SDW1_DMA_RX_IRQ_MASK(i) (ACP70_P1_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3)))
+
+#define ACP70_SW0_AUDIO0_TX_EN ACP_SW0_AUDIO0_TX_EN
+#define ACP70_SW0_AUDIO1_TX_EN ACP_SW0_AUDIO1_TX_EN
+#define ACP70_SW0_AUDIO2_TX_EN ACP_SW0_AUDIO2_TX_EN
+#define ACP70_SW0_AUDIO0_RX_EN ACP_SW0_AUDIO0_RX_EN
+#define ACP70_SW0_AUDIO1_RX_EN ACP_SW0_AUDIO1_RX_EN
+#define ACP70_SW0_AUDIO2_RX_EN ACP_SW0_AUDIO2_RX_EN
+
+#define ACP70_SW1_AUDIO0_TX_EN 0x0003C10
+#define ACP70_SW1_AUDIO1_TX_EN 0x0003C50
+#define ACP70_SW1_AUDIO2_TX_EN 0x0003C6C
+#define ACP70_SW1_AUDIO0_RX_EN 0x0003C88
+#define ACP70_SW1_AUDIO1_RX_EN 0x0003D28
+#define ACP70_SW1_AUDIO2_RX_EN 0x0003D44
+
enum acp_config {
ACP_CONFIG_0 = 0,
ACP_CONFIG_1,
@@ -146,20 +204,34 @@ enum acp_config {
ACP_CONFIG_13,
ACP_CONFIG_14,
ACP_CONFIG_15,
+ ACP_CONFIG_16,
+ ACP_CONFIG_17,
+ ACP_CONFIG_18,
+ ACP_CONFIG_19,
+ ACP_CONFIG_20,
+};
+
+enum amd_acp63_sdw0_channel {
+ ACP63_SDW0_AUDIO0_TX = 0,
+ ACP63_SDW0_AUDIO1_TX,
+ ACP63_SDW0_AUDIO2_TX,
+ ACP63_SDW0_AUDIO0_RX,
+ ACP63_SDW0_AUDIO1_RX,
+ ACP63_SDW0_AUDIO2_RX,
};
-enum amd_sdw0_channel {
- ACP_SDW0_AUDIO0_TX = 0,
- ACP_SDW0_AUDIO1_TX,
- ACP_SDW0_AUDIO2_TX,
- ACP_SDW0_AUDIO0_RX,
- ACP_SDW0_AUDIO1_RX,
- ACP_SDW0_AUDIO2_RX,
+enum amd_acp63_sdw1_channel {
+ ACP63_SDW1_AUDIO1_TX,
+ ACP63_SDW1_AUDIO1_RX,
};
-enum amd_sdw1_channel {
- ACP_SDW1_AUDIO1_TX,
- ACP_SDW1_AUDIO1_RX,
+enum amd_acp70_sdw_channel {
+ ACP70_SDW_AUDIO0_TX = 0,
+ ACP70_SDW_AUDIO1_TX,
+ ACP70_SDW_AUDIO2_TX,
+ ACP70_SDW_AUDIO0_RX,
+ ACP70_SDW_AUDIO1_RX,
+ ACP70_SDW_AUDIO2_RX,
};
struct pdm_stream_instance {
@@ -180,8 +252,11 @@ struct pdm_dev_data {
struct sdw_dma_dev_data {
void __iomem *acp_base;
struct mutex *acp_lock; /* used to protect acp common register access */
- struct snd_pcm_substream *sdw0_dma_stream[ACP63_SDW0_DMA_MAX_STREAMS];
- struct snd_pcm_substream *sdw1_dma_stream[ACP63_SDW1_DMA_MAX_STREAMS];
+ u32 acp_rev;
+ struct snd_pcm_substream *acp63_sdw0_dma_stream[ACP63_SDW0_DMA_MAX_STREAMS];
+ struct snd_pcm_substream *acp63_sdw1_dma_stream[ACP63_SDW1_DMA_MAX_STREAMS];
+ struct snd_pcm_substream *acp70_sdw0_dma_stream[ACP70_SDW0_DMA_MAX_STREAMS];
+ struct snd_pcm_substream *acp70_sdw1_dma_stream[ACP70_SDW1_DMA_MAX_STREAMS];
};
struct acp_sdw_dma_stream {
@@ -212,10 +287,35 @@ struct sdw_dma_ring_buf_reg {
u32 pos_high_reg;
};
+struct acp63_dev_data;
+
+/**
+ * struct acp_hw_ops - ACP PCI driver platform specific ops
+ * @acp_init: ACP initialization
+ * @acp_deinit: ACP de-initialization
+ * @acp_get_config: function to read the acp pin configuration
+ * @acp_sdw_dma_irq_thread: ACP SoundWire DMA interrupt thread
+ * acp_suspend: ACP system level suspend callback
+ * acp_resume: ACP system level resume callback
+ * acp_suspend_runtime: ACP runtime suspend callback
+ * acp_resume_runtime: ACP runtime resume callback
+ */
+struct acp_hw_ops {
+ int (*acp_init)(void __iomem *acp_base, struct device *dev);
+ int (*acp_deinit)(void __iomem *acp_base, struct device *dev);
+ void (*acp_get_config)(struct pci_dev *pci, struct acp63_dev_data *acp_data);
+ void (*acp_sdw_dma_irq_thread)(struct acp63_dev_data *acp_data);
+ int (*acp_suspend)(struct device *dev);
+ int (*acp_resume)(struct device *dev);
+ int (*acp_suspend_runtime)(struct device *dev);
+ int (*acp_resume_runtime)(struct device *dev);
+};
+
/**
* struct acp63_dev_data - acp pci driver context
* @acp63_base: acp mmio base
* @res: resource
+ * @hw_ops: ACP pci driver platform-specific ops
* @pdm_dev: ACP PDM controller platform device
* @dmic_codec: platform device for DMIC Codec
* sdw_dma_dev: platform device for SoundWire DMA controller
@@ -229,16 +329,25 @@ struct sdw_dma_ring_buf_reg {
* @is_pdm_config: flat set to true when PDM configuration is selected from BIOS
* @is_sdw_config: flag set to true when SDW configuration is selected from BIOS
* @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled
+ * @acp70_sdw0_wake_event: flag set to true when wake irq asserted for SW0 instance
+ * @acp70_sdw1_wake_event: flag set to true when wake irq asserted for SW1 instance
* @addr: pci ioremap address
* @reg_range: ACP reigister range
* @acp_rev: ACP PCI revision id
- * @sdw0-dma_intr_stat: DMA interrupt status array for SoundWire manager-SW0 instance
- * @sdw_dma_intr_stat: DMA interrupt status array for SoundWire manager-SW1 instance
+ * @acp63_sdw0-dma_intr_stat: DMA interrupt status array for ACP6.3 platform SoundWire
+ * manager-SW0 instance
+ * @acp63_sdw_dma_intr_stat: DMA interrupt status array for ACP6.3 platform SoundWire
+ * manager-SW1 instance
+ * @acp70_sdw0-dma_intr_stat: DMA interrupt status array for ACP7.0 platform SoundWire
+ * manager-SW0 instance
+ * @acp70_sdw_dma_intr_stat: DMA interrupt status array for ACP7.0 platform SoundWire
+ * manager-SW1 instance
*/
struct acp63_dev_data {
void __iomem *acp63_base;
struct resource *res;
+ struct acp_hw_ops *hw_ops;
struct platform_device *pdm_dev;
struct platform_device *dmic_codec_dev;
struct platform_device *sdw_dma_dev;
@@ -253,11 +362,80 @@ struct acp63_dev_data {
bool is_pdm_config;
bool is_sdw_config;
bool sdw_en_stat;
+ bool acp70_sdw0_wake_event;
+ bool acp70_sdw1_wake_event;
u32 addr;
u32 reg_range;
u32 acp_rev;
- u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS];
- u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS];
+ u16 acp63_sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS];
+ u16 acp63_sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS];
+ u16 acp70_sdw0_dma_intr_stat[ACP70_SDW0_DMA_MAX_STREAMS];
+ u16 acp70_sdw1_dma_intr_stat[ACP70_SDW1_DMA_MAX_STREAMS];
};
+void acp63_hw_init_ops(struct acp_hw_ops *hw_ops);
+void acp70_hw_init_ops(struct acp_hw_ops *hw_ops);
+
+static inline int acp_hw_init(struct acp63_dev_data *adata, struct device *dev)
+{
+ if (adata && adata->hw_ops && adata->hw_ops->acp_init)
+ return ACP_HW_OPS(adata, acp_init)(adata->acp63_base, dev);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_deinit(struct acp63_dev_data *adata, struct device *dev)
+{
+ if (adata && adata->hw_ops && adata->hw_ops->acp_deinit)
+ return ACP_HW_OPS(adata, acp_deinit)(adata->acp63_base, dev);
+ return -EOPNOTSUPP;
+}
+
+static inline void acp_hw_get_config(struct pci_dev *pci, struct acp63_dev_data *adata)
+{
+ if (adata && adata->hw_ops && adata->hw_ops->acp_get_config)
+ ACP_HW_OPS(adata, acp_get_config)(pci, adata);
+}
+
+static inline void acp_hw_sdw_dma_irq_thread(struct acp63_dev_data *adata)
+{
+ if (adata && adata->hw_ops && adata->hw_ops->acp_sdw_dma_irq_thread)
+ ACP_HW_OPS(adata, acp_sdw_dma_irq_thread)(adata);
+}
+
+static inline int acp_hw_suspend(struct device *dev)
+{
+ struct acp63_dev_data *adata = dev_get_drvdata(dev);
+
+ if (adata && adata->hw_ops && adata->hw_ops->acp_suspend)
+ return ACP_HW_OPS(adata, acp_suspend)(dev);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata = dev_get_drvdata(dev);
+
+ if (adata && adata->hw_ops && adata->hw_ops->acp_resume)
+ return ACP_HW_OPS(adata, acp_resume)(dev);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_suspend_runtime(struct device *dev)
+{
+ struct acp63_dev_data *adata = dev_get_drvdata(dev);
+
+ if (adata && adata->hw_ops && adata->hw_ops->acp_suspend_runtime)
+ return ACP_HW_OPS(adata, acp_suspend_runtime)(dev);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_hw_runtime_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata = dev_get_drvdata(dev);
+
+ if (adata && adata->hw_ops && adata->hw_ops->acp_resume_runtime)
+ return ACP_HW_OPS(adata, acp_resume_runtime)(dev);
+ return -EOPNOTSUPP;
+}
+
int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
index 4575326d0635..8e57f31ef7f7 100644
--- a/sound/soc/amd/ps/pci-ps.c
+++ b/sound/soc/amd/ps/pci-ps.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * AMD Pink Sardine ACP PCI Driver
+ * AMD common ACP PCI driver for ACP6.3, ACP7.0 & ACP7.1 platforms.
*
- * Copyright 2022 Advanced Micro Devices, Inc.
+ * Copyright 2022, 2025 Advanced Micro Devices, Inc.
*/
#include <linux/pci.h>
@@ -21,107 +21,168 @@
#include "acp63.h"
-static int acp63_power_on(void __iomem *acp_base)
+static void handle_acp70_sdw_wake_event(struct acp63_dev_data *adata)
{
- u32 val;
-
- val = readl(acp_base + ACP_PGFSM_STATUS);
-
- if (!val)
- return val;
+ struct amd_sdw_manager *amd_manager;
- if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS)
- writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+ if (adata->acp70_sdw0_wake_event) {
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
+ if (amd_manager)
+ pm_request_resume(amd_manager->dev);
+ adata->acp70_sdw0_wake_event = 0;
+ }
- return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT);
+ if (adata->acp70_sdw1_wake_event) {
+ amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
+ if (amd_manager)
+ pm_request_resume(amd_manager->dev);
+ adata->acp70_sdw1_wake_event = 0;
+ }
}
-static int acp63_reset(void __iomem *acp_base)
+static short int check_and_handle_acp70_sdw_wake_irq(struct acp63_dev_data *adata)
{
- u32 val;
- int ret;
+ u32 ext_intr_stat1;
+ int irq_flag = 0;
+ bool sdw_wake_irq = false;
- writel(1, acp_base + ACP_SOFT_RESET);
-
- ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
- val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
- DELAY_US, ACP_TIMEOUT);
- if (ret)
- return ret;
-
- writel(0, acp_base + ACP_SOFT_RESET);
-
- return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT);
-}
-
-static void acp63_enable_interrupts(void __iomem *acp_base)
-{
- writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
- writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
-}
+ ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ if (ext_intr_stat1 & ACP70_SDW0_HOST_WAKE_STAT) {
+ writel(ACP70_SDW0_HOST_WAKE_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ adata->acp70_sdw0_wake_event = true;
+ sdw_wake_irq = true;
+ }
-static void acp63_disable_interrupts(void __iomem *acp_base)
-{
- writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT);
- writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
- writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
-}
+ if (ext_intr_stat1 & ACP70_SDW1_HOST_WAKE_STAT) {
+ writel(ACP70_SDW1_HOST_WAKE_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ adata->acp70_sdw1_wake_event = true;
+ sdw_wake_irq = true;
+ }
-static int acp63_init(void __iomem *acp_base, struct device *dev)
-{
- int ret;
+ if (ext_intr_stat1 & ACP70_SDW0_PME_STAT) {
+ writel(0, adata->acp63_base + ACP_SW0_WAKE_EN);
+ writel(ACP70_SDW0_PME_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ adata->acp70_sdw0_wake_event = true;
+ sdw_wake_irq = true;
+ }
- ret = acp63_power_on(acp_base);
- if (ret) {
- dev_err(dev, "ACP power on failed\n");
- return ret;
+ if (ext_intr_stat1 & ACP70_SDW1_PME_STAT) {
+ writel(0, adata->acp63_base + ACP_SW1_WAKE_EN);
+ writel(ACP70_SDW1_PME_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ adata->acp70_sdw1_wake_event = true;
+ sdw_wake_irq = true;
}
- writel(0x01, acp_base + ACP_CONTROL);
- ret = acp63_reset(acp_base);
- if (ret) {
- dev_err(dev, "ACP reset failed\n");
- return ret;
+
+ if (sdw_wake_irq) {
+ handle_acp70_sdw_wake_event(adata);
+ irq_flag = 1;
}
- acp63_enable_interrupts(acp_base);
- return 0;
+ return irq_flag;
}
-static int acp63_deinit(void __iomem *acp_base, struct device *dev)
+static short int check_and_handle_sdw_dma_irq(struct acp63_dev_data *adata, u32 ext_intr_stat,
+ u32 ext_intr_stat1)
{
- int ret;
+ u32 stream_id = 0;
+ u16 sdw_dma_irq_flag = 0;
+ u16 index;
- acp63_disable_interrupts(acp_base);
- ret = acp63_reset(acp_base);
- if (ret) {
- dev_err(dev, "ACP reset failed\n");
- return ret;
+ if (ext_intr_stat & ACP63_SDW_DMA_IRQ_MASK) {
+ for (index = ACP_AUDIO2_RX_THRESHOLD; index <= ACP_AUDIO0_TX_THRESHOLD; index++) {
+ if (ext_intr_stat & BIT(index)) {
+ writel(BIT(index), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+ switch (index) {
+ case ACP_AUDIO0_TX_THRESHOLD:
+ stream_id = ACP63_SDW0_AUDIO0_TX;
+ break;
+ case ACP_AUDIO1_TX_THRESHOLD:
+ stream_id = ACP63_SDW0_AUDIO1_TX;
+ break;
+ case ACP_AUDIO2_TX_THRESHOLD:
+ stream_id = ACP63_SDW0_AUDIO2_TX;
+ break;
+ case ACP_AUDIO0_RX_THRESHOLD:
+ stream_id = ACP63_SDW0_AUDIO0_RX;
+ break;
+ case ACP_AUDIO1_RX_THRESHOLD:
+ stream_id = ACP63_SDW0_AUDIO1_RX;
+ break;
+ case ACP_AUDIO2_RX_THRESHOLD:
+ stream_id = ACP63_SDW0_AUDIO2_RX;
+ break;
+ }
+ switch (adata->acp_rev) {
+ case ACP63_PCI_REV:
+ adata->acp63_sdw0_dma_intr_stat[stream_id] = 1;
+ break;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ adata->acp70_sdw0_dma_intr_stat[stream_id] = 1;
+ break;
+ }
+ sdw_dma_irq_flag = 1;
+ }
+ }
}
- writel(0, acp_base + ACP_CONTROL);
- return 0;
+ switch (adata->acp_rev) {
+ case ACP63_PCI_REV:
+ if (ext_intr_stat1 & ACP63_P1_AUDIO1_RX_THRESHOLD) {
+ writel(ACP63_P1_AUDIO1_RX_THRESHOLD,
+ adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ adata->acp63_sdw1_dma_intr_stat[ACP63_SDW1_AUDIO1_RX] = 1;
+ sdw_dma_irq_flag = 1;
+ }
+ if (ext_intr_stat1 & ACP63_P1_AUDIO1_TX_THRESHOLD) {
+ writel(ACP63_P1_AUDIO1_TX_THRESHOLD,
+ adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ adata->acp63_sdw1_dma_intr_stat[ACP63_SDW1_AUDIO1_TX] = 1;
+ sdw_dma_irq_flag = 1;
+ }
+ break;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ if (ext_intr_stat1 & ACP70_P1_SDW_DMA_IRQ_MASK) {
+ for (index = ACP70_P1_AUDIO2_RX_THRESHOLD;
+ index <= ACP70_P1_AUDIO0_TX_THRESHOLD; index++) {
+ if (ext_intr_stat1 & BIT(index)) {
+ writel(BIT(index),
+ adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+ switch (index) {
+ case ACP70_P1_AUDIO0_TX_THRESHOLD:
+ stream_id = ACP70_SDW_AUDIO0_TX;
+ break;
+ case ACP70_P1_AUDIO1_TX_THRESHOLD:
+ stream_id = ACP70_SDW_AUDIO1_TX;
+ break;
+ case ACP70_P1_AUDIO2_TX_THRESHOLD:
+ stream_id = ACP70_SDW_AUDIO2_TX;
+ break;
+ case ACP70_P1_AUDIO0_RX_THRESHOLD:
+ stream_id = ACP70_SDW_AUDIO0_RX;
+ break;
+ case ACP70_P1_AUDIO1_RX_THRESHOLD:
+ stream_id = ACP70_SDW_AUDIO1_RX;
+ break;
+ case ACP70_P1_AUDIO2_RX_THRESHOLD:
+ stream_id = ACP70_SDW_AUDIO2_RX;
+ break;
+ }
+
+ adata->acp70_sdw1_dma_intr_stat[stream_id] = 1;
+ sdw_dma_irq_flag = 1;
+ }
+ }
+ }
+ break;
+ }
+ return sdw_dma_irq_flag;
}
static irqreturn_t acp63_irq_thread(int irq, void *context)
{
- struct sdw_dma_dev_data *sdw_dma_data;
struct acp63_dev_data *adata = context;
- u32 stream_index;
- sdw_dma_data = dev_get_drvdata(&adata->sdw_dma_dev->dev);
-
- for (stream_index = 0; stream_index < ACP63_SDW0_DMA_MAX_STREAMS; stream_index++) {
- if (adata->sdw0_dma_intr_stat[stream_index]) {
- if (sdw_dma_data->sdw0_dma_stream[stream_index])
- snd_pcm_period_elapsed(sdw_dma_data->sdw0_dma_stream[stream_index]);
- adata->sdw0_dma_intr_stat[stream_index] = 0;
- }
- }
- for (stream_index = 0; stream_index < ACP63_SDW1_DMA_MAX_STREAMS; stream_index++) {
- if (adata->sdw1_dma_intr_stat[stream_index]) {
- if (sdw_dma_data->sdw1_dma_stream[stream_index])
- snd_pcm_period_elapsed(sdw_dma_data->sdw1_dma_stream[stream_index]);
- adata->sdw1_dma_intr_stat[stream_index] = 0;
- }
- }
+ acp_hw_sdw_dma_irq_thread(adata);
return IRQ_HANDLED;
}
@@ -131,10 +192,8 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
struct pdm_dev_data *ps_pdm_data;
struct amd_sdw_manager *amd_manager;
u32 ext_intr_stat, ext_intr_stat1;
- u32 stream_id = 0;
u16 irq_flag = 0;
u16 sdw_dma_irq_flag = 0;
- u16 index;
adata = dev_id;
if (!adata)
@@ -171,6 +230,9 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
irq_flag = 1;
}
+ if (adata->acp_rev >= ACP70_PCI_REV)
+ irq_flag = check_and_handle_acp70_sdw_wake_irq(adata);
+
if (ext_intr_stat & BIT(PDM_DMA_STAT)) {
ps_pdm_data = dev_get_drvdata(&adata->pdm_dev->dev);
writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
@@ -178,51 +240,8 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
irq_flag = 1;
}
- if (ext_intr_stat & ACP_SDW_DMA_IRQ_MASK) {
- for (index = ACP_AUDIO2_RX_THRESHOLD; index <= ACP_AUDIO0_TX_THRESHOLD; index++) {
- if (ext_intr_stat & BIT(index)) {
- writel(BIT(index), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
- switch (index) {
- case ACP_AUDIO0_TX_THRESHOLD:
- stream_id = ACP_SDW0_AUDIO0_TX;
- break;
- case ACP_AUDIO1_TX_THRESHOLD:
- stream_id = ACP_SDW0_AUDIO1_TX;
- break;
- case ACP_AUDIO2_TX_THRESHOLD:
- stream_id = ACP_SDW0_AUDIO2_TX;
- break;
- case ACP_AUDIO0_RX_THRESHOLD:
- stream_id = ACP_SDW0_AUDIO0_RX;
- break;
- case ACP_AUDIO1_RX_THRESHOLD:
- stream_id = ACP_SDW0_AUDIO1_RX;
- break;
- case ACP_AUDIO2_RX_THRESHOLD:
- stream_id = ACP_SDW0_AUDIO2_RX;
- break;
- }
-
- adata->sdw0_dma_intr_stat[stream_id] = 1;
- sdw_dma_irq_flag = 1;
- }
- }
- }
-
- if (ext_intr_stat1 & ACP_P1_AUDIO1_RX_THRESHOLD) {
- writel(ACP_P1_AUDIO1_RX_THRESHOLD,
- adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
- adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_RX] = 1;
- sdw_dma_irq_flag = 1;
- }
-
- if (ext_intr_stat1 & ACP_P1_AUDIO1_TX_THRESHOLD) {
- writel(ACP_P1_AUDIO1_TX_THRESHOLD,
- adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
- adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_TX] = 1;
- sdw_dma_irq_flag = 1;
- }
+ sdw_dma_irq_flag = check_and_handle_sdw_dma_irq(adata, ext_intr_stat, ext_intr_stat1);
if (sdw_dma_irq_flag)
return IRQ_WAKE_THREAD;
@@ -312,6 +331,7 @@ static struct snd_soc_acpi_mach *acp63_sdw_machine_select(struct device *dev)
if (mach && mach->link_mask) {
mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask;
+ mach->mach_params.subsystem_rev = acp_data->acp_rev;
return mach;
}
}
@@ -377,7 +397,6 @@ static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *a
const union acpi_object *obj;
acpi_handle handle;
acpi_integer dmic_status;
- u32 config;
bool is_dmic_dev = false;
bool is_sdw_dev = false;
bool wov_en, dmic_en;
@@ -387,30 +406,7 @@ static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *a
wov_en = true;
dmic_en = false;
- config = readl(acp_data->acp63_base + ACP_PIN_CONFIG);
- switch (config) {
- case ACP_CONFIG_4:
- case ACP_CONFIG_5:
- case ACP_CONFIG_10:
- case ACP_CONFIG_11:
- acp_data->is_pdm_config = true;
- break;
- case ACP_CONFIG_2:
- case ACP_CONFIG_3:
- acp_data->is_sdw_config = true;
- break;
- case ACP_CONFIG_6:
- case ACP_CONFIG_7:
- case ACP_CONFIG_12:
- case ACP_CONFIG_8:
- case ACP_CONFIG_13:
- case ACP_CONFIG_14:
- acp_data->is_pdm_config = true;
- acp_data->is_sdw_config = true;
- break;
- default:
- break;
- }
+ acp_hw_get_config(pci, acp_data);
if (acp_data->is_pdm_config) {
pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0);
@@ -537,11 +533,33 @@ unregister_dmic_codec_dev:
unregister_pdm_dev:
platform_device_unregister(adata->pdm_dev);
de_init:
- if (acp63_deinit(adata->acp63_base, &pci->dev))
+ if (acp_hw_deinit(adata, &pci->dev))
dev_err(&pci->dev, "ACP de-init failed\n");
return ret;
}
+static int acp_hw_init_ops(struct acp63_dev_data *adata, struct pci_dev *pci)
+{
+ adata->hw_ops = devm_kzalloc(&pci->dev, sizeof(struct acp_hw_ops),
+ GFP_KERNEL);
+ if (!adata->hw_ops)
+ return -ENOMEM;
+
+ switch (adata->acp_rev) {
+ case ACP63_PCI_REV:
+ acp63_hw_init_ops(adata->hw_ops);
+ break;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ acp70_hw_init_ops(adata->hw_ops);
+ break;
+ default:
+ dev_err(&pci->dev, "ACP device not found\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
static int snd_acp63_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
@@ -557,12 +575,14 @@ static int snd_acp63_probe(struct pci_dev *pci,
if (flag)
return -ENODEV;
- /* Pink Sardine device check */
+ /* ACP PCI revision id check for ACP6.3, ACP7.0 & ACP7.1 platforms */
switch (pci->revision) {
- case 0x63:
+ case ACP63_PCI_REV:
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
break;
default:
- dev_dbg(&pci->dev, "acp63 pci device not found\n");
+ dev_dbg(&pci->dev, "acp63/acp70/acp71 pci device not found\n");
return -ENODEV;
}
if (pci_enable_device(pci)) {
@@ -595,7 +615,12 @@ static int snd_acp63_probe(struct pci_dev *pci,
pci_set_master(pci);
pci_set_drvdata(pci, adata);
mutex_init(&adata->acp_lock);
- ret = acp63_init(adata->acp63_base, &pci->dev);
+ ret = acp_hw_init_ops(adata, pci);
+ if (ret) {
+ dev_err(&pci->dev, "ACP hw ops init failed\n");
+ goto release_regions;
+ }
+ ret = acp_hw_init(adata, &pci->dev);
if (ret)
goto release_regions;
ret = devm_request_threaded_irq(&pci->dev, pci->irq, acp63_irq_handler,
@@ -615,7 +640,11 @@ static int snd_acp63_probe(struct pci_dev *pci,
dev_err(&pci->dev, "ACP platform devices creation failed\n");
goto de_init;
}
- adata->machines = snd_soc_acpi_amd_acp63_sdw_machines;
+ if (adata->acp_rev >= ACP70_PCI_REV)
+ adata->machines = snd_soc_acpi_amd_acp70_sdw_machines;
+ else
+ adata->machines = snd_soc_acpi_amd_acp63_sdw_machines;
+
ret = acp63_machine_register(&pci->dev);
if (ret) {
dev_err(&pci->dev, "ACP machine register failed\n");
@@ -629,7 +658,7 @@ skip_pdev_creation:
pm_runtime_allow(&pci->dev);
return 0;
de_init:
- if (acp63_deinit(adata->acp63_base, &pci->dev))
+ if (acp_hw_deinit(adata, &pci->dev))
dev_err(&pci->dev, "ACP de-init failed\n");
release_regions:
pci_release_regions(pci);
@@ -639,85 +668,24 @@ disable_pci:
return ret;
}
-static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata)
+static int snd_acp_suspend(struct device *dev)
{
- u32 sdw0_en, sdw1_en;
-
- sdw0_en = readl(adata->acp63_base + ACP_SW0_EN);
- sdw1_en = readl(adata->acp63_base + ACP_SW1_EN);
- return (sdw0_en || sdw1_en);
-}
-
-static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata)
-{
- u32 val;
-
- val = readl(adata->acp63_base + ACP_SW0_WAKE_EN);
- if (val && adata->sdw->pdev[0])
- pm_request_resume(&adata->sdw->pdev[0]->dev);
-
- val = readl(adata->acp63_base + ACP_SW1_WAKE_EN);
- if (val && adata->sdw->pdev[1])
- pm_request_resume(&adata->sdw->pdev[1]->dev);
-}
-
-static int __maybe_unused snd_acp63_suspend(struct device *dev)
-{
- struct acp63_dev_data *adata;
- int ret;
-
- adata = dev_get_drvdata(dev);
- if (adata->is_sdw_dev) {
- adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
- if (adata->sdw_en_stat)
- return 0;
- }
- ret = acp63_deinit(adata->acp63_base, dev);
- if (ret)
- dev_err(dev, "ACP de-init failed\n");
-
- return ret;
+ return acp_hw_suspend(dev);
}
-static int __maybe_unused snd_acp63_runtime_resume(struct device *dev)
+static int snd_acp_runtime_resume(struct device *dev)
{
- struct acp63_dev_data *adata;
- int ret;
-
- adata = dev_get_drvdata(dev);
- if (adata->sdw_en_stat)
- return 0;
-
- ret = acp63_init(adata->acp63_base, dev);
- if (ret) {
- dev_err(dev, "ACP init failed\n");
- return ret;
- }
-
- if (!adata->sdw_en_stat)
- handle_acp63_sdw_pme_event(adata);
- return 0;
+ return acp_hw_runtime_resume(dev);
}
-static int __maybe_unused snd_acp63_resume(struct device *dev)
+static int snd_acp_resume(struct device *dev)
{
- struct acp63_dev_data *adata;
- int ret;
-
- adata = dev_get_drvdata(dev);
- if (adata->sdw_en_stat)
- return 0;
-
- ret = acp63_init(adata->acp63_base, dev);
- if (ret)
- dev_err(dev, "ACP init failed\n");
-
- return ret;
+ return acp_hw_resume(dev);
}
static const struct dev_pm_ops acp63_pm_ops = {
- SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume)
+ RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume)
};
static void snd_acp63_remove(struct pci_dev *pci)
@@ -736,7 +704,7 @@ static void snd_acp63_remove(struct pci_dev *pci)
}
if (adata->mach_dev)
platform_device_unregister(adata->mach_dev);
- ret = acp63_deinit(adata->acp63_base, &pci->dev);
+ ret = acp_hw_deinit(adata, &pci->dev);
if (ret)
dev_err(&pci->dev, "ACP de-init failed\n");
pm_runtime_forbid(&pci->dev);
@@ -759,7 +727,7 @@ static struct pci_driver ps_acp63_driver = {
.probe = snd_acp63_probe,
.remove = snd_acp63_remove,
.driver = {
- .pm = &acp63_pm_ops,
+ .pm = pm_ptr(&acp63_pm_ops),
}
};
@@ -767,7 +735,7 @@ module_pci_driver(ps_acp63_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
-MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver");
+MODULE_DESCRIPTION("AMD common ACP PCI driver for ACP6.3, ACP7.0 & ACP7.1 platforms");
MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT");
MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/amd/ps/ps-common.c b/sound/soc/amd/ps/ps-common.c
new file mode 100644
index 000000000000..1c89fb5fe1da
--- /dev/null
+++ b/sound/soc/amd/ps/ps-common.c
@@ -0,0 +1,475 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AMD ACP PCI driver callback routines for ACP6.3, ACP7.0 & ACP7.1
+ * platforms.
+ *
+ * Copyright 2025 Advanced Micro Devices, Inc.
+ * Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <sound/pcm_params.h>
+
+#include "acp63.h"
+
+static int acp63_power_on(void __iomem *acp_base)
+{
+ u32 val;
+
+ val = readl(acp_base + ACP_PGFSM_STATUS);
+
+ if (!val)
+ return val;
+
+ if ((val & ACP63_PGFSM_STATUS_MASK) != ACP63_POWER_ON_IN_PROGRESS)
+ writel(ACP63_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+
+ return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP63_TIMEOUT);
+}
+
+static int acp63_reset(void __iomem *acp_base)
+{
+ u32 val;
+ int ret;
+
+ writel(1, acp_base + ACP_SOFT_RESET);
+
+ ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
+ val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
+ DELAY_US, ACP63_TIMEOUT);
+ if (ret)
+ return ret;
+
+ writel(0, acp_base + ACP_SOFT_RESET);
+
+ return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP63_TIMEOUT);
+}
+
+static void acp63_enable_interrupts(void __iomem *acp_base)
+{
+ writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
+ writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
+}
+
+static void acp63_disable_interrupts(void __iomem *acp_base)
+{
+ writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT);
+ writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
+}
+
+static int acp63_init(void __iomem *acp_base, struct device *dev)
+{
+ int ret;
+
+ ret = acp63_power_on(acp_base);
+ if (ret) {
+ dev_err(dev, "ACP power on failed\n");
+ return ret;
+ }
+ writel(0x01, acp_base + ACP_CONTROL);
+ ret = acp63_reset(acp_base);
+ if (ret) {
+ dev_err(dev, "ACP reset failed\n");
+ return ret;
+ }
+ acp63_enable_interrupts(acp_base);
+ writel(0, acp_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+}
+
+static int acp63_deinit(void __iomem *acp_base, struct device *dev)
+{
+ int ret;
+
+ acp63_disable_interrupts(acp_base);
+ ret = acp63_reset(acp_base);
+ if (ret) {
+ dev_err(dev, "ACP reset failed\n");
+ return ret;
+ }
+ writel(0, acp_base + ACP_CONTROL);
+ writel(1, acp_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+}
+
+static void acp63_get_config(struct pci_dev *pci, struct acp63_dev_data *acp_data)
+{
+ u32 config;
+
+ config = readl(acp_data->acp63_base + ACP_PIN_CONFIG);
+ dev_dbg(&pci->dev, "ACP config value: %d\n", config);
+ switch (config) {
+ case ACP_CONFIG_4:
+ case ACP_CONFIG_5:
+ case ACP_CONFIG_10:
+ case ACP_CONFIG_11:
+ acp_data->is_pdm_config = true;
+ break;
+ case ACP_CONFIG_2:
+ case ACP_CONFIG_3:
+ acp_data->is_sdw_config = true;
+ break;
+ case ACP_CONFIG_6:
+ case ACP_CONFIG_7:
+ case ACP_CONFIG_12:
+ case ACP_CONFIG_8:
+ case ACP_CONFIG_13:
+ case ACP_CONFIG_14:
+ acp_data->is_pdm_config = true;
+ acp_data->is_sdw_config = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata)
+{
+ u32 sdw0_en, sdw1_en;
+
+ sdw0_en = readl(adata->acp63_base + ACP_SW0_EN);
+ sdw1_en = readl(adata->acp63_base + ACP_SW1_EN);
+ return (sdw0_en || sdw1_en);
+}
+
+static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata)
+{
+ u32 val;
+
+ val = readl(adata->acp63_base + ACP_SW0_WAKE_EN);
+ if (val && adata->sdw->pdev[0])
+ pm_request_resume(&adata->sdw->pdev[0]->dev);
+
+ val = readl(adata->acp63_base + ACP_SW1_WAKE_EN);
+ if (val && adata->sdw->pdev[1])
+ pm_request_resume(&adata->sdw->pdev[1]->dev);
+}
+
+static int __maybe_unused snd_acp63_suspend(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+ if (adata->is_sdw_dev) {
+ adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
+ if (adata->sdw_en_stat) {
+ writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+ }
+ }
+ ret = acp_hw_deinit(adata, dev);
+ if (ret)
+ dev_err(dev, "ACP de-init failed\n");
+
+ return ret;
+}
+
+static int __maybe_unused snd_acp63_runtime_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+ if (adata->sdw_en_stat) {
+ writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+ }
+ ret = acp_hw_init(adata, dev);
+ if (ret) {
+ dev_err(dev, "ACP init failed\n");
+ return ret;
+ }
+
+ if (!adata->sdw_en_stat)
+ handle_acp63_sdw_pme_event(adata);
+ return 0;
+}
+
+static int __maybe_unused snd_acp63_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+ if (adata->sdw_en_stat) {
+ writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+ }
+
+ ret = acp_hw_init(adata, dev);
+ if (ret)
+ dev_err(dev, "ACP init failed\n");
+
+ return ret;
+}
+
+static void acp63_sdw_dma_irq_thread(struct acp63_dev_data *adata)
+{
+ struct sdw_dma_dev_data *sdw_data;
+ u32 stream_id;
+
+ sdw_data = dev_get_drvdata(&adata->sdw_dma_dev->dev);
+
+ for (stream_id = 0; stream_id < ACP63_SDW0_DMA_MAX_STREAMS; stream_id++) {
+ if (adata->acp63_sdw0_dma_intr_stat[stream_id]) {
+ if (sdw_data->acp63_sdw0_dma_stream[stream_id])
+ snd_pcm_period_elapsed(sdw_data->acp63_sdw0_dma_stream[stream_id]);
+ adata->acp63_sdw0_dma_intr_stat[stream_id] = 0;
+ }
+ }
+ for (stream_id = 0; stream_id < ACP63_SDW1_DMA_MAX_STREAMS; stream_id++) {
+ if (adata->acp63_sdw1_dma_intr_stat[stream_id]) {
+ if (sdw_data->acp63_sdw1_dma_stream[stream_id])
+ snd_pcm_period_elapsed(sdw_data->acp63_sdw1_dma_stream[stream_id]);
+ adata->acp63_sdw1_dma_intr_stat[stream_id] = 0;
+ }
+ }
+}
+
+void acp63_hw_init_ops(struct acp_hw_ops *hw_ops)
+{
+ hw_ops->acp_init = acp63_init;
+ hw_ops->acp_deinit = acp63_deinit;
+ hw_ops->acp_get_config = acp63_get_config;
+ hw_ops->acp_sdw_dma_irq_thread = acp63_sdw_dma_irq_thread;
+ hw_ops->acp_suspend = snd_acp63_suspend;
+ hw_ops->acp_resume = snd_acp63_resume;
+ hw_ops->acp_suspend_runtime = snd_acp63_suspend;
+ hw_ops->acp_resume_runtime = snd_acp63_runtime_resume;
+}
+
+static int acp70_power_on(void __iomem *acp_base)
+{
+ u32 val = 0;
+
+ val = readl(acp_base + ACP_PGFSM_STATUS);
+
+ if (!val)
+ return 0;
+ if (val & ACP70_PGFSM_STATUS_MASK)
+ writel(ACP70_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL);
+
+ return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP70_TIMEOUT);
+}
+
+static int acp70_reset(void __iomem *acp_base)
+{
+ u32 val;
+ int ret;
+
+ writel(1, acp_base + ACP_SOFT_RESET);
+
+ ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val,
+ val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK,
+ DELAY_US, ACP70_TIMEOUT);
+ if (ret)
+ return ret;
+
+ writel(0, acp_base + ACP_SOFT_RESET);
+
+ return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP70_TIMEOUT);
+}
+
+static void acp70_enable_sdw_host_wake_interrupts(void __iomem *acp_base)
+{
+ u32 ext_intr_cntl1;
+
+ ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1);
+ ext_intr_cntl1 |= ACP70_SDW_HOST_WAKE_MASK;
+ writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1);
+}
+
+static void acp70_enable_interrupts(void __iomem *acp_base)
+{
+ u32 sdw0_wake_en, sdw1_wake_en;
+
+ writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
+ writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ sdw0_wake_en = readl(acp_base + ACP_SW0_WAKE_EN);
+ sdw1_wake_en = readl(acp_base + ACP_SW1_WAKE_EN);
+ if (sdw0_wake_en || sdw1_wake_en)
+ acp70_enable_sdw_host_wake_interrupts(acp_base);
+}
+
+static void acp70_disable_interrupts(void __iomem *acp_base)
+{
+ writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT);
+ writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL);
+ writel(0, acp_base + ACP_EXTERNAL_INTR_ENB);
+}
+
+static int acp70_init(void __iomem *acp_base, struct device *dev)
+{
+ int ret;
+
+ ret = acp70_power_on(acp_base);
+ if (ret) {
+ dev_err(dev, "ACP power on failed\n");
+ return ret;
+ }
+ writel(0x01, acp_base + ACP_CONTROL);
+ ret = acp70_reset(acp_base);
+ if (ret) {
+ dev_err(dev, "ACP reset failed\n");
+ return ret;
+ }
+ writel(0, acp_base + ACP_ZSC_DSP_CTRL);
+ acp70_enable_interrupts(acp_base);
+ writel(0x1, acp_base + ACP_PME_EN);
+ return 0;
+}
+
+static int acp70_deinit(void __iomem *acp_base, struct device *dev)
+{
+ int ret;
+
+ acp70_disable_interrupts(acp_base);
+ ret = acp70_reset(acp_base);
+ if (ret) {
+ dev_err(dev, "ACP reset failed\n");
+ return ret;
+ }
+ writel(0x01, acp_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+}
+
+static void acp70_get_config(struct pci_dev *pci, struct acp63_dev_data *acp_data)
+{
+ u32 config;
+
+ config = readl(acp_data->acp63_base + ACP_PIN_CONFIG);
+ dev_dbg(&pci->dev, "ACP config value: %d\n", config);
+ switch (config) {
+ case ACP_CONFIG_4:
+ case ACP_CONFIG_5:
+ case ACP_CONFIG_10:
+ case ACP_CONFIG_11:
+ case ACP_CONFIG_20:
+ acp_data->is_pdm_config = true;
+ break;
+ case ACP_CONFIG_2:
+ case ACP_CONFIG_3:
+ case ACP_CONFIG_16:
+ acp_data->is_sdw_config = true;
+ break;
+ case ACP_CONFIG_6:
+ case ACP_CONFIG_7:
+ case ACP_CONFIG_12:
+ case ACP_CONFIG_8:
+ case ACP_CONFIG_13:
+ case ACP_CONFIG_14:
+ case ACP_CONFIG_17:
+ case ACP_CONFIG_18:
+ case ACP_CONFIG_19:
+ acp_data->is_pdm_config = true;
+ acp_data->is_sdw_config = true;
+ break;
+ default:
+ break;
+ }
+}
+
+static void acp70_sdw_dma_irq_thread(struct acp63_dev_data *adata)
+{
+ struct sdw_dma_dev_data *sdw_data;
+ u32 stream_id;
+
+ sdw_data = dev_get_drvdata(&adata->sdw_dma_dev->dev);
+
+ for (stream_id = 0; stream_id < ACP70_SDW0_DMA_MAX_STREAMS; stream_id++) {
+ if (adata->acp70_sdw0_dma_intr_stat[stream_id]) {
+ if (sdw_data->acp70_sdw0_dma_stream[stream_id])
+ snd_pcm_period_elapsed(sdw_data->acp70_sdw0_dma_stream[stream_id]);
+ adata->acp70_sdw0_dma_intr_stat[stream_id] = 0;
+ }
+ }
+ for (stream_id = 0; stream_id < ACP70_SDW1_DMA_MAX_STREAMS; stream_id++) {
+ if (adata->acp70_sdw1_dma_intr_stat[stream_id]) {
+ if (sdw_data->acp70_sdw1_dma_stream[stream_id])
+ snd_pcm_period_elapsed(sdw_data->acp70_sdw1_dma_stream[stream_id]);
+ adata->acp70_sdw1_dma_intr_stat[stream_id] = 0;
+ }
+ }
+}
+
+static int __maybe_unused snd_acp70_suspend(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+ if (adata->is_sdw_dev) {
+ adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
+ if (adata->sdw_en_stat) {
+ writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL);
+ return 0;
+ }
+ }
+ ret = acp_hw_deinit(adata, dev);
+ if (ret)
+ dev_err(dev, "ACP de-init failed\n");
+
+ return ret;
+}
+
+static int __maybe_unused snd_acp70_runtime_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+
+ if (adata->sdw_en_stat) {
+ writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
+ writel(1, adata->acp63_base + ACP_PME_EN);
+ return 0;
+ }
+
+ ret = acp_hw_init(adata, dev);
+ if (ret) {
+ dev_err(dev, "ACP init failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int __maybe_unused snd_acp70_resume(struct device *dev)
+{
+ struct acp63_dev_data *adata;
+ int ret;
+
+ adata = dev_get_drvdata(dev);
+
+ if (adata->sdw_en_stat) {
+ writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL);
+ writel(1, adata->acp63_base + ACP_PME_EN);
+ return 0;
+ }
+
+ ret = acp_hw_init(adata, dev);
+ if (ret)
+ dev_err(dev, "ACP init failed\n");
+
+ return ret;
+}
+
+void acp70_hw_init_ops(struct acp_hw_ops *hw_ops)
+{
+ hw_ops->acp_init = acp70_init;
+ hw_ops->acp_deinit = acp70_deinit;
+ hw_ops->acp_get_config = acp70_get_config;
+ hw_ops->acp_sdw_dma_irq_thread = acp70_sdw_dma_irq_thread;
+ hw_ops->acp_suspend = snd_acp70_suspend;
+ hw_ops->acp_resume = snd_acp70_resume;
+ hw_ops->acp_suspend_runtime = snd_acp70_suspend;
+ hw_ops->acp_resume_runtime = snd_acp70_runtime_resume;
+}
diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c
index 318fc260f293..9cfbe05ad996 100644
--- a/sound/soc/amd/ps/ps-pdm-dma.c
+++ b/sound/soc/amd/ps/ps-pdm-dma.c
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * AMD ALSA SoC Pink Sardine PDM Driver
+ * AMD ALSA SoC common PDM Driver for ACP6.3, ACP7.0 & ACP7.1 platforms.
*
- * Copyright 2022 Advanced Micro Devices, Inc.
+ * Copyright 2022, 2025 Advanced Micro Devices, Inc.
*/
#include <linux/platform_device.h>
@@ -402,7 +402,7 @@ static void acp63_pdm_audio_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused acp63_pdm_resume(struct device *dev)
+static int acp63_pdm_resume(struct device *dev)
{
struct pdm_dev_data *adata;
struct snd_pcm_runtime *runtime;
@@ -423,7 +423,7 @@ static int __maybe_unused acp63_pdm_resume(struct device *dev)
return 0;
}
-static int __maybe_unused acp63_pdm_suspend(struct device *dev)
+static int acp63_pdm_suspend(struct device *dev)
{
struct pdm_dev_data *adata;
@@ -432,7 +432,7 @@ static int __maybe_unused acp63_pdm_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev)
+static int acp63_pdm_runtime_resume(struct device *dev)
{
struct pdm_dev_data *adata;
@@ -442,8 +442,8 @@ static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops acp63_pdm_pm_ops = {
- SET_RUNTIME_PM_OPS(acp63_pdm_suspend, acp63_pdm_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(acp63_pdm_suspend, acp63_pdm_resume)
+ RUNTIME_PM_OPS(acp63_pdm_suspend, acp63_pdm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(acp63_pdm_suspend, acp63_pdm_resume)
};
static struct platform_driver acp63_pdm_dma_driver = {
@@ -451,13 +451,13 @@ static struct platform_driver acp63_pdm_dma_driver = {
.remove = acp63_pdm_audio_remove,
.driver = {
.name = "acp_ps_pdm_dma",
- .pm = &acp63_pdm_pm_ops,
+ .pm = pm_ptr(&acp63_pdm_pm_ops),
},
};
module_platform_driver(acp63_pdm_dma_driver);
MODULE_AUTHOR("Syed.SabaKareem@amd.com");
-MODULE_DESCRIPTION("AMD PINK SARDINE PDM Driver");
+MODULE_DESCRIPTION("AMD common PDM Driver for ACP6.3, ACP7,0 & ACP7.1 platforms");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c
index b602cca92b8b..1b933a017c06 100644
--- a/sound/soc/amd/ps/ps-sdw-dma.c
+++ b/sound/soc/amd/ps/ps-sdw-dma.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * AMD ALSA SoC Pink Sardine SoundWire DMA Driver
+ * AMD ALSA SoC common SoundWire DMA Driver for ACP6.3, ACP7.0 and ACP7.1
+ * platforms.
*
- * Copyright 2023 Advanced Micro Devices, Inc.
+ * Copyright 2023, 2025 Advanced Micro Devices, Inc.
*/
#include <linux/err.h>
@@ -18,7 +19,7 @@
#define DRV_NAME "amd_ps_sdw_dma"
-static struct sdw_dma_ring_buf_reg sdw0_dma_ring_buf_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
+static struct sdw_dma_ring_buf_reg acp63_sdw0_dma_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
{ACP_AUDIO0_TX_DMA_SIZE, ACP_AUDIO0_TX_FIFOADDR, ACP_AUDIO0_TX_FIFOSIZE,
ACP_AUDIO0_TX_RINGBUFSIZE, ACP_AUDIO0_TX_RINGBUFADDR, ACP_AUDIO0_TX_INTR_WATERMARK_SIZE,
ACP_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH},
@@ -44,7 +45,7 @@ static struct sdw_dma_ring_buf_reg sdw0_dma_ring_buf_reg[ACP63_SDW0_DMA_MAX_STRE
* For TX/RX streams DMA registers programming for SDW1 instance, it uses ACP_P1_AUDIO1 register
* set as per hardware register documentation
*/
-static struct sdw_dma_ring_buf_reg sdw1_dma_ring_buf_reg[ACP63_SDW1_DMA_MAX_STREAMS] = {
+static struct sdw_dma_ring_buf_reg acp63_sdw1_dma_reg[ACP63_SDW1_DMA_MAX_STREAMS] = {
{ACP_P1_AUDIO1_TX_DMA_SIZE, ACP_P1_AUDIO1_TX_FIFOADDR, ACP_P1_AUDIO1_TX_FIFOSIZE,
ACP_P1_AUDIO1_TX_RINGBUFSIZE, ACP_P1_AUDIO1_TX_RINGBUFADDR,
ACP_P1_AUDIO1_TX_INTR_WATERMARK_SIZE,
@@ -55,7 +56,7 @@ static struct sdw_dma_ring_buf_reg sdw1_dma_ring_buf_reg[ACP63_SDW1_DMA_MAX_STRE
ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
};
-static u32 sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
+static u32 acp63_sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
ACP_SW0_AUDIO0_TX_EN,
ACP_SW0_AUDIO1_TX_EN,
ACP_SW0_AUDIO2_TX_EN,
@@ -70,11 +71,77 @@ static u32 sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = {
* it uses ACP_SW1_AUDIO1_TX_EN and ACP_SW1_AUDIO1_RX_EN registers
* as per hardware register documentation.
*/
-static u32 sdw1_dma_enable_reg[ACP63_SDW1_DMA_MAX_STREAMS] = {
+static u32 acp63_sdw1_dma_enable_reg[ACP63_SDW1_DMA_MAX_STREAMS] = {
ACP_SW1_AUDIO1_TX_EN,
ACP_SW1_AUDIO1_RX_EN,
};
+static struct sdw_dma_ring_buf_reg acp70_sdw0_dma_reg[ACP70_SDW0_DMA_MAX_STREAMS] = {
+ {ACP_AUDIO0_TX_DMA_SIZE, ACP_AUDIO0_TX_FIFOADDR, ACP_AUDIO0_TX_FIFOSIZE,
+ ACP_AUDIO0_TX_RINGBUFSIZE, ACP_AUDIO0_TX_RINGBUFADDR, ACP_AUDIO0_TX_INTR_WATERMARK_SIZE,
+ ACP_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_AUDIO1_TX_DMA_SIZE, ACP_AUDIO1_TX_FIFOADDR, ACP_AUDIO1_TX_FIFOSIZE,
+ ACP_AUDIO1_TX_RINGBUFSIZE, ACP_AUDIO1_TX_RINGBUFADDR, ACP_AUDIO1_TX_INTR_WATERMARK_SIZE,
+ ACP_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_AUDIO2_TX_DMA_SIZE, ACP_AUDIO2_TX_FIFOADDR, ACP_AUDIO2_TX_FIFOSIZE,
+ ACP_AUDIO2_TX_RINGBUFSIZE, ACP_AUDIO2_TX_RINGBUFADDR, ACP_AUDIO2_TX_INTR_WATERMARK_SIZE,
+ ACP_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_AUDIO0_RX_DMA_SIZE, ACP_AUDIO0_RX_FIFOADDR, ACP_AUDIO0_RX_FIFOSIZE,
+ ACP_AUDIO0_RX_RINGBUFSIZE, ACP_AUDIO0_RX_RINGBUFADDR, ACP_AUDIO0_RX_INTR_WATERMARK_SIZE,
+ ACP_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_AUDIO1_RX_DMA_SIZE, ACP_AUDIO1_RX_FIFOADDR, ACP_AUDIO1_RX_FIFOSIZE,
+ ACP_AUDIO1_RX_RINGBUFSIZE, ACP_AUDIO1_RX_RINGBUFADDR, ACP_AUDIO1_RX_INTR_WATERMARK_SIZE,
+ ACP_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_AUDIO2_RX_DMA_SIZE, ACP_AUDIO2_RX_FIFOADDR, ACP_AUDIO2_RX_FIFOSIZE,
+ ACP_AUDIO2_RX_RINGBUFSIZE, ACP_AUDIO2_RX_RINGBUFADDR, ACP_AUDIO2_RX_INTR_WATERMARK_SIZE,
+ ACP_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH}
+};
+
+static struct sdw_dma_ring_buf_reg acp70_sdw1_dma_reg[ACP70_SDW1_DMA_MAX_STREAMS] = {
+ {ACP_P1_AUDIO0_TX_DMA_SIZE, ACP_P1_AUDIO0_TX_FIFOADDR, ACP_P1_AUDIO0_TX_FIFOSIZE,
+ ACP_P1_AUDIO0_TX_RINGBUFSIZE, ACP_P1_AUDIO0_TX_RINGBUFADDR,
+ ACP_P1_AUDIO0_TX_INTR_WATERMARK_SIZE,
+ ACP_P1_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_P1_AUDIO1_TX_DMA_SIZE, ACP_P1_AUDIO1_TX_FIFOADDR, ACP_P1_AUDIO1_TX_FIFOSIZE,
+ ACP_P1_AUDIO1_TX_RINGBUFSIZE, ACP_P1_AUDIO1_TX_RINGBUFADDR,
+ ACP_P1_AUDIO1_TX_INTR_WATERMARK_SIZE,
+ ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_P1_AUDIO2_TX_DMA_SIZE, ACP_P1_AUDIO2_TX_FIFOADDR, ACP_P1_AUDIO2_TX_FIFOSIZE,
+ ACP_P1_AUDIO2_TX_RINGBUFSIZE, ACP_P1_AUDIO2_TX_RINGBUFADDR,
+ ACP_P1_AUDIO2_TX_INTR_WATERMARK_SIZE,
+ ACP_P1_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_P1_AUDIO0_RX_DMA_SIZE, ACP_P1_AUDIO0_RX_FIFOADDR, ACP_P1_AUDIO0_RX_FIFOSIZE,
+ ACP_P1_AUDIO0_RX_RINGBUFSIZE, ACP_P1_AUDIO0_RX_RINGBUFADDR,
+ ACP_P1_AUDIO0_RX_INTR_WATERMARK_SIZE,
+ ACP_P1_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_P1_AUDIO1_RX_DMA_SIZE, ACP_P1_AUDIO1_RX_FIFOADDR, ACP_P1_AUDIO1_RX_FIFOSIZE,
+ ACP_P1_AUDIO1_RX_RINGBUFSIZE, ACP_P1_AUDIO1_RX_RINGBUFADDR,
+ ACP_P1_AUDIO1_RX_INTR_WATERMARK_SIZE,
+ ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH},
+ {ACP_P1_AUDIO2_RX_DMA_SIZE, ACP_P1_AUDIO2_RX_FIFOADDR, ACP_P1_AUDIO2_RX_FIFOSIZE,
+ ACP_P1_AUDIO2_RX_RINGBUFSIZE, ACP_P1_AUDIO2_RX_RINGBUFADDR,
+ ACP_P1_AUDIO2_RX_INTR_WATERMARK_SIZE,
+ ACP_P1_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH}
+};
+
+static u32 acp70_sdw0_dma_enable_reg[ACP70_SDW0_DMA_MAX_STREAMS] = {
+ ACP70_SW0_AUDIO0_TX_EN,
+ ACP70_SW0_AUDIO1_TX_EN,
+ ACP70_SW0_AUDIO2_TX_EN,
+ ACP70_SW0_AUDIO0_RX_EN,
+ ACP70_SW0_AUDIO1_RX_EN,
+ ACP70_SW0_AUDIO2_RX_EN,
+};
+
+static u32 acp70_sdw1_dma_enable_reg[ACP70_SDW1_DMA_MAX_STREAMS] = {
+ ACP70_SW1_AUDIO0_TX_EN,
+ ACP70_SW1_AUDIO1_TX_EN,
+ ACP70_SW1_AUDIO2_TX_EN,
+ ACP70_SW1_AUDIO0_RX_EN,
+ ACP70_SW1_AUDIO1_RX_EN,
+ ACP70_SW1_AUDIO2_RX_EN,
+};
+
static const struct snd_pcm_hardware acp63_sdw_hardware_playback = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -114,11 +181,10 @@ static const struct snd_pcm_hardware acp63_sdw_hardware_capture = {
.periods_max = SDW_CAPTURE_MAX_NUM_PERIODS,
};
-static void acp63_enable_disable_sdw_dma_interrupts(void __iomem *acp_base, bool enable)
+static void acp63_enable_disable_sdw_dma_interrupts(void __iomem *acp_base, u32 irq_mask,
+ u32 irq_mask1, bool enable)
{
u32 ext_intr_cntl, ext_intr_cntl1;
- u32 irq_mask = ACP_SDW_DMA_IRQ_MASK;
- u32 irq_mask1 = ACP_P1_SDW_DMA_IRQ_MASK;
if (enable) {
ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL);
@@ -167,7 +233,7 @@ static void acp63_config_dma(struct acp_sdw_dma_stream *stream, void __iomem *ac
}
static int acp63_configure_sdw_ringbuffer(void __iomem *acp_base, u32 stream_id, u32 size,
- u32 manager_instance)
+ u32 manager_instance, u32 acp_rev)
{
u32 reg_dma_size;
u32 reg_fifo_addr;
@@ -180,20 +246,47 @@ static int acp63_configure_sdw_ringbuffer(void __iomem *acp_base, u32 stream_id,
u32 sdw_ring_buf_size;
u32 sdw_mem_window_offset;
- switch (manager_instance) {
- case ACP_SDW0:
- reg_dma_size = sdw0_dma_ring_buf_reg[stream_id].reg_dma_size;
- reg_fifo_addr = sdw0_dma_ring_buf_reg[stream_id].reg_fifo_addr;
- reg_fifo_size = sdw0_dma_ring_buf_reg[stream_id].reg_fifo_size;
- reg_ring_buf_size = sdw0_dma_ring_buf_reg[stream_id].reg_ring_buf_size;
- reg_ring_buf_addr = sdw0_dma_ring_buf_reg[stream_id].reg_ring_buf_addr;
+ switch (acp_rev) {
+ case ACP63_PCI_REV:
+ switch (manager_instance) {
+ case ACP_SDW0:
+ reg_dma_size = acp63_sdw0_dma_reg[stream_id].reg_dma_size;
+ reg_fifo_addr = acp63_sdw0_dma_reg[stream_id].reg_fifo_addr;
+ reg_fifo_size = acp63_sdw0_dma_reg[stream_id].reg_fifo_size;
+ reg_ring_buf_size = acp63_sdw0_dma_reg[stream_id].reg_ring_buf_size;
+ reg_ring_buf_addr = acp63_sdw0_dma_reg[stream_id].reg_ring_buf_addr;
+ break;
+ case ACP_SDW1:
+ reg_dma_size = acp63_sdw1_dma_reg[stream_id].reg_dma_size;
+ reg_fifo_addr = acp63_sdw1_dma_reg[stream_id].reg_fifo_addr;
+ reg_fifo_size = acp63_sdw1_dma_reg[stream_id].reg_fifo_size;
+ reg_ring_buf_size = acp63_sdw1_dma_reg[stream_id].reg_ring_buf_size;
+ reg_ring_buf_addr = acp63_sdw1_dma_reg[stream_id].reg_ring_buf_addr;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
- case ACP_SDW1:
- reg_dma_size = sdw1_dma_ring_buf_reg[stream_id].reg_dma_size;
- reg_fifo_addr = sdw1_dma_ring_buf_reg[stream_id].reg_fifo_addr;
- reg_fifo_size = sdw1_dma_ring_buf_reg[stream_id].reg_fifo_size;
- reg_ring_buf_size = sdw1_dma_ring_buf_reg[stream_id].reg_ring_buf_size;
- reg_ring_buf_addr = sdw1_dma_ring_buf_reg[stream_id].reg_ring_buf_addr;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ switch (manager_instance) {
+ case ACP_SDW0:
+ reg_dma_size = acp70_sdw0_dma_reg[stream_id].reg_dma_size;
+ reg_fifo_addr = acp70_sdw0_dma_reg[stream_id].reg_fifo_addr;
+ reg_fifo_size = acp70_sdw0_dma_reg[stream_id].reg_fifo_size;
+ reg_ring_buf_size = acp70_sdw0_dma_reg[stream_id].reg_ring_buf_size;
+ reg_ring_buf_addr = acp70_sdw0_dma_reg[stream_id].reg_ring_buf_addr;
+ break;
+ case ACP_SDW1:
+ reg_dma_size = acp70_sdw1_dma_reg[stream_id].reg_dma_size;
+ reg_fifo_addr = acp70_sdw1_dma_reg[stream_id].reg_fifo_addr;
+ reg_fifo_size = acp70_sdw1_dma_reg[stream_id].reg_fifo_size;
+ reg_ring_buf_size = acp70_sdw1_dma_reg[stream_id].reg_ring_buf_size;
+ reg_ring_buf_addr = acp70_sdw1_dma_reg[stream_id].reg_ring_buf_addr;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
@@ -265,21 +358,53 @@ static int acp63_sdw_dma_hw_params(struct snd_soc_component *component,
if (!stream)
return -EINVAL;
stream_id = stream->stream_id;
- switch (stream->instance) {
- case ACP_SDW0:
- sdw_data->sdw0_dma_stream[stream_id] = substream;
- water_mark_size_reg = sdw0_dma_ring_buf_reg[stream_id].water_mark_size_reg;
- acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- irq_mask = BIT(SDW0_DMA_TX_IRQ_MASK(stream_id));
- else
- irq_mask = BIT(SDW0_DMA_RX_IRQ_MASK(stream_id));
+ switch (sdw_data->acp_rev) {
+ case ACP63_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ sdw_data->acp63_sdw0_dma_stream[stream_id] = substream;
+ water_mark_size_reg = acp63_sdw0_dma_reg[stream_id].water_mark_size_reg;
+ acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ irq_mask = BIT(ACP63_SDW0_DMA_TX_IRQ_MASK(stream_id));
+ else
+ irq_mask = BIT(ACP63_SDW0_DMA_RX_IRQ_MASK(stream_id));
+ break;
+ case ACP_SDW1:
+ sdw_data->acp63_sdw1_dma_stream[stream_id] = substream;
+ acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1;
+ water_mark_size_reg = acp63_sdw1_dma_reg[stream_id].water_mark_size_reg;
+ irq_mask = BIT(ACP63_SDW1_DMA_IRQ_MASK(stream_id));
+ break;
+ default:
+ return -EINVAL;
+ }
break;
- case ACP_SDW1:
- sdw_data->sdw1_dma_stream[stream_id] = substream;
- acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1;
- water_mark_size_reg = sdw1_dma_ring_buf_reg[stream_id].water_mark_size_reg;
- irq_mask = BIT(SDW1_DMA_IRQ_MASK(stream_id));
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ sdw_data->acp70_sdw0_dma_stream[stream_id] = substream;
+ water_mark_size_reg = acp70_sdw0_dma_reg[stream_id].water_mark_size_reg;
+ acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ irq_mask = BIT(ACP70_SDW0_DMA_TX_IRQ_MASK(stream_id));
+ else
+ irq_mask = BIT(ACP70_SDW0_DMA_RX_IRQ_MASK(stream_id));
+ break;
+ case ACP_SDW1:
+ sdw_data->acp70_sdw1_dma_stream[stream_id] = substream;
+ acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1;
+ water_mark_size_reg = acp70_sdw1_dma_reg[stream_id].water_mark_size_reg;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ irq_mask = BIT(ACP70_SDW1_DMA_TX_IRQ_MASK(stream_id));
+ else
+ irq_mask = BIT(ACP70_SDW1_DMA_RX_IRQ_MASK(stream_id));
+
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
@@ -290,7 +415,7 @@ static int acp63_sdw_dma_hw_params(struct snd_soc_component *component,
stream->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT);
acp63_config_dma(stream, sdw_data->acp_base, stream_id);
ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, stream_id, size,
- stream->instance);
+ stream->instance, sdw_data->acp_rev);
if (ret) {
dev_err(component->dev, "Invalid DMA channel\n");
return -EINVAL;
@@ -302,20 +427,42 @@ static int acp63_sdw_dma_hw_params(struct snd_soc_component *component,
return 0;
}
-static u64 acp63_sdw_get_byte_count(struct acp_sdw_dma_stream *stream, void __iomem *acp_base)
+static u64 acp63_sdw_get_byte_count(struct acp_sdw_dma_stream *stream, void __iomem *acp_base,
+ u32 acp_rev)
{
union acp_sdw_dma_count byte_count;
u32 pos_low_reg, pos_high_reg;
byte_count.bytescount = 0;
- switch (stream->instance) {
- case ACP_SDW0:
- pos_low_reg = sdw0_dma_ring_buf_reg[stream->stream_id].pos_low_reg;
- pos_high_reg = sdw0_dma_ring_buf_reg[stream->stream_id].pos_high_reg;
+ switch (acp_rev) {
+ case ACP63_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ pos_low_reg = acp63_sdw0_dma_reg[stream->stream_id].pos_low_reg;
+ pos_high_reg = acp63_sdw0_dma_reg[stream->stream_id].pos_high_reg;
+ break;
+ case ACP_SDW1:
+ pos_low_reg = acp63_sdw1_dma_reg[stream->stream_id].pos_low_reg;
+ pos_high_reg = acp63_sdw1_dma_reg[stream->stream_id].pos_high_reg;
+ break;
+ default:
+ goto POINTER_RETURN_BYTES;
+ }
break;
- case ACP_SDW1:
- pos_low_reg = sdw1_dma_ring_buf_reg[stream->stream_id].pos_low_reg;
- pos_high_reg = sdw1_dma_ring_buf_reg[stream->stream_id].pos_high_reg;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ pos_low_reg = acp70_sdw0_dma_reg[stream->stream_id].pos_low_reg;
+ pos_high_reg = acp70_sdw0_dma_reg[stream->stream_id].pos_high_reg;
+ break;
+ case ACP_SDW1:
+ pos_low_reg = acp70_sdw1_dma_reg[stream->stream_id].pos_low_reg;
+ pos_high_reg = acp70_sdw1_dma_reg[stream->stream_id].pos_high_reg;
+ break;
+ default:
+ goto POINTER_RETURN_BYTES;
+ }
break;
default:
goto POINTER_RETURN_BYTES;
@@ -340,7 +487,7 @@ static snd_pcm_uframes_t acp63_sdw_dma_pointer(struct snd_soc_component *comp,
stream = substream->runtime->private_data;
buffersize = frames_to_bytes(substream->runtime,
substream->runtime->buffer_size);
- bytescount = acp63_sdw_get_byte_count(stream, sdw_data->acp_base);
+ bytescount = acp63_sdw_get_byte_count(stream, sdw_data->acp_base, sdw_data->acp_rev);
if (bytescount > stream->bytescount)
bytescount -= stream->bytescount;
pos = do_div(bytescount, buffersize);
@@ -367,12 +514,31 @@ static int acp63_sdw_dma_close(struct snd_soc_component *component,
stream = substream->runtime->private_data;
if (!stream)
return -EINVAL;
- switch (stream->instance) {
- case ACP_SDW0:
- sdw_data->sdw0_dma_stream[stream->stream_id] = NULL;
+ switch (sdw_data->acp_rev) {
+ case ACP63_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ sdw_data->acp63_sdw0_dma_stream[stream->stream_id] = NULL;
+ break;
+ case ACP_SDW1:
+ sdw_data->acp63_sdw1_dma_stream[stream->stream_id] = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
- case ACP_SDW1:
- sdw_data->sdw1_dma_stream[stream->stream_id] = NULL;
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ sdw_data->acp70_sdw0_dma_stream[stream->stream_id] = NULL;
+ break;
+ case ACP_SDW1:
+ sdw_data->acp70_sdw1_dma_stream[stream->stream_id] = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
@@ -382,7 +548,7 @@ static int acp63_sdw_dma_close(struct snd_soc_component *component,
}
static int acp63_sdw_dma_enable(struct snd_pcm_substream *substream,
- void __iomem *acp_base, bool sdw_dma_enable)
+ void __iomem *acp_base, u32 acp_rev, bool sdw_dma_enable)
{
struct acp_sdw_dma_stream *stream;
u32 stream_id;
@@ -393,12 +559,31 @@ static int acp63_sdw_dma_enable(struct snd_pcm_substream *substream,
stream = substream->runtime->private_data;
stream_id = stream->stream_id;
- switch (stream->instance) {
- case ACP_SDW0:
- sdw_dma_en_reg = sdw0_dma_enable_reg[stream_id];
+ switch (acp_rev) {
+ case ACP63_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ sdw_dma_en_reg = acp63_sdw0_dma_enable_reg[stream_id];
+ break;
+ case ACP_SDW1:
+ sdw_dma_en_reg = acp63_sdw1_dma_enable_reg[stream_id];
+ break;
+ default:
+ return -EINVAL;
+ }
break;
- case ACP_SDW1:
- sdw_dma_en_reg = sdw1_dma_enable_reg[stream_id];
+ case ACP70_PCI_REV:
+ case ACP71_PCI_REV:
+ switch (stream->instance) {
+ case ACP_SDW0:
+ sdw_dma_en_reg = acp70_sdw0_dma_enable_reg[stream_id];
+ break;
+ case ACP_SDW1:
+ sdw_dma_en_reg = acp70_sdw1_dma_enable_reg[stream_id];
+ break;
+ default:
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
@@ -422,12 +607,12 @@ static int acp63_sdw_dma_trigger(struct snd_soc_component *comp,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, true);
+ ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, sdw_data->acp_rev, true);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
- ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, false);
+ ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, sdw_data->acp_rev, false);
break;
default:
ret = -EINVAL;
@@ -474,6 +659,7 @@ static int acp63_sdw_platform_probe(struct platform_device *pdev)
return -ENOMEM;
sdw_data->acp_lock = &acp_data->acp_lock;
+ sdw_data->acp_rev = acp_data->acp_rev;
dev_set_drvdata(&pdev->dev, sdw_data);
status = devm_snd_soc_register_component(&pdev->dev,
&acp63_sdw_component,
@@ -495,15 +681,17 @@ static void acp63_sdw_platform_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
+static int acp63_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
{
struct acp_sdw_dma_stream *stream;
struct snd_pcm_substream *substream;
struct snd_pcm_runtime *runtime;
u32 period_bytes, buf_size, water_mark_size_reg;
- u32 stream_count;
+ u32 stream_count, irq_mask, irq_mask1;
int index, instance, ret;
+ irq_mask = ACP63_SDW_DMA_IRQ_MASK;
+ irq_mask1 = ACP63_P1_SDW_DMA_IRQ_MASK;
for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) {
if (instance == ACP_SDW0)
stream_count = ACP63_SDW0_DMA_MAX_STREAMS;
@@ -512,13 +700,11 @@ static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
for (index = 0; index < stream_count; index++) {
if (instance == ACP_SDW0) {
- substream = sdw_data->sdw0_dma_stream[index];
- water_mark_size_reg =
- sdw0_dma_ring_buf_reg[index].water_mark_size_reg;
+ substream = sdw_data->acp63_sdw0_dma_stream[index];
+ water_mark_size_reg = acp63_sdw0_dma_reg[index].water_mark_size_reg;
} else {
- substream = sdw_data->sdw1_dma_stream[index];
- water_mark_size_reg =
- sdw1_dma_ring_buf_reg[index].water_mark_size_reg;
+ substream = sdw_data->acp63_sdw1_dma_stream[index];
+ water_mark_size_reg = acp63_sdw1_dma_reg[index].water_mark_size_reg;
}
if (substream && substream->runtime) {
@@ -528,27 +714,72 @@ static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
buf_size = frames_to_bytes(runtime, runtime->buffer_size);
acp63_config_dma(stream, sdw_data->acp_base, index);
ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index,
- buf_size, instance);
+ buf_size, instance,
+ ACP63_PCI_REV);
if (ret)
return ret;
writel(period_bytes, sdw_data->acp_base + water_mark_size_reg);
}
}
}
- acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, true);
+ acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, irq_mask, irq_mask1, true);
return 0;
}
-static int __maybe_unused acp63_sdw_pcm_resume(struct device *dev)
+static int acp70_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data)
+{
+ struct acp_sdw_dma_stream *stream;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+ u32 period_bytes, buf_size, water_mark_size_reg;
+ u32 stream_count, irq_mask, irq_mask1;
+ int index, instance, ret;
+
+ irq_mask = ACP70_SDW_DMA_IRQ_MASK;
+ irq_mask1 = ACP70_P1_SDW_DMA_IRQ_MASK;
+ stream_count = ACP70_SDW0_DMA_MAX_STREAMS;
+ for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) {
+ for (index = 0; index < stream_count; index++) {
+ if (instance == ACP_SDW0) {
+ substream = sdw_data->acp70_sdw0_dma_stream[index];
+ water_mark_size_reg = acp70_sdw0_dma_reg[index].water_mark_size_reg;
+ } else {
+ substream = sdw_data->acp70_sdw1_dma_stream[index];
+ water_mark_size_reg = acp70_sdw1_dma_reg[index].water_mark_size_reg;
+ }
+
+ if (substream && substream->runtime) {
+ runtime = substream->runtime;
+ stream = runtime->private_data;
+ period_bytes = frames_to_bytes(runtime, runtime->period_size);
+ buf_size = frames_to_bytes(runtime, runtime->buffer_size);
+ acp63_config_dma(stream, sdw_data->acp_base, index);
+ ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index,
+ buf_size, instance,
+ sdw_data->acp_rev);
+ if (ret)
+ return ret;
+ writel(period_bytes, sdw_data->acp_base + water_mark_size_reg);
+ }
+ }
+ }
+ acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, irq_mask, irq_mask1, true);
+ return 0;
+}
+
+static int acp63_sdw_pcm_resume(struct device *dev)
{
struct sdw_dma_dev_data *sdw_data;
sdw_data = dev_get_drvdata(dev);
- return acp_restore_sdw_dma_config(sdw_data);
+ if (sdw_data->acp_rev == ACP63_PCI_REV)
+ return acp63_restore_sdw_dma_config(sdw_data);
+ else
+ return acp70_restore_sdw_dma_config(sdw_data);
}
static const struct dev_pm_ops acp63_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume)
+ SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume)
};
static struct platform_driver acp63_sdw_dma_driver = {
@@ -556,13 +787,13 @@ static struct platform_driver acp63_sdw_dma_driver = {
.remove = acp63_sdw_platform_remove,
.driver = {
.name = "amd_ps_sdw_dma",
- .pm = &acp63_pm_ops,
+ .pm = pm_ptr(&acp63_pm_ops),
},
};
module_platform_driver(acp63_sdw_dma_driver);
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
-MODULE_DESCRIPTION("AMD ACP6.3 PS SDW DMA Driver");
+MODULE_DESCRIPTION("AMD common SDW DMA Driver for ACP6.3, ACP7.0 & ACP7.1 platforms");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/amd/rpl/rpl-pci-acp6x.c b/sound/soc/amd/rpl/rpl-pci-acp6x.c
index a8e548ed991b..e3afe9172bdf 100644
--- a/sound/soc/amd/rpl/rpl-pci-acp6x.c
+++ b/sound/soc/amd/rpl/rpl-pci-acp6x.c
@@ -159,7 +159,7 @@ disable_pci:
return ret;
}
-static int __maybe_unused snd_rpl_suspend(struct device *dev)
+static int snd_rpl_suspend(struct device *dev)
{
struct rpl_dev_data *adata;
int ret;
@@ -171,7 +171,7 @@ static int __maybe_unused snd_rpl_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused snd_rpl_resume(struct device *dev)
+static int snd_rpl_resume(struct device *dev)
{
struct rpl_dev_data *adata;
int ret;
@@ -184,8 +184,8 @@ static int __maybe_unused snd_rpl_resume(struct device *dev)
}
static const struct dev_pm_ops rpl_pm = {
- SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume)
+ RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume)
};
static void snd_rpl_remove(struct pci_dev *pci)
@@ -217,7 +217,7 @@ static struct pci_driver rpl_acp6x_driver = {
.probe = snd_rpl_probe,
.remove = snd_rpl_remove,
.driver = {
- .pm = &rpl_pm,
+ .pm = pm_ptr(&rpl_pm),
}
};
diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
index d5965f2b09bc..aa4726899434 100644
--- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c
+++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c
@@ -420,7 +420,7 @@ static void acp5x_audio_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused acp5x_pcm_resume(struct device *dev)
+static int acp5x_pcm_resume(struct device *dev)
{
struct i2s_dev_data *adata;
struct i2s_stream_instance *rtd;
@@ -473,7 +473,7 @@ static int __maybe_unused acp5x_pcm_resume(struct device *dev)
return 0;
}
-static int __maybe_unused acp5x_pcm_suspend(struct device *dev)
+static int acp5x_pcm_suspend(struct device *dev)
{
struct i2s_dev_data *adata;
@@ -482,7 +482,7 @@ static int __maybe_unused acp5x_pcm_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused acp5x_pcm_runtime_resume(struct device *dev)
+static int acp5x_pcm_runtime_resume(struct device *dev)
{
struct i2s_dev_data *adata;
@@ -492,9 +492,8 @@ static int __maybe_unused acp5x_pcm_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops acp5x_pm_ops = {
- SET_RUNTIME_PM_OPS(acp5x_pcm_suspend,
- acp5x_pcm_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(acp5x_pcm_suspend, acp5x_pcm_resume)
+ RUNTIME_PM_OPS(acp5x_pcm_suspend, acp5x_pcm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(acp5x_pcm_suspend, acp5x_pcm_resume)
};
static struct platform_driver acp5x_dma_driver = {
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index ecf57a6cb7c3..e632f16c9102 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -252,6 +252,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "21M6"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "21ME"),
}
},
@@ -307,6 +314,41 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
{
.driver_data = &acp6x_card,
.matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83L3"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83N6"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83Q2"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83J2"),
+ }
+ },
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"),
}
@@ -549,6 +591,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"),
+ }
+ },
{}
};
diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c
index 3eb3e82efb10..ac758b90f441 100644
--- a/sound/soc/amd/yc/acp6x-pdm-dma.c
+++ b/sound/soc/amd/yc/acp6x-pdm-dma.c
@@ -394,7 +394,7 @@ static void acp6x_pdm_audio_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused acp6x_pdm_resume(struct device *dev)
+static int acp6x_pdm_resume(struct device *dev)
{
struct pdm_dev_data *adata;
struct snd_pcm_runtime *runtime;
@@ -415,7 +415,7 @@ static int __maybe_unused acp6x_pdm_resume(struct device *dev)
return 0;
}
-static int __maybe_unused acp6x_pdm_suspend(struct device *dev)
+static int acp6x_pdm_suspend(struct device *dev)
{
struct pdm_dev_data *adata;
@@ -424,7 +424,7 @@ static int __maybe_unused acp6x_pdm_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused acp6x_pdm_runtime_resume(struct device *dev)
+static int acp6x_pdm_runtime_resume(struct device *dev)
{
struct pdm_dev_data *adata;
@@ -434,8 +434,8 @@ static int __maybe_unused acp6x_pdm_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops acp6x_pdm_pm_ops = {
- SET_RUNTIME_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_resume)
+ RUNTIME_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_resume)
};
static struct platform_driver acp6x_pdm_dma_driver = {
@@ -443,7 +443,7 @@ static struct platform_driver acp6x_pdm_dma_driver = {
.remove = acp6x_pdm_audio_remove,
.driver = {
.name = "acp_yc_pdm_dma",
- .pm = &acp6x_pdm_pm_ops,
+ .pm = pm_ptr(&acp6x_pdm_pm_ops),
},
};
diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c
index 7af6a349b1d4..1140ed1cbb3d 100644
--- a/sound/soc/amd/yc/pci-acp6x.c
+++ b/sound/soc/amd/yc/pci-acp6x.c
@@ -277,7 +277,7 @@ disable_pci:
return ret;
}
-static int __maybe_unused snd_acp6x_suspend(struct device *dev)
+static int snd_acp6x_suspend(struct device *dev)
{
struct acp6x_dev_data *adata;
int ret;
@@ -289,7 +289,7 @@ static int __maybe_unused snd_acp6x_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused snd_acp6x_resume(struct device *dev)
+static int snd_acp6x_resume(struct device *dev)
{
struct acp6x_dev_data *adata;
int ret;
@@ -302,8 +302,8 @@ static int __maybe_unused snd_acp6x_resume(struct device *dev)
}
static const struct dev_pm_ops acp6x_pm = {
- SET_RUNTIME_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume)
+ RUNTIME_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume)
};
static void snd_acp6x_remove(struct pci_dev *pci)
@@ -339,7 +339,7 @@ static struct pci_driver yc_acp6x_driver = {
.probe = snd_acp6x_probe,
.remove = snd_acp6x_remove,
.driver = {
- .pm = &acp6x_pm,
+ .pm = pm_ptr(&acp6x_pm),
}
};
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c
index ba314b279919..1f8c60d2de82 100644
--- a/sound/soc/atmel/atmel-classd.c
+++ b/sound/soc/atmel/atmel-classd.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
@@ -275,7 +276,7 @@ static int atmel_classd_component_probe(struct snd_soc_component *component)
dev_info(component->dev,
"PWM modulation type is %s, non-overlapping is %s\n",
pwm_type[pdata->pwm_type],
- pdata->non_overlap_enable?"enabled":"disabled");
+ str_enabled_disabled(pdata->non_overlap_enable));
return 0;
}
diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c
index 0a9efd5f2861..2a1d0408a4cf 100644
--- a/sound/soc/atmel/tse850-pcm5142.c
+++ b/sound/soc/atmel/tse850-pcm5142.c
@@ -227,16 +227,9 @@ static const struct snd_kcontrol_new mux1 =
static const struct snd_kcontrol_new mux2 =
SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2);
-#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = xget, \
- .put = xput, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
-
static const struct snd_kcontrol_new mix[] = {
- TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0,
- tse850_get_mix, tse850_put_mix),
+ SOC_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0,
+ tse850_get_mix, tse850_put_mix),
};
static const char * const ana_text[] = {
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
index 7d296f29dade..57735004f416 100644
--- a/sound/soc/au1x/i2sc.c
+++ b/sound/soc/au1x/i2sc.c
@@ -279,7 +279,6 @@ static void au1xi2s_drvremove(struct platform_device *pdev)
WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
}
-#ifdef CONFIG_PM
static int au1xi2s_drvsuspend(struct device *dev)
{
struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
@@ -294,23 +293,13 @@ static int au1xi2s_drvresume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops au1xi2sc_pmops = {
- .suspend = au1xi2s_drvsuspend,
- .resume = au1xi2s_drvresume,
-};
-
-#define AU1XI2SC_PMOPS (&au1xi2sc_pmops)
-
-#else
-
-#define AU1XI2SC_PMOPS NULL
-
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(au1xi2sc_pmops, au1xi2s_drvsuspend,
+ au1xi2s_drvresume);
static struct platform_driver au1xi2s_driver = {
.driver = {
.name = "alchemy-i2sc",
- .pm = AU1XI2SC_PMOPS,
+ .pm = pm_ptr(&au1xi2sc_pmops),
},
.probe = au1xi2s_drvprobe,
.remove = au1xi2s_drvremove,
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 8a59a50978b9..94698e08a513 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -436,7 +436,6 @@ static void au1xpsc_ac97_drvremove(struct platform_device *pdev)
au1xpsc_ac97_workdata = NULL; /* MDEV */
}
-#ifdef CONFIG_PM
static int au1xpsc_ac97_drvsuspend(struct device *dev)
{
struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
@@ -467,23 +466,13 @@ static int au1xpsc_ac97_drvresume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops au1xpscac97_pmops = {
- .suspend = au1xpsc_ac97_drvsuspend,
- .resume = au1xpsc_ac97_drvresume,
-};
-
-#define AU1XPSCAC97_PMOPS &au1xpscac97_pmops
-
-#else
-
-#define AU1XPSCAC97_PMOPS NULL
-
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(au1xpscac97_pmops, au1xpsc_ac97_drvsuspend,
+ au1xpsc_ac97_drvresume);
static struct platform_driver au1xpsc_ac97_driver = {
.driver = {
.name = "au1xpsc_ac97",
- .pm = AU1XPSCAC97_PMOPS,
+ .pm = pm_ptr(&au1xpscac97_pmops),
},
.probe = au1xpsc_ac97_drvprobe,
.remove = au1xpsc_ac97_drvremove,
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index bee013555e7a..bf59105fcb7a 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -354,7 +354,6 @@ static void au1xpsc_i2s_drvremove(struct platform_device *pdev)
wmb(); /* drain writebuffer */
}
-#ifdef CONFIG_PM
static int au1xpsc_i2s_drvsuspend(struct device *dev)
{
struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
@@ -385,23 +384,13 @@ static int au1xpsc_i2s_drvresume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops au1xpsci2s_pmops = {
- .suspend = au1xpsc_i2s_drvsuspend,
- .resume = au1xpsc_i2s_drvresume,
-};
-
-#define AU1XPSCI2S_PMOPS &au1xpsci2s_pmops
-
-#else
-
-#define AU1XPSCI2S_PMOPS NULL
-
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(au1xpsci2s_pmops, au1xpsc_i2s_drvsuspend,
+ au1xpsc_i2s_drvresume);
static struct platform_driver au1xpsc_i2s_driver = {
.driver = {
.name = "au1xpsc_i2s",
- .pm = AU1XPSCI2S_PMOPS,
+ .pm = pm_ptr(&au1xpsci2s_pmops),
},
.probe = au1xpsc_i2s_drvprobe,
.remove = au1xpsc_i2s_drvremove,
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0b9e87dc2b6c..40bb7a1d44bc 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -58,6 +58,7 @@ config SND_SOC_ALL_CODECS
imply SND_SOC_AW87390
imply SND_SOC_AW88395
imply SND_SOC_AW88081
+ imply SND_SOC_AW88166
imply SND_SOC_AW88261
imply SND_SOC_AW88399
imply SND_SOC_BT_SCO
@@ -678,6 +679,18 @@ config SND_SOC_AW88395
digital Smart K audio amplifier with an integrated 10V
smart boost convert.
+config SND_SOC_AW88166
+ tristate "Soc Audio for awinic aw88166"
+ depends on I2C
+ select REGMAP_I2C
+ select GPIOLIB
+ select SND_SOC_AW88395_LIB
+ help
+ This option enables support for aw88166 Smart PA.
+ The awinic AW88166 is an I2S/TDM input, high efficiency
+ digital Smart K audio amplifier with sound quality
+ enhancement algorithms and speaker protection.
+
config SND_SOC_AW88261
tristate "Soc Audio for awinic aw88261"
depends on I2C
@@ -692,7 +705,7 @@ config SND_SOC_AW88261
the input amplitude.
config SND_SOC_AW88081
- tristate "Soc Audio for awinic aw88081"
+ tristate "Soc Audio for awinic aw88081/aw88083"
depends on I2C
select REGMAP_I2C
select SND_SOC_AW88395_LIB
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f37e82ddb7a1..10f726066b6c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -53,6 +53,7 @@ snd-soc-aw88081-y := aw88081.o
snd-soc-aw88395-lib-y := aw88395/aw88395_lib.o
snd-soc-aw88395-y := aw88395/aw88395.o \
aw88395/aw88395_device.o
+snd-soc-aw88166-y := aw88166.o
snd-soc-aw88261-y := aw88261.o
snd-soc-aw88399-y := aw88399.o
snd-soc-bd28623-y := bd28623.o
@@ -80,7 +81,7 @@ snd-soc-cs35l56-shared-y := cs35l56-shared.o
snd-soc-cs35l56-i2c-y := cs35l56-i2c.o
snd-soc-cs35l56-spi-y := cs35l56-spi.o
snd-soc-cs35l56-sdw-y := cs35l56-sdw.o
-snd-soc-cs40l50-objs := cs40l50-codec.o
+snd-soc-cs40l50-y := cs40l50-codec.o
snd-soc-cs42l42-y := cs42l42.o
snd-soc-cs42l42-i2c-y := cs42l42-i2c.o
snd-soc-cs42l42-sdw-y := cs42l42-sdw.o
@@ -92,7 +93,7 @@ snd-soc-cs42l52-y := cs42l52.o
snd-soc-cs42l56-y := cs42l56.o
snd-soc-cs42l73-y := cs42l73.o
snd-soc-cs42l83-i2c-y := cs42l83-i2c.o
-snd-soc-cs42l84-objs := cs42l84.o
+snd-soc-cs42l84-y := cs42l84.o
snd-soc-cs4234-y := cs4234.o
snd-soc-cs4265-y := cs4265.o
snd-soc-cs4270-y := cs4270.o
@@ -334,8 +335,8 @@ snd-soc-wcd-classh-y := wcd-clsh-v2.o
snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o
snd-soc-wcd9335-y := wcd9335.o
snd-soc-wcd934x-y := wcd934x.o
-snd-soc-wcd937x-objs := wcd937x.o
-snd-soc-wcd937x-sdw-objs := wcd937x-sdw.o
+snd-soc-wcd937x-y := wcd937x.o
+snd-soc-wcd937x-sdw-y := wcd937x-sdw.o
snd-soc-wcd938x-y := wcd938x.o
snd-soc-wcd938x-sdw-y := wcd938x-sdw.o
snd-soc-wcd939x-y := wcd939x.o
@@ -470,6 +471,7 @@ obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o
obj-$(CONFIG_SND_SOC_AW88081) += snd-soc-aw88081.o
obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o
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_BD28623) += snd-soc-bd28623.o
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c
index 15d74bb31c4c..6aa168e01fbb 100644
--- a/sound/soc/codecs/ad193x-i2c.c
+++ b/sound/soc/codecs/ad193x-i2c.c
@@ -23,7 +23,6 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id);
static int ad193x_i2c_probe(struct i2c_client *client)
{
struct regmap_config config;
- const struct i2c_device_id *id = i2c_match_id(ad193x_id, client);
config = ad193x_regmap_config;
config.val_bits = 8;
@@ -31,7 +30,7 @@ static int ad193x_i2c_probe(struct i2c_client *client)
return ad193x_probe(&client->dev,
devm_regmap_init_i2c(client, &config),
- (enum ad193x_type)id->driver_data);
+ (uintptr_t)i2c_get_match_data(client));
}
static struct i2c_driver ad193x_i2c_driver = {
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 291249e0a2a3..6876462d8bdb 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -325,9 +325,7 @@ static int adau1701_reset(struct snd_soc_component *component, unsigned int clkd
__assign_bit(1, values, 1);
break;
}
- gpiod_set_array_value_cansleep(adau1701->gpio_pll_mode->ndescs,
- adau1701->gpio_pll_mode->desc, adau1701->gpio_pll_mode->info,
- values);
+ gpiod_multi_set_value_cansleep(adau1701->gpio_pll_mode, values);
}
adau1701->pll_clkdiv = clkdiv;
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c
index a554255186ae..eba7e4f42c78 100644
--- a/sound/soc/codecs/adau1761-i2c.c
+++ b/sound/soc/codecs/adau1761-i2c.c
@@ -14,12 +14,9 @@
#include "adau1761.h"
-static const struct i2c_device_id adau1761_i2c_ids[];
-
static int adau1761_i2c_probe(struct i2c_client *client)
{
struct regmap_config config;
- const struct i2c_device_id *id = i2c_match_id(adau1761_i2c_ids, client);
config = adau1761_regmap_config;
config.val_bits = 8;
@@ -27,7 +24,7 @@ static int adau1761_i2c_probe(struct i2c_client *client)
return adau1761_probe(&client->dev,
devm_regmap_init_i2c(client, &config),
- id->driver_data, NULL);
+ (uintptr_t)i2c_get_match_data(client), NULL);
}
static void adau1761_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c
index 3a170fd78ff3..cb67fde8d9a8 100644
--- a/sound/soc/codecs/adau1781-i2c.c
+++ b/sound/soc/codecs/adau1781-i2c.c
@@ -14,12 +14,9 @@
#include "adau1781.h"
-static const struct i2c_device_id adau1781_i2c_ids[];
-
static int adau1781_i2c_probe(struct i2c_client *client)
{
struct regmap_config config;
- const struct i2c_device_id *id = i2c_match_id(adau1781_i2c_ids, client);
config = adau1781_regmap_config;
config.val_bits = 8;
@@ -27,7 +24,7 @@ static int adau1781_i2c_probe(struct i2c_client *client)
return adau1781_probe(&client->dev,
devm_regmap_init_i2c(client, &config),
- id->driver_data, NULL);
+ (uintptr_t)i2c_get_match_data(client), NULL);
}
static void adau1781_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 4dcc984761e0..0b6b0d2115eb 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -255,7 +255,7 @@ static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol,
#define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \
const struct snd_kcontrol_new _name = \
- SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\
+ SOC_ENUM_EXT(_label, (const struct soc_enum)\
SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \
ARRAY_SIZE(_text), _text), \
adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put)
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c
index 24c7b9c84c19..441c8079246a 100644
--- a/sound/soc/codecs/adau1977-i2c.c
+++ b/sound/soc/codecs/adau1977-i2c.c
@@ -14,12 +14,9 @@
#include "adau1977.h"
-static const struct i2c_device_id adau1977_i2c_ids[];
-
static int adau1977_i2c_probe(struct i2c_client *client)
{
struct regmap_config config;
- const struct i2c_device_id *id = i2c_match_id(adau1977_i2c_ids, client);
config = adau1977_regmap_config;
config.val_bits = 8;
@@ -27,7 +24,7 @@ static int adau1977_i2c_probe(struct i2c_client *client)
return adau1977_probe(&client->dev,
devm_regmap_init_i2c(client, &config),
- id->driver_data, NULL);
+ (uintptr_t)i2c_get_match_data(client), NULL);
}
static const struct i2c_device_id adau1977_i2c_ids[] = {
diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c
index 3ee5a5c3c5fe..452559d8c97b 100644
--- a/sound/soc/codecs/ak4375.c
+++ b/sound/soc/codecs/ak4375.c
@@ -438,7 +438,7 @@ static int ak4375_power_on(struct ak4375_priv *ak4375)
return 0;
}
-static int __maybe_unused ak4375_runtime_suspend(struct device *dev)
+static int ak4375_runtime_suspend(struct device *dev)
{
struct ak4375_priv *ak4375 = dev_get_drvdata(dev);
@@ -448,7 +448,7 @@ static int __maybe_unused ak4375_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ak4375_runtime_resume(struct device *dev)
+static int ak4375_runtime_resume(struct device *dev)
{
struct ak4375_priv *ak4375 = dev_get_drvdata(dev);
int ret;
@@ -490,9 +490,8 @@ static const struct ak4375_drvdata ak4375_drvdata = {
};
static const struct dev_pm_ops ak4375_pm = {
- SET_RUNTIME_PM_OPS(ak4375_runtime_suspend, ak4375_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(ak4375_runtime_suspend, ak4375_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static int ak4375_i2c_probe(struct i2c_client *i2c)
@@ -594,7 +593,7 @@ MODULE_DEVICE_TABLE(of, ak4375_of_match);
static struct i2c_driver ak4375_i2c_driver = {
.driver = {
.name = "ak4375",
- .pm = &ak4375_pm,
+ .pm = pm_ptr(&ak4375_pm),
.of_match_table = ak4375_of_match,
},
.probe = ak4375_i2c_probe,
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c
index d472d9952628..5f3a68dfe7bd 100644
--- a/sound/soc/codecs/ak4458.c
+++ b/sound/soc/codecs/ak4458.c
@@ -639,8 +639,7 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active)
}
}
-#ifdef CONFIG_PM
-static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
+static int ak4458_runtime_suspend(struct device *dev)
{
struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
@@ -656,7 +655,7 @@ static int __maybe_unused ak4458_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ak4458_runtime_resume(struct device *dev)
+static int ak4458_runtime_resume(struct device *dev)
{
struct ak4458_priv *ak4458 = dev_get_drvdata(dev);
int ret;
@@ -678,7 +677,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev)
return regcache_sync(ak4458->regmap);
}
-#endif /* CONFIG_PM */
static const struct snd_soc_component_driver soc_codec_dev_ak4458 = {
.controls = ak4458_snd_controls,
@@ -727,9 +725,8 @@ static const struct ak4458_drvdata ak4497_drvdata = {
};
static const struct dev_pm_ops ak4458_pm = {
- SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static int ak4458_i2c_probe(struct i2c_client *i2c)
@@ -805,7 +802,7 @@ MODULE_DEVICE_TABLE(of, ak4458_of_match);
static struct i2c_driver ak4458_i2c_driver = {
.driver = {
.name = "ak4458",
- .pm = &ak4458_pm,
+ .pm = pm_ptr(&ak4458_pm),
.of_match_table = ak4458_of_match,
},
.probe = ak4458_i2c_probe,
diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c
index 6c767609f95d..683f3e472f50 100644
--- a/sound/soc/codecs/ak5558.c
+++ b/sound/soc/codecs/ak5558.c
@@ -342,7 +342,7 @@ static void ak5558_remove(struct snd_soc_component *component)
ak5558_reset(ak5558, true);
}
-static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
+static int ak5558_runtime_suspend(struct device *dev)
{
struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
@@ -354,7 +354,7 @@ static int __maybe_unused ak5558_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ak5558_runtime_resume(struct device *dev)
+static int ak5558_runtime_resume(struct device *dev)
{
struct ak5558_priv *ak5558 = dev_get_drvdata(dev);
int ret;
@@ -376,9 +376,8 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops ak5558_pm = {
- SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct snd_soc_component_driver soc_codec_dev_ak5558 = {
@@ -495,7 +494,7 @@ static struct i2c_driver ak5558_i2c_driver = {
.driver = {
.name = "ak5558",
.of_match_table = of_match_ptr(ak5558_i2c_dt_ids),
- .pm = &ak5558_pm,
+ .pm = pm_ptr(&ak5558_pm),
},
.probe = ak5558_i2c_probe,
.remove = ak5558_i2c_remove,
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index b24c32206884..fbf723758079 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -987,9 +987,9 @@ static int alc5623_i2c_probe(struct i2c_client *client)
struct alc5623_priv *alc5623;
struct device_node *np;
unsigned int vid1, vid2;
+ unsigned int matched_id;
int ret;
u32 val32;
- const struct i2c_device_id *id;
alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv),
GFP_KERNEL);
@@ -1016,12 +1016,12 @@ static int alc5623_i2c_probe(struct i2c_client *client)
}
vid2 >>= 8;
- id = i2c_match_id(alc5623_i2c_table, client);
+ matched_id = (uintptr_t)i2c_get_match_data(client);
- if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) {
+ if ((vid1 != 0x10ec) || (vid2 != matched_id)) {
dev_err(&client->dev, "unknown or wrong codec\n");
- dev_err(&client->dev, "Expected %x:%lx, got %x:%x\n",
- 0x10ec, id->driver_data,
+ dev_err(&client->dev, "Expected %x:%x, got %x:%x\n",
+ 0x10ec, matched_id,
vid1, vid2);
return -ENODEV;
}
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index d5021f266930..72f4622204ff 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1108,7 +1108,7 @@ static int alc5632_i2c_probe(struct i2c_client *client)
struct alc5632_priv *alc5632;
int ret, ret1, ret2;
unsigned int vid1, vid2;
- const struct i2c_device_id *id;
+ unsigned int matched_id;
alc5632 = devm_kzalloc(&client->dev,
sizeof(struct alc5632_priv), GFP_KERNEL);
@@ -1134,9 +1134,9 @@ static int alc5632_i2c_probe(struct i2c_client *client)
vid2 >>= 8;
- id = i2c_match_id(alc5632_i2c_table, client);
+ matched_id = (uintptr_t)i2c_get_match_data(client);
- if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) {
+ if ((vid1 != 0x10EC) || (vid2 != matched_id)) {
dev_err(&client->dev,
"Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2);
return -EINVAL;
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 402b9a2ff024..f2f47f1c1ac8 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -967,7 +967,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_up_pending++;
- priv->out_up_delay += 17;
+ priv->out_up_delay += 17000;
break;
case ARIZONA_OUT4L_ENA_SHIFT:
case ARIZONA_OUT4R_ENA_SHIFT:
@@ -977,7 +977,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case WM8997:
break;
default:
- priv->out_up_delay += 10;
+ priv->out_up_delay += 10000;
break;
}
break;
@@ -999,7 +999,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
if (!priv->out_up_pending && priv->out_up_delay) {
dev_dbg(component->dev, "Power up delay: %d\n",
priv->out_up_delay);
- msleep(priv->out_up_delay);
+ fsleep(priv->out_up_delay);
priv->out_up_delay = 0;
}
break;
@@ -1017,7 +1017,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
case ARIZONA_OUT3L_ENA_SHIFT:
case ARIZONA_OUT3R_ENA_SHIFT:
priv->out_down_pending++;
- priv->out_down_delay++;
+ priv->out_down_delay += 1000;
break;
case ARIZONA_OUT4L_ENA_SHIFT:
case ARIZONA_OUT4R_ENA_SHIFT:
@@ -1028,10 +1028,10 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
break;
case WM8998:
case WM1814:
- priv->out_down_delay += 5;
+ priv->out_down_delay += 5000;
break;
default:
- priv->out_down_delay++;
+ priv->out_down_delay += 1000;
break;
}
break;
@@ -1053,7 +1053,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
if (!priv->out_down_pending && priv->out_down_delay) {
dev_dbg(component->dev, "Power down delay: %d\n",
priv->out_down_delay);
- msleep(priv->out_down_delay);
+ fsleep(priv->out_down_delay);
priv->out_down_delay = 0;
}
break;
@@ -1457,7 +1457,7 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_DSP_B:
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
- != SND_SOC_DAIFMT_CBM_CFM) {
+ != SND_SOC_DAIFMT_CBP_CFP) {
arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
return -EINVAL;
}
@@ -1468,7 +1468,7 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_LEFT_J:
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
- != SND_SOC_DAIFMT_CBM_CFM) {
+ != SND_SOC_DAIFMT_CBP_CFP) {
arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
return -EINVAL;
}
@@ -1481,15 +1481,15 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
bclk |= ARIZONA_AIF1_BCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
bclk |= ARIZONA_AIF1_BCLK_MSTR;
lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR;
break;
diff --git a/sound/soc/codecs/aw88081.c b/sound/soc/codecs/aw88081.c
index 58b8e002d76f..ad16ab6812cd 100644
--- a/sound/soc/codecs/aw88081.c
+++ b/sound/soc/codecs/aw88081.c
@@ -14,13 +14,18 @@
#include "aw88081.h"
#include "aw88395/aw88395_device.h"
+enum aw8808x_type {
+ AW88081,
+ AW88083,
+};
+
struct aw88081 {
struct aw_device *aw_pa;
struct mutex lock;
struct delayed_work start_work;
struct regmap *regmap;
struct aw_container *aw_cfg;
-
+ enum aw8808x_type devtype;
bool phase_sync;
};
@@ -32,6 +37,14 @@ static const struct regmap_config aw88081_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_BIG,
};
+static const struct regmap_config aw88083_regmap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88083_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
static int aw88081_dev_get_iis_status(struct aw_device *aw_dev)
{
unsigned int reg_val;
@@ -196,6 +209,41 @@ static void aw88081_dev_amppd(struct aw_device *aw_dev, bool amppd)
~AW88081_EN_PA_MASK, AW88081_EN_PA_WORKING_VALUE);
}
+static void aw88083_i2c_wen(struct aw88081 *aw88081, bool flag)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ if (aw88081->devtype != AW88083)
+ return;
+
+ if (flag)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88083_I2C_WEN_MASK, AW88083_I2C_WEN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88083_I2C_WEN_MASK, AW88083_I2C_WEN_DISABLE_VALUE);
+}
+
+static void aw88083_dev_amppd(struct aw_device *aw_dev, bool amppd)
+{
+ if (amppd)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88083_AMPPD_MASK, AW88083_AMPPD_POWER_DOWN_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88083_AMPPD_MASK, AW88083_AMPPD_WORKING_VALUE);
+}
+
+static void aw88083_dev_pllpd(struct aw_device *aw_dev, bool pllpd)
+{
+ if (pllpd)
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88083_PLL_PD_MASK, AW88083_PLL_PD_WORKING_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88081_SYSCTRL_REG,
+ ~AW88083_PLL_PD_MASK, AW88083_PLL_PD_POWER_DOWN_VALUE);
+}
+
static void aw88081_dev_clear_int_status(struct aw_device *aw_dev)
{
unsigned int int_status;
@@ -284,12 +332,90 @@ static void aw88081_dev_uls_hmute(struct aw_device *aw_dev, bool uls_hmute)
AW88081_ULS_HMUTE_DISABLE_VALUE);
}
+static int aw88081_dev_reg_value_check(struct aw_device *aw_dev,
+ unsigned char reg_addr, unsigned short *reg_val)
+{
+ unsigned int read_vol;
+
+ if (reg_addr == AW88081_SYSCTRL_REG) {
+ *reg_val &= ~(~AW88081_EN_PA_MASK |
+ ~AW88081_PWDN_MASK |
+ ~AW88081_HMUTE_MASK |
+ ~AW88081_ULS_HMUTE_MASK);
+
+ *reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE |
+ AW88081_PWDN_POWER_DOWN_VALUE |
+ AW88081_HMUTE_ENABLE_VALUE |
+ AW88081_ULS_HMUTE_ENABLE_VALUE;
+ }
+
+ if (reg_addr == AW88081_SYSCTRL2_REG) {
+ read_vol = (*reg_val & (~AW88081_VOL_MASK)) >> AW88081_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ /* i2stxen */
+ if (reg_addr == AW88081_I2SCTRL3_REG) {
+ /* close tx */
+ *reg_val &= AW88081_I2STXEN_MASK;
+ *reg_val |= AW88081_I2STXEN_DISABLE_VALUE;
+ }
+
+ return 0;
+}
+
+static int aw88083_dev_reg_value_check(struct aw_device *aw_dev,
+ unsigned char reg_addr, unsigned short *reg_val)
+{
+ unsigned int read_vol;
+
+ if (reg_addr == AW88081_SYSCTRL_REG) {
+ *reg_val &= ~(~AW88083_AMPPD_MASK |
+ ~AW88081_PWDN_MASK |
+ ~AW88081_HMUTE_MASK |
+ ~AW88083_I2C_WEN_MASK);
+
+ *reg_val |= AW88083_AMPPD_POWER_DOWN_VALUE |
+ AW88081_PWDN_POWER_DOWN_VALUE |
+ AW88081_HMUTE_ENABLE_VALUE |
+ AW88083_I2C_WEN_ENABLE_VALUE;
+ }
+
+ if (reg_addr == AW88081_SYSCTRL2_REG) {
+ read_vol = (*reg_val & (~AW88081_VOL_MASK)) >> AW88081_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ return 0;
+}
+
+static int aw88081_reg_value_check(struct aw88081 *aw88081,
+ unsigned char reg_addr, unsigned short *reg_val)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+ int ret;
+
+ switch (aw88081->devtype) {
+ case AW88081:
+ ret = aw88081_dev_reg_value_check(aw_dev, reg_addr, reg_val);
+ break;
+ case AW88083:
+ ret = aw88083_dev_reg_value_check(aw_dev, reg_addr, reg_val);
+ break;
+ default:
+ dev_err(aw_dev->dev, "unsupported device\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
static int aw88081_dev_reg_update(struct aw88081 *aw88081,
unsigned char *data, unsigned int len)
{
struct aw_device *aw_dev = aw88081->aw_pa;
struct aw_volume_desc *vol_desc = &aw_dev->volume_desc;
- unsigned int read_vol;
int data_len, i, ret;
int16_t *reg_data;
u16 reg_val;
@@ -312,30 +438,9 @@ static int aw88081_dev_reg_update(struct aw88081 *aw88081,
reg_addr = reg_data[i];
reg_val = reg_data[i + 1];
- if (reg_addr == AW88081_SYSCTRL_REG) {
- reg_val &= ~(~AW88081_EN_PA_MASK |
- ~AW88081_PWDN_MASK |
- ~AW88081_HMUTE_MASK |
- ~AW88081_ULS_HMUTE_MASK);
-
- reg_val |= AW88081_EN_PA_POWER_DOWN_VALUE |
- AW88081_PWDN_POWER_DOWN_VALUE |
- AW88081_HMUTE_ENABLE_VALUE |
- AW88081_ULS_HMUTE_ENABLE_VALUE;
- }
-
- if (reg_addr == AW88081_SYSCTRL2_REG) {
- read_vol = (reg_val & (~AW88081_VOL_MASK)) >>
- AW88081_VOL_START_BIT;
- aw_dev->volume_desc.init_volume = read_vol;
- }
-
- /* i2stxen */
- if (reg_addr == AW88081_I2SCTRL3_REG) {
- /* close tx */
- reg_val &= AW88081_I2STXEN_MASK;
- reg_val |= AW88081_I2STXEN_DISABLE_VALUE;
- }
+ ret = aw88081_reg_value_check(aw88081, reg_addr, &reg_val);
+ if (ret)
+ return ret;
ret = regmap_write(aw_dev->regmap, reg_addr, reg_val);
if (ret)
@@ -474,8 +579,60 @@ pll_check_fail:
return ret;
}
-static int aw88081_dev_stop(struct aw_device *aw_dev)
+static int aw88083_dev_start(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ if (aw_dev->status == AW88081_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ aw88083_i2c_wen(aw88081, true);
+
+ /* power on */
+ aw88081_dev_pwd(aw_dev, false);
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 10);
+
+ aw88083_dev_pllpd(aw_dev, true);
+ /* amppd on */
+ aw88083_dev_amppd(aw_dev, false);
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 50);
+
+ /* close mute */
+ aw88081_dev_mute(aw_dev, false);
+
+ aw88083_i2c_wen(aw88081, false);
+
+ aw_dev->status = AW88081_DEV_PW_ON;
+
+ return 0;
+}
+
+static int aw88081_device_start(struct aw88081 *aw88081)
+{
+ int ret;
+
+ switch (aw88081->devtype) {
+ case AW88081:
+ ret = aw88081_dev_start(aw88081);
+ break;
+ case AW88083:
+ ret = aw88083_dev_start(aw88081);
+ break;
+ default:
+ ret = -EINVAL;
+ dev_err(aw88081->aw_pa->dev, "unsupported device\n");
+ break;
+ }
+
+ return ret;
+}
+
+static int aw88081_dev_stop(struct aw88081 *aw88081)
{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
if (aw_dev->status == AW88081_DEV_PW_OFF) {
dev_dbg(aw_dev->dev, "already power off");
return 0;
@@ -503,6 +660,56 @@ static int aw88081_dev_stop(struct aw_device *aw_dev)
return 0;
}
+static int aw88083_dev_stop(struct aw88081 *aw88081)
+{
+ struct aw_device *aw_dev = aw88081->aw_pa;
+
+ if (aw_dev->status == AW88081_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88081_DEV_PW_OFF;
+
+ aw88083_i2c_wen(aw88081, true);
+ /* set mute */
+ aw88081_dev_mute(aw_dev, true);
+
+ usleep_range(AW88081_2000_US, AW88081_2000_US + 100);
+
+ /* enable amppd */
+ aw88083_dev_amppd(aw_dev, true);
+
+ aw88083_dev_pllpd(aw_dev, false);
+
+ /* set power down */
+ aw88081_dev_pwd(aw_dev, true);
+
+ aw88083_i2c_wen(aw88081, false);
+
+ return 0;
+}
+
+static int aw88081_stop(struct aw88081 *aw88081)
+{
+ int ret;
+
+ switch (aw88081->devtype) {
+ case AW88081:
+ ret = aw88081_dev_stop(aw88081);
+ break;
+ case AW88083:
+ ret = aw88083_dev_stop(aw88081);
+ break;
+ default:
+ dev_err(aw88081->aw_pa->dev, "unsupported device\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
static int aw88081_reg_update(struct aw88081 *aw88081, bool force)
{
struct aw_device *aw_dev = aw88081->aw_pa;
@@ -540,7 +747,7 @@ static void aw88081_start_pa(struct aw88081 *aw88081)
dev_err(aw88081->aw_pa->dev, "fw update failed, cnt:%d\n", i);
continue;
}
- ret = aw88081_dev_start(aw88081);
+ ret = aw88081_device_start(aw88081);
if (ret) {
dev_err(aw88081->aw_pa->dev, "aw88081 device start failed. retry = %d", i);
continue;
@@ -745,7 +952,7 @@ static int aw88081_profile_set(struct snd_kcontrol *kcontrol,
}
if (aw88081->aw_pa->status) {
- aw88081_dev_stop(aw88081->aw_pa);
+ aw88081_stop(aw88081);
aw88081_start(aw88081, AW88081_SYNC_START);
}
@@ -781,12 +988,16 @@ static int aw88081_volume_set(struct snd_kcontrol *kcontrol,
if (value < mc->min || value > mc->max)
return -EINVAL;
+ aw88083_i2c_wen(aw88081, true);
+
if (vol_desc->ctl_volume != value) {
vol_desc->ctl_volume = value;
aw88081_dev_set_volume(aw88081->aw_pa, vol_desc->ctl_volume);
return 1;
}
+ aw88083_i2c_wen(aw88081, false);
+
return 0;
}
@@ -860,13 +1071,19 @@ static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct
dev_err(&i2c->dev, "%s read chipid error. ret = %d", __func__, ret);
return ret;
}
- if (chip_id != AW88081_CHIP_ID) {
+
+ switch (chip_id) {
+ case AW88081_CHIP_ID:
+ dev_dbg(&i2c->dev, "chip id = 0x%x\n", chip_id);
+ break;
+ case AW88083_CHIP_ID:
+ dev_dbg(&i2c->dev, "chip id = 0x%x\n", chip_id);
+ break;
+ default:
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;
@@ -875,7 +1092,7 @@ static int aw88081_init(struct aw88081 *aw88081, struct i2c_client *i2c, struct
aw_dev->i2c = i2c;
aw_dev->regmap = regmap;
aw_dev->dev = &i2c->dev;
- aw_dev->chip_id = AW88081_CHIP_ID;
+ aw_dev->chip_id = chip_id;
aw_dev->acf = NULL;
aw_dev->prof_info.prof_desc = NULL;
aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID;
@@ -912,21 +1129,8 @@ static int aw88081_dev_init(struct aw88081 *aw88081, struct aw_container *aw_cfg
return ret;
}
- aw88081_dev_clear_int_status(aw_dev);
-
- aw88081_dev_uls_hmute(aw_dev, true);
-
- aw88081_dev_mute(aw_dev, true);
-
- usleep_range(AW88081_5000_US, AW88081_5000_US + 10);
-
- aw88081_dev_i2s_tx_enable(aw_dev, false);
-
- usleep_range(AW88081_1000_US, AW88081_1000_US + 100);
-
- aw88081_dev_amppd(aw_dev, true);
-
- aw88081_dev_pwd(aw_dev, true);
+ aw_dev->status = AW88081_DEV_PW_ON;
+ aw88081_stop(aw88081);
return 0;
}
@@ -977,7 +1181,7 @@ static int aw88081_playback_event(struct snd_soc_dapm_widget *w,
aw88081_start(aw88081, AW88081_ASYNC_START);
break;
case SND_SOC_DAPM_POST_PMD:
- aw88081_dev_stop(aw88081->aw_pa);
+ aw88081_stop(aw88081);
break;
default:
break;
@@ -1036,8 +1240,17 @@ static const struct snd_soc_component_driver soc_codec_dev_aw88081 = {
.num_controls = ARRAY_SIZE(aw88081_controls),
};
+static const struct i2c_device_id aw88081_i2c_id[] = {
+ { AW88081_I2C_NAME, AW88081},
+ { AW88083_I2C_NAME, AW88083},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id);
+
static int aw88081_i2c_probe(struct i2c_client *i2c)
{
+ const struct regmap_config *regmap_config;
+ const struct i2c_device_id *id;
struct aw88081 *aw88081;
int ret;
@@ -1049,11 +1262,25 @@ static int aw88081_i2c_probe(struct i2c_client *i2c)
if (!aw88081)
return -ENOMEM;
+ id = i2c_match_id(aw88081_i2c_id, i2c);
+ aw88081->devtype = id->driver_data;
+
mutex_init(&aw88081->lock);
i2c_set_clientdata(i2c, aw88081);
- aw88081->regmap = devm_regmap_init_i2c(i2c, &aw88081_regmap_config);
+ switch (aw88081->devtype) {
+ case AW88081:
+ regmap_config = &aw88081_regmap_config;
+ break;
+ case AW88083:
+ regmap_config = &aw88083_regmap_config;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ aw88081->regmap = devm_regmap_init_i2c(i2c, regmap_config);
if (IS_ERR(aw88081->regmap))
return dev_err_probe(&i2c->dev, PTR_ERR(aw88081->regmap),
"failed to init regmap\n");
@@ -1068,12 +1295,6 @@ static int aw88081_i2c_probe(struct i2c_client *i2c)
aw88081_dai, ARRAY_SIZE(aw88081_dai));
}
-static const struct i2c_device_id aw88081_i2c_id[] = {
- { AW88081_I2C_NAME },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, aw88081_i2c_id);
-
static struct i2c_driver aw88081_i2c_driver = {
.driver = {
.name = AW88081_I2C_NAME,
diff --git a/sound/soc/codecs/aw88081.h b/sound/soc/codecs/aw88081.h
index b4bf7288021a..7a4564270ab3 100644
--- a/sound/soc/codecs/aw88081.h
+++ b/sound/soc/codecs/aw88081.h
@@ -231,6 +231,49 @@
#define AW88081_CCO_MUX_BYPASS_VALUE \
(AW88081_CCO_MUX_BYPASS << AW88081_CCO_MUX_START_BIT)
+#define AW88083_I2C_WEN_START_BIT (14)
+#define AW88083_I2C_WEN_BITS_LEN (2)
+#define AW88083_I2C_WEN_MASK \
+ (~(((1<<AW88083_I2C_WEN_BITS_LEN)-1) << AW88083_I2C_WEN_START_BIT))
+
+#define AW88083_I2C_WEN_DISABLE (0)
+#define AW88083_I2C_WEN_DISABLE_VALUE \
+ (AW88083_I2C_WEN_DISABLE << AW88083_I2C_WEN_START_BIT)
+
+#define AW88083_I2C_WEN_ENABLE (2)
+#define AW88083_I2C_WEN_ENABLE_VALUE \
+ (AW88083_I2C_WEN_ENABLE << AW88083_I2C_WEN_START_BIT)
+
+#define AW88083_PLL_PD_START_BIT (2)
+#define AW88083_PLL_PD_BITS_LEN (1)
+#define AW88083_PLL_PD_MASK \
+ (~(((1<<AW88083_PLL_PD_BITS_LEN)-1) << AW88083_PLL_PD_START_BIT))
+
+#define AW88083_PLL_PD_POWER_DOWN (1)
+#define AW88083_PLL_PD_POWER_DOWN_VALUE \
+ (AW88083_PLL_PD_POWER_DOWN << AW88083_PLL_PD_START_BIT)
+
+#define AW88083_PLL_PD_WORKING (0)
+#define AW88083_PLL_PD_WORKING_VALUE \
+ (AW88083_PLL_PD_WORKING << AW88083_PLL_PD_START_BIT)
+
+#define AW88083_AMPPD_START_BIT (1)
+#define AW88083_AMPPD_BITS_LEN (1)
+#define AW88083_AMPPD_MASK \
+ (~(((1<<AW88083_AMPPD_BITS_LEN)-1) << AW88083_AMPPD_START_BIT))
+
+#define AW88083_AMPPD_WORKING (0)
+#define AW88083_AMPPD_WORKING_VALUE \
+ (AW88083_AMPPD_WORKING << AW88083_AMPPD_START_BIT)
+
+#define AW88083_AMPPD_POWER_DOWN (1)
+#define AW88083_AMPPD_POWER_DOWN_VALUE \
+ (AW88083_AMPPD_POWER_DOWN << AW88083_AMPPD_START_BIT)
+
+#define AW88083_REG_MAX (0x7D)
+#define AW88083_I2C_NAME "aw88083"
+#define AW88083_CHIP_ID 0x2407
+
#define AW88081_START_RETRIES (5)
#define AW88081_START_WORK_DELAY_MS (0)
diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c
new file mode 100644
index 000000000000..6c50c4a18b6a
--- /dev/null
+++ b/sound/soc/codecs/aw88166.c
@@ -0,0 +1,1933 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88166.c -- ALSA SoC AW88166 codec support
+//
+// Copyright (c) 2025 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#include <linux/crc32.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "aw88166.h"
+#include "aw88395/aw88395_device.h"
+
+struct aw88166 {
+ 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 re_init_val;
+ unsigned int dither_st;
+ bool phase_sync;
+};
+
+static const struct regmap_config aw88166_remap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+ .max_register = AW88166_REG_MAX,
+ .reg_format_endian = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static int aw_dev_dsp_write_16bit(struct aw_device *aw_dev,
+ unsigned short dsp_addr, unsigned int dsp_data)
+{
+ int ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s write addr error, ret=%d", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPMDAT_REG, (u16)dsp_data);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s write data error, ret=%d", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aw_dev_dsp_read_16bit(struct aw_device *aw_dev,
+ unsigned short dsp_addr, unsigned int *dsp_data)
+{
+ unsigned int temp_data;
+ int ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s write error, ret=%d", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret);
+ return ret;
+ }
+ *dsp_data = temp_data;
+
+ return 0;
+}
+
+static int aw_dev_dsp_read_32bit(struct aw_device *aw_dev,
+ unsigned short dsp_addr, unsigned int *dsp_data)
+{
+ unsigned int temp_data;
+ int ret;
+
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s write error, ret=%d", __func__, ret);
+ return ret;
+ }
+
+ ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret);
+ return ret;
+ }
+ *dsp_data = temp_data;
+
+ ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data);
+ if (ret) {
+ dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret);
+ return ret;
+ }
+ *dsp_data |= (temp_data << 16);
+
+ return 0;
+}
+
+static int aw_dev_dsp_read(struct aw_device *aw_dev,
+ unsigned short dsp_addr, unsigned int *dsp_data, unsigned char data_type)
+{
+ u32 reg_value;
+ int ret;
+
+ mutex_lock(&aw_dev->dsp_lock);
+ switch (data_type) {
+ case AW88166_DSP_16_DATA:
+ ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data);
+ if (ret)
+ dev_err(aw_dev->dev, "read dsp_addr[0x%x] 16-bit failed", (u32)dsp_addr);
+ break;
+ case AW88166_DSP_32_DATA:
+ ret = aw_dev_dsp_read_32bit(aw_dev, dsp_addr, dsp_data);
+ if (ret)
+ dev_err(aw_dev->dev, "read dsp_addr[0x%x] 32-bit failed", (u32)dsp_addr);
+ break;
+ default:
+ dev_err(aw_dev->dev, "data type[%d] unsupported", data_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ /* clear dsp chip select state */
+ if (regmap_read(aw_dev->regmap, AW88166_ID_REG, &reg_value))
+ dev_err(aw_dev->dev, "%s fail to clear chip state. ret=%d\n", __func__, ret);
+ mutex_unlock(&aw_dev->dsp_lock);
+
+ return ret;
+}
+
+static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd)
+{
+ int ret;
+
+ if (pwd)
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
+ ~AW88166_PWDN_MASK, AW88166_PWDN_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
+ ~AW88166_PWDN_MASK, AW88166_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, AW88166_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, AW88166_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+ if ((reg_val & AW88166_BIT_PLL_CHECK) != AW88166_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 < AW88166_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(AW88166_2000_US, AW88166_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, AW88166_PLLCTRL2_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ reg_val &= (~AW88166_CCO_MUX_MASK);
+ if (reg_val == AW88166_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, AW88166_PLLCTRL2_REG,
+ ~AW88166_CCO_MUX_MASK, AW88166_CCO_MUX_DIVIDED_VALUE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AW88166_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(AW88166_2000_US, AW88166_2000_US + 10);
+ } else {
+ break;
+ }
+ }
+
+ /* change mode1 */
+ regmap_update_bits(aw_dev->regmap, AW88166_PLLCTRL2_REG,
+ ~AW88166_CCO_MUX_MASK, AW88166_CCO_MUX_BYPASS_VALUE);
+ if (ret == 0) {
+ usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
+ for (i = 0; i < AW88166_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(AW88166_2000_US, AW88166_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, AW88166_PWMCTRL3_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg_val & (~AW88166_NOISE_GATE_EN_MASK))
+ check_val = AW88166_BIT_SYSST_NOSWS_CHECK;
+ else
+ check_val = AW88166_BIT_SYSST_SWS_CHECK;
+
+ for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) {
+ ret = regmap_read(aw_dev->regmap, AW88166_SYSST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ if ((reg_val & (~AW88166_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, AW88166_BIT_SYSST_NOSWS_CHECK);
+ usleep_range(AW88166_2000_US, AW88166_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, AW88166_SYSCTRL_REG,
+ ~AW88166_AMPPD_MASK, AW88166_AMPPD_POWER_DOWN_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
+ ~AW88166_AMPPD_MASK, AW88166_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, AW88166_SYSCTRL_REG,
+ ~AW88166_DSPBY_MASK, AW88166_DSPBY_WORKING_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
+ ~AW88166_DSPBY_MASK, AW88166_DSPBY_BYPASS_VALUE);
+
+ if (ret)
+ dev_dbg(aw_dev->dev, "%s failed\n", __func__);
+}
+
+static int aw88166_dev_get_icalk(struct aw88166 *aw88166, int16_t *icalk)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ unsigned int efrm_reg_val, efrl_reg_val;
+ uint16_t ef_isn_geslp, ef_isn_h5bits;
+ uint16_t icalk_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88166_EFRM2_REG, &efrm_reg_val);
+ if (ret)
+ return ret;
+
+ ef_isn_geslp = (efrm_reg_val & (~AW88166_EF_ISN_GESLP_MASK)) >>
+ AW88166_EF_ISN_GESLP_SHIFT;
+
+ ret = regmap_read(aw_dev->regmap, AW88166_EFRL_REG, &efrl_reg_val);
+ if (ret)
+ return ret;
+
+ ef_isn_h5bits = (efrl_reg_val & (~AW88166_EF_ISN_H5BITS_MASK)) >>
+ AW88166_EF_ISN_H5BITS_SHIFT;
+
+ if (aw88166->check_val == AW_EF_AND_CHECK)
+ icalk_val = ef_isn_geslp & (ef_isn_h5bits | AW88166_EF_ISN_H5BITS_SIGN_MASK);
+ else
+ icalk_val = ef_isn_geslp | (ef_isn_h5bits & (~AW88166_EF_ISN_H5BITS_SIGN_MASK));
+
+ if (icalk_val & (~AW88166_ICALK_SIGN_MASK))
+ icalk_val = icalk_val | AW88166_ICALK_NEG_MASK;
+ *icalk = (int16_t)icalk_val;
+
+ return 0;
+}
+
+static int aw88166_dev_get_vcalk(struct aw88166 *aw88166, int16_t *vcalk)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ unsigned int efrm_reg_val, efrl_reg_val;
+ uint16_t ef_vsn_geslp, ef_vsn_h3bits;
+ uint16_t vcalk_val;
+ int ret;
+
+ ret = regmap_read(aw_dev->regmap, AW88166_EFRM2_REG, &efrm_reg_val);
+ if (ret)
+ return ret;
+
+ ef_vsn_geslp = (efrm_reg_val & (~AW88166_EF_VSN_GESLP_MASK)) >>
+ AW88166_EF_VSN_GESLP_SHIFT;
+
+ ret = regmap_read(aw_dev->regmap, AW88166_EFRL_REG, &efrl_reg_val);
+ if (ret)
+ return ret;
+
+ ef_vsn_h3bits = (efrl_reg_val & (~AW88166_EF_VSN_H3BITS_MASK)) >>
+ AW88166_EF_VSN_H3BITS_SHIFT;
+
+ if (aw88166->check_val == AW_EF_AND_CHECK)
+ vcalk_val = ef_vsn_geslp & (ef_vsn_h3bits | AW88166_EF_VSN_H3BITS_SIGN_MASK);
+ else
+ vcalk_val = ef_vsn_geslp | (ef_vsn_h3bits & (~AW88166_EF_VSN_H3BITS_SIGN_MASK));
+
+ if (vcalk_val & (~AW88166_VCALK_SIGN_MASK))
+ vcalk_val = vcalk_val | AW88166_VCALK_NEG_MASK;
+ *vcalk = (int16_t)vcalk_val;
+
+ return 0;
+}
+
+static int aw88166_dev_set_vcalb(struct aw88166 *aw88166)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int32_t ical_k, vcal_k, vcalb;
+ int16_t icalk, vcalk;
+ unsigned int reg_val;
+ int ret;
+
+ ret = aw88166_dev_get_icalk(aw88166, &icalk);
+ if (ret) {
+ dev_err(aw_dev->dev, "get icalk failed\n");
+ return ret;
+ }
+ ical_k = icalk * AW88166_ICABLK_FACTOR + AW88166_CABL_BASE_VALUE;
+
+ ret = aw88166_dev_get_vcalk(aw88166, &vcalk);
+ if (ret) {
+ dev_err(aw_dev->dev, "get vbcalk failed\n");
+ return ret;
+ }
+ vcal_k = vcalk * AW88166_VCABLK_FACTOR + AW88166_CABL_BASE_VALUE;
+
+ vcalb = AW88166_VCALB_ACCURACY * AW88166_VSCAL_FACTOR /
+ AW88166_ISCAL_FACTOR * ical_k / vcal_k * aw88166->vcalb_init_val;
+
+ vcalb = vcalb >> AW88166_VCALB_ADJ_FACTOR;
+ reg_val = (uint32_t)vcalb;
+
+ regmap_write(aw_dev->regmap, AW88166_DSPVCALB_REG, reg_val);
+
+ return 0;
+}
+
+static int aw_dev_init_vcalb_update(struct aw88166 *aw88166, int flag)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int ret;
+
+ switch (flag) {
+ case AW88166_RECOVERY_SEC_DATA:
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPVCALB_REG, aw88166->vcalb_init_val);
+ break;
+ case AW88166_RECORD_SEC_DATA:
+ ret = regmap_read(aw_dev->regmap, AW88166_DSPVCALB_REG, &aw88166->vcalb_init_val);
+ break;
+ default:
+ dev_err(aw_dev->dev, "unsupported type:%d\n", flag);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int aw_dev_init_re_update(struct aw88166 *aw88166, int flag)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ unsigned int re_temp_h, re_temp_l;
+ int ret;
+
+ switch (flag) {
+ case AW88166_RECOVERY_SEC_DATA:
+ ret = regmap_write(aw_dev->regmap, AW88166_ACR1_REG, aw88166->re_init_val >> 16);
+ if (ret)
+ return ret;
+ ret = regmap_write(aw_dev->regmap, AW88166_ACR2_REG,
+ (uint16_t)aw88166->re_init_val);
+ if (ret)
+ return ret;
+ break;
+ case AW88166_RECORD_SEC_DATA:
+ ret = regmap_read(aw_dev->regmap, AW88166_ACR1_REG, &re_temp_h);
+ if (ret)
+ return ret;
+ ret = regmap_read(aw_dev->regmap, AW88166_ACR2_REG, &re_temp_l);
+ if (ret)
+ return ret;
+ aw88166->re_init_val = (re_temp_h << 16) + re_temp_l;
+ break;
+ default:
+ dev_err(aw_dev->dev, "unsupported type:%d\n", flag);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void aw_dev_backup_sec_record(struct aw88166 *aw88166)
+{
+ aw_dev_init_vcalb_update(aw88166, AW88166_RECORD_SEC_DATA);
+ aw_dev_init_re_update(aw88166, AW88166_RECOVERY_SEC_DATA);
+}
+
+static void aw_dev_backup_sec_recovery(struct aw88166 *aw88166)
+{
+ aw_dev_init_vcalb_update(aw88166, AW88166_RECOVERY_SEC_DATA);
+ aw_dev_init_re_update(aw88166, AW88166_RECOVERY_SEC_DATA);
+}
+
+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 >= AW88166_CALI_RE_MAX) ||
+ (aw_dev->cali_desc.cali_re <= AW88166_CALI_RE_MIN))
+ return -EINVAL;
+
+ cali_re = AW88166_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re +
+ aw_dev->cali_desc.ra), AW88166_DSP_RE_SHIFT);
+
+ re_hbits = (cali_re & (~AW88166_CALI_RE_HBITS_MASK)) >> AW88166_CALI_RE_HBITS_SHIFT;
+ re_lbits = (cali_re & (~AW88166_CALI_RE_LBITS_MASK)) >> AW88166_CALI_RE_LBITS_SHIFT;
+
+ ret = regmap_write(aw_dev->regmap, AW88166_ACR1_REG, re_hbits);
+ if (ret) {
+ dev_err(aw_dev->dev, "set cali re error");
+ return ret;
+ }
+
+ ret = regmap_write(aw_dev->regmap, AW88166_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) + AW88166_CRC_FW_BASE_ADDR;
+
+ /* write fw_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
+ ~AW88166_CRC_END_ADDR_MASK, fw_len_val);
+ if (ret)
+ return ret;
+ /* enable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
+ ~AW88166_CRC_CODE_EN_MASK, AW88166_CRC_CODE_EN_ENABLE_VALUE);
+
+ usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
+
+ /* read crc check result */
+ regmap_read(aw_dev->regmap, AW88166_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88166_CRC_CHECK_BITS_MASK)) >> AW88166_CRC_CHECK_START_BIT;
+
+ /* disable fw crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
+ ~AW88166_CRC_CODE_EN_MASK, AW88166_CRC_CODE_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88166_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x\n",
+ __func__, check_val, AW88166_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) + AW88166_CRC_CFG_BASE_ADDR;
+
+ /* write cfg_end_addr to crc_end_addr */
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
+ ~AW88166_CRC_END_ADDR_MASK, cfg_len_val);
+ if (ret)
+ return ret;
+
+ /* enable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
+ ~AW88166_CRC_CFG_EN_MASK, AW88166_CRC_CFG_EN_ENABLE_VALUE);
+ if (ret)
+ return ret;
+
+ usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
+
+ /* read crc check result */
+ ret = regmap_read(aw_dev->regmap, AW88166_HAGCST_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ check_val = (reg_val & (~AW88166_CRC_CHECK_BITS_MASK)) >> AW88166_CRC_CHECK_START_BIT;
+
+ /* disable cfg crc check */
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG,
+ ~AW88166_CRC_CFG_EN_MASK, AW88166_CRC_CFG_EN_DISABLE_VALUE);
+ if (ret)
+ return ret;
+
+ if (check_val != AW88166_CRC_CHECK_PASS_VAL) {
+ dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x\n",
+ check_val, AW88166_CRC_CHECK_PASS_VAL);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int aw_dev_hw_crc_check(struct aw88166 *aw88166)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG,
+ ~AW88166_RAM_CG_BYP_MASK, AW88166_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, AW88166_CRCCTRL_REG, aw88166->crc_init_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG,
+ ~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_WORK_VALUE);
+
+ return ret;
+
+crc_check_failed:
+ regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG,
+ ~AW88166_RAM_CG_BYP_MASK, AW88166_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, AW88166_I2SCTRL3_REG,
+ ~AW88166_I2STXEN_MASK, AW88166_I2STXEN_ENABLE_VALUE);
+ else
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCTRL3_REG,
+ ~AW88166_I2STXEN_MASK, AW88166_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, AW88166_WDT_REG, &reg_val);
+ if (ret)
+ return ret;
+ if (!(reg_val & (~AW88166_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 AW88166_DEV_DSP_BYPASS:
+ dev_dbg(aw_dev->dev, "dsp bypass");
+ ret = 0;
+ break;
+ case AW88166_DEV_DSP_WORK:
+ aw_dev_dsp_enable(aw_dev, false);
+ aw_dev_dsp_enable(aw_dev, true);
+ usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
+ for (i = 0; i < AW88166_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(AW88166_2000_US, AW88166_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)AW88166_MUTE_VOL);
+
+ ret = regmap_read(aw_dev->regmap, AW88166_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 << AW88166_VOL_START_BIT) | (reg_value & AW88166_VOL_MASK);
+
+ ret = regmap_write(aw_dev->regmap, AW88166_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 = AW88166_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, AW88166_MUTE_VOL);
+ return;
+ }
+
+ for (i = desc->ctl_volume; i <= AW88166_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 != AW88166_MUTE_VOL) {
+ aw_dev_set_volume(aw_dev, AW88166_MUTE_VOL);
+ usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10);
+ }
+}
+
+static void aw88166_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, AW88166_SYSCTRL_REG,
+ ~AW88166_HMUTE_MASK, AW88166_HMUTE_ENABLE_VALUE);
+ } else {
+ regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG,
+ ~AW88166_HMUTE_MASK, AW88166_HMUTE_DISABLE_VALUE);
+ aw_dev_fade_in(aw_dev);
+ }
+}
+
+static void aw88166_dev_set_dither(struct aw88166 *aw88166, bool dither)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+
+ if (dither)
+ regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
+ ~AW88166_DITHER_EN_MASK, AW88166_DITHER_EN_ENABLE_VALUE);
+ else
+ regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
+ ~AW88166_DITHER_EN_MASK, AW88166_DITHER_EN_DISABLE_VALUE);
+}
+
+static int aw88166_dev_start(struct aw88166 *aw88166)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int ret;
+
+ if (aw_dev->status == AW88166_DEV_PW_ON) {
+ dev_dbg(aw_dev->dev, "already power on");
+ return 0;
+ }
+
+ aw88166_dev_set_dither(aw88166, false);
+
+ /* power on */
+ aw_dev_pwd(aw_dev, false);
+ usleep_range(AW88166_2000_US, AW88166_2000_US + 10);
+
+ ret = aw_dev_check_syspll(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "pll check failed cannot start\n");
+ goto pll_check_fail;
+ }
+
+ /* amppd on */
+ aw_dev_amppd(aw_dev, false);
+ usleep_range(AW88166_1000_US, AW88166_1000_US + 50);
+
+ /* check i2s status */
+ ret = aw_dev_check_sysst(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "sysst check failed\n");
+ goto sysst_check_fail;
+ }
+
+ if (aw_dev->dsp_cfg == AW88166_DEV_DSP_WORK) {
+ aw_dev_backup_sec_recovery(aw88166);
+ ret = aw_dev_hw_crc_check(aw88166);
+ if (ret) {
+ dev_err(aw_dev->dev, "dsp crc check failed\n");
+ goto crc_check_fail;
+ }
+ aw_dev_dsp_enable(aw_dev, false);
+ aw88166_dev_set_vcalb(aw88166);
+ 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\n");
+ 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 (aw88166->dither_st == AW88166_DITHER_EN_ENABLE_VALUE)
+ aw88166_dev_set_dither(aw88166, true);
+
+ /* close mute */
+ aw88166_dev_mute(aw_dev, false);
+ /* clear inturrupt */
+ aw_dev_clear_int_status(aw_dev);
+ aw_dev->status = AW88166_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 = AW88166_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;
+
+ mutex_lock(&aw_dev->dsp_lock);
+ ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, base);
+ if (ret)
+ goto error_operation;
+
+ for (i = 0; i < len; i += AW88166_MAX_RAM_WRITE_BYTE_SIZE) {
+ if ((len - i) < AW88166_MAX_RAM_WRITE_BYTE_SIZE)
+ tmp_len = len - i;
+ else
+ tmp_len = AW88166_MAX_RAM_WRITE_BYTE_SIZE;
+
+ ret = regmap_raw_write(aw_dev->regmap, AW88166_DSPMDAT_REG,
+ &data[i], tmp_len);
+ if (ret)
+ goto error_operation;
+ }
+ mutex_unlock(&aw_dev->dsp_lock);
+
+ return 0;
+
+error_operation:
+ mutex_unlock(&aw_dev->dsp_lock);
+ return ret;
+}
+
+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, AW88166_DSP_REG_CFG_ADPZ_RA,
+ &dsp_ra, AW88166_DSP_32_DATA);
+ if (ret) {
+ dev_err(aw_dev->dev, "read ra error\n");
+ return ret;
+ }
+
+ cali_desc->ra = AW88166_DSP_RE_TO_SHOW_RE(dsp_ra,
+ AW88166_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\n");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88166_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\n");
+ return -EINVAL;
+ }
+
+ aw_dev->dsp_fw_len = len;
+ ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88166_DSP_FW_ADDR);
+
+ return ret;
+}
+
+static int aw_dev_check_sram(struct aw_device *aw_dev)
+{
+ unsigned int reg_val;
+
+ mutex_lock(&aw_dev->dsp_lock);
+ /* read dsp_rom_check_reg */
+ aw_dev_dsp_read_16bit(aw_dev, AW88166_DSP_ROM_CHECK_ADDR, &reg_val);
+ if (reg_val != AW88166_DSP_ROM_CHECK_DATA) {
+ dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]\n",
+ reg_val, AW88166_DSP_ROM_CHECK_DATA);
+ goto error;
+ }
+
+ /* check dsp_cfg_base_addr */
+ aw_dev_dsp_write_16bit(aw_dev, AW88166_DSP_CFG_ADDR, AW88166_DSP_ODD_NUM_BIT_TEST);
+ aw_dev_dsp_read_16bit(aw_dev, AW88166_DSP_CFG_ADDR, &reg_val);
+ if (reg_val != AW88166_DSP_ODD_NUM_BIT_TEST) {
+ dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]\n",
+ reg_val, AW88166_DSP_ODD_NUM_BIT_TEST);
+ goto error;
+ }
+ mutex_unlock(&aw_dev->dsp_lock);
+
+ return 0;
+error:
+ mutex_unlock(&aw_dev->dsp_lock);
+ return -EPERM;
+}
+
+static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag)
+{
+ int ret;
+
+ switch (flag) {
+ case AW88166_DEV_MEMCLK_PLL:
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
+ ~AW88166_MEM_CLKSEL_MASK,
+ AW88166_MEM_CLKSEL_DAPHCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select pll failed\n");
+ break;
+ case AW88166_DEV_MEMCLK_OSC:
+ ret = regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG,
+ ~AW88166_MEM_CLKSEL_MASK,
+ AW88166_MEM_CLKSEL_OSCCLK_VALUE);
+ if (ret)
+ dev_err(aw_dev->dev, "memclk select OSC failed\n");
+ break;
+ default:
+ dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x\n", flag);
+ break;
+ }
+}
+
+static int aw_dev_update_reg_container(struct aw88166 *aw88166,
+ unsigned char *data, unsigned int len)
+{
+ struct aw_device *aw_dev = aw88166->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\n", 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 == AW88166_DSPVCALB_REG) {
+ aw88166->vcalb_init_val = reg_val;
+ continue;
+ }
+
+ if (reg_addr == AW88166_SYSCTRL_REG) {
+ if (reg_val & (~AW88166_DSPBY_MASK))
+ aw_dev->dsp_cfg = AW88166_DEV_DSP_BYPASS;
+ else
+ aw_dev->dsp_cfg = AW88166_DEV_DSP_WORK;
+
+ reg_val &= (AW88166_HMUTE_MASK | AW88166_PWDN_MASK |
+ AW88166_DSPBY_MASK);
+ reg_val |= (AW88166_HMUTE_ENABLE_VALUE | AW88166_PWDN_POWER_DOWN_VALUE |
+ AW88166_DSPBY_BYPASS_VALUE);
+ }
+
+ if (reg_addr == AW88166_I2SCTRL3_REG) {
+ reg_val &= AW88166_I2STXEN_MASK;
+ reg_val |= AW88166_I2STXEN_DISABLE_VALUE;
+ }
+
+ if (reg_addr == AW88166_SYSCTRL2_REG) {
+ read_vol = (reg_val & (~AW88166_VOL_MASK)) >>
+ AW88166_VOL_START_BIT;
+ aw_dev->volume_desc.init_volume = read_vol;
+ }
+
+ if (reg_addr == AW88166_DBGCTRL_REG) {
+ if ((reg_val & (~AW88166_EF_DBMD_MASK)) == AW88166_EF_DBMD_OR_VALUE)
+ aw88166->check_val = AW_EF_OR_CHECK;
+ else
+ aw88166->check_val = AW_EF_AND_CHECK;
+
+ aw88166->dither_st = reg_val & (~AW88166_DITHER_EN_MASK);
+ }
+
+ if (reg_addr == AW88166_ACR1_REG) {
+ aw88166->re_init_val |= (uint32_t)reg_val << 16;
+ continue;
+ }
+
+ if (reg_addr == AW88166_ACR2_REG) {
+ aw88166->re_init_val |= (uint32_t)reg_val;
+ continue;
+ }
+
+ if (reg_addr == AW88166_CRCCTRL_REG)
+ aw88166->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(AW88166_1000_US, AW88166_1000_US + 10);
+
+ 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 aw88166 *aw88166,
+ unsigned char *data, unsigned int len)
+{
+ int ret;
+
+ if (!len || !data) {
+ dev_err(aw88166->aw_pa->dev, "reg data is null or len is 0\n");
+ return -EINVAL;
+ }
+
+ ret = aw_dev_update_reg_container(aw88166, data, len);
+ if (ret)
+ dev_err(aw88166->aw_pa->dev, "reg update failed\n");
+
+ return ret;
+}
+
+static int aw88166_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]\n",
+ 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 aw88166_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 aw88166_dev_fw_update(struct aw88166 *aw88166, bool up_dsp_fw_en, bool force_up_en)
+{
+ struct aw_device *aw_dev = aw88166->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 == AW88166_FORCE_UPDATE_OFF)) {
+ dev_dbg(aw_dev->dev, "scene no change, not update");
+ return 0;
+ }
+
+ if (aw_dev->fw_status == AW88166_DEV_FW_FAILED) {
+ dev_err(aw_dev->dev, "fw status[%d] error\n", aw_dev->fw_status);
+ return -EPERM;
+ }
+
+ ret = aw88166_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 = aw88166_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(aw88166, sec_desc[AW88395_DATA_TYPE_REG].data,
+ sec_desc[AW88395_DATA_TYPE_REG].len);
+ if (ret) {
+ dev_err(aw_dev->dev, "update reg failed\n");
+ return ret;
+ }
+
+ aw88166_dev_mute(aw_dev, true);
+
+ if (aw_dev->dsp_cfg == AW88166_DEV_DSP_WORK)
+ aw_dev_dsp_enable(aw_dev, false);
+
+ aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_OSC);
+
+ ret = aw_dev_check_sram(aw_dev);
+ if (ret) {
+ dev_err(aw_dev->dev, "check sram failed\n");
+ goto error;
+ }
+
+ aw_dev_backup_sec_recovery(aw88166);
+
+ 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\n");
+ 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\n");
+ goto error;
+ }
+
+ aw_dev_backup_sec_record(aw88166);
+
+ aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL);
+
+ aw_dev->prof_cur = aw_dev->prof_index;
+
+ return 0;
+
+error:
+ aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL);
+ return ret;
+}
+
+static void aw88166_start_pa(struct aw88166 *aw88166)
+{
+ int ret, i;
+
+ for (i = 0; i < AW88166_START_RETRIES; i++) {
+ ret = aw88166_dev_start(aw88166);
+ if (ret) {
+ dev_err(aw88166->aw_pa->dev, "aw88166 device start failed. retry = %d", i);
+ ret = aw88166_dev_fw_update(aw88166, AW88166_DSP_FW_UPDATE_ON, true);
+ if (ret) {
+ dev_err(aw88166->aw_pa->dev, "fw update failed");
+ continue;
+ }
+ } else {
+ dev_dbg(aw88166->aw_pa->dev, "start success\n");
+ break;
+ }
+ }
+}
+
+static void aw88166_startup_work(struct work_struct *work)
+{
+ struct aw88166 *aw88166 =
+ container_of(work, struct aw88166, start_work.work);
+
+ mutex_lock(&aw88166->lock);
+ aw88166_start_pa(aw88166);
+ mutex_unlock(&aw88166->lock);
+}
+
+static void aw88166_start(struct aw88166 *aw88166, bool sync_start)
+{
+ int ret;
+
+ if (aw88166->aw_pa->fw_status != AW88166_DEV_FW_OK)
+ return;
+
+ if (aw88166->aw_pa->status == AW88166_DEV_PW_ON)
+ return;
+
+ ret = aw88166_dev_fw_update(aw88166, AW88166_DSP_FW_UPDATE_OFF, aw88166->phase_sync);
+ if (ret) {
+ dev_err(aw88166->aw_pa->dev, "fw update failed\n");
+ return;
+ }
+
+ if (sync_start == AW88166_SYNC_START)
+ aw88166_start_pa(aw88166);
+ else
+ queue_delayed_work(system_wq,
+ &aw88166->start_work,
+ AW88166_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 & AW88166_BIT_SYSINT_CHECK) {
+ dev_err(aw_dev->dev, "pa stop check fail:0x%04x\n", reg_val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int aw88166_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 == AW88166_DEV_PW_OFF) {
+ dev_dbg(aw_dev->dev, "already power off");
+ return 0;
+ }
+
+ aw_dev->status = AW88166_DEV_PW_OFF;
+
+ aw88166_dev_mute(aw_dev, true);
+ usleep_range(AW88166_4000_US, AW88166_4000_US + 100);
+
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88166_1000_US, AW88166_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, AW88166_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, AW88166_DEV_MEMCLK_PLL);
+ }
+
+ aw_dev_pwd(aw_dev, true);
+
+ return 0;
+}
+
+static struct snd_soc_dai_driver aw88166_dai[] = {
+ {
+ .name = "aw88166-aif",
+ .id = 1,
+ .playback = {
+ .stream_name = "Speaker_Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88166_RATES,
+ .formats = AW88166_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Speaker_Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AW88166_RATES,
+ .formats = AW88166_FORMATS,
+ },
+ },
+};
+
+static int aw88166_get_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88166->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_in_time;
+
+ return 0;
+}
+
+static int aw88166_set_fade_in_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int time;
+
+ time = ucontrol->value.integer.value[0];
+
+ if (time < mc->min || time > mc->max)
+ return -EINVAL;
+
+ if (time != aw_dev->fade_in_time) {
+ aw_dev->fade_in_time = time;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88166_get_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
+ struct aw_device *aw_dev = aw88166->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->fade_out_time;
+
+ return 0;
+}
+
+static int aw88166_set_fade_out_time(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int time;
+
+ time = ucontrol->value.integer.value[0];
+ if (time < mc->min || time > mc->max)
+ return -EINVAL;
+
+ if (time != aw_dev->fade_out_time) {
+ aw_dev->fade_out_time = time;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88166_dev_set_profile_index(struct aw_device *aw_dev, int index)
+{
+ /* check the index whether is valid */
+ if ((index >= aw_dev->prof_info.count) || (index < 0))
+ return -EINVAL;
+ /* check the index whether change */
+ if (aw_dev->prof_index == index)
+ return -EINVAL;
+
+ aw_dev->prof_index = index;
+ dev_dbg(aw_dev->dev, "set prof[%s]",
+ aw_dev->prof_info.prof_name_list[aw_dev->prof_info.prof_desc[index].id]);
+
+ return 0;
+}
+
+static int aw88166_profile_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ char *prof_name, *name;
+ int count, ret;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+
+ count = aw88166->aw_pa->prof_info.count;
+ if (count <= 0) {
+ uinfo->value.enumerated.items = 0;
+ return 0;
+ }
+
+ uinfo->value.enumerated.items = count;
+
+ if (uinfo->value.enumerated.item >= count)
+ uinfo->value.enumerated.item = count - 1;
+
+ name = uinfo->value.enumerated.name;
+ count = uinfo->value.enumerated.item;
+
+ ret = aw88166_dev_get_prof_name(aw88166->aw_pa, count, &prof_name);
+ if (ret) {
+ strscpy(uinfo->value.enumerated.name, "null",
+ strlen("null") + 1);
+ return 0;
+ }
+
+ strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name));
+
+ return 0;
+}
+
+static int aw88166_profile_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88166->aw_pa->prof_index;
+
+ return 0;
+}
+
+static int aw88166_profile_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ int ret;
+
+ mutex_lock(&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;
+ }
+
+ if (aw88166->aw_pa->status) {
+ aw88166_stop(aw88166->aw_pa);
+ aw88166_start(aw88166, AW88166_SYNC_START);
+ }
+
+ mutex_unlock(&aw88166->lock);
+
+ return 1;
+}
+
+static int aw88166_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc;
+
+ ucontrol->value.integer.value[0] = vol_desc->ctl_volume;
+
+ return 0;
+}
+
+static int aw88166_volume_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (vol_desc->ctl_volume != value) {
+ vol_desc->ctl_volume = value;
+ aw_dev_set_volume(aw88166->aw_pa, vol_desc->ctl_volume);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88166_get_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = aw88166->aw_pa->fade_step;
+
+ return 0;
+}
+
+static int aw88166_set_fade_step(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (aw88166->aw_pa->fade_step != value) {
+ aw88166->aw_pa->fade_step = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88166_re_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ struct aw_device *aw_dev = aw88166->aw_pa;
+
+ ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_re;
+
+ return 0;
+}
+
+static int aw88166_re_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ int value;
+
+ value = ucontrol->value.integer.value[0];
+ if (value < mc->min || value > mc->max)
+ return -EINVAL;
+
+ if (aw_dev->cali_desc.cali_re != value) {
+ aw_dev->cali_desc.cali_re = value;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg)
+{
+ struct aw_device *aw_dev = aw88166->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\n");
+ return -EINVAL;
+ }
+ aw_dev->fade_in_time = AW88166_1000_US / 10;
+ aw_dev->fade_out_time = AW88166_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 = aw88166_dev_fw_update(aw88166, AW88166_FORCE_UPDATE_ON, AW88166_DSP_FW_UPDATE_ON);
+ if (ret) {
+ dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret);
+ return ret;
+ }
+
+ aw88166_dev_mute(aw_dev, true);
+
+ /* close tx feedback */
+ aw_dev_i2s_tx_enable(aw_dev, false);
+ usleep_range(AW88166_1000_US, AW88166_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 aw88166_request_firmware_file(struct aw88166 *aw88166)
+{
+ const struct firmware *cont = NULL;
+ int ret;
+
+ aw88166->aw_pa->fw_status = AW88166_DEV_FW_FAILED;
+
+ ret = request_firmware(&cont, AW88166_ACF_FILE, aw88166->aw_pa->dev);
+ if (ret) {
+ dev_err(aw88166->aw_pa->dev, "request [%s] failed!\n", AW88166_ACF_FILE);
+ return ret;
+ }
+
+ dev_dbg(aw88166->aw_pa->dev, "loaded %s - size: %zu\n",
+ AW88166_ACF_FILE, cont ? cont->size : 0);
+
+ 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);
+ 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) {
+ dev_err(aw88166->aw_pa->dev, "load [%s] failed!\n", AW88166_ACF_FILE);
+ 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);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new aw88166_controls[] = {
+ SOC_SINGLE_EXT("PCM Playback Volume", AW88166_SYSCTRL2_REG,
+ 6, AW88166_MUTE_VOL, 0, aw88166_volume_get,
+ aw88166_volume_set),
+ SOC_SINGLE_EXT("Fade Step", 0, 0, AW88166_MUTE_VOL, 0,
+ aw88166_get_fade_step, aw88166_set_fade_step),
+ SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88166_get_fade_in_time, aw88166_set_fade_in_time),
+ SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN,
+ aw88166_get_fade_out_time, aw88166_set_fade_out_time),
+ SOC_SINGLE_EXT("Calib", 0, 0, AW88166_CALI_RE_MAX, 0,
+ aw88166_re_get, aw88166_re_set),
+ AW88166_PROFILE_EXT("AW88166 Profile Set", aw88166_profile_info,
+ aw88166_profile_get, aw88166_profile_set),
+};
+
+static int aw88166_playback_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ 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);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ aw88166_start(aw88166, AW88166_ASYNC_START);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ aw88166_stop(aw88166->aw_pa);
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(&aw88166->lock);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aw88166_dapm_widgets[] = {
+ /* playback */
+ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0,
+ aw88166_playback_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUTPUT("DAC Output"),
+
+ /* capture */
+ SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_INPUT("ADC Input"),
+};
+
+static const struct snd_soc_dapm_route aw88166_audio_map[] = {
+ {"DAC Output", NULL, "AIF_RX"},
+ {"AIF_TX", NULL, "ADC Input"},
+};
+
+static int aw88166_codec_probe(struct snd_soc_component *component)
+{
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ INIT_DELAYED_WORK(&aw88166->start_work, aw88166_startup_work);
+
+ ret = aw88166_request_firmware_file(aw88166);
+ if (ret)
+ dev_err(aw88166->aw_pa->dev, "%s failed\n", __func__);
+
+ return ret;
+}
+
+static void aw88166_codec_remove(struct snd_soc_component *aw_codec)
+{
+ struct aw88166 *aw88166 = snd_soc_component_get_drvdata(aw_codec);
+
+ cancel_delayed_work_sync(&aw88166->start_work);
+}
+
+static const struct snd_soc_component_driver soc_codec_dev_aw88166 = {
+ .probe = aw88166_codec_probe,
+ .remove = aw88166_codec_remove,
+ .dapm_widgets = aw88166_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aw88166_dapm_widgets),
+ .dapm_routes = aw88166_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(aw88166_audio_map),
+ .controls = aw88166_controls,
+ .num_controls = ARRAY_SIZE(aw88166_controls),
+};
+
+static void aw88166_hw_reset(struct aw88166 *aw88166)
+{
+ if (aw88166->reset_gpio) {
+ gpiod_set_value_cansleep(aw88166->reset_gpio, 1);
+ usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
+ gpiod_set_value_cansleep(aw88166->reset_gpio, 0);
+ usleep_range(AW88166_1000_US, AW88166_1000_US + 10);
+ }
+}
+
+static void aw88166_parse_channel_dt(struct aw88166 *aw88166)
+{
+ struct aw_device *aw_dev = aw88166->aw_pa;
+ 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;
+ aw88166->phase_sync = of_property_read_bool(np, "awinic,sync-flag");
+}
+
+static int aw88166_init(struct aw88166 *aw88166, struct i2c_client *i2c, struct regmap *regmap)
+{
+ struct aw_device *aw_dev;
+ unsigned int chip_id;
+ int ret;
+
+ ret = regmap_read(regmap, AW88166_ID_REG, &chip_id);
+ if (ret) {
+ dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret);
+ return ret;
+ }
+
+ aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL);
+ if (!aw_dev)
+ return -ENOMEM;
+ aw88166->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 = AW88166_DEV_DEFAULT_CH;
+ aw_dev->fw_status = AW88166_DEV_FW_FAILED;
+
+ aw_dev->fade_step = AW88166_VOLUME_STEP_DB;
+ aw_dev->volume_desc.ctl_volume = AW88166_VOL_DEFAULT_VALUE;
+
+ aw88166_parse_channel_dt(aw88166);
+
+ return 0;
+}
+
+static int aw88166_i2c_probe(struct i2c_client *i2c)
+{
+ struct aw88166 *aw88166;
+ int ret;
+
+ if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
+ return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n");
+
+ aw88166 = devm_kzalloc(&i2c->dev, sizeof(*aw88166), GFP_KERNEL);
+ if (!aw88166)
+ return -ENOMEM;
+
+ mutex_init(&aw88166->lock);
+
+ i2c_set_clientdata(i2c, aw88166);
+
+ aw88166->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(aw88166->reset_gpio))
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88166->reset_gpio),
+ "reset gpio not defined\n");
+ aw88166_hw_reset(aw88166);
+
+ aw88166->regmap = devm_regmap_init_i2c(i2c, &aw88166_remap_config);
+ if (IS_ERR(aw88166->regmap))
+ return dev_err_probe(&i2c->dev, PTR_ERR(aw88166->regmap),
+ "failed to init regmap\n");
+
+ /* aw pa init */
+ ret = aw88166_init(aw88166, i2c, aw88166->regmap);
+ if (ret)
+ return ret;
+
+ return devm_snd_soc_register_component(&i2c->dev,
+ &soc_codec_dev_aw88166,
+ aw88166_dai, ARRAY_SIZE(aw88166_dai));
+}
+
+static const struct i2c_device_id aw88166_i2c_id[] = {
+ { AW88166_I2C_NAME },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aw88166_i2c_id);
+
+static struct i2c_driver aw88166_i2c_driver = {
+ .driver = {
+ .name = AW88166_I2C_NAME,
+ },
+ .probe = aw88166_i2c_probe,
+ .id_table = aw88166_i2c_id,
+};
+module_i2c_driver(aw88166_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC AW88166 Smart PA Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/aw88166.h b/sound/soc/codecs/aw88166.h
new file mode 100644
index 000000000000..3a53ba0ac625
--- /dev/null
+++ b/sound/soc/codecs/aw88166.h
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// aw88166.h -- ALSA SoC AW88166 codec support
+//
+// Copyright (c) 2025 AWINIC Technology CO., LTD
+//
+// Author: Weidong Wang <wangweidong.a@awinic.com>
+//
+
+#ifndef __AW88166_H__
+#define __AW88166_H__
+
+/* registers list */
+#define AW88166_ID_REG (0x00)
+#define AW88166_SYSST_REG (0x01)
+#define AW88166_SYSINT_REG (0x02)
+#define AW88166_SYSINTM_REG (0x03)
+#define AW88166_SYSCTRL_REG (0x04)
+#define AW88166_SYSCTRL2_REG (0x05)
+#define AW88166_I2SCTRL1_REG (0x06)
+#define AW88166_I2SCTRL2_REG (0x07)
+#define AW88166_I2SCTRL3_REG (0x08)
+#define AW88166_DACCFG1_REG (0x09)
+#define AW88166_DACCFG2_REG (0x0A)
+#define AW88166_DACCFG3_REG (0x0B)
+#define AW88166_DACCFG4_REG (0x0C)
+#define AW88166_DACCFG5_REG (0x0D)
+#define AW88166_DACCFG6_REG (0x0E)
+#define AW88166_DACCFG7_REG (0x0F)
+#define AW88166_MPDCFG1_REG (0x10)
+#define AW88166_MPDCFG2_REG (0x11)
+#define AW88166_MPDCFG3_REG (0x12)
+#define AW88166_MPDCFG4_REG (0x13)
+#define AW88166_PWMCTRL1_REG (0x14)
+#define AW88166_PWMCTRL2_REG (0x15)
+#define AW88166_PWMCTRL3_REG (0x16)
+#define AW88166_I2SCFG1_REG (0x17)
+#define AW88166_DBGCTRL_REG (0x18)
+#define AW88166_HAGCST_REG (0x20)
+#define AW88166_VBAT_REG (0x21)
+#define AW88166_TEMP_REG (0x22)
+#define AW88166_PVDD_REG (0x23)
+#define AW88166_ISNDAT_REG (0x24)
+#define AW88166_I2SINT_REG (0x25)
+#define AW88166_I2SCAPCNT_REG (0x26)
+#define AW88166_ANASTA1_REG (0x27)
+#define AW88166_ANASTA2_REG (0x28)
+#define AW88166_ANASTA3_REG (0x29)
+#define AW88166_TESTDET_REG (0x2A)
+#define AW88166_TESTIN_REG (0x38)
+#define AW88166_TESTOUT_REG (0x39)
+#define AW88166_MEMTEST_REG (0x3A)
+#define AW88166_DSPMADD_REG (0x40)
+#define AW88166_DSPMDAT_REG (0x41)
+#define AW88166_WDT_REG (0x42)
+#define AW88166_ACR1_REG (0x43)
+#define AW88166_ACR2_REG (0x44)
+#define AW88166_ASR1_REG (0x45)
+#define AW88166_ASR2_REG (0x46)
+#define AW88166_DSPCFG_REG (0x47)
+#define AW88166_ASR3_REG (0x48)
+#define AW88166_ASR4_REG (0x49)
+#define AW88166_DSPVCALB_REG (0x4A)
+#define AW88166_CRCCTRL_REG (0x4B)
+#define AW88166_DSPDBG1_REG (0x4C)
+#define AW88166_DSPDBG2_REG (0x4D)
+#define AW88166_DSPDBG3_REG (0x4E)
+#define AW88166_ISNCTRL1_REG (0x50)
+#define AW88166_PLLCTRL1_REG (0x51)
+#define AW88166_PLLCTRL2_REG (0x52)
+#define AW88166_PLLCTRL3_REG (0x53)
+#define AW88166_CDACTRL1_REG (0x54)
+#define AW88166_CDACTRL2_REG (0x55)
+#define AW88166_CDACTRL3_REG (0x56)
+#define AW88166_SADCCTRL1_REG (0x57)
+#define AW88166_SADCCTRL2_REG (0x58)
+#define AW88166_BOPCTRL1_REG (0x59)
+#define AW88166_BOPCTRL2_REG (0x5A)
+#define AW88166_BOPCTRL3_REG (0x5B)
+#define AW88166_BOPCTRL4_REG (0x5C)
+#define AW88166_BOPCTRL5_REG (0x5D)
+#define AW88166_BOPCTRL6_REG (0x5E)
+#define AW88166_BOPCTRL7_REG (0x5F)
+#define AW88166_BSTCTRL1_REG (0x60)
+#define AW88166_BSTCTRL2_REG (0x61)
+#define AW88166_BSTCTRL3_REG (0x62)
+#define AW88166_BSTCTRL4_REG (0x63)
+#define AW88166_BSTCTRL5_REG (0x64)
+#define AW88166_BSTCTRL6_REG (0x65)
+#define AW88166_DSMCFG1_REG (0x66)
+#define AW88166_DSMCFG2_REG (0x67)
+#define AW88166_DSMCFG3_REG (0x68)
+#define AW88166_DSMCFG4_REG (0x69)
+#define AW88166_DSMCFG5_REG (0x6A)
+#define AW88166_DSMCFG6_REG (0x6B)
+#define AW88166_DSMCFG7_REG (0x6C)
+#define AW88166_DSMCFG8_REG (0x6D)
+#define AW88166_TESTCTRL1_REG (0x70)
+#define AW88166_TESTCTRL2_REG (0x71)
+#define AW88166_EFCTRL1_REG (0x72)
+#define AW88166_EFCTRL2_REG (0x73)
+#define AW88166_EFWH_REG (0x74)
+#define AW88166_EFWM2_REG (0x75)
+#define AW88166_EFWM1_REG (0x76)
+#define AW88166_EFRH_REG (0x77)
+#define AW88166_EFRM2_REG (0x78)
+#define AW88166_EFRM1_REG (0x79)
+#define AW88166_EFRL_REG (0x7A)
+#define AW88166_TM_REG (0x7C)
+#define AW88166_TM2_REG (0x7D)
+
+#define AW88166_REG_MAX (0x7E)
+#define AW88166_MUTE_VOL (1023)
+
+#define AW88166_DSP_CFG_ADDR (0x9B00)
+#define AW88166_DSP_REG_CFG_ADPZ_RA (0x9B68)
+#define AW88166_DSP_FW_ADDR (0x8980)
+#define AW88166_DSP_ROM_CHECK_ADDR (0x1F40)
+
+#define AW88166_CALI_RE_HBITS_MASK (~(0xFFFF0000))
+#define AW88166_CALI_RE_HBITS_SHIFT (16)
+
+#define AW88166_CALI_RE_LBITS_MASK (~(0xFFFF))
+#define AW88166_CALI_RE_LBITS_SHIFT (0)
+
+#define AW88166_I2STXEN_START_BIT (9)
+#define AW88166_I2STXEN_BITS_LEN (1)
+#define AW88166_I2STXEN_MASK \
+ (~(((1<<AW88166_I2STXEN_BITS_LEN)-1) << AW88166_I2STXEN_START_BIT))
+
+#define AW88166_I2STXEN_DISABLE (0)
+#define AW88166_I2STXEN_DISABLE_VALUE \
+ (AW88166_I2STXEN_DISABLE << AW88166_I2STXEN_START_BIT)
+
+#define AW88166_I2STXEN_ENABLE (1)
+#define AW88166_I2STXEN_ENABLE_VALUE \
+ (AW88166_I2STXEN_ENABLE << AW88166_I2STXEN_START_BIT)
+
+#define AW88166_VOL_START_BIT (0)
+#define AW88166_VOL_BITS_LEN (10)
+#define AW88166_VOL_MASK \
+ (~(((1<<AW88166_VOL_BITS_LEN)-1) << AW88166_VOL_START_BIT))
+
+#define AW88166_PWDN_START_BIT (0)
+#define AW88166_PWDN_BITS_LEN (1)
+#define AW88166_PWDN_MASK \
+ (~(((1<<AW88166_PWDN_BITS_LEN)-1) << AW88166_PWDN_START_BIT))
+
+#define AW88166_PWDN_POWER_DOWN (1)
+#define AW88166_PWDN_POWER_DOWN_VALUE \
+ (AW88166_PWDN_POWER_DOWN << AW88166_PWDN_START_BIT)
+
+#define AW88166_PWDN_WORKING (0)
+#define AW88166_PWDN_WORKING_VALUE \
+ (AW88166_PWDN_WORKING << AW88166_PWDN_START_BIT)
+
+#define AW88166_DSPBY_START_BIT (2)
+#define AW88166_DSPBY_BITS_LEN (1)
+#define AW88166_DSPBY_MASK \
+ (~(((1<<AW88166_DSPBY_BITS_LEN)-1) << AW88166_DSPBY_START_BIT))
+
+#define AW88166_DSPBY_WORKING (0)
+#define AW88166_DSPBY_WORKING_VALUE \
+ (AW88166_DSPBY_WORKING << AW88166_DSPBY_START_BIT)
+
+#define AW88166_DSPBY_BYPASS (1)
+#define AW88166_DSPBY_BYPASS_VALUE \
+ (AW88166_DSPBY_BYPASS << AW88166_DSPBY_START_BIT)
+
+#define AW88166_MEM_CLKSEL_START_BIT (3)
+#define AW88166_MEM_CLKSEL_BITS_LEN (1)
+#define AW88166_MEM_CLKSEL_MASK \
+ (~(((1<<AW88166_MEM_CLKSEL_BITS_LEN)-1) << AW88166_MEM_CLKSEL_START_BIT))
+
+#define AW88166_MEM_CLKSEL_OSCCLK (0)
+#define AW88166_MEM_CLKSEL_OSCCLK_VALUE \
+ (AW88166_MEM_CLKSEL_OSCCLK << AW88166_MEM_CLKSEL_START_BIT)
+
+#define AW88166_MEM_CLKSEL_DAPHCLK (1)
+#define AW88166_MEM_CLKSEL_DAPHCLK_VALUE \
+ (AW88166_MEM_CLKSEL_DAPHCLK << AW88166_MEM_CLKSEL_START_BIT)
+
+#define AW88166_DITHER_EN_START_BIT (15)
+#define AW88166_DITHER_EN_BITS_LEN (1)
+#define AW88166_DITHER_EN_MASK \
+ (~(((1<<AW88166_DITHER_EN_BITS_LEN)-1) << AW88166_DITHER_EN_START_BIT))
+
+#define AW88166_DITHER_EN_DISABLE (0)
+#define AW88166_DITHER_EN_DISABLE_VALUE \
+ (AW88166_DITHER_EN_DISABLE << AW88166_DITHER_EN_START_BIT)
+
+#define AW88166_DITHER_EN_ENABLE (1)
+#define AW88166_DITHER_EN_ENABLE_VALUE \
+ (AW88166_DITHER_EN_ENABLE << AW88166_DITHER_EN_START_BIT)
+
+#define AW88166_HMUTE_START_BIT (8)
+#define AW88166_HMUTE_BITS_LEN (1)
+#define AW88166_HMUTE_MASK \
+ (~(((1<<AW88166_HMUTE_BITS_LEN)-1) << AW88166_HMUTE_START_BIT))
+
+#define AW88166_HMUTE_DISABLE (0)
+#define AW88166_HMUTE_DISABLE_VALUE \
+ (AW88166_HMUTE_DISABLE << AW88166_HMUTE_START_BIT)
+
+#define AW88166_HMUTE_ENABLE (1)
+#define AW88166_HMUTE_ENABLE_VALUE \
+ (AW88166_HMUTE_ENABLE << AW88166_HMUTE_START_BIT)
+
+#define AW88166_EF_DBMD_START_BIT (2)
+#define AW88166_EF_DBMD_BITS_LEN (1)
+#define AW88166_EF_DBMD_MASK \
+ (~(((1<<AW88166_EF_DBMD_BITS_LEN)-1) << AW88166_EF_DBMD_START_BIT))
+
+#define AW88166_EF_DBMD_OR (1)
+#define AW88166_EF_DBMD_OR_VALUE \
+ (AW88166_EF_DBMD_OR << AW88166_EF_DBMD_START_BIT)
+
+#define AW88166_CLKI_START_BIT (4)
+#define AW88166_NOCLKI_START_BIT (5)
+#define AW88166_PLLI_START_BIT (0)
+#define AW88166_PLLI_INT_VALUE (1)
+#define AW88166_PLLI_INT_INTERRUPT \
+ (AW88166_PLLI_INT_VALUE << AW88166_PLLI_START_BIT)
+
+#define AW88166_CLKI_INT_VALUE (1)
+#define AW88166_CLKI_INT_INTERRUPT \
+ (AW88166_CLKI_INT_VALUE << AW88166_CLKI_START_BIT)
+
+#define AW88166_NOCLKI_INT_VALUE (1)
+#define AW88166_NOCLKI_INT_INTERRUPT \
+ (AW88166_NOCLKI_INT_VALUE << AW88166_NOCLKI_START_BIT)
+
+#define AW88166_BIT_SYSINT_CHECK \
+ (AW88166_PLLI_INT_INTERRUPT | \
+ AW88166_CLKI_INT_INTERRUPT | \
+ AW88166_NOCLKI_INT_INTERRUPT)
+
+#define AW88166_CRC_CHECK_START_BIT (12)
+#define AW88166_CRC_CHECK_BITS_LEN (3)
+#define AW88166_CRC_CHECK_BITS_MASK \
+ (~(((1<<AW88166_CRC_CHECK_BITS_LEN)-1) << AW88166_CRC_CHECK_START_BIT))
+
+#define AW88166_RCV_MODE_RECEIVER (1)
+#define AW88166_RCV_MODE_RECEIVER_VALUE \
+ (AW88166_RCV_MODE_RECEIVER << AW88166_RCV_MODE_START_BIT)
+
+#define AW88166_AMPPD_START_BIT (1)
+#define AW88166_AMPPD_BITS_LEN (1)
+#define AW88166_AMPPD_MASK \
+ (~(((1<<AW88166_AMPPD_BITS_LEN)-1) << AW88166_AMPPD_START_BIT))
+
+#define AW88166_AMPPD_WORKING (0)
+#define AW88166_AMPPD_WORKING_VALUE \
+ (AW88166_AMPPD_WORKING << AW88166_AMPPD_START_BIT)
+
+#define AW88166_AMPPD_POWER_DOWN (1)
+#define AW88166_AMPPD_POWER_DOWN_VALUE \
+ (AW88166_AMPPD_POWER_DOWN << AW88166_AMPPD_START_BIT)
+
+#define AW88166_RAM_CG_BYP_START_BIT (0)
+#define AW88166_RAM_CG_BYP_BITS_LEN (1)
+#define AW88166_RAM_CG_BYP_MASK \
+ (~(((1<<AW88166_RAM_CG_BYP_BITS_LEN)-1) << AW88166_RAM_CG_BYP_START_BIT))
+
+#define AW88166_RAM_CG_BYP_WORK (0)
+#define AW88166_RAM_CG_BYP_WORK_VALUE \
+ (AW88166_RAM_CG_BYP_WORK << AW88166_RAM_CG_BYP_START_BIT)
+
+#define AW88166_RAM_CG_BYP_BYPASS (1)
+#define AW88166_RAM_CG_BYP_BYPASS_VALUE \
+ (AW88166_RAM_CG_BYP_BYPASS << AW88166_RAM_CG_BYP_START_BIT)
+
+#define AW88166_CRC_END_ADDR_START_BIT (0)
+#define AW88166_CRC_END_ADDR_BITS_LEN (12)
+#define AW88166_CRC_END_ADDR_MASK \
+ (~(((1<<AW88166_CRC_END_ADDR_BITS_LEN)-1) << AW88166_CRC_END_ADDR_START_BIT))
+
+#define AW88166_CRC_CODE_EN_START_BIT (13)
+#define AW88166_CRC_CODE_EN_BITS_LEN (1)
+#define AW88166_CRC_CODE_EN_MASK \
+ (~(((1<<AW88166_CRC_CODE_EN_BITS_LEN)-1) << AW88166_CRC_CODE_EN_START_BIT))
+
+#define AW88166_CRC_CODE_EN_DISABLE (0)
+#define AW88166_CRC_CODE_EN_DISABLE_VALUE \
+ (AW88166_CRC_CODE_EN_DISABLE << AW88166_CRC_CODE_EN_START_BIT)
+
+#define AW88166_CRC_CODE_EN_ENABLE (1)
+#define AW88166_CRC_CODE_EN_ENABLE_VALUE \
+ (AW88166_CRC_CODE_EN_ENABLE << AW88166_CRC_CODE_EN_START_BIT)
+
+#define AW88166_CRC_CFG_EN_START_BIT (12)
+#define AW88166_CRC_CFG_EN_BITS_LEN (1)
+#define AW88166_CRC_CFG_EN_MASK \
+ (~(((1<<AW88166_CRC_CFG_EN_BITS_LEN)-1) << AW88166_CRC_CFG_EN_START_BIT))
+
+#define AW88166_CRC_CFG_EN_DISABLE (0)
+#define AW88166_CRC_CFG_EN_DISABLE_VALUE \
+ (AW88166_CRC_CFG_EN_DISABLE << AW88166_CRC_CFG_EN_START_BIT)
+
+#define AW88166_CRC_CFG_EN_ENABLE (1)
+#define AW88166_CRC_CFG_EN_ENABLE_VALUE \
+ (AW88166_CRC_CFG_EN_ENABLE << AW88166_CRC_CFG_EN_START_BIT)
+
+#define AW88166_OCDS_START_BIT (3)
+#define AW88166_OCDS_OC (1)
+#define AW88166_OCDS_OC_VALUE \
+ (AW88166_OCDS_OC << AW88166_OCDS_START_BIT)
+
+#define AW88166_NOCLKS_START_BIT (5)
+#define AW88166_NOCLKS_NO_CLOCK (1)
+#define AW88166_NOCLKS_NO_CLOCK_VALUE \
+ (AW88166_NOCLKS_NO_CLOCK << AW88166_NOCLKS_START_BIT)
+
+#define AW88166_SWS_START_BIT (8)
+#define AW88166_SWS_SWITCHING (1)
+#define AW88166_SWS_SWITCHING_VALUE \
+ (AW88166_SWS_SWITCHING << AW88166_SWS_START_BIT)
+
+#define AW88166_BSTS_START_BIT (9)
+#define AW88166_BSTS_FINISHED (1)
+#define AW88166_BSTS_FINISHED_VALUE \
+ (AW88166_BSTS_FINISHED << AW88166_BSTS_START_BIT)
+
+#define AW88166_UVLS_START_BIT (14)
+#define AW88166_UVLS_NORMAL (0)
+#define AW88166_UVLS_NORMAL_VALUE \
+ (AW88166_UVLS_NORMAL << AW88166_UVLS_START_BIT)
+
+#define AW88166_BSTOCS_START_BIT (11)
+#define AW88166_BSTOCS_OVER_CURRENT (1)
+#define AW88166_BSTOCS_OVER_CURRENT_VALUE \
+ (AW88166_BSTOCS_OVER_CURRENT << AW88166_BSTOCS_START_BIT)
+
+#define AW88166_OTHS_START_BIT (1)
+#define AW88166_OTHS_OT (1)
+#define AW88166_OTHS_OT_VALUE \
+ (AW88166_OTHS_OT << AW88166_OTHS_START_BIT)
+
+#define AW88166_PLLS_START_BIT (0)
+#define AW88166_PLLS_LOCKED (1)
+#define AW88166_PLLS_LOCKED_VALUE \
+ (AW88166_PLLS_LOCKED << AW88166_PLLS_START_BIT)
+
+#define AW88166_CLKS_START_BIT (4)
+#define AW88166_CLKS_STABLE (1)
+#define AW88166_CLKS_STABLE_VALUE \
+ (AW88166_CLKS_STABLE << AW88166_CLKS_START_BIT)
+
+#define AW88166_BIT_PLL_CHECK \
+ (AW88166_CLKS_STABLE_VALUE | \
+ AW88166_PLLS_LOCKED_VALUE)
+
+#define AW88166_BIT_SYSST_CHECK_MASK \
+ (~(AW88166_UVLS_NORMAL_VALUE | \
+ AW88166_BSTOCS_OVER_CURRENT_VALUE | \
+ AW88166_BSTS_FINISHED_VALUE | \
+ AW88166_SWS_SWITCHING_VALUE | \
+ AW88166_NOCLKS_NO_CLOCK_VALUE | \
+ AW88166_CLKS_STABLE_VALUE | \
+ AW88166_OCDS_OC_VALUE | \
+ AW88166_OTHS_OT_VALUE | \
+ AW88166_PLLS_LOCKED_VALUE))
+
+#define AW88166_BIT_SYSST_NOSWS_CHECK \
+ (AW88166_BSTS_FINISHED_VALUE | \
+ AW88166_CLKS_STABLE_VALUE | \
+ AW88166_PLLS_LOCKED_VALUE)
+
+#define AW88166_BIT_SYSST_SWS_CHECK \
+ (AW88166_BSTS_FINISHED_VALUE | \
+ AW88166_CLKS_STABLE_VALUE | \
+ AW88166_PLLS_LOCKED_VALUE | \
+ AW88166_SWS_SWITCHING_VALUE)
+
+#define AW88166_CCO_MUX_START_BIT (14)
+#define AW88166_CCO_MUX_BITS_LEN (1)
+#define AW88166_CCO_MUX_MASK \
+ (~(((1<<AW88166_CCO_MUX_BITS_LEN)-1) << AW88166_CCO_MUX_START_BIT))
+
+#define AW88166_CCO_MUX_DIVIDED (0)
+#define AW88166_CCO_MUX_DIVIDED_VALUE \
+ (AW88166_CCO_MUX_DIVIDED << AW88166_CCO_MUX_START_BIT)
+
+#define AW88166_CCO_MUX_BYPASS (1)
+#define AW88166_CCO_MUX_BYPASS_VALUE \
+ (AW88166_CCO_MUX_BYPASS << AW88166_CCO_MUX_START_BIT)
+
+#define AW88166_NOISE_GATE_EN_START_BIT (13)
+#define AW88166_NOISE_GATE_EN_BITS_LEN (1)
+#define AW88166_NOISE_GATE_EN_MASK \
+ (~(((1<<AW88166_NOISE_GATE_EN_BITS_LEN)-1) << AW88166_NOISE_GATE_EN_START_BIT))
+
+#define AW88166_WDT_CNT_START_BIT (0)
+#define AW88166_WDT_CNT_BITS_LEN (8)
+#define AW88166_WDT_CNT_MASK \
+ (~(((1<<AW88166_WDT_CNT_BITS_LEN)-1) << AW88166_WDT_CNT_START_BIT))
+
+#define AW88166_EF_ISN_GESLP_START_BIT (0)
+#define AW88166_EF_ISN_GESLP_BITS_LEN (10)
+#define AW88166_EF_ISN_GESLP_MASK \
+ (~(((1<<AW88166_EF_ISN_GESLP_BITS_LEN)-1) << AW88166_EF_ISN_GESLP_START_BIT))
+#define AW88166_EF_ISN_GESLP_SHIFT (0)
+
+#define AW88166_EF_VSN_GESLP_START_BIT (10)
+#define AW88166_EF_VSN_GESLP_BITS_LEN (6)
+#define AW88166_EF_VSN_GESLP_MASK \
+ (~(((1<<AW88166_EF_VSN_GESLP_BITS_LEN)-1) << AW88166_EF_VSN_GESLP_START_BIT))
+#define AW88166_EF_VSN_GESLP_SHIFT (10)
+
+#define AW88166_EF_VSN_H3BITS_START_BIT (13)
+#define AW88166_EF_VSN_H3BITS_BITS_LEN (3)
+#define AW88166_EF_VSN_H3BITS_MASK \
+ (~(((1<<AW88166_EF_VSN_H3BITS_BITS_LEN)-1) << AW88166_EF_VSN_H3BITS_START_BIT))
+#define AW88166_EF_VSN_H3BITS_SHIFT (10)
+#define AW88166_EF_VSN_H3BITS_SIGN_MASK (0x7)
+
+#define AW88166_EF_ISN_H5BITS_START_BIT (8)
+#define AW88166_EF_ISN_H5BITS_BITS_LEN (5)
+#define AW88166_EF_ISN_H5BITS_MASK \
+ (~(((1<<AW88166_EF_ISN_H5BITS_BITS_LEN)-1) << AW88166_EF_ISN_H5BITS_START_BIT))
+#define AW88166_EF_ISN_H5BITS_SIGN_MASK (0x1F)
+#define AW88166_EF_ISN_H5BITS_SHIFT (3)
+
+#define AW88166_VSCAL_FACTOR (65300)
+#define AW88166_ISCAL_FACTOR (34667)
+#define AW88166_CABL_BASE_VALUE (1000)
+#define AW88166_VCALK_SIGN_MASK (~(1 << 5))
+#define AW88166_VCALK_NEG_MASK (0xFFE0)
+#define AW88166_ICALK_SIGN_MASK (~(1 << 9))
+#define AW88166_ICALK_NEG_MASK (0xFE00)
+#define AW88166_ICABLK_FACTOR (1)
+#define AW88166_VCABLK_FACTOR (2)
+#define AW88166_VCALB_ADJ_FACTOR (12)
+#define AW88166_VCALB_ACCURACY (1 << 12)
+#define AW88166_DSP_RE_SHIFT (12)
+#define AW88166_CALI_RE_MAX (15000)
+#define AW88166_CALI_RE_MIN (4000)
+#define AW88166_VOLUME_STEP_DB (64)
+#define AW88166_VOL_DEFAULT_VALUE (0)
+#define AW88166_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift))
+#define AW88166_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000))
+
+#define AW88166_DSP_ODD_NUM_BIT_TEST (0x5555)
+#define AW88166_DSP_ROM_CHECK_DATA (0xFF99)
+
+#define AW88166_DEV_DEFAULT_CH (0)
+#define AW88166_DEV_DSP_CHECK_MAX (5)
+#define AW88166_MAX_RAM_WRITE_BYTE_SIZE (128)
+#define AW_FW_ADDR_LEN (4)
+#define AW88166_CRC_CHECK_PASS_VAL (0x4)
+#define AW88166_CRC_CFG_BASE_ADDR (0xD80)
+#define AW88166_CRC_FW_BASE_ADDR (0x4C0)
+#define AW88166_DEV_SYSST_CHECK_MAX (10)
+#define AW88166_START_RETRIES (5)
+#define AW88166_START_WORK_DELAY_MS (0)
+#define FADE_TIME_MAX 100000
+#define FADE_TIME_MIN 0
+#define AW88166_CHIP_ID (0x2066)
+#define AW88166_I2C_NAME "aw88166"
+#define AW88166_ACF_FILE "aw88166_acf.bin"
+
+#define AW88166_RATES (SNDRV_PCM_RATE_8000_48000 | \
+ SNDRV_PCM_RATE_96000)
+#define AW88166_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AW88166_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \
+{ \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = xname, \
+ .info = profile_info, \
+ .get = profile_get, \
+ .put = profile_set, \
+}
+
+enum {
+ AW_EF_AND_CHECK = 0,
+ AW_EF_OR_CHECK,
+};
+
+enum {
+ AW88166_DSP_FW_UPDATE_OFF = 0,
+ AW88166_DSP_FW_UPDATE_ON = 1,
+};
+
+enum {
+ AW88166_FORCE_UPDATE_OFF = 0,
+ AW88166_FORCE_UPDATE_ON = 1,
+};
+
+enum {
+ AW88166_1000_US = 1000,
+ AW88166_2000_US = 2000,
+ AW88166_3000_US = 3000,
+ AW88166_4000_US = 4000,
+};
+
+enum AW88166_DEV_STATUS {
+ AW88166_DEV_PW_OFF = 0,
+ AW88166_DEV_PW_ON,
+};
+
+enum AW88166_DEV_FW_STATUS {
+ AW88166_DEV_FW_FAILED = 0,
+ AW88166_DEV_FW_OK,
+};
+
+enum AW88166_DEV_MEMCLK {
+ AW88166_DEV_MEMCLK_OSC = 0,
+ AW88166_DEV_MEMCLK_PLL = 1,
+};
+
+enum AW88166_DEV_DSP_CFG {
+ AW88166_DEV_DSP_WORK = 0,
+ AW88166_DEV_DSP_BYPASS = 1,
+};
+
+enum {
+ AW88166_DSP_16_DATA = 0,
+ AW88166_DSP_32_DATA = 1,
+};
+
+enum {
+ AW88166_SYNC_START = 0,
+ AW88166_ASYNC_START,
+};
+
+enum {
+ AW88166_RECORD_SEC_DATA = 0,
+ AW88166_RECOVERY_SEC_DATA = 1,
+};
+
+#endif
diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c
index 6b333d1c6e94..b7ea8be0d0cb 100644
--- a/sound/soc/codecs/aw88395/aw88395_device.c
+++ b/sound/soc/codecs/aw88395/aw88395_device.c
@@ -424,7 +424,7 @@ static int aw_dev_dsp_set_crc32(struct aw_device *aw_dev)
return -EINVAL;
}
- crc_value = __crc32c_le(0xFFFFFFFF, crc_dsp_cfg->data, crc_data_len) ^ 0xFFFFFFFF;
+ crc_value = crc32c(0xFFFFFFFF, crc_dsp_cfg->data, crc_data_len) ^ 0xFFFFFFFF;
return aw_dev_dsp_write(aw_dev, AW88395_DSP_REG_CRC_ADDR, crc_value,
AW88395_DSP_32_DATA);
diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 04304a7ad915..3eb862643b53 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -11,11 +11,21 @@
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/mfd/motorola-cpcap.h>
#include <sound/core.h>
+#include <linux/input.h>
+#include <sound/jack.h>
#include <sound/soc.h>
#include <sound/tlv.h>
+/* Register 8 - CPCAP_REG_INTS1 --- Interrupt Sense 1 */
+#define CPCAP_BIT_HS_S 9 /* Headset */
+#define CPCAP_BIT_MB2_S 10 /* Mic Bias2 */
+
+/* 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
@@ -260,6 +270,10 @@ struct cpcap_audio {
int codec_clk_id;
int codec_freq;
int codec_format;
+ struct regulator *vaudio;
+ int hsirq;
+ int mb2irq;
+ struct snd_soc_jack jack;
};
static int cpcap_st_workaround(struct snd_soc_dapm_widget *w,
@@ -1626,17 +1640,123 @@ static int cpcap_audio_reset(struct snd_soc_component *component,
return 0;
}
+static irqreturn_t cpcap_hs_irq_thread(int irq, void *data)
+{
+ struct snd_soc_component *component = data;
+ struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cpcap->regmap;
+ int status = 0;
+ int mask = SND_JACK_HEADSET;
+ int val;
+
+ if (!regmap_test_bits(regmap, CPCAP_REG_INTS1, BIT(CPCAP_BIT_HS_S))) {
+ val = BIT(CPCAP_BIT_MB_ON2) | BIT(CPCAP_BIT_PTT_CMP_EN);
+ regmap_update_bits(regmap, CPCAP_REG_TXI, val, val);
+
+ val = BIT(CPCAP_BIT_ST_HS_CP_EN);
+ regmap_update_bits(regmap, CPCAP_REG_RXOA, val, val);
+
+ regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_NORMAL);
+
+ /* Give PTTS time to settle */
+ msleep(20);
+
+ if (!regmap_test_bits(regmap, CPCAP_REG_INTS2,
+ BIT(CPCAP_BIT_PTT_S))) {
+ /* Headphones detected. (May also be a headset with the
+ * MFB pressed.)
+ */
+ status = SND_JACK_HEADPHONE;
+ dev_info(component->dev, "HP plugged in\n");
+ } else if (regmap_test_bits(regmap, CPCAP_REG_INTS1,
+ BIT(CPCAP_BIT_MB2_S)) == 1) {
+ status = SND_JACK_HEADSET;
+ dev_info(component->dev, "HS plugged in\n");
+ } else
+ dev_info(component->dev, "Unsupported HS plugged in\n");
+ } else {
+ bool mic = cpcap->jack.status & SND_JACK_MICROPHONE;
+
+ dev_info(component->dev, "H%s disconnect\n", mic ? "S" : "P");
+ val = BIT(CPCAP_BIT_MB_ON2) | BIT(CPCAP_BIT_PTT_CMP_EN);
+ regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, val, 0);
+
+ val = BIT(CPCAP_BIT_ST_HS_CP_EN);
+ regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA, val, 0);
+
+ regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_STANDBY);
+
+ mask |= SND_JACK_BTN_0;
+ }
+
+ snd_soc_jack_report(&cpcap->jack, status, mask);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cpcap_mb2_irq_thread(int irq, void *data)
+{
+ struct snd_soc_component *component = data;
+ struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+ struct regmap *regmap = cpcap->regmap;
+ int status = 0;
+ int mb2;
+ int ptt;
+
+ if (regmap_test_bits(regmap, CPCAP_REG_INTS1, BIT(CPCAP_BIT_HS_S)) == 1)
+ return IRQ_HANDLED;
+
+ mb2 = regmap_test_bits(regmap, CPCAP_REG_INTS1, BIT(CPCAP_BIT_MB2_S));
+ ptt = regmap_test_bits(regmap, CPCAP_REG_INTS2, BIT(CPCAP_BIT_PTT_S));
+
+ /* Initial detection might have been with MFB pressed */
+ if (!(cpcap->jack.status & SND_JACK_MICROPHONE)) {
+ if (ptt == 1 && mb2 == 1) {
+ dev_info(component->dev, "MIC plugged in\n");
+ snd_soc_jack_report(&cpcap->jack, SND_JACK_MICROPHONE,
+ SND_JACK_MICROPHONE);
+ }
+
+ return IRQ_HANDLED;
+ }
+
+ if (!mb2 || !ptt)
+ status = SND_JACK_BTN_0;
+
+ snd_soc_jack_report(&cpcap->jack, status, SND_JACK_BTN_0);
+
+ return IRQ_HANDLED;
+}
+
static int cpcap_soc_probe(struct snd_soc_component *component)
{
+ struct platform_device *pdev = to_platform_device(component->dev);
+ struct snd_soc_card *card = component->card;
struct cpcap_audio *cpcap;
int err;
cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL);
if (!cpcap)
return -ENOMEM;
+
snd_soc_component_set_drvdata(component, cpcap);
cpcap->component = component;
+ cpcap->vaudio = devm_regulator_get(component->dev, "VAUDIO");
+ if (IS_ERR(cpcap->vaudio))
+ return dev_err_probe(component->dev, PTR_ERR(cpcap->vaudio),
+ "Cannot get VAUDIO regulator\n");
+
+ err = snd_soc_card_jack_new(card, "Headphones",
+ SND_JACK_HEADSET | SND_JACK_BTN_0,
+ &cpcap->jack);
+ if (err < 0) {
+ dev_err(component->dev, "Cannot create HS jack: %i\n", err);
+ return err;
+ }
+
+ snd_jack_set_key(cpcap->jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
+
cpcap->regmap = dev_get_regmap(component->dev->parent, NULL);
if (!cpcap->regmap)
return -ENODEV;
@@ -1646,17 +1766,95 @@ static int cpcap_soc_probe(struct snd_soc_component *component)
if (err)
return err;
- return cpcap_audio_reset(component, false);
+ cpcap->hsirq = platform_get_irq_byname(pdev, "hs");
+ if (cpcap->hsirq < 0)
+ return cpcap->hsirq;
+
+ err = devm_request_threaded_irq(component->dev, cpcap->hsirq, NULL,
+ cpcap_hs_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "cpcap-codec-hs",
+ component);
+ if (err) {
+ dev_warn(component->dev, "no HS irq%i: %i\n",
+ cpcap->hsirq, err);
+ return err;
+ }
+
+ cpcap->mb2irq = platform_get_irq_byname(pdev, "mb2");
+ if (cpcap->mb2irq < 0)
+ return cpcap->mb2irq;
+
+ err = devm_request_threaded_irq(component->dev, cpcap->mb2irq, NULL,
+ cpcap_mb2_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "cpcap-codec-mb2",
+ component);
+ if (err) {
+ dev_warn(component->dev, "no MB2 irq%i: %i\n",
+ cpcap->mb2irq, err);
+ return err;
+ }
+
+ err = cpcap_audio_reset(component, false);
+ if (err)
+ return err;
+
+ cpcap_hs_irq_thread(cpcap->hsirq, component);
+
+ enable_irq_wake(cpcap->hsirq);
+ enable_irq_wake(cpcap->mb2irq);
+
+ return 0;
+}
+
+static void cpcap_soc_remove(struct snd_soc_component *component)
+{
+ struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+
+ disable_irq_wake(cpcap->hsirq);
+ disable_irq_wake(cpcap->mb2irq);
+}
+
+static int cpcap_set_bias_level(struct snd_soc_component *component,
+ enum snd_soc_bias_level level)
+{
+ struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+
+ /* VAIDIO should be kept in normal mode in order MIC/PTT to work */
+ if (cpcap->jack.status & SND_JACK_MICROPHONE)
+ return 0;
+
+ switch (level) {
+ case SND_SOC_BIAS_OFF:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_NORMAL);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_STANDBY);
+ break;
+ case SND_SOC_BIAS_ON:
+ break;
+ }
+
+ return 0;
}
static const struct snd_soc_component_driver soc_codec_dev_cpcap = {
.probe = cpcap_soc_probe,
+ .remove = cpcap_soc_remove,
.controls = cpcap_snd_controls,
.num_controls = ARRAY_SIZE(cpcap_snd_controls),
.dapm_widgets = cpcap_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(cpcap_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
+ .set_bias_level = cpcap_set_bias_level,
.idle_bias_on = 1,
.use_pmdown_time = 1,
.endianness = 1,
diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c
index 11e7b3f6d410..571222ec520c 100644
--- a/sound/soc/codecs/cros_ec_codec.c
+++ b/sound/soc/codecs/cros_ec_codec.c
@@ -21,6 +21,7 @@
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
+#include <linux/string_choices.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -657,7 +658,7 @@ static int wov_enable_put(struct snd_kcontrol *kcontrol,
(uint8_t *)&p, sizeof(p), NULL, 0);
if (ret) {
dev_err(priv->dev, "failed to %s wov\n",
- enabled ? "enable" : "disable");
+ str_enable_disable(enabled));
return ret;
}
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c
index 96555263e10b..0bb4bdb3deec 100644
--- a/sound/soc/codecs/cs35l32.c
+++ b/sound/soc/codecs/cs35l32.c
@@ -153,12 +153,12 @@ static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct snd_soc_component *component = codec_dai->component;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
CS35L32_ADSP_MASTER_MASK,
CS35L32_ADSP_MASTER_MASK);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
snd_soc_component_update_bits(component, CS35L32_ADSP_CTL,
CS35L32_ADSP_MASTER_MASK, 0);
break;
@@ -504,7 +504,6 @@ static void cs35l32_i2c_remove(struct i2c_client *i2c_client)
gpiod_set_value_cansleep(cs35l32->reset_gpio, 0);
}
-#ifdef CONFIG_PM
static int cs35l32_runtime_suspend(struct device *dev)
{
struct cs35l32_private *cs35l32 = dev_get_drvdata(dev);
@@ -543,11 +542,9 @@ static int cs35l32_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops cs35l32_runtime_pm = {
- SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, NULL)
};
static const struct of_device_id cs35l32_of_match[] = {
@@ -567,7 +564,7 @@ MODULE_DEVICE_TABLE(i2c, cs35l32_id);
static struct i2c_driver cs35l32_i2c_driver = {
.driver = {
.name = "cs35l32",
- .pm = &cs35l32_runtime_pm,
+ .pm = pm_ptr(&cs35l32_runtime_pm),
.of_match_table = cs35l32_of_match,
},
.id_table = cs35l32_id,
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c
index b03aab147530..c927592f90c9 100644
--- a/sound/soc/codecs/cs35l33.c
+++ b/sound/soc/codecs/cs35l33.c
@@ -438,12 +438,12 @@ static int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct cs35l33_private *priv = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL,
CS35L33_MS_MASK, CS35L33_MS_MASK);
dev_dbg(component->dev, "Audio port in master mode\n");
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL,
CS35L33_MS_MASK, 0);
dev_dbg(component->dev, "Audio port in slave mode\n");
@@ -853,7 +853,7 @@ static const struct regmap_config cs35l33_regmap = {
.use_single_write = true,
};
-static int __maybe_unused cs35l33_runtime_resume(struct device *dev)
+static int cs35l33_runtime_resume(struct device *dev)
{
struct cs35l33_private *cs35l33 = dev_get_drvdata(dev);
int ret;
@@ -891,7 +891,7 @@ err:
return ret;
}
-static int __maybe_unused cs35l33_runtime_suspend(struct device *dev)
+static int cs35l33_runtime_suspend(struct device *dev)
{
struct cs35l33_private *cs35l33 = dev_get_drvdata(dev);
@@ -909,9 +909,7 @@ static int __maybe_unused cs35l33_runtime_suspend(struct device *dev)
}
static const struct dev_pm_ops cs35l33_pm_ops = {
- SET_RUNTIME_PM_OPS(cs35l33_runtime_suspend,
- cs35l33_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(cs35l33_runtime_suspend, cs35l33_runtime_resume, NULL)
};
static int cs35l33_get_hg_data(const struct device_node *np,
@@ -1273,7 +1271,7 @@ MODULE_DEVICE_TABLE(i2c, cs35l33_id);
static struct i2c_driver cs35l33_i2c_driver = {
.driver = {
.name = "cs35l33",
- .pm = &cs35l33_pm_ops,
+ .pm = pm_ptr(&cs35l33_pm_ops),
.of_match_table = cs35l33_of_match,
},
diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c
index 287b27476a10..a5a8075598ff 100644
--- a/sound/soc/codecs/cs35l34.c
+++ b/sound/soc/codecs/cs35l34.c
@@ -523,11 +523,11 @@ static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct cs35l34_private *priv = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
0x80, 0x80);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL,
0x80, 0x00);
break;
@@ -1116,7 +1116,7 @@ static void cs35l34_i2c_remove(struct i2c_client *client)
cs35l34->core_supplies);
}
-static int __maybe_unused cs35l34_runtime_resume(struct device *dev)
+static int cs35l34_runtime_resume(struct device *dev)
{
struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
int ret;
@@ -1149,7 +1149,7 @@ err:
return ret;
}
-static int __maybe_unused cs35l34_runtime_suspend(struct device *dev)
+static int cs35l34_runtime_suspend(struct device *dev)
{
struct cs35l34_private *cs35l34 = dev_get_drvdata(dev);
@@ -1165,9 +1165,7 @@ static int __maybe_unused cs35l34_runtime_suspend(struct device *dev)
}
static const struct dev_pm_ops cs35l34_pm_ops = {
- SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend,
- cs35l34_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(cs35l34_runtime_suspend, cs35l34_runtime_resume, NULL)
};
static const struct of_device_id cs35l34_of_match[] = {
@@ -1185,7 +1183,7 @@ MODULE_DEVICE_TABLE(i2c, cs35l34_id);
static struct i2c_driver cs35l34_i2c_driver = {
.driver = {
.name = "cs35l34",
- .pm = &cs35l34_pm_ops,
+ .pm = pm_ptr(&cs35l34_pm_ops),
.of_match_table = cs35l34_of_match,
},
diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c
index a6db44520c06..f9b6bf7bea9c 100644
--- a/sound/soc/codecs/cs35l41-spi.c
+++ b/sound/soc/codecs/cs35l41-spi.c
@@ -32,13 +32,16 @@ static int cs35l41_spi_probe(struct spi_device *spi)
const struct regmap_config *regmap_config = &cs35l41_regmap_spi;
struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev);
struct cs35l41_private *cs35l41;
+ int ret;
cs35l41 = devm_kzalloc(&spi->dev, sizeof(struct cs35l41_private), GFP_KERNEL);
if (!cs35l41)
return -ENOMEM;
spi->max_speed_hz = CS35L41_SPI_MAX_FREQ;
- spi_setup(spi);
+ ret = spi_setup(spi);
+ if (ret < 0)
+ return ret;
spi_set_drvdata(spi, cs35l41);
cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config);
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 07a5cab35fe1..ff4134bee858 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -1148,21 +1148,31 @@ err_dsp:
return ret;
}
+#ifdef CONFIG_ACPI
static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41)
{
- acpi_handle handle = ACPI_HANDLE(cs35l41->dev);
+ struct acpi_device *adev = ACPI_COMPANION(cs35l41->dev);
+ acpi_handle handle = acpi_device_handle(adev);
+ const char *hid;
const char *sub;
- /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
- if (!handle)
+ /* If there is no acpi_device, there is no ACPI for this system, return 0 */
+ if (!adev)
return 0;
sub = acpi_get_subsystem_id(handle);
if (IS_ERR(sub)) {
- /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */
- if (PTR_ERR(sub) == -ENODATA)
- return 0;
- else
+ /* If no _SUB, fallback to _HID, otherwise fail */
+ if (PTR_ERR(sub) == -ENODATA) {
+ hid = acpi_device_hid(adev);
+ /* If dummy hid, return 0 and fallback to legacy firmware path */
+ if (!strcmp(hid, "device"))
+ return 0;
+ sub = kstrdup(hid, GFP_KERNEL);
+ if (!sub)
+ sub = ERR_PTR(-ENOMEM);
+
+ } else
return PTR_ERR(sub);
}
@@ -1171,6 +1181,12 @@ static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41)
return 0;
}
+#else
+static int cs35l41_acpi_get_name(struct cs35l41_private *cs35l41)
+{
+ return 0;
+}
+#endif /* CONFIG_ACPI */
int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg)
{
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index e0ed4fc11155..e28bfefa72f3 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -10,6 +10,7 @@
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
#include <linux/types.h>
#include <sound/cs-amp-lib.h>
@@ -303,6 +304,79 @@ void cs35l56_wait_min_reset_pulse(void)
}
EXPORT_SYMBOL_NS_GPL(cs35l56_wait_min_reset_pulse, "SND_SOC_CS35L56_SHARED");
+static const struct {
+ u32 addr;
+ u32 value;
+} cs35l56_spi_system_reset_stages[] = {
+ { .addr = CS35L56_DSP_VIRTUAL1_MBOX_1, .value = CS35L56_MBOX_CMD_SYSTEM_RESET },
+ /* The next write is necessary to delimit the soft reset */
+ { .addr = CS35L56_DSP_MBOX_1_RAW, .value = CS35L56_MBOX_CMD_PING },
+};
+
+static void cs35l56_spi_issue_bus_locked_reset(struct cs35l56_base *cs35l56_base,
+ struct spi_device *spi)
+{
+ struct cs35l56_spi_payload *buf = cs35l56_base->spi_payload_buf;
+ struct spi_transfer t = {
+ .tx_buf = buf,
+ .len = sizeof(*buf),
+ };
+ struct spi_message m;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(cs35l56_spi_system_reset_stages); i++) {
+ buf->addr = cpu_to_be32(cs35l56_spi_system_reset_stages[i].addr);
+ buf->value = cpu_to_be32(cs35l56_spi_system_reset_stages[i].value);
+ spi_message_init_with_transfers(&m, &t, 1);
+ ret = spi_sync_locked(spi, &m);
+ if (ret)
+ dev_warn(cs35l56_base->dev, "spi_sync failed: %d\n", ret);
+
+ usleep_range(CS35L56_SPI_RESET_TO_PORT_READY_US,
+ 2 * CS35L56_SPI_RESET_TO_PORT_READY_US);
+ }
+}
+
+static void cs35l56_spi_system_reset(struct cs35l56_base *cs35l56_base)
+{
+ struct spi_device *spi = to_spi_device(cs35l56_base->dev);
+ unsigned int val;
+ int read_ret, ret;
+
+ /*
+ * There must not be any other SPI bus activity while the amp is
+ * soft-resetting.
+ */
+ ret = spi_bus_lock(spi->controller);
+ if (ret) {
+ dev_warn(cs35l56_base->dev, "spi_bus_lock failed: %d\n", ret);
+ return;
+ }
+
+ cs35l56_spi_issue_bus_locked_reset(cs35l56_base, spi);
+ spi_bus_unlock(spi->controller);
+
+ /*
+ * Check firmware boot by testing for a response in MBOX_2.
+ * HALO_STATE cannot be trusted yet because the reset sequence
+ * can leave it with stale state. But MBOX is reset.
+ * The regmap must remain in cache-only until the chip has
+ * booted, so use a bypassed read.
+ */
+ ret = read_poll_timeout(regmap_read_bypassed, read_ret,
+ (val > 0) && (val < 0xffffffff),
+ CS35L56_HALO_STATE_POLL_US,
+ CS35L56_HALO_STATE_TIMEOUT_US,
+ false,
+ cs35l56_base->regmap,
+ CS35L56_DSP_VIRTUAL1_MBOX_2,
+ &val);
+ if (ret) {
+ dev_err(cs35l56_base->dev, "SPI reboot timed out(%d): MBOX2=%#x\n",
+ read_ret, val);
+ }
+}
+
static const struct reg_sequence cs35l56_system_reset_seq[] = {
REG_SEQ0(CS35L56_DSP1_HALO_STATE, 0),
REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
@@ -315,6 +389,12 @@ void cs35l56_system_reset(struct cs35l56_base *cs35l56_base, bool is_soundwire)
* accesses other than the controlled system reset sequence below.
*/
regcache_cache_only(cs35l56_base->regmap, true);
+
+ if (cs35l56_is_spi(cs35l56_base)) {
+ cs35l56_spi_system_reset(cs35l56_base);
+ return;
+ }
+
regmap_multi_reg_write_bypassed(cs35l56_base->regmap,
cs35l56_system_reset_seq,
ARRAY_SIZE(cs35l56_system_reset_seq));
diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
index c101134e8532..ca6c03a8766d 100644
--- a/sound/soc/codecs/cs35l56-spi.c
+++ b/sound/soc/codecs/cs35l56-spi.c
@@ -33,6 +33,9 @@ static int cs35l56_spi_probe(struct spi_device *spi)
cs35l56->base.dev = &spi->dev;
cs35l56->base.can_hibernate = true;
+ ret = cs35l56_init_config_for_spi(&cs35l56->base, spi);
+ if (ret)
+ return ret;
ret = cs35l56_common_probe(cs35l56);
if (ret != 0)
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index ae045c88c48d..b3158a84b87a 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -646,6 +646,12 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
.rates = CS35L56_RATES,
.formats = CS35L56_RX_FORMATS,
},
+ .symmetric_rate = 1,
+ .ops = &cs35l56_sdw_dai_ops,
+ },
+ {
+ .name = "cs35l56-sdw1c",
+ .id = 2,
.capture = {
.stream_name = "SDW1 Capture",
.channels_min = 1,
@@ -655,7 +661,7 @@ static struct snd_soc_dai_driver cs35l56_dai[] = {
},
.symmetric_rate = 1,
.ops = &cs35l56_sdw_dai_ops,
- }
+ },
};
static int cs35l56_write_cal(struct cs35l56_private *cs35l56)
@@ -1435,7 +1441,6 @@ void cs35l56_remove(struct cs35l56_private *cs35l56)
if (cs35l56->base.irq)
devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base);
- flush_workqueue(cs35l56->dsp_wq);
destroy_workqueue(cs35l56->dsp_wq);
pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c
index 69287ba7e955..dda7f5b4f2fb 100644
--- a/sound/soc/codecs/cs4234.c
+++ b/sound/soc/codecs/cs4234.c
@@ -307,9 +307,9 @@ static int cs4234_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int format
}
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
if (cs4234->format == SND_SOC_DAIFMT_DSP_A) {
dev_err(component->dev, "Unsupported DSP A format in master mode\n");
return -EINVAL;
@@ -860,7 +860,7 @@ static void cs4234_i2c_remove(struct i2c_client *i2c_client)
cs4234_shutdown(cs4234);
}
-static int __maybe_unused cs4234_runtime_resume(struct device *dev)
+static int cs4234_runtime_resume(struct device *dev)
{
struct cs4234 *cs4234 = dev_get_drvdata(dev);
int ret;
@@ -881,7 +881,7 @@ static int __maybe_unused cs4234_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused cs4234_runtime_suspend(struct device *dev)
+static int cs4234_runtime_suspend(struct device *dev)
{
struct cs4234 *cs4234 = dev_get_drvdata(dev);
@@ -891,7 +891,7 @@ static int __maybe_unused cs4234_runtime_suspend(struct device *dev)
}
static const struct dev_pm_ops cs4234_pm = {
- SET_RUNTIME_PM_OPS(cs4234_runtime_suspend, cs4234_runtime_resume, NULL)
+ RUNTIME_PM_OPS(cs4234_runtime_suspend, cs4234_runtime_resume, NULL)
};
static const struct of_device_id cs4234_of_match[] = {
@@ -903,7 +903,7 @@ MODULE_DEVICE_TABLE(of, cs4234_of_match);
static struct i2c_driver cs4234_i2c_driver = {
.driver = {
.name = "cs4234",
- .pm = &cs4234_pm,
+ .pm = pm_ptr(&cs4234_pm),
.of_match_table = cs4234_of_match,
},
.probe = cs4234_i2c_probe,
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 78ffb7fa7fc5..3f759c13d6d1 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -344,12 +344,12 @@ static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u8 iface = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
snd_soc_component_update_bits(component, CS4265_ADC_CTL,
CS4265_ADC_MASTER,
CS4265_ADC_MASTER);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
snd_soc_component_update_bits(component, CS4265_ADC_CTL,
CS4265_ADC_MASTER,
0);
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 67e92bfecb56..9f9dc8b017a3 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -287,10 +287,10 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
cs4270->slave_mode = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
cs4270->slave_mode = 0;
break;
default:
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index e864188ae5eb..6a3cca3d26c7 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -209,10 +209,10 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
int ret;
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
cs4271->master = false;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
cs4271->master = true;
val |= CS4271_MODE1_MASTER;
break;
diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c
index 8a1d5c7a61d7..98b6718ccabf 100644
--- a/sound/soc/codecs/cs42l42-i2c.c
+++ b/sound/soc/codecs/cs42l42-i2c.c
@@ -48,7 +48,7 @@ static void cs42l42_i2c_remove(struct i2c_client *i2c_client)
cs42l42_common_remove(cs42l42);
}
-static int __maybe_unused cs42l42_i2c_resume(struct device *dev)
+static int cs42l42_i2c_resume(struct device *dev)
{
int ret;
@@ -62,7 +62,7 @@ static int __maybe_unused cs42l42_i2c_resume(struct device *dev)
}
static const struct dev_pm_ops cs42l42_i2c_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume)
+ SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume)
};
static const struct of_device_id __maybe_unused cs42l42_of_match[] = {
@@ -87,7 +87,7 @@ MODULE_DEVICE_TABLE(i2c, cs42l42_id);
static struct i2c_driver cs42l42_i2c_driver = {
.driver = {
.name = "cs42l42",
- .pm = &cs42l42_i2c_pm_ops,
+ .pm = pm_ptr(&cs42l42_i2c_pm_ops),
.of_match_table = of_match_ptr(cs42l42_of_match),
.acpi_match_table = ACPI_PTR(cs42l42_acpi_match),
},
diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c
index ae1401b250a3..f837c7eff10b 100644
--- a/sound/soc/codecs/cs42l42-sdw.c
+++ b/sound/soc/codecs/cs42l42-sdw.c
@@ -411,7 +411,7 @@ static const struct sdw_slave_ops cs42l42_sdw_ops = {
.port_prep = cs42l42_sdw_port_prep,
};
-static int __maybe_unused cs42l42_sdw_runtime_suspend(struct device *dev)
+static int cs42l42_sdw_runtime_suspend(struct device *dev)
{
struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
@@ -426,11 +426,11 @@ static int __maybe_unused cs42l42_sdw_runtime_suspend(struct device *dev)
return 0;
}
-static const struct reg_sequence __maybe_unused cs42l42_soft_reboot_seq[] = {
+static const struct reg_sequence cs42l42_soft_reboot_seq[] = {
REG_SEQ0(CS42L42_SOFT_RESET_REBOOT, 0x1e),
};
-static int __maybe_unused cs42l42_sdw_handle_unattach(struct cs42l42_private *cs42l42)
+static int cs42l42_sdw_handle_unattach(struct cs42l42_private *cs42l42)
{
struct sdw_slave *peripheral = cs42l42->sdw_peripheral;
@@ -460,7 +460,7 @@ static int __maybe_unused cs42l42_sdw_handle_unattach(struct cs42l42_private *cs
return 0;
}
-static int __maybe_unused cs42l42_sdw_runtime_resume(struct device *dev)
+static int cs42l42_sdw_runtime_resume(struct device *dev)
{
static const unsigned int ts_dbnce_ms[] = { 0, 125, 250, 500, 750, 1000, 1250, 1500};
struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
@@ -491,7 +491,7 @@ static int __maybe_unused cs42l42_sdw_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused cs42l42_sdw_resume(struct device *dev)
+static int cs42l42_sdw_resume(struct device *dev)
{
struct cs42l42_private *cs42l42 = dev_get_drvdata(dev);
int ret;
@@ -596,8 +596,8 @@ static int cs42l42_sdw_remove(struct sdw_slave *peripheral)
}
static const struct dev_pm_ops cs42l42_sdw_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_sdw_resume)
- SET_RUNTIME_PM_OPS(cs42l42_sdw_runtime_suspend, cs42l42_sdw_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_sdw_resume)
+ RUNTIME_PM_OPS(cs42l42_sdw_runtime_suspend, cs42l42_sdw_runtime_resume, NULL)
};
static const struct sdw_device_id cs42l42_sdw_id[] = {
@@ -609,7 +609,7 @@ MODULE_DEVICE_TABLE(sdw, cs42l42_sdw_id);
static struct sdw_driver cs42l42_sdw_driver = {
.driver = {
.name = "cs42l42-sdw",
- .pm = &cs42l42_sdw_pm,
+ .pm = pm_ptr(&cs42l42_sdw_pm),
},
.probe = cs42l42_sdw_probe,
.remove = cs42l42_sdw_remove,
diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 501c951cc327..56668c392063 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -830,11 +830,11 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u32 asp_cfg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
asp_cfg_val |= CS42L42_ASP_MASTER_MODE <<
CS42L42_ASP_MODE_SHIFT;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
asp_cfg_val |= CS42L42_ASP_SLAVE_MODE <<
CS42L42_ASP_MODE_SHIFT;
break;
diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
index d9ab003e166b..ac19a572fe70 100644
--- a/sound/soc/codecs/cs42l43-jack.c
+++ b/sound/soc/codecs/cs42l43-jack.c
@@ -167,7 +167,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
autocontrol |= 0x3 << CS42L43_JACKDET_MODE_SHIFT;
ret = cs42l43_find_index(priv, "cirrus,tip-fall-db-ms", 500,
- NULL, cs42l43_accdet_db_ms,
+ &priv->tip_fall_db_ms, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
goto error;
@@ -175,7 +175,7 @@ int cs42l43_set_jack(struct snd_soc_component *component,
tip_deb |= ret << CS42L43_TIPSENSE_FALLING_DB_TIME_SHIFT;
ret = cs42l43_find_index(priv, "cirrus,tip-rise-db-ms", 500,
- NULL, cs42l43_accdet_db_ms,
+ &priv->tip_rise_db_ms, cs42l43_accdet_db_ms,
ARRAY_SIZE(cs42l43_accdet_db_ms));
if (ret < 0)
goto error;
@@ -764,6 +764,8 @@ void cs42l43_tip_sense_work(struct work_struct *work)
error:
mutex_unlock(&priv->jack_lock);
+ priv->suspend_jack_debounce = false;
+
pm_runtime_mark_last_busy(priv->dev);
pm_runtime_put_autosuspend(priv->dev);
}
@@ -771,14 +773,19 @@ error:
irqreturn_t cs42l43_tip_sense(int irq, void *data)
{
struct cs42l43_codec *priv = data;
+ unsigned int db_delay = priv->tip_debounce_ms;
cancel_delayed_work(&priv->bias_sense_timeout);
cancel_delayed_work(&priv->tip_sense_work);
cancel_delayed_work(&priv->button_press_work);
cancel_work(&priv->button_release_work);
+ // Ensure delay after suspend is long enough to avoid false detection
+ if (priv->suspend_jack_debounce)
+ db_delay += priv->tip_fall_db_ms + priv->tip_rise_db_ms;
+
queue_delayed_work(system_long_wq, &priv->tip_sense_work,
- msecs_to_jiffies(priv->tip_debounce_ms));
+ msecs_to_jiffies(db_delay));
return IRQ_HANDLED;
}
diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c
index 83c21c17fb80..ea84ac64c775 100644
--- a/sound/soc/codecs/cs42l43.c
+++ b/sound/soc/codecs/cs42l43.c
@@ -12,7 +12,7 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
-#include <linux/find.h>
+#include <linux/bitmap.h>
#include <linux/gcd.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
@@ -1146,7 +1146,7 @@ static const struct snd_kcontrol_new cs42l43_controls[] = {
SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L43_ADC_B_CTRL1, CS42L43_ADC_B_CTRL2,
CS42L43_ADC_PGA_GAIN_SHIFT,
- 0xF, 5, cs42l43_adc_tlv),
+ 0xF, 4, cs42l43_adc_tlv),
SOC_DOUBLE("PDM1 Invert Switch", CS42L43_DMIC_PDM_CTRL,
CS42L43_PDM1L_INV_SHIFT, CS42L43_PDM1R_INV_SHIFT, 1, 0),
@@ -2402,9 +2402,22 @@ static int cs42l43_codec_runtime_resume(struct device *dev)
return 0;
}
+static int cs42l43_codec_runtime_force_suspend(struct device *dev)
+{
+ struct cs42l43_codec *priv = dev_get_drvdata(dev);
+
+ dev_dbg(priv->dev, "Runtime suspend\n");
+
+ priv->suspend_jack_debounce = true;
+
+ pm_runtime_force_suspend(dev);
+
+ return 0;
+}
+
static const struct dev_pm_ops cs42l43_codec_pm_ops = {
RUNTIME_PM_OPS(NULL, cs42l43_codec_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ SYSTEM_SLEEP_PM_OPS(cs42l43_codec_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct platform_device_id cs42l43_codec_id_table[] = {
diff --git a/sound/soc/codecs/cs42l43.h b/sound/soc/codecs/cs42l43.h
index 9c144e129535..1cd9d8a71c43 100644
--- a/sound/soc/codecs/cs42l43.h
+++ b/sound/soc/codecs/cs42l43.h
@@ -78,6 +78,8 @@ struct cs42l43_codec {
bool use_ring_sense;
unsigned int tip_debounce_ms;
+ unsigned int tip_fall_db_ms;
+ unsigned int tip_rise_db_ms;
unsigned int bias_low;
unsigned int bias_sense_ua;
unsigned int bias_ramp_ms;
@@ -95,6 +97,7 @@ struct cs42l43_codec {
bool button_detect_running;
bool jack_present;
int jack_override;
+ bool suspend_jack_debounce;
struct work_struct hp_ilimit_work;
struct delayed_work hp_ilimit_clear_work;
diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c
index e7cc50096297..ba7e237619f2 100644
--- a/sound/soc/codecs/cs42l51-i2c.c
+++ b/sound/soc/codecs/cs42l51-i2c.c
@@ -13,9 +13,9 @@
#include "cs42l51.h"
-static struct i2c_device_id cs42l51_i2c_id[] = {
- {"cs42l51"},
- {}
+static const struct i2c_device_id cs42l51_i2c_id[] = {
+ { "cs42l51" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, cs42l51_i2c_id);
@@ -40,7 +40,7 @@ static void cs42l51_i2c_remove(struct i2c_client *i2c)
}
static const struct dev_pm_ops cs42l51_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume)
+ SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume)
};
static struct i2c_driver cs42l51_i2c_driver = {
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 6e51954bdb1e..8083a339dc7b 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -322,10 +322,10 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
cs42l51->func = MODE_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
cs42l51->func = MODE_SLAVE_AUTO;
break;
default:
@@ -805,7 +805,7 @@ void cs42l51_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(cs42l51_remove);
-int __maybe_unused cs42l51_suspend(struct device *dev)
+int cs42l51_suspend(struct device *dev)
{
struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
@@ -816,7 +816,7 @@ int __maybe_unused cs42l51_suspend(struct device *dev)
}
EXPORT_SYMBOL_GPL(cs42l51_suspend);
-int __maybe_unused cs42l51_resume(struct device *dev)
+int cs42l51_resume(struct device *dev)
{
struct cs42l51_private *cs42l51 = dev_get_drvdata(dev);
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 7128d4c62f50..cd3f92c19045 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -733,10 +733,10 @@ static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u8 iface = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
iface = CS42L52_IFACE_CTL1_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
iface = CS42L52_IFACE_CTL1_SLAVE;
break;
default:
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c
index aaa10c459b52..aaf90c8b7339 100644
--- a/sound/soc/codecs/cs42l56.c
+++ b/sound/soc/codecs/cs42l56.c
@@ -757,10 +757,10 @@ static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
cs42l56->iface = CS42L56_MASTER_MODE;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
cs42l56->iface = CS42L56_SLAVE_MODE;
break;
default:
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 21ba796a5cd9..ddf36001100e 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -943,11 +943,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
mmcc = snd_soc_component_read(component, CS42L73_MMCC(id));
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
mmcc |= CS42L73_MS_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
mmcc &= ~CS42L73_MS_MASTER;
break;
diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c
index 42c3e1efdc08..53a7fe1ab3dd 100644
--- a/sound/soc/codecs/cs42l83-i2c.c
+++ b/sound/soc/codecs/cs42l83-i2c.c
@@ -199,7 +199,7 @@ static void cs42l83_i2c_remove(struct i2c_client *i2c_client)
cs42l42_common_remove(cs42l83);
}
-static int __maybe_unused cs42l83_i2c_resume(struct device *dev)
+static int cs42l83_i2c_resume(struct device *dev)
{
int ret;
@@ -213,7 +213,7 @@ static int __maybe_unused cs42l83_i2c_resume(struct device *dev)
}
static const struct dev_pm_ops cs42l83_i2c_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume)
+ SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume)
};
static const struct of_device_id __maybe_unused cs42l83_of_match[] = {
@@ -225,7 +225,7 @@ MODULE_DEVICE_TABLE(of, cs42l83_of_match);
static struct i2c_driver cs42l83_i2c_driver = {
.driver = {
.name = "cs42l83",
- .pm = &cs42l83_i2c_pm_ops,
+ .pm = pm_ptr(&cs42l83_i2c_pm_ops),
.of_match_table = of_match_ptr(cs42l83_of_match),
},
.probe = cs42l83_i2c_probe,
diff --git a/sound/soc/codecs/cs42l84.c b/sound/soc/codecs/cs42l84.c
index 17d5c96e334d..88cf3c03986e 100644
--- a/sound/soc/codecs/cs42l84.c
+++ b/sound/soc/codecs/cs42l84.c
@@ -1087,7 +1087,7 @@ static const struct of_device_id cs42l84_of_match[] = {
MODULE_DEVICE_TABLE(of, cs42l84_of_match);
static const struct i2c_device_id cs42l84_id[] = {
- {"cs42l84", 0},
+ { "cs42l84" },
{}
};
MODULE_DEVICE_TABLE(i2c, cs42l84_id);
diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c
index ecaebf8e1c8f..039b3ecb3b9b 100644
--- a/sound/soc/codecs/cs42xx8-i2c.c
+++ b/sound/soc/codecs/cs42xx8-i2c.c
@@ -61,7 +61,7 @@ MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id);
static struct i2c_driver cs42xx8_i2c_driver = {
.driver = {
.name = "cs42xx8",
- .pm = &cs42xx8_pm,
+ .pm = pm_ptr(&cs42xx8_pm),
.of_match_table = cs42xx8_of_match,
},
.probe = cs42xx8_i2c_probe,
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c
index 9c44b6283b8f..6a925f3f7137 100644
--- a/sound/soc/codecs/cs42xx8.c
+++ b/sound/soc/codecs/cs42xx8.c
@@ -242,10 +242,10 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* Set master/slave audio interface */
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
cs42xx8->slave_mode = true;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
cs42xx8->slave_mode = false;
break;
default:
@@ -606,7 +606,6 @@ err_enable:
}
EXPORT_SYMBOL_GPL(cs42xx8_probe);
-#ifdef CONFIG_PM
static int cs42xx8_runtime_resume(struct device *dev)
{
struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev);
@@ -665,14 +664,11 @@ static int cs42xx8_runtime_suspend(struct device *dev)
return 0;
}
-#endif
-const struct dev_pm_ops cs42xx8_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
+EXPORT_GPL_DEV_PM_OPS(cs42xx8_pm) = {
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL)
};
-EXPORT_SYMBOL_GPL(cs42xx8_pm);
MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver");
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c
index f8e2fb69ada2..d9b3d73c8388 100644
--- a/sound/soc/codecs/cs43130.c
+++ b/sound/soc/codecs/cs43130.c
@@ -640,10 +640,10 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
}
switch (cs43130->dais[dai_id].dai_mode) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
dai_mode_val = 0;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
dai_mode_val = 1;
break;
default:
@@ -851,7 +851,7 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+ if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBP_CFP)
regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG,
CS43130_DSD_MASTER, CS43130_DSD_MASTER);
else
@@ -951,7 +951,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream,
break;
}
- if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM)
+ if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBP_CFP)
/* Calculate SCLK in master mode if unassigned */
sclk = params_rate(params) * bitwidth_dai *
params_channels(params);
@@ -1516,11 +1516,11 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBC_CFC;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBP_CFP;
break;
default:
dev_err(cs43130->dev, "unsupported mode\n");
@@ -1579,11 +1579,11 @@ static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS;
+ case SND_SOC_DAIFMT_CBC_CFC:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBC_CFC;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
- cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM;
+ case SND_SOC_DAIFMT_CBP_CFP:
+ cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBP_CFP;
break;
default:
dev_err(cs43130->dev, "Unsupported DAI format.\n");
@@ -2672,7 +2672,7 @@ static void cs43130_i2c_remove(struct i2c_client *client)
regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies);
}
-static int __maybe_unused cs43130_runtime_suspend(struct device *dev)
+static int cs43130_runtime_suspend(struct device *dev)
{
struct cs43130_private *cs43130 = dev_get_drvdata(dev);
@@ -2691,7 +2691,7 @@ static int __maybe_unused cs43130_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cs43130_runtime_resume(struct device *dev)
+static int cs43130_runtime_resume(struct device *dev)
{
struct cs43130_private *cs43130 = dev_get_drvdata(dev);
int ret;
@@ -2727,8 +2727,7 @@ err:
}
static const struct dev_pm_ops cs43130_runtime_pm = {
- SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume, NULL)
};
#if IS_ENABLED(CONFIG_OF)
@@ -2768,7 +2767,7 @@ static struct i2c_driver cs43130_i2c_driver = {
.name = "cs43130",
.of_match_table = of_match_ptr(cs43130_of_match),
.acpi_match_table = ACPI_PTR(cs43130_acpi_match),
- .pm = &cs43130_runtime_pm,
+ .pm = pm_ptr(&cs43130_runtime_pm),
},
.id_table = cs43130_i2c_id,
.probe = cs43130_i2c_probe,
diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c
index d87aae31c516..b726e22ef57d 100644
--- a/sound/soc/codecs/cs4341.c
+++ b/sound/soc/codecs/cs4341.c
@@ -49,7 +49,7 @@ static int cs4341_set_fmt(struct snd_soc_dai *dai, unsigned int format)
struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component);
switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c
index a134ca722892..d9a9c34fffe3 100644
--- a/sound/soc/codecs/cs4349.c
+++ b/sound/soc/codecs/cs4349.c
@@ -312,7 +312,6 @@ static void cs4349_i2c_remove(struct i2c_client *client)
gpiod_set_value_cansleep(cs4349->reset_gpio, 0);
}
-#ifdef CONFIG_PM
static int cs4349_runtime_suspend(struct device *dev)
{
struct cs4349_private *cs4349 = dev_get_drvdata(dev);
@@ -346,11 +345,9 @@ static int cs4349_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops cs4349_runtime_pm = {
- SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume, NULL)
};
static const struct of_device_id cs4349_of_match[] = {
@@ -371,7 +368,7 @@ static struct i2c_driver cs4349_i2c_driver = {
.driver = {
.name = "cs4349",
.of_match_table = cs4349_of_match,
- .pm = &cs4349_runtime_pm,
+ .pm = pm_ptr(&cs4349_runtime_pm),
},
.id_table = cs4349_i2c_id,
.probe = cs4349_i2c_probe,
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
index 252e66c8449e..b9eff240b929 100644
--- a/sound/soc/codecs/cs530x.c
+++ b/sound/soc/codecs/cs530x.c
@@ -557,9 +557,9 @@ static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int asp_fmt, asp_cfg = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
asp_cfg = CS530X_ASP_PRIMARY;
break;
default:
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c
index 28f4be37dec1..61bf72681674 100644
--- a/sound/soc/codecs/cs53l30.c
+++ b/sound/soc/codecs/cs53l30.c
@@ -572,10 +572,10 @@ static int cs53l30_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u8 aspcfg = 0, aspctl1 = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aspcfg |= CS53L30_ASP_MS;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
@@ -1031,7 +1031,6 @@ static void cs53l30_i2c_remove(struct i2c_client *client)
cs53l30->supplies);
}
-#ifdef CONFIG_PM
static int cs53l30_runtime_suspend(struct device *dev)
{
struct cs53l30_private *cs53l30 = dev_get_drvdata(dev);
@@ -1070,11 +1069,9 @@ static int cs53l30_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops cs53l30_runtime_pm = {
- SET_RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume, NULL)
};
static const struct of_device_id cs53l30_of_match[] = {
@@ -1095,7 +1092,7 @@ static struct i2c_driver cs53l30_i2c_driver = {
.driver = {
.name = "cs53l30",
.of_match_table = cs53l30_of_match,
- .pm = &cs53l30_runtime_pm,
+ .pm = pm_ptr(&cs53l30_runtime_pm),
},
.id_table = cs53l30_id,
.probe = cs53l30_i2c_probe,
diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c
index 8cfec8dcf839..934526f8f292 100644
--- a/sound/soc/codecs/cx2072x.c
+++ b/sound/soc/codecs/cx2072x.c
@@ -1611,7 +1611,7 @@ static const struct regmap_config cx2072x_regmap = {
.reg_write = cx2072x_reg_write,
};
-static int __maybe_unused cx2072x_runtime_suspend(struct device *dev)
+static int cx2072x_runtime_suspend(struct device *dev)
{
struct cx2072x_priv *cx2072x = dev_get_drvdata(dev);
@@ -1619,7 +1619,7 @@ static int __maybe_unused cx2072x_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cx2072x_runtime_resume(struct device *dev)
+static int cx2072x_runtime_resume(struct device *dev)
{
struct cx2072x_priv *cx2072x = dev_get_drvdata(dev);
@@ -1696,17 +1696,15 @@ MODULE_DEVICE_TABLE(acpi, cx2072x_acpi_match);
#endif
static const struct dev_pm_ops cx2072x_runtime_pm = {
- SET_RUNTIME_PM_OPS(cx2072x_runtime_suspend, cx2072x_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(cx2072x_runtime_suspend, cx2072x_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct i2c_driver cx2072x_i2c_driver = {
.driver = {
.name = "cx2072x",
.acpi_match_table = ACPI_PTR(cx2072x_acpi_match),
- .pm = &cx2072x_runtime_pm,
+ .pm = pm_ptr(&cx2072x_runtime_pm),
},
.probe = cx2072x_i2c_probe,
.remove = cx2072x_i2c_remove,
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index da2d0242019e..a889f05119f8 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -882,11 +882,11 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
return -EINVAL;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
da7210->master = 1;
dai_cfg1 |= DA7210_DAI_MODE_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
da7210->master = 0;
dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
break;
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
index ca4cc954efa8..a4496cc26902 100644
--- a/sound/soc/codecs/da7213.c
+++ b/sound/soc/codecs/da7213.c
@@ -2203,6 +2203,8 @@ static int da7213_i2c_probe(struct i2c_client *i2c)
return ret;
}
+ mutex_init(&da7213->ctrl_lock);
+
pm_runtime_set_autosuspend_delay(&i2c->dev, 100);
pm_runtime_use_autosuspend(&i2c->dev);
pm_runtime_set_active(&i2c->dev);
@@ -2222,7 +2224,7 @@ static void da7213_i2c_remove(struct i2c_client *i2c)
pm_runtime_disable(&i2c->dev);
}
-static int __maybe_unused da7213_runtime_suspend(struct device *dev)
+static int da7213_runtime_suspend(struct device *dev)
{
struct da7213_priv *da7213 = dev_get_drvdata(dev);
@@ -2233,7 +2235,7 @@ static int __maybe_unused da7213_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused da7213_runtime_resume(struct device *dev)
+static int da7213_runtime_resume(struct device *dev)
{
struct da7213_priv *da7213 = dev_get_drvdata(dev);
int ret;
@@ -2246,8 +2248,8 @@ static int __maybe_unused da7213_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops da7213_pm = {
- SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct i2c_device_id da7213_i2c_id[] = {
@@ -2262,7 +2264,7 @@ static struct i2c_driver da7213_i2c_driver = {
.name = "da7213",
.of_match_table = of_match_ptr(da7213_of_match),
.acpi_match_table = ACPI_PTR(da7213_acpi_match),
- .pm = &da7213_pm,
+ .pm = pm_ptr(&da7213_pm),
},
.probe = da7213_i2c_probe,
.remove = da7213_i2c_remove,
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c
index 8aacd7350798..5f2f67e3bd29 100644
--- a/sound/soc/codecs/da7218.c
+++ b/sound/soc/codecs/da7218.c
@@ -1935,10 +1935,10 @@ static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u8 dai_clk_mode = 0, dai_ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
da7218->master = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
da7218->master = false;
break;
default:
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index e2da3e317b5a..3958e88a2445 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1312,10 +1312,10 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u8 dai_clk_mode = 0, dai_ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
da7219->master = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
da7219->master = false;
break;
default:
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c
index b747f6fa12e4..016c9be3ebda 100644
--- a/sound/soc/codecs/da732x.c
+++ b/sound/soc/codecs/da732x.c
@@ -1034,11 +1034,11 @@ static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
aif1 = DA732X_AIF_SLAVE;
aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif1 = DA732X_AIF_CLK_FROM_SRC;
aif_mclk = DA732X_CLK_GENERATION_AIF_A;
break;
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c
index 8bb8fef2a1d1..eb795abe9acd 100644
--- a/sound/soc/codecs/da9055.c
+++ b/sound/soc/codecs/da9055.c
@@ -1160,12 +1160,12 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
u8 aif_clk_mode, aif_ctrl, mode;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
/* DA9055 in I2S Master Mode */
mode = 1;
aif_clk_mode = DA9055_AIF_CLK_EN_MASTER_MODE;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
/* DA9055 in I2S Slave Mode */
mode = 0;
aif_clk_mode = DA9055_AIF_CLK_EN_SLAVE_MODE;
diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c
index 4fd6f97e5a49..61e1bf1b3c9e 100644
--- a/sound/soc/codecs/dmic.c
+++ b/sound/soc/codecs/dmic.c
@@ -9,6 +9,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
@@ -25,6 +26,7 @@ module_param(wakeup_delay, uint, 0644);
struct dmic {
struct gpio_desc *gpio_en;
+ struct regulator *vref;
int wakeup_delay;
/* Delay after DMIC mode switch */
int modeswitch_delay;
@@ -55,22 +57,33 @@ static int dmic_aif_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 dmic *dmic = snd_soc_component_get_drvdata(component);
+ int ret = 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (dmic->gpio_en)
gpiod_set_value_cansleep(dmic->gpio_en, 1);
+ if (dmic->vref) {
+ ret = regulator_enable(dmic->vref);
+ if (ret)
+ return ret;
+ }
+
if (dmic->wakeup_delay)
msleep(dmic->wakeup_delay);
break;
case SND_SOC_DAPM_POST_PMD:
if (dmic->gpio_en)
gpiod_set_value_cansleep(dmic->gpio_en, 0);
+
+ if (dmic->vref)
+ ret = regulator_disable(dmic->vref);
+
break;
}
- return 0;
+ return ret;
}
static struct snd_soc_dai_driver dmic_dai = {
@@ -85,7 +98,9 @@ static struct snd_soc_dai_driver dmic_dai = {
| SNDRV_PCM_FMTBIT_S16_LE
| SNDRV_PCM_FMTBIT_DSD_U8
| SNDRV_PCM_FMTBIT_DSD_U16_LE
- | SNDRV_PCM_FMTBIT_DSD_U32_LE,
+ | SNDRV_PCM_FMTBIT_DSD_U32_LE
+ | SNDRV_PCM_FMTBIT_DSD_U16_BE
+ | SNDRV_PCM_FMTBIT_DSD_U32_BE,
},
.ops = &dmic_dai_ops,
};
@@ -98,6 +113,14 @@ static int dmic_component_probe(struct snd_soc_component *component)
if (!dmic)
return -ENOMEM;
+ dmic->vref = devm_regulator_get_optional(component->dev, "vref");
+ if (IS_ERR(dmic->vref)) {
+ if (PTR_ERR(dmic->vref) != -ENODEV)
+ return dev_err_probe(component->dev, PTR_ERR(dmic->vref),
+ "Failed to get vref\n");
+ dmic->vref = NULL;
+ }
+
dmic->gpio_en = devm_gpiod_get_optional(component->dev,
"dmicen", GPIOD_OUT_LOW);
if (IS_ERR(dmic->gpio_en))
diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c
index f508df01145b..e7bd561a8f40 100644
--- a/sound/soc/codecs/es8316.c
+++ b/sound/soc/codecs/es8316.c
@@ -101,7 +101,7 @@ static const struct snd_kcontrol_new es8316_snd_controls[] = {
SOC_DOUBLE_R_TLV("DAC Playback Volume", ES8316_DAC_VOLL,
ES8316_DAC_VOLR, 0, 0xc0, 1, dac_vol_tlv),
SOC_SINGLE("DAC Soft Ramp Switch", ES8316_DAC_SET1, 4, 1, 1),
- SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 4, 0),
+ SOC_SINGLE("DAC Soft Ramp Rate", ES8316_DAC_SET1, 2, 3, 0),
SOC_SINGLE("DAC Notch Filter Switch", ES8316_DAC_SET2, 6, 1, 0),
SOC_SINGLE("DAC Double Fs Switch", ES8316_DAC_SET2, 7, 1, 0),
SOC_SINGLE("DAC Stereo Enhancement", ES8316_DAC_SET3, 0, 7, 0),
diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c
index 6f4fa36ea34d..a9822998199f 100644
--- a/sound/soc/codecs/es8323.c
+++ b/sound/soc/codecs/es8323.c
@@ -758,7 +758,7 @@ static int es8323_i2c_probe(struct i2c_client *i2c_client)
}
static const struct i2c_device_id es8323_i2c_id[] = {
- { "es8323", 0 },
+ { "es8323" },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8323_i2c_id);
diff --git a/sound/soc/codecs/es8326.c b/sound/soc/codecs/es8326.c
index b06eead7e0f6..066d92b54312 100644
--- a/sound/soc/codecs/es8326.c
+++ b/sound/soc/codecs/es8326.c
@@ -911,7 +911,7 @@ static void es8326_jack_detect_handler(struct work_struct *work)
regmap_write(es8326->regmap, ES8326_INT_SOURCE,
(ES8326_INT_SRC_PIN9 | ES8326_INT_SRC_BUTTON));
regmap_write(es8326->regmap, ES8326_SYS_BIAS, 0x1f);
- regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x0f, 0x08);
+ regmap_update_bits(es8326->regmap, ES8326_HP_DRIVER_REF, 0x0f, 0x0d);
queue_delayed_work(system_wq, &es8326->jack_detect_work,
msecs_to_jiffies(400));
es8326->hp = 1;
@@ -1023,7 +1023,7 @@ static void es8326_init(struct snd_soc_component *component)
struct es8326_priv *es8326 = snd_soc_component_get_drvdata(component);
regmap_write(es8326->regmap, ES8326_RESET, 0x1f);
- regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x0E);
+ regmap_write(es8326->regmap, ES8326_VMIDSEL, 0x3E);
regmap_write(es8326->regmap, ES8326_ANA_LP, 0xf0);
usleep_range(10000, 15000);
regmap_write(es8326->regmap, ES8326_HPJACK_TIMER, 0xd9);
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index f3c97da798dc..76159c45e6b5 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -233,7 +233,6 @@ static const struct snd_kcontrol_new es8328_right_line_controls =
/* Left Mixer */
static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
- SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 7, 1, 0),
SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 6, 1, 0),
SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 7, 1, 0),
SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 6, 1, 0),
@@ -243,7 +242,6 @@ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 7, 1, 0),
SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 6, 1, 0),
- SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 7, 1, 0),
SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 6, 1, 0),
};
@@ -336,10 +334,10 @@ static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
ES8328_DACPOWER_LDAC_OFF, 1),
- SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_MIXER("Left Mixer", ES8328_DACCONTROL17, 7, 0,
&es8328_left_mixer_controls[0],
ARRAY_SIZE(es8328_left_mixer_controls)),
- SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_MIXER("Right Mixer", ES8328_DACCONTROL20, 7, 0,
&es8328_right_mixer_controls[0],
ARRAY_SIZE(es8328_right_mixer_controls)),
@@ -418,19 +416,14 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
{ "Right Line Mux", "PGA", "Right PGA Mux" },
{ "Right Line Mux", "Differential", "Differential Mux" },
- { "Left Out 1", NULL, "Left DAC" },
- { "Right Out 1", NULL, "Right DAC" },
- { "Left Out 2", NULL, "Left DAC" },
- { "Right Out 2", NULL, "Right DAC" },
-
- { "Left Mixer", "Playback Switch", "Left DAC" },
+ { "Left Mixer", NULL, "Left DAC" },
{ "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
{ "Left Mixer", "Right Playback Switch", "Right DAC" },
{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
{ "Right Mixer", "Left Playback Switch", "Left DAC" },
{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
- { "Right Mixer", "Playback Switch", "Right DAC" },
+ { "Right Mixer", NULL, "Right DAC" },
{ "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
{ "DAC DIG", NULL, "DAC STM" },
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index e1a7f0b0c0f3..1139a2754ca3 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1017,8 +1017,7 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_device *hdev,
return -ENOMEM;
}
- se->texts = devm_kmemdup(&hdev->dev, items,
- (num_items * sizeof(char *)), GFP_KERNEL);
+ se->texts = devm_kmemdup_array(&hdev->dev, items, num_items, sizeof(items[0]), GFP_KERNEL);
if (!se->texts)
return -ENOMEM;
@@ -2033,7 +2032,6 @@ static void hdmi_codec_remove(struct snd_soc_component *component)
pm_runtime_disable(&hdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int hdmi_codec_resume(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
@@ -2056,9 +2054,6 @@ static int hdmi_codec_resume(struct device *dev)
hdac_hdmi_present_sense_all_pins(hdev, hdmi, false);
return 0;
}
-#else
-#define hdmi_codec_resume NULL
-#endif
static const struct snd_soc_component_driver hdmi_hda_codec = {
.probe = hdmi_codec_probe,
@@ -2228,7 +2223,6 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev)
return 0;
}
-#ifdef CONFIG_PM
static int hdac_hdmi_runtime_suspend(struct device *dev)
{
struct hdac_device *hdev = dev_to_hdac_dev(dev);
@@ -2297,14 +2291,10 @@ static int hdac_hdmi_runtime_resume(struct device *dev)
return 0;
}
-#else
-#define hdac_hdmi_runtime_suspend NULL
-#define hdac_hdmi_runtime_resume NULL
-#endif
static const struct dev_pm_ops hdac_hdmi_pm = {
- SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, hdmi_codec_resume)
+ RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, hdmi_codec_resume)
};
static const struct hda_device_id hdmi_list[] = {
@@ -2323,7 +2313,7 @@ MODULE_DEVICE_TABLE(hdaudio, hdmi_list);
static struct hdac_driver hdmi_driver = {
.driver = {
.name = "HDMI HDA Codec",
- .pm = &hdac_hdmi_pm,
+ .pm = pm_ptr(&hdac_hdmi_pm),
},
.id_table = hdmi_list,
.probe = hdac_hdmi_dev_probe,
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index d9df29a26f4f..497376bcd3ff 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -281,6 +281,7 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
struct hdmi_codec_priv {
struct hdmi_codec_pdata hcd;
uint8_t eld[MAX_ELD_BYTES];
+ struct snd_parsed_hdmi_eld eld_parsed;
struct snd_pcm_chmap *chmap_info;
unsigned int chmap_idx;
struct mutex lock;
@@ -288,6 +289,7 @@ struct hdmi_codec_priv {
struct snd_soc_jack *jack;
unsigned int jack_status;
u8 iec_status[AES_IEC958_STATUS_SIZE];
+ struct snd_info_entry *proc_entry;
};
static const struct snd_soc_dapm_widget hdmi_widgets[] = {
@@ -469,6 +471,9 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream,
if (ret)
goto err;
+ 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;
@@ -714,7 +719,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction)
*/
if (hcp->hcd.ops->mute_stream &&
(direction == SNDRV_PCM_STREAM_PLAYBACK ||
- !hcp->hcd.ops->no_capture_mute))
+ !hcp->hcd.no_capture_mute))
return hcp->hcd.ops->mute_stream(dai->dev->parent,
hcp->hcd.data,
mute, direction);
@@ -825,8 +830,54 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd,
return 0;
}
+#ifdef CONFIG_SND_PROC_FS
+static void print_eld_info(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct hdmi_codec_priv *hcp = entry->private_data;
+
+ snd_print_eld_info(&hcp->eld_parsed, buffer);
+}
+
+static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp,
+ struct snd_soc_dai *dai)
+{
+ struct snd_info_entry *entry;
+ char name[32];
+ int err;
+
+ snprintf(name, sizeof(name), "eld#%d", dai->id);
+ err = snd_card_proc_new(dai->component->card->snd_card, name, &entry);
+ if (err < 0)
+ return err;
+
+ snd_info_set_text_ops(entry, hcp, print_eld_info);
+ hcp->proc_entry = entry;
+
+ return 0;
+}
+
+static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp)
+{
+ snd_info_free_entry(hcp->proc_entry);
+ hcp->proc_entry = NULL;
+}
+#else
+static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp,
+ struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp)
+{
+}
+#endif
+
static int hdmi_dai_probe(struct snd_soc_dai *dai)
{
+ struct hdmi_codec_priv *hcp =
+ snd_soc_component_get_drvdata(dai->component);
struct snd_soc_dapm_context *dapm;
struct hdmi_codec_daifmt *daifmt;
struct snd_soc_dapm_route route[] = {
@@ -859,6 +910,15 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
snd_soc_dai_dma_data_set_playback(dai, daifmt);
+ return hdmi_dai_proc_new(hcp, dai);
+}
+
+static int hdmi_dai_remove(struct snd_soc_dai *dai)
+{
+ struct hdmi_codec_priv *hcp =
+ snd_soc_component_get_drvdata(dai->component);
+
+ hdmi_dai_proc_free(hcp);
return 0;
}
@@ -875,11 +935,18 @@ static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp,
static void plugged_cb(struct device *dev, bool plugged)
{
struct hdmi_codec_priv *hcp = dev_get_drvdata(dev);
+ int ret;
if (plugged) {
if (hcp->hcd.ops->get_eld) {
hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data,
hcp->eld, sizeof(hcp->eld));
+ ret = snd_parse_eld(dev, &hcp->eld_parsed,
+ hcp->eld, sizeof(hcp->eld));
+ if (ret < 0)
+ dev_dbg(dev, "Failed to parse ELD: %d\n", ret);
+ else
+ snd_show_eld(dev, &hcp->eld_parsed);
}
hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT);
} else {
@@ -926,6 +993,7 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai)
static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
.probe = hdmi_dai_probe,
+ .remove = hdmi_dai_remove,
.startup = hdmi_codec_startup,
.shutdown = hdmi_codec_shutdown,
.hw_params = hdmi_codec_hw_params,
@@ -995,7 +1063,7 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component,
int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */
if (hcp->hcd.ops->get_dai_id)
- ret = hcp->hcd.ops->get_dai_id(component, endpoint);
+ ret = hcp->hcd.ops->get_dai_id(component, endpoint, hcp->hcd.data);
return ret;
}
diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c
index 6217e611259f..e04af1b9ace8 100644
--- a/sound/soc/codecs/jz4760.c
+++ b/sound/soc/codecs/jz4760.c
@@ -314,37 +314,13 @@ static const struct snd_kcontrol_new jz4760_codec_snd_controls[] = {
};
static const struct snd_kcontrol_new jz4760_codec_pcm_playback_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Volume",
- .info = snd_soc_info_volsw,
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
- | SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .tlv.p = dac_tlv,
- .get = snd_soc_dapm_get_volsw,
- .put = snd_soc_dapm_put_volsw,
- .private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR6,
- JZ4760_CODEC_REG_GCR5,
- REG_GCR_GAIN_OFFSET,
- REG_GCR_GAIN_MAX, 1),
- },
+ SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4760_CODEC_REG_GCR6, JZ4760_CODEC_REG_GCR5,
+ REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, dac_tlv),
};
static const struct snd_kcontrol_new jz4760_codec_hp_playback_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Volume",
- .info = snd_soc_info_volsw,
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
- | SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .tlv.p = out_tlv,
- .get = snd_soc_dapm_get_volsw,
- .put = snd_soc_dapm_put_volsw,
- .private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR2,
- JZ4760_CODEC_REG_GCR1,
- REG_GCR_GAIN_OFFSET,
- REG_GCR_GAIN_MAX, 1),
- },
+ SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4760_CODEC_REG_GCR2, JZ4760_CODEC_REG_GCR1,
+ REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, out_tlv),
};
static int hpout_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c
index acb9eaa7ea1c..312202ab5cea 100644
--- a/sound/soc/codecs/jz4770.c
+++ b/sound/soc/codecs/jz4770.c
@@ -331,43 +331,15 @@ static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = {
};
static const struct snd_kcontrol_new jz4770_codec_pcm_playback_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Volume",
- .info = snd_soc_info_volsw,
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
- | SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .tlv.p = dac_tlv,
- .get = snd_soc_dapm_get_volsw,
- .put = snd_soc_dapm_put_volsw,
- /*
- * NOTE: DACR/DACL are inversed; the gain value written to DACR
- * seems to affect the left channel, and the gain value written
- * to DACL seems to affect the right channel.
- */
- .private_value = SOC_DOUBLE_R_VALUE(JZ4770_CODEC_REG_GCR_DACR,
- JZ4770_CODEC_REG_GCR_DACL,
- REG_GCR_GAIN_OFFSET,
- REG_GCR_GAIN_MAX, 1),
- },
+ SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4770_CODEC_REG_GCR_DACR,
+ JZ4770_CODEC_REG_GCR_DACL, REG_GCR_GAIN_OFFSET,
+ REG_GCR_GAIN_MAX, 1, dac_tlv),
};
static const struct snd_kcontrol_new jz4770_codec_hp_playback_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Volume",
- .info = snd_soc_info_volsw,
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
- | SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .tlv.p = out_tlv,
- .get = snd_soc_dapm_get_volsw,
- .put = snd_soc_dapm_put_volsw,
- /* HPR/HPL inversed for the same reason as above */
- .private_value = SOC_DOUBLE_R_VALUE(JZ4770_CODEC_REG_GCR_HPR,
- JZ4770_CODEC_REG_GCR_HPL,
- REG_GCR_GAIN_OFFSET,
- REG_GCR_GAIN_MAX, 1),
- },
+ SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4770_CODEC_REG_GCR_HPR,
+ JZ4770_CODEC_REG_GCR_HPL, REG_GCR_GAIN_OFFSET,
+ REG_GCR_GAIN_MAX, 1, out_tlv),
};
static int hpout_event(struct snd_soc_dapm_widget *w,
diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c
index 5e0bd0d24ed3..a3d6318c9050 100644
--- a/sound/soc/codecs/lochnagar-sc.c
+++ b/sound/soc/codecs/lochnagar-sc.c
@@ -129,12 +129,12 @@ static int lochnagar_sc_check_fmt(struct snd_soc_dai *dai, unsigned int fmt,
static int lochnagar_sc_set_line_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
- return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBS_CFS);
+ return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBC_CFC);
}
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_CBM_CFM);
+ return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBP_CFP);
}
static const struct snd_soc_dai_ops lochnagar_sc_line_ops = {
diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c
index febbbe073962..45a6b83808b2 100644
--- a/sound/soc/codecs/lpass-rx-macro.c
+++ b/sound/soc/codecs/lpass-rx-macro.c
@@ -3963,7 +3963,7 @@ static const struct of_device_id rx_macro_dt_match[] = {
};
MODULE_DEVICE_TABLE(of, rx_macro_dt_match);
-static int __maybe_unused rx_macro_runtime_suspend(struct device *dev)
+static int rx_macro_runtime_suspend(struct device *dev)
{
struct rx_macro *rx = dev_get_drvdata(dev);
@@ -3977,7 +3977,7 @@ static int __maybe_unused rx_macro_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rx_macro_runtime_resume(struct device *dev)
+static int rx_macro_runtime_resume(struct device *dev)
{
struct rx_macro *rx = dev_get_drvdata(dev);
int ret;
@@ -4012,7 +4012,7 @@ err_npl:
}
static const struct dev_pm_ops rx_macro_pm_ops = {
- SET_RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL)
+ RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL)
};
static struct platform_driver rx_macro_driver = {
@@ -4020,7 +4020,7 @@ static struct platform_driver rx_macro_driver = {
.name = "rx_macro",
.of_match_table = rx_macro_dt_match,
.suppress_bind_attrs = true,
- .pm = &rx_macro_pm_ops,
+ .pm = pm_ptr(&rx_macro_pm_ops),
},
.probe = rx_macro_probe,
.remove = rx_macro_remove,
diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c
index a134584acf90..27bae58f4072 100644
--- a/sound/soc/codecs/lpass-tx-macro.c
+++ b/sound/soc/codecs/lpass-tx-macro.c
@@ -2400,7 +2400,7 @@ static void tx_macro_remove(struct platform_device *pdev)
lpass_macro_pds_exit(tx->pds);
}
-static int __maybe_unused tx_macro_runtime_suspend(struct device *dev)
+static int tx_macro_runtime_suspend(struct device *dev)
{
struct tx_macro *tx = dev_get_drvdata(dev);
@@ -2414,7 +2414,7 @@ static int __maybe_unused tx_macro_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tx_macro_runtime_resume(struct device *dev)
+static int tx_macro_runtime_resume(struct device *dev)
{
struct tx_macro *tx = dev_get_drvdata(dev);
int ret;
@@ -2450,7 +2450,7 @@ err_npl:
}
static const struct dev_pm_ops tx_macro_pm_ops = {
- SET_RUNTIME_PM_OPS(tx_macro_runtime_suspend, tx_macro_runtime_resume, NULL)
+ RUNTIME_PM_OPS(tx_macro_runtime_suspend, tx_macro_runtime_resume, NULL)
};
static const struct tx_macro_data lpass_ver_9 = {
@@ -2531,7 +2531,7 @@ static struct platform_driver tx_macro_driver = {
.name = "tx_macro",
.of_match_table = tx_macro_dt_match,
.suppress_bind_attrs = true,
- .pm = &tx_macro_pm_ops,
+ .pm = pm_ptr(&tx_macro_pm_ops),
},
.probe = tx_macro_probe,
.remove = tx_macro_remove,
diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c
index c781da476240..74ada6e77526 100644
--- a/sound/soc/codecs/lpass-va-macro.c
+++ b/sound/soc/codecs/lpass-va-macro.c
@@ -1674,7 +1674,7 @@ static void va_macro_remove(struct platform_device *pdev)
lpass_macro_pds_exit(va->pds);
}
-static int __maybe_unused va_macro_runtime_suspend(struct device *dev)
+static int va_macro_runtime_suspend(struct device *dev)
{
struct va_macro *va = dev_get_drvdata(dev);
@@ -1689,7 +1689,7 @@ static int __maybe_unused va_macro_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused va_macro_runtime_resume(struct device *dev)
+static int va_macro_runtime_resume(struct device *dev)
{
struct va_macro *va = dev_get_drvdata(dev);
int ret;
@@ -1717,7 +1717,7 @@ static int __maybe_unused va_macro_runtime_resume(struct device *dev)
static const struct dev_pm_ops va_macro_pm_ops = {
- SET_RUNTIME_PM_OPS(va_macro_runtime_suspend, va_macro_runtime_resume, NULL)
+ RUNTIME_PM_OPS(va_macro_runtime_suspend, va_macro_runtime_resume, NULL)
};
static const struct of_device_id va_macro_dt_match[] = {
@@ -1735,7 +1735,7 @@ static struct platform_driver va_macro_driver = {
.name = "va_macro",
.of_match_table = va_macro_dt_match,
.suppress_bind_attrs = true,
- .pm = &va_macro_pm_ops,
+ .pm = pm_ptr(&va_macro_pm_ops),
},
.probe = va_macro_probe,
.remove = va_macro_remove,
diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c
index c989d82d1d3c..b261fa373e65 100644
--- a/sound/soc/codecs/lpass-wsa-macro.c
+++ b/sound/soc/codecs/lpass-wsa-macro.c
@@ -2900,7 +2900,7 @@ static void wsa_macro_remove(struct platform_device *pdev)
clk_disable_unprepare(wsa->fsgen);
}
-static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev)
+static int wsa_macro_runtime_suspend(struct device *dev)
{
struct wsa_macro *wsa = dev_get_drvdata(dev);
@@ -2914,7 +2914,7 @@ static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wsa_macro_runtime_resume(struct device *dev)
+static int wsa_macro_runtime_resume(struct device *dev)
{
struct wsa_macro *wsa = dev_get_drvdata(dev);
int ret;
@@ -2950,7 +2950,7 @@ err_npl:
}
static const struct dev_pm_ops wsa_macro_pm_ops = {
- SET_RUNTIME_PM_OPS(wsa_macro_runtime_suspend, wsa_macro_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wsa_macro_runtime_suspend, wsa_macro_runtime_resume, NULL)
};
static const struct of_device_id wsa_macro_dt_match[] = {
@@ -2977,7 +2977,7 @@ static struct platform_driver wsa_macro_driver = {
.driver = {
.name = "wsa_macro",
.of_match_table = wsa_macro_dt_match,
- .pm = &wsa_macro_pm_ops,
+ .pm = pm_ptr(&wsa_macro_pm_ops),
},
.probe = wsa_macro_probe,
.remove = wsa_macro_remove,
diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c
index b24d6472ad5f..bc3470cf2c54 100644
--- a/sound/soc/codecs/madera.c
+++ b/sound/soc/codecs/madera.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/tlv.h>
@@ -2322,10 +2323,10 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case CS42L92:
case CS47L92:
case CS47L93:
- out_up_delay = 6;
+ out_up_delay = 6000;
break;
default:
- out_up_delay = 17;
+ out_up_delay = 17000;
break;
}
@@ -2356,7 +2357,7 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case MADERA_OUT3R_ENA_SHIFT:
priv->out_up_pending--;
if (!priv->out_up_pending) {
- msleep(priv->out_up_delay);
+ fsleep(priv->out_up_delay);
priv->out_up_delay = 0;
}
break;
@@ -2375,7 +2376,7 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case MADERA_OUT3L_ENA_SHIFT:
case MADERA_OUT3R_ENA_SHIFT:
priv->out_down_pending++;
- priv->out_down_delay++;
+ priv->out_down_delay += 1000;
break;
default:
break;
@@ -2392,7 +2393,7 @@ int madera_out_ev(struct snd_soc_dapm_widget *w,
case MADERA_OUT3R_ENA_SHIFT:
priv->out_down_pending--;
if (!priv->out_down_pending) {
- msleep(priv->out_down_delay);
+ fsleep(priv->out_down_delay);
priv->out_down_delay = 0;
}
break;
@@ -2775,7 +2776,7 @@ static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_DSP_B:
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) !=
- SND_SOC_DAIFMT_CBM_CFM) {
+ SND_SOC_DAIFMT_CBP_CFP) {
madera_aif_err(dai, "DSP_B not valid in slave mode\n");
return -EINVAL;
}
@@ -2786,7 +2787,7 @@ static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break;
case SND_SOC_DAIFMT_LEFT_J:
if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) !=
- SND_SOC_DAIFMT_CBM_CFM) {
+ SND_SOC_DAIFMT_CBP_CFP) {
madera_aif_err(dai, "LEFT_J not valid in slave mode\n");
return -EINVAL;
}
@@ -2799,15 +2800,15 @@ static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
lrclk |= MADERA_AIF1TX_LRCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
bclk |= MADERA_AIF1_BCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
bclk |= MADERA_AIF1_BCLK_MSTR;
lrclk |= MADERA_AIF1TX_LRCLK_MSTR;
break;
@@ -3965,7 +3966,7 @@ static int madera_enable_fll(struct madera_fll *fll)
}
madera_fll_dbg(fll, "Enabling FLL, initially %s\n",
- already_enabled ? "enabled" : "disabled");
+ str_enabled_disabled(already_enabled));
if (fll->fout < MADERA_FLL_MIN_FOUT ||
fll->fout > MADERA_FLL_MAX_FOUT) {
@@ -4252,7 +4253,7 @@ static int madera_enable_fll_ao(struct madera_fll *fll,
pm_runtime_get_sync(madera->dev);
madera_fll_dbg(fll, "Enabling FLL_AO, initially %s\n",
- already_enabled ? "enabled" : "disabled");
+ str_enabled_disabled(already_enabled));
/* FLL_AO_HOLD must be set before configuring any registers */
regmap_update_bits(fll->madera->regmap,
@@ -4576,7 +4577,7 @@ static int madera_fllhj_enable(struct madera_fll *fll)
pm_runtime_get_sync(madera->dev);
madera_fll_dbg(fll, "Enabling FLL, initially %s\n",
- already_enabled ? "enabled" : "disabled");
+ str_enabled_disabled(already_enabled));
/* FLLn_HOLD must be set before configuring any registers */
regmap_update_bits(fll->madera->regmap,
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 8915f5250695..37e61d8d4be6 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -1731,7 +1731,6 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id);
static int max98088_i2c_probe(struct i2c_client *i2c)
{
struct max98088_priv *max98088;
- const struct i2c_device_id *id;
max98088 = devm_kzalloc(&i2c->dev, sizeof(struct max98088_priv),
GFP_KERNEL);
@@ -1747,8 +1746,7 @@ static int max98088_i2c_probe(struct i2c_client *i2c)
if (PTR_ERR(max98088->mclk) == -EPROBE_DEFER)
return PTR_ERR(max98088->mclk);
- id = i2c_match_id(max98088_i2c_id, i2c);
- max98088->devtype = id->driver_data;
+ max98088->devtype = (uintptr_t)i2c_get_match_data(i2c);
i2c_set_clientdata(i2c, max98088);
max98088->pdata = i2c->dev.platform_data;
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 2adf744c6526..22177c1ce160 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -2543,8 +2543,6 @@ MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
static int max98090_i2c_probe(struct i2c_client *i2c)
{
struct max98090_priv *max98090;
- const struct acpi_device_id *acpi_id;
- kernel_ulong_t driver_data = 0;
int ret;
pr_debug("max98090_i2c_probe\n");
@@ -2554,21 +2552,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c)
if (max98090 == NULL)
return -ENOMEM;
- if (ACPI_HANDLE(&i2c->dev)) {
- acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
- &i2c->dev);
- if (!acpi_id) {
- dev_err(&i2c->dev, "No driver data\n");
- return -EINVAL;
- }
- driver_data = acpi_id->driver_data;
- } else {
- const struct i2c_device_id *i2c_id =
- i2c_match_id(max98090_i2c_id, i2c);
- driver_data = i2c_id->driver_data;
- }
-
- max98090->devtype = driver_data;
+ max98090->devtype = (uintptr_t)i2c_get_match_data(i2c);
i2c_set_clientdata(i2c, max98090);
max98090->pdata = i2c->dev.platform_data;
@@ -2620,7 +2604,6 @@ static void max98090_i2c_remove(struct i2c_client *client)
max98090_i2c_shutdown(client);
}
-#ifdef CONFIG_PM
static int max98090_runtime_resume(struct device *dev)
{
struct max98090_priv *max98090 = dev_get_drvdata(dev);
@@ -2642,9 +2625,7 @@ static int max98090_runtime_suspend(struct device *dev)
return 0;
}
-#endif
-#ifdef CONFIG_PM_SLEEP
static int max98090_resume(struct device *dev)
{
struct max98090_priv *max98090 = dev_get_drvdata(dev);
@@ -2661,12 +2642,10 @@ static int max98090_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops max98090_pm = {
- SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
- max98090_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume)
+ RUNTIME_PM_OPS(max98090_runtime_suspend, max98090_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume)
};
#ifdef CONFIG_OF
@@ -2689,7 +2668,7 @@ MODULE_DEVICE_TABLE(acpi, max98090_acpi_match);
static struct i2c_driver max98090_i2c_driver = {
.driver = {
.name = "max98090",
- .pm = &max98090_pm,
+ .pm = pm_ptr(&max98090_pm),
.of_match_table = of_match_ptr(max98090_of_match),
.acpi_match_table = ACPI_PTR(max98090_acpi_match),
},
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 7e525d49328d..cfb63fe69267 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -2115,7 +2115,6 @@ static int max98095_i2c_probe(struct i2c_client *i2c)
{
struct max98095_priv *max98095;
int ret;
- const struct i2c_device_id *id;
max98095 = devm_kzalloc(&i2c->dev, sizeof(struct max98095_priv),
GFP_KERNEL);
@@ -2131,8 +2130,7 @@ static int max98095_i2c_probe(struct i2c_client *i2c)
return ret;
}
- id = i2c_match_id(max98095_i2c_id, i2c);
- max98095->devtype = id->driver_data;
+ max98095->devtype = (uintptr_t)i2c_get_match_data(i2c);
i2c_set_clientdata(i2c, max98095);
max98095->pdata = i2c->dev.platform_data;
diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c
index 1f7ff3dbcbbe..56c4ba1f3782 100644
--- a/sound/soc/codecs/max98373-i2c.c
+++ b/sound/soc/codecs/max98373-i2c.c
@@ -472,7 +472,6 @@ static struct snd_soc_dai_driver max98373_dai[] = {
}
};
-#ifdef CONFIG_PM_SLEEP
static int max98373_suspend(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
@@ -496,10 +495,9 @@ static int max98373_resume(struct device *dev)
regcache_sync(max98373->regmap);
return 0;
}
-#endif
static const struct dev_pm_ops max98373_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
+ SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
};
static const struct regmap_config max98373_regmap = {
@@ -605,7 +603,7 @@ static struct i2c_driver max98373_i2c_driver = {
.name = "max98373",
.of_match_table = of_match_ptr(max98373_of_match),
.acpi_match_table = ACPI_PTR(max98373_acpi_match),
- .pm = &max98373_pm,
+ .pm = pm_ptr(&max98373_pm),
},
.probe = max98373_i2c_probe,
.id_table = max98373_i2c_id,
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 26860882fd91..6088278e6503 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -246,7 +246,7 @@ static const struct regmap_config max98373_sdw_regmap = {
};
/* Power management functions and structure */
-static __maybe_unused int max98373_suspend(struct device *dev)
+static int max98373_suspend(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
int i;
@@ -262,7 +262,7 @@ static __maybe_unused int max98373_suspend(struct device *dev)
#define MAX98373_PROBE_TIMEOUT 5000
-static __maybe_unused int max98373_resume(struct device *dev)
+static int max98373_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct max98373_priv *max98373 = dev_get_drvdata(dev);
@@ -292,8 +292,8 @@ regmap_sync:
}
static const struct dev_pm_ops max98373_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
- SET_RUNTIME_PM_OPS(max98373_suspend, max98373_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume)
+ RUNTIME_PM_OPS(max98373_suspend, max98373_resume, NULL)
};
static int max98373_read_prop(struct sdw_slave *slave)
@@ -874,7 +874,7 @@ static struct sdw_driver max98373_sdw_driver = {
.name = "max98373",
.of_match_table = of_match_ptr(max98373_of_match),
.acpi_match_table = ACPI_PTR(max98373_acpi_match),
- .pm = &max98373_pm,
+ .pm = pm_ptr(&max98373_pm),
},
.probe = max98373_sdw_probe,
.remove = max98373_sdw_remove,
diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c
index 1bae253618fd..76296176f948 100644
--- a/sound/soc/codecs/max98390.c
+++ b/sound/soc/codecs/max98390.c
@@ -943,7 +943,6 @@ static int max98390_probe(struct snd_soc_component *component)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int max98390_suspend(struct device *dev)
{
struct max98390_priv *max98390 = dev_get_drvdata(dev);
@@ -967,10 +966,9 @@ static int max98390_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops max98390_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume)
+ SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume)
};
static const struct snd_soc_component_driver soc_codec_dev_max98390 = {
@@ -1130,7 +1128,7 @@ static struct i2c_driver max98390_i2c_driver = {
.name = "max98390",
.of_match_table = of_match_ptr(max98390_of_match),
.acpi_match_table = ACPI_PTR(max98390_acpi_match),
- .pm = &max98390_pm,
+ .pm = pm_ptr(&max98390_pm),
},
.probe = max98390_i2c_probe,
.id_table = max98390_i2c_id,
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c
index e52bb2266fa1..c1888cd83dbc 100644
--- a/sound/soc/codecs/max98396.c
+++ b/sound/soc/codecs/max98396.c
@@ -1571,7 +1571,6 @@ static int max98396_probe(struct snd_soc_component *component)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int max98396_suspend(struct device *dev)
{
struct max98396_priv *max98396 = dev_get_drvdata(dev);
@@ -1616,10 +1615,9 @@ static int max98396_resume(struct device *dev)
regcache_sync(max98396->regmap);
return 0;
}
-#endif
static const struct dev_pm_ops max98396_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume)
+ SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume)
};
static const struct snd_soc_component_driver soc_codec_dev_max98396 = {
@@ -1904,7 +1902,7 @@ static struct i2c_driver max98396_i2c_driver = {
.name = "max98396",
.of_match_table = of_match_ptr(max98396_of_match),
.acpi_match_table = ACPI_PTR(max98396_acpi_match),
- .pm = &max98396_pm,
+ .pm = pm_ptr(&max98396_pm),
},
.probe = max98396_i2c_probe,
.id_table = max98396_i2c_id,
diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c
index 479ded22672e..adf5a898c6df 100644
--- a/sound/soc/codecs/max98520.c
+++ b/sound/soc/codecs/max98520.c
@@ -621,7 +621,7 @@ static int max98520_probe(struct snd_soc_component *component)
return 0;
}
-static int __maybe_unused max98520_suspend(struct device *dev)
+static int max98520_suspend(struct device *dev)
{
struct max98520_priv *max98520 = dev_get_drvdata(dev);
@@ -630,7 +630,7 @@ static int __maybe_unused max98520_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused max98520_resume(struct device *dev)
+static int max98520_resume(struct device *dev)
{
struct max98520_priv *max98520 = dev_get_drvdata(dev);
@@ -641,7 +641,7 @@ static int __maybe_unused max98520_resume(struct device *dev)
}
static const struct dev_pm_ops max98520_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(max98520_suspend, max98520_resume)
+ SYSTEM_SLEEP_PM_OPS(max98520_suspend, max98520_resume)
};
static const struct snd_soc_component_driver soc_codec_dev_max98520 = {
@@ -752,7 +752,7 @@ static struct i2c_driver max98520_i2c_driver = {
.driver = {
.name = "max98520",
.of_match_table = of_match_ptr(max98520_of_match),
- .pm = &max98520_pm,
+ .pm = pm_ptr(&max98520_pm),
},
.probe = max98520_i2c_probe,
.id_table = max98520_i2c_id,
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c
index 4015ed2c47ec..716d16daf7d7 100644
--- a/sound/soc/codecs/max9860.c
+++ b/sound/soc/codecs/max9860.c
@@ -539,7 +539,6 @@ static const struct snd_soc_component_driver max9860_component_driver = {
.endianness = 1,
};
-#ifdef CONFIG_PM
static int max9860_suspend(struct device *dev)
{
struct max9860_priv *max9860 = dev_get_drvdata(dev);
@@ -584,10 +583,9 @@ static int max9860_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops max9860_pm_ops = {
- SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL)
+ RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL)
};
static int max9860_probe(struct i2c_client *i2c)
@@ -729,7 +727,7 @@ static struct i2c_driver max9860_i2c_driver = {
.driver = {
.name = "max9860",
.of_match_table = max9860_of_match,
- .pm = &max9860_pm_ops,
+ .pm = pm_ptr(&max9860_pm_ops),
},
};
diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c
index 747aa6f1d54f..55cc18451a2d 100644
--- a/sound/soc/codecs/max98927.c
+++ b/sound/soc/codecs/max98927.c
@@ -731,7 +731,6 @@ static int max98927_probe(struct snd_soc_component *component)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int max98927_suspend(struct device *dev)
{
struct max98927_priv *max98927 = dev_get_drvdata(dev);
@@ -750,10 +749,9 @@ static int max98927_resume(struct device *dev)
regcache_sync(max98927->regmap);
return 0;
}
-#endif
static const struct dev_pm_ops max98927_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume)
+ SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume)
};
static const struct snd_soc_component_driver soc_component_dev_max98927 = {
@@ -902,7 +900,7 @@ static struct i2c_driver max98927_i2c_driver = {
.name = "max98927",
.of_match_table = of_match_ptr(max98927_of_match),
.acpi_match_table = ACPI_PTR(max98927_acpi_match),
- .pm = &max98927_pm,
+ .pm = pm_ptr(&max98927_pm),
},
.probe = max98927_i2c_probe,
.remove = max98927_i2c_remove,
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c
index 9247b90d1b99..e033027fd4c7 100644
--- a/sound/soc/codecs/mt6358.c
+++ b/sound/soc/codecs/mt6358.c
@@ -162,47 +162,6 @@ static void capture_gpio_reset(struct mt6358_priv *priv)
0xf << 12, 0x0);
}
-/* use only when not govern by DAPM */
-static int mt6358_set_dcxo(struct mt6358_priv *priv, bool enable)
-{
- regmap_update_bits(priv->regmap, MT6358_DCXO_CW14,
- 0x1 << RG_XO_AUDIO_EN_M_SFT,
- (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT);
- return 0;
-}
-
-/* use only when not govern by DAPM */
-static int mt6358_set_clksq(struct mt6358_priv *priv, bool enable)
-{
- /* audio clk source from internal dcxo */
- regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
- RG_CLKSQ_IN_SEL_TEST_MASK_SFT,
- 0x0);
-
- /* Enable/disable CLKSQ 26MHz */
- regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6,
- RG_CLKSQ_EN_MASK_SFT,
- (enable ? 1 : 0) << RG_CLKSQ_EN_SFT);
- return 0;
-}
-
-/* use only when not govern by DAPM */
-static int mt6358_set_aud_global_bias(struct mt6358_priv *priv, bool enable)
-{
- regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13,
- RG_AUDGLB_PWRDN_VA28_MASK_SFT,
- (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA28_SFT);
- return 0;
-}
-
-/* use only when not govern by DAPM */
-static int mt6358_set_topck(struct mt6358_priv *priv, bool enable)
-{
- regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0,
- 0x0066, enable ? 0x0 : 0x66);
- return 0;
-}
-
static int mt6358_mtkaif_tx_enable(struct mt6358_priv *priv)
{
switch (priv->mtkaif_protocol) {
@@ -252,69 +211,6 @@ static int mt6358_mtkaif_tx_disable(struct mt6358_priv *priv)
return 0;
}
-int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt)
-{
- struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
-
- playback_gpio_set(priv);
- capture_gpio_set(priv);
- mt6358_mtkaif_tx_enable(priv);
-
- mt6358_set_dcxo(priv, true);
- mt6358_set_aud_global_bias(priv, true);
- mt6358_set_clksq(priv, true);
- mt6358_set_topck(priv, true);
-
- /* set dat_miso_loopback on */
- regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
- RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
- 1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
- regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
- RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
- 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable);
-
-int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt)
-{
- struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
-
- /* set dat_miso_loopback off */
- regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
- RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT,
- 0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT);
- regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
- RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT,
- 0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT);
-
- mt6358_set_topck(priv, false);
- mt6358_set_clksq(priv, false);
- mt6358_set_aud_global_bias(priv, false);
- mt6358_set_dcxo(priv, false);
-
- mt6358_mtkaif_tx_disable(priv);
- playback_gpio_reset(priv);
- capture_gpio_reset(priv);
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable);
-
-int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
- int phase_1, int phase_2)
-{
- struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt);
-
- regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
- RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT,
- phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT);
- regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG,
- RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT,
- phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT);
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase);
-
/* dl pga gain */
enum {
DL_GAIN_8DB = 0,
diff --git a/sound/soc/codecs/mt6358.h b/sound/soc/codecs/mt6358.h
index a5953315eaa2..b729c3899b7e 100644
--- a/sound/soc/codecs/mt6358.h
+++ b/sound/soc/codecs/mt6358.h
@@ -2307,8 +2307,4 @@ enum {
/* set only during init */
int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt,
int mtkaif_protocol);
-int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt);
-int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt);
-int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt,
- int phase_1, int phase_2);
#endif /* __MT6358_H__ */
diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h
index c234f2f4276a..78ada3a5bfae 100644
--- a/sound/soc/codecs/mt6359-accdet.h
+++ b/sound/soc/codecs/mt6359-accdet.h
@@ -123,6 +123,15 @@ struct mt6359_accdet {
struct workqueue_struct *jd_workqueue;
};
+#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET)
int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *jack);
+#else
+static inline int
+mt6359_accdet_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack)
+{
+ return -EOPNOTSUPP;
+}
+#endif
#endif
diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c
index 0b76a55664b0..f73120c6a6ce 100644
--- a/sound/soc/codecs/mt6359.c
+++ b/sound/soc/codecs/mt6359.c
@@ -2867,9 +2867,12 @@ static int mt6359_parse_dt(struct mt6359_priv *priv)
struct device *dev = priv->dev;
struct device_node *np;
- np = of_get_child_by_name(dev->parent->of_node, "mt6359codec");
- if (!np)
- return -EINVAL;
+ np = of_get_child_by_name(dev->parent->of_node, "audio-codec");
+ if (!np) {
+ np = of_get_child_by_name(dev->parent->of_node, "mt6359codec");
+ if (!np)
+ return -EINVAL;
+ }
ret = of_property_read_u32(np, "mediatek,dmic-mode",
&priv->dmic_one_wire_mode);
diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c
index 39a57f643d81..d16bccebae52 100644
--- a/sound/soc/codecs/mt6660.c
+++ b/sound/soc/codecs/mt6660.c
@@ -529,7 +529,7 @@ static void mt6660_i2c_remove(struct i2c_client *client)
mutex_destroy(&chip->io_lock);
}
-static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev)
+static int mt6660_i2c_runtime_suspend(struct device *dev)
{
struct mt6660_chip *chip = dev_get_drvdata(dev);
@@ -538,7 +538,7 @@ static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev)
MT6660_REG_SYSTEM_CTRL, 0x01, 0x01);
}
-static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev)
+static int mt6660_i2c_runtime_resume(struct device *dev)
{
struct mt6660_chip *chip = dev_get_drvdata(dev);
@@ -548,8 +548,7 @@ static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops mt6660_dev_pm_ops = {
- SET_RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend,
- mt6660_i2c_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend, mt6660_i2c_runtime_resume, NULL)
};
static const struct of_device_id __maybe_unused mt6660_of_id[] = {
@@ -568,7 +567,7 @@ static struct i2c_driver mt6660_i2c_driver = {
.driver = {
.name = "mt6660",
.of_match_table = of_match_ptr(mt6660_of_id),
- .pm = &mt6660_dev_pm_ops,
+ .pm = pm_ptr(&mt6660_dev_pm_ops),
},
.probe = mt6660_i2c_probe,
.remove = mt6660_i2c_remove,
diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c
index 7e59448e7ac6..caf2edb23088 100644
--- a/sound/soc/codecs/nau8540.c
+++ b/sound/soc/codecs/nau8540.c
@@ -482,10 +482,10 @@ static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int ctrl1_val = 0, ctrl2_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ctrl2_val |= NAU8540_I2S_MS_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c
index dc3aaca89919..6f432b992941 100644
--- a/sound/soc/codecs/nau8810.c
+++ b/sound/soc/codecs/nau8810.c
@@ -613,10 +613,10 @@ static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai,
u16 ctrl1_val = 0, ctrl2_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ctrl2_val |= NAU8810_CLKIO_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c
index fd4a96a12060..15d6f8d01f78 100644
--- a/sound/soc/codecs/nau8822.c
+++ b/sound/soc/codecs/nau8822.c
@@ -806,10 +806,10 @@ static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
dev_dbg(component->dev, "%s\n", __func__);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ctrl2_val |= 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
ctrl2_val &= ~1;
break;
default:
diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
index 12540397fd4d..542bd22e6180 100644
--- a/sound/soc/codecs/nau8824.c
+++ b/sound/soc/codecs/nau8824.c
@@ -368,13 +368,13 @@ static const struct snd_kcontrol_new nau8824_snd_controls[] = {
SOC_ENUM("DAC Oversampling Rate", nau8824_dac_oversampl_enum),
SOC_SINGLE_TLV("Speaker Right DACR Volume",
- NAU8824_REG_CLASSD_GAIN_1, 8, 0x1f, 0, spk_vol_tlv),
+ NAU8824_REG_CLASSD_GAIN_1, 8, 0x19, 0, spk_vol_tlv),
SOC_SINGLE_TLV("Speaker Left DACL Volume",
- NAU8824_REG_CLASSD_GAIN_2, 0, 0x1f, 0, spk_vol_tlv),
+ NAU8824_REG_CLASSD_GAIN_2, 0, 0x19, 0, spk_vol_tlv),
SOC_SINGLE_TLV("Speaker Left DACR Volume",
- NAU8824_REG_CLASSD_GAIN_1, 0, 0x1f, 0, spk_vol_tlv),
+ NAU8824_REG_CLASSD_GAIN_1, 0, 0x19, 0, spk_vol_tlv),
SOC_SINGLE_TLV("Speaker Right DACL Volume",
- NAU8824_REG_CLASSD_GAIN_2, 8, 0x1f, 0, spk_vol_tlv),
+ NAU8824_REG_CLASSD_GAIN_2, 8, 0x19, 0, spk_vol_tlv),
SOC_SINGLE_TLV("Headphone Right DACR Volume",
NAU8824_REG_ATT_PORT0, 8, 0x1f, 0, hp_vol_tlv),
@@ -1159,10 +1159,10 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int ctrl1_val = 0, ctrl2_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ctrl2_val |= NAU8824_I2S_MS_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index bde25bc6909d..25b8b19e27ec 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1356,10 +1356,10 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
unsigned int ctrl1_val = 0, ctrl2_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ctrl2_val |= NAU8825_I2S_MS_MASTER;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/ntp8835.c b/sound/soc/codecs/ntp8835.c
index 796e1410496f..2cc4c6395f55 100644
--- a/sound/soc/codecs/ntp8835.c
+++ b/sound/soc/codecs/ntp8835.c
@@ -454,7 +454,7 @@ static int ntp8835_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ntp8835_i2c_id[] = {
- { "ntp8835", 0 },
+ { "ntp8835" },
{}
};
MODULE_DEVICE_TABLE(i2c, ntp8835_i2c_id);
diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c
index 0493ab6acbe4..5593d48ef696 100644
--- a/sound/soc/codecs/ntp8918.c
+++ b/sound/soc/codecs/ntp8918.c
@@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
-#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
@@ -371,7 +370,7 @@ static int ntp8918_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ntp8918_i2c_id[] = {
- { "ntp8918", 0 },
+ { "ntp8918" },
{}
};
MODULE_DEVICE_TABLE(i2c, ntp8918_i2c_id);
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
index fc152496d5dc..a1ec881d7084 100644
--- a/sound/soc/codecs/pcm1681.c
+++ b/sound/soc/codecs/pcm1681.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/of.h>
diff --git a/sound/soc/codecs/pcm186x-i2c.c b/sound/soc/codecs/pcm186x-i2c.c
index a514ebd1b68a..a50f9f6e39c1 100644
--- a/sound/soc/codecs/pcm186x-i2c.c
+++ b/sound/soc/codecs/pcm186x-i2c.c
@@ -33,8 +33,7 @@ MODULE_DEVICE_TABLE(i2c, pcm186x_i2c_id);
static int pcm186x_i2c_probe(struct i2c_client *i2c)
{
- const struct i2c_device_id *id = i2c_match_id(pcm186x_i2c_id, i2c);
- const enum pcm186x_type type = (enum pcm186x_type)id->driver_data;
+ const enum pcm186x_type type = (uintptr_t)i2c_get_match_data(i2c);
int irq = i2c->irq;
struct regmap *regmap;
diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c
index 09c6c1326833..d3d2e7f40170 100644
--- a/sound/soc/codecs/pcm3008.c
+++ b/sound/soc/codecs/pcm3008.c
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
@@ -22,17 +22,22 @@
#include <sound/initval.h>
#include <sound/soc.h>
-#include "pcm3008.h"
+struct pcm3008 {
+ struct gpio_desc *dem0_pin;
+ struct gpio_desc *dem1_pin;
+ struct gpio_desc *pdad_pin;
+ struct gpio_desc *pdda_pin;
+};
static int pcm3008_dac_ev(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 pcm3008_setup_data *setup = component->dev->platform_data;
+ struct pcm3008 *pcm = component->dev->platform_data;
- gpio_set_value_cansleep(setup->pdda_pin,
- SND_SOC_DAPM_EVENT_ON(event));
+ gpiod_set_value_cansleep(pcm->pdda_pin,
+ SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
@@ -42,10 +47,10 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
int event)
{
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
- struct pcm3008_setup_data *setup = component->dev->platform_data;
+ struct pcm3008 *pcm = component->dev->platform_data;
- gpio_set_value_cansleep(setup->pdad_pin,
- SND_SOC_DAPM_EVENT_ON(event));
+ gpiod_set_value_cansleep(pcm->pdad_pin,
+ SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
@@ -106,11 +111,13 @@ static const struct snd_soc_component_driver soc_component_dev_pcm3008 = {
static int pcm3008_codec_probe(struct platform_device *pdev)
{
- struct pcm3008_setup_data *setup = pdev->dev.platform_data;
- int ret;
+ struct device *dev = &pdev->dev;
+ struct pcm3008 *pcm;
- if (!setup)
- return -EINVAL;
+ pcm = devm_kzalloc(dev, sizeof(*pcm), GFP_KERNEL);
+ if (!pcm)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, pcm);
/* DEM1 DEM0 DE-EMPHASIS_MODE
* Low Low De-emphasis 44.1 kHz ON
@@ -120,30 +127,26 @@ static int pcm3008_codec_probe(struct platform_device *pdev)
*/
/* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
- ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
- GPIOF_OUT_INIT_HIGH, "codec_dem0");
- if (ret != 0)
- return ret;
+ pcm->dem0_pin = devm_gpiod_get(dev, "dem0", GPIOD_OUT_HIGH);
+ if (IS_ERR(pcm->dem0_pin))
+ return PTR_ERR(pcm->dem0_pin);
/* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
- ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
- GPIOF_OUT_INIT_LOW, "codec_dem1");
- if (ret != 0)
- return ret;
+ pcm->dem1_pin = devm_gpiod_get(dev, "dem1", GPIOD_OUT_LOW);
+ if (IS_ERR(pcm->dem1_pin))
+ return PTR_ERR(pcm->dem1_pin);
/* Configure PDAD GPIO. */
- ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
- GPIOF_OUT_INIT_LOW, "codec_pdad");
- if (ret != 0)
- return ret;
+ pcm->pdad_pin = devm_gpiod_get(dev, "pdad", GPIOD_OUT_LOW);
+ if (IS_ERR(pcm->pdad_pin))
+ return PTR_ERR(pcm->pdad_pin);
/* Configure PDDA GPIO. */
- ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
- GPIOF_OUT_INIT_LOW, "codec_pdda");
- if (ret != 0)
- return ret;
+ pcm->pdda_pin = devm_gpiod_get(dev, "pdda", GPIOD_OUT_LOW);
+ if (IS_ERR(pcm->pdda_pin))
+ return PTR_ERR(pcm->pdda_pin);
- return devm_snd_soc_register_component(&pdev->dev,
+ return devm_snd_soc_register_component(dev,
&soc_component_dev_pcm3008, &pcm3008_dai, 1);
}
diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h
deleted file mode 100644
index f7f4fbbd89db..000000000000
--- a/sound/soc/codecs/pcm3008.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * PCM3008 ALSA SoC Layer
- *
- * Author: Hugo Villeneuve
- * Copyright (C) 2008 Lyrtech inc
- */
-
-#ifndef __LINUX_SND_SOC_PCM3008_H
-#define __LINUX_SND_SOC_PCM3008_H
-
-struct pcm3008_setup_data {
- unsigned dem0_pin;
- unsigned dem1_pin;
- unsigned pdad_pin;
- unsigned pdda_pin;
-};
-
-#endif
diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c
index 7052cc0c97d1..ff18c74b616c 100644
--- a/sound/soc/codecs/pcm3168a-i2c.c
+++ b/sound/soc/codecs/pcm3168a-i2c.c
@@ -10,6 +10,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <sound/soc.h>
@@ -37,6 +38,13 @@ static const struct i2c_device_id pcm3168a_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id);
+static const struct acpi_device_id pcm3168a_acpi_match[] = {
+ { "PCM3168A" },
+ { "104C3168" },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, pcm3168a_acpi_match);
+
static const struct of_device_id pcm3168a_of_match[] = {
{ .compatible = "ti,pcm3168a", },
{ }
@@ -49,8 +57,9 @@ static struct i2c_driver pcm3168a_i2c_driver = {
.id_table = pcm3168a_i2c_id,
.driver = {
.name = "pcm3168a",
+ .acpi_match_table = pcm3168a_acpi_match,
.of_match_table = pcm3168a_of_match,
- .pm = &pcm3168a_pm_ops,
+ .pm = pm_ptr(&pcm3168a_pm_ops),
},
};
module_i2c_driver(pcm3168a_i2c_driver);
diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c
index b5b08046f545..0871338eacba 100644
--- a/sound/soc/codecs/pcm3168a-spi.c
+++ b/sound/soc/codecs/pcm3168a-spi.c
@@ -50,7 +50,7 @@ static struct spi_driver pcm3168a_spi_driver = {
.driver = {
.name = "pcm3168a",
.of_match_table = pcm3168a_of_match,
- .pm = &pcm3168a_pm_ops,
+ .pm = pm_ptr(&pcm3168a_pm_ops),
},
};
module_spi_driver(pcm3168a_spi_driver);
diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c
index fac0617ab95b..c8617a488b11 100644
--- a/sound/soc/codecs/pcm3168a.c
+++ b/sound/soc/codecs/pcm3168a.c
@@ -493,9 +493,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
}
break;
case 24:
- if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) ||
- (format == SND_SOC_DAIFMT_DSP_B)) {
- dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n");
+ if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) ||
+ (format == SND_SOC_DAIFMT_DSP_B))) {
+ dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n");
return -EINVAL;
}
break;
@@ -743,7 +743,7 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst),
"failed to acquire RST gpio\n");
- pcm3168a->scki = devm_clk_get(dev, "scki");
+ pcm3168a->scki = devm_clk_get_optional(dev, "scki");
if (IS_ERR(pcm3168a->scki))
return dev_err_probe(dev, PTR_ERR(pcm3168a->scki),
"failed to acquire clock 'scki'\n");
@@ -755,6 +755,9 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
}
pcm3168a->sysclk = clk_get_rate(pcm3168a->scki);
+ /* Fallback to the default if no clk entry available. */
+ if (!pcm3168a->sysclk)
+ pcm3168a->sysclk = 24576000;
for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++)
pcm3168a->supplies[i].supply = pcm3168a_supply_names[i];
@@ -846,7 +849,6 @@ void pcm3168a_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(pcm3168a_remove);
-#ifdef CONFIG_PM
static int pcm3168a_rt_resume(struct device *dev)
{
struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev);
@@ -902,12 +904,10 @@ static int pcm3168a_rt_suspend(struct device *dev)
return 0;
}
-#endif
-const struct dev_pm_ops pcm3168a_pm_ops = {
- SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
+EXPORT_GPL_DEV_PM_OPS(pcm3168a_pm_ops) = {
+ RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL)
};
-EXPORT_SYMBOL_GPL(pcm3168a_pm_ops);
MODULE_DESCRIPTION("PCM3168A codec driver");
MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>");
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c
index 92bcf5179779..a1d849b0c50f 100644
--- a/sound/soc/codecs/pcm512x-i2c.c
+++ b/sound/soc/codecs/pcm512x-i2c.c
@@ -79,7 +79,7 @@ static struct i2c_driver pcm512x_i2c_driver = {
.name = "pcm512x",
.of_match_table = of_match_ptr(pcm512x_of_match),
.acpi_match_table = ACPI_PTR(pcm512x_acpi_match),
- .pm = &pcm512x_pm_ops,
+ .pm = pm_ptr(&pcm512x_pm_ops),
},
};
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c
index 6629b862f47d..92f7f78a4e20 100644
--- a/sound/soc/codecs/pcm512x-spi.c
+++ b/sound/soc/codecs/pcm512x-spi.c
@@ -58,7 +58,7 @@ static struct spi_driver pcm512x_spi_driver = {
.driver = {
.name = "pcm512x",
.of_match_table = pcm512x_of_match,
- .pm = &pcm512x_pm_ops,
+ .pm = pm_ptr(&pcm512x_pm_ops),
},
};
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index aa8edf87b743..007dfc0fa224 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -1725,7 +1725,6 @@ void pcm512x_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(pcm512x_remove);
-#ifdef CONFIG_PM
static int pcm512x_suspend(struct device *dev)
{
struct pcm512x_priv *pcm512x = dev_get_drvdata(dev);
@@ -1787,12 +1786,10 @@ static int pcm512x_resume(struct device *dev)
return 0;
}
-#endif
-const struct dev_pm_ops pcm512x_pm_ops = {
- SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
+EXPORT_GPL_DEV_PM_OPS(pcm512x_pm_ops) = {
+ RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL)
};
-EXPORT_SYMBOL_GPL(pcm512x_pm_ops);
MODULE_DESCRIPTION("ASoC PCM512x codec driver");
MODULE_AUTHOR("Mark Brown <broonie@kernel.org>");
diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c
index 5d99877f8839..b2bd2f172ae7 100644
--- a/sound/soc/codecs/pcm6240.c
+++ b/sound/soc/codecs/pcm6240.c
@@ -14,7 +14,7 @@
#include <linux/unaligned.h>
#include <linux/firmware.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_irq.h>
@@ -2035,10 +2035,8 @@ static const struct regmap_config pcmdevice_i2c_regmap = {
static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev)
{
- if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
- gpio_free(pcm_dev->irq_info.gpio);
- free_irq(pcm_dev->irq_info.nmb, pcm_dev);
- }
+ if (pcm_dev->irq)
+ free_irq(pcm_dev->irq, pcm_dev);
mutex_destroy(&pcm_dev->codec_lock);
}
@@ -2059,7 +2057,6 @@ static char *str_to_upper(char *str)
static int pcmdevice_i2c_probe(struct i2c_client *i2c)
{
- const struct i2c_device_id *id = i2c_match_id(pcmdevice_i2c_id, i2c);
struct pcmdevice_priv *pcm_dev;
struct device_node *np;
unsigned int dev_addrs[PCMDEVICE_MAX_I2C_DEVICES];
@@ -2069,7 +2066,7 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
if (!pcm_dev)
return -ENOMEM;
- pcm_dev->chip_id = (id != NULL) ? id->driver_data : 0;
+ pcm_dev->chip_id = (uintptr_t)i2c_get_match_data(i2c);
pcm_dev->dev = &i2c->dev;
pcm_dev->client = i2c;
@@ -2110,7 +2107,7 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
ndev = 1;
dev_addrs[0] = i2c->addr;
}
- pcm_dev->irq_info.gpio = of_irq_get(np, 0);
+ pcm_dev->irq = of_irq_get(np, 0);
for (i = 0; i < ndev; i++)
pcm_dev->addr[i] = dev_addrs[i];
@@ -2133,22 +2130,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c)
if (pcm_dev->chip_id == PCM1690)
goto skip_interrupt;
- if (gpio_is_valid(pcm_dev->irq_info.gpio)) {
- dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio);
-
- ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ");
- if (!ret) {
- int gpio = pcm_dev->irq_info.gpio;
-
- gpio_direction_input(gpio);
- pcm_dev->irq_info.nmb = gpio_to_irq(gpio);
-
- } else
- dev_err(pcm_dev->dev, "%s: GPIO %d request error\n",
- __func__, pcm_dev->irq_info.gpio);
+ if (pcm_dev->irq) {
+ dev_dbg(pcm_dev->dev, "irq = %d", pcm_dev->irq);
} else
- dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n",
- pcm_dev->irq_info.gpio);
+ dev_err(pcm_dev->dev, "No irq provided\n");
skip_interrupt:
ret = devm_snd_soc_register_component(&i2c->dev,
diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h
index 1e125bb97286..2d8f9e798139 100644
--- a/sound/soc/codecs/pcm6240.h
+++ b/sound/soc/codecs/pcm6240.h
@@ -208,11 +208,6 @@ struct pcmdevice_regbin {
struct pcmdevice_config_info **cfg_info;
};
-struct pcmdevice_irqinfo {
- int gpio;
- int nmb;
-};
-
struct pcmdevice_priv {
struct snd_soc_component *component;
struct i2c_client *client;
@@ -221,7 +216,7 @@ struct pcmdevice_priv {
struct gpio_desc *hw_rst;
struct regmap *regmap;
struct pcmdevice_regbin regbin;
- struct pcmdevice_irqinfo irq_info;
+ int irq;
unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES];
unsigned int chip_id;
int cur_conf;
diff --git a/sound/soc/codecs/peb2466.c b/sound/soc/codecs/peb2466.c
index bb9ca6354ae1..a989cfe058f0 100644
--- a/sound/soc/codecs/peb2466.c
+++ b/sound/soc/codecs/peb2466.c
@@ -26,8 +26,7 @@ struct peb2466_lookup {
unsigned int count;
};
-#define PEB2466_TLV_SIZE (sizeof((unsigned int []){TLV_DB_SCALE_ITEM(0, 0, 0)}) / \
- sizeof(unsigned int))
+#define PEB2466_TLV_SIZE ARRAY_SIZE(((unsigned int[]){TLV_DB_SCALE_ITEM(0, 0, 0)}))
struct peb2466_lkup_ctrl {
int reg;
diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c
index 3c5b66357661..3c9957b00881 100644
--- a/sound/soc/codecs/rk817_codec.c
+++ b/sound/soc/codecs/rk817_codec.c
@@ -303,10 +303,10 @@ static int rk817_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int i2s_mst = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
i2s_mst |= RK817_I2S_MODE_SLV;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
i2s_mst |= RK817_I2S_MODE_MST;
break;
default:
diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c
index a0e75b03e9dc..b84dd18ddde9 100644
--- a/sound/soc/codecs/rt1011.c
+++ b/sound/soc/codecs/rt1011.c
@@ -1671,7 +1671,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
snd_soc_dapm_mutex_lock(dapm);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT1011_I2S_TDM_MS_S;
break;
default:
@@ -2192,15 +2192,15 @@ static const struct regmap_config rt1011_regmap = {
#if defined(CONFIG_OF)
static const struct of_device_id rt1011_of_match[] = {
{ .compatible = "realtek,rt1011", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt1011_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1011_acpi_match[] = {
- {"10EC1011", 0,},
- {},
+ { "10EC1011" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1011_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c
index 0f806dde9c39..818b45226b72 100644
--- a/sound/soc/codecs/rt1015.c
+++ b/sound/soc/codecs/rt1015.c
@@ -753,10 +753,10 @@ static int rt1015_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0, reg_val2 = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
reg_val |= RT1015_TCON_TDM_MS_M;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT1015_TCON_TDM_MS_S;
break;
default:
@@ -1105,15 +1105,15 @@ MODULE_DEVICE_TABLE(i2c, rt1015_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id rt1015_of_match[] = {
{ .compatible = "realtek,rt1015", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt1015_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1015_acpi_match[] = {
- {"10EC1015", 0,},
- {},
+ { "10EC1015" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1015_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c
index fed4da23cba2..9f86f071fca8 100644
--- a/sound/soc/codecs/rt1016.c
+++ b/sound/soc/codecs/rt1016.c
@@ -367,11 +367,11 @@ static int rt1016_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
reg_val |= RT1016_I2S_MS_M;
rt1016->master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT1016_I2S_MS_S;
break;
default:
@@ -616,15 +616,15 @@ MODULE_DEVICE_TABLE(i2c, rt1016_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id rt1016_of_match[] = {
{ .compatible = "realtek,rt1016", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt1016_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1016_acpi_match[] = {
- {"10EC1016", 0,},
- {},
+ { "10EC1016" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1016_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index 7c8103a0d562..88fc23a4999f 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -758,7 +758,7 @@ static const struct sdw_device_id rt1017_sdca_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id);
-static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev)
+static int rt1017_sdca_dev_suspend(struct device *dev)
{
struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
@@ -772,7 +772,7 @@ static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev)
#define RT1017_PROBE_TIMEOUT 5000
-static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev)
+static int rt1017_sdca_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev);
@@ -802,14 +802,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt1017_sdca_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume)
- SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL)
};
static struct sdw_driver rt1017_sdca_sdw_driver = {
.driver = {
.name = "rt1017-sdca",
- .pm = &rt1017_sdca_pm,
+ .pm = pm_ptr(&rt1017_sdca_pm),
},
.probe = rt1017_sdca_sdw_probe,
.remove = rt1017_sdca_sdw_remove,
diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c
index d989d06a2614..86539c6f6cc1 100644
--- a/sound/soc/codecs/rt1019.c
+++ b/sound/soc/codecs/rt1019.c
@@ -547,14 +547,14 @@ MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id);
static const struct of_device_id rt1019_of_match[] __maybe_unused = {
{ .compatible = "realtek,rt1019", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt1019_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1019_acpi_match[] = {
- { "10EC1019", 0},
- { },
+ { "10EC1019" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c
index c2b55be8d165..26b7382f97ef 100644
--- a/sound/soc/codecs/rt1305.c
+++ b/sound/soc/codecs/rt1305.c
@@ -697,11 +697,11 @@ static int rt1305_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0, reg1_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
reg_val |= RT1305_SEL_I2S_OUT_MODE_M;
rt1305->master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT1305_SEL_I2S_OUT_MODE_S;
rt1305->master = 0;
break;
@@ -966,16 +966,16 @@ static const struct regmap_config rt1305_regmap = {
static const struct of_device_id rt1305_of_match[] = {
{ .compatible = "realtek,rt1305", },
{ .compatible = "realtek,rt1306", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt1305_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1305_acpi_match[] = {
- {"10EC1305", 0,},
- {"10EC1306", 0,},
- {},
+ { "10EC1305" },
+ { "10EC1306" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1305_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 563df483a466..ea708068f0e8 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -753,7 +753,7 @@ static const struct sdw_device_id rt1308_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt1308_id);
-static int __maybe_unused rt1308_dev_suspend(struct device *dev)
+static int rt1308_dev_suspend(struct device *dev)
{
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
@@ -767,7 +767,7 @@ static int __maybe_unused rt1308_dev_suspend(struct device *dev)
#define RT1308_PROBE_TIMEOUT 5000
-static int __maybe_unused rt1308_dev_resume(struct device *dev)
+static int rt1308_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
@@ -797,14 +797,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt1308_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume)
- SET_RUNTIME_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume)
+ RUNTIME_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume, NULL)
};
static struct sdw_driver rt1308_sdw_driver = {
.driver = {
.name = "rt1308",
- .pm = &rt1308_pm,
+ .pm = pm_ptr(&rt1308_pm),
},
.probe = rt1308_sdw_probe,
.remove = rt1308_sdw_remove,
diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c
index b366338cea71..df50b38c24b9 100644
--- a/sound/soc/codecs/rt1308.c
+++ b/sound/soc/codecs/rt1308.c
@@ -523,7 +523,7 @@ static int rt1308_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0, reg1_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
rt1308->master = 0;
break;
default:
@@ -781,15 +781,15 @@ static const struct regmap_config rt1308_regmap = {
#ifdef CONFIG_OF
static const struct of_device_id rt1308_of_match[] = {
{ .compatible = "realtek,rt1308", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, rt1308_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1308_acpi_match[] = {
- { "10EC1308", 0, },
- { },
+ { "10EC1308" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1308_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 22f1ed4e03f1..960b6c4f5a66 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -730,7 +730,7 @@ static const struct sdw_device_id rt1316_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt1316_id);
-static int __maybe_unused rt1316_dev_suspend(struct device *dev)
+static int rt1316_dev_suspend(struct device *dev)
{
struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
@@ -744,7 +744,7 @@ static int __maybe_unused rt1316_dev_suspend(struct device *dev)
#define RT1316_PROBE_TIMEOUT 5000
-static int __maybe_unused rt1316_dev_resume(struct device *dev)
+static int rt1316_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev);
@@ -774,14 +774,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt1316_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume)
- SET_RUNTIME_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume)
+ RUNTIME_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume, NULL)
};
static struct sdw_driver rt1316_sdw_driver = {
.driver = {
.name = "rt1316-sdca",
- .pm = &rt1316_pm,
+ .pm = pm_ptr(&rt1316_pm),
},
.probe = rt1316_sdw_probe,
.remove = rt1316_sdw_remove,
diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c
index 319f71f5e60d..4eb636e0c9ed 100644
--- a/sound/soc/codecs/rt1318-sdw.c
+++ b/sound/soc/codecs/rt1318-sdw.c
@@ -807,7 +807,7 @@ static const struct sdw_device_id rt1318_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt1318_id);
-static int __maybe_unused rt1318_dev_suspend(struct device *dev)
+static int rt1318_dev_suspend(struct device *dev)
{
struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
@@ -820,7 +820,7 @@ static int __maybe_unused rt1318_dev_suspend(struct device *dev)
#define RT1318_PROBE_TIMEOUT 5000
-static int __maybe_unused rt1318_dev_resume(struct device *dev)
+static int rt1318_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev);
@@ -848,14 +848,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt1318_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume)
- SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume)
+ RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL)
};
static struct sdw_driver rt1318_sdw_driver = {
.driver = {
.name = "rt1318-sdca",
- .pm = &rt1318_pm,
+ .pm = pm_ptr(&rt1318_pm),
},
.probe = rt1318_sdw_probe,
.remove = rt1318_sdw_remove,
diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c
index e12b1e96a53a..ae01b2ce630b 100644
--- a/sound/soc/codecs/rt1318.c
+++ b/sound/soc/codecs/rt1318.c
@@ -1147,14 +1147,14 @@ MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id);
static const struct of_device_id rt1318_of_match[] = {
{ .compatible = "realtek,rt1318", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt1318_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt1318_acpi_match[] = {
- { "10EC1318", 0},
- { },
+ { "10EC1318" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 3510c3819074..f51ba345a16e 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -535,6 +535,9 @@ static int rt1320_read_prop(struct sdw_slave *slave)
/* set the timeout values */
prop->clk_stop_timeout = 64;
+ /* BIOS may set wake_capable. Make sure it is 0 as wake events are disabled. */
+ prop->wake_capable = 0;
+
return 0;
}
@@ -1455,7 +1458,7 @@ static const struct sdw_device_id rt1320_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt1320_id);
-static int __maybe_unused rt1320_dev_suspend(struct device *dev)
+static int rt1320_dev_suspend(struct device *dev)
{
struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
@@ -1469,7 +1472,7 @@ static int __maybe_unused rt1320_dev_suspend(struct device *dev)
#define RT1320_PROBE_TIMEOUT 5000
-static int __maybe_unused rt1320_dev_resume(struct device *dev)
+static int rt1320_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev);
@@ -1498,14 +1501,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt1320_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume)
- SET_RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume)
+ RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL)
};
static struct sdw_driver rt1320_sdw_driver = {
.driver = {
.name = "rt1320-sdca",
- .pm = &rt1320_pm,
+ .pm = pm_ptr(&rt1320_pm),
},
.probe = rt1320_sdw_probe,
.remove = rt1320_sdw_remove,
diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c
index bd61a257d7b5..2c055c45111f 100644
--- a/sound/soc/codecs/rt274.c
+++ b/sound/soc/codecs/rt274.c
@@ -706,12 +706,12 @@ static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
snd_soc_component_update_bits(component,
RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M);
rt274->master = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
snd_soc_component_update_bits(component,
RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S);
rt274->master = false;
@@ -1091,7 +1091,7 @@ static const struct regmap_config rt274_regmap = {
#ifdef CONFIG_OF
static const struct of_device_id rt274_of_match[] = {
{.compatible = "realtek,rt274"},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt274_of_match);
#endif
@@ -1104,9 +1104,9 @@ MODULE_DEVICE_TABLE(i2c, rt274_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt274_acpi_match[] = {
- { "10EC0274", 0 },
- { "INT34C2", 0 },
- {},
+ { "10EC0274" },
+ { "INT34C2" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt274_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index d0f533120c33..fd8de8b49793 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -765,11 +765,11 @@ static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct snd_soc_component *component = dai->component;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
snd_soc_component_update_bits(component,
RT286_I2S_CTRL1, 0x800, 0x800);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
snd_soc_component_update_bits(component,
RT286_I2S_CTRL1, 0x800, 0x0);
break;
@@ -1083,8 +1083,9 @@ MODULE_DEVICE_TABLE(i2c, rt286_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt286_acpi_match[] = {
- { "INT343A", 0 },
- {},
+ { "10EC0286" },
+ { "INT343A" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c
index 13aef6c5e91c..ee3d9291eea6 100644
--- a/sound/soc/codecs/rt298.c
+++ b/sound/soc/codecs/rt298.c
@@ -829,11 +829,11 @@ static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct snd_soc_component *component = dai->component;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
snd_soc_component_update_bits(component,
RT298_I2S_CTRL1, 0x800, 0x800);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
snd_soc_component_update_bits(component,
RT298_I2S_CTRL1, 0x800, 0x0);
break;
@@ -1144,8 +1144,9 @@ MODULE_DEVICE_TABLE(i2c, rt298_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt298_acpi_match[] = {
- { "INT343A", 0 },
- {},
+ { "10EC0298" },
+ { "INT343A" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt298_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c
index f475c8cfadae..54d84581ec47 100644
--- a/sound/soc/codecs/rt5514-spi.c
+++ b/sound/soc/codecs/rt5514-spi.c
@@ -458,7 +458,7 @@ static int rt5514_spi_probe(struct spi_device *spi)
return 0;
}
-static int __maybe_unused rt5514_suspend(struct device *dev)
+static int rt5514_suspend(struct device *dev)
{
int irq = to_spi_device(dev)->irq;
@@ -468,7 +468,7 @@ static int __maybe_unused rt5514_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt5514_resume(struct device *dev)
+static int rt5514_resume(struct device *dev)
{
struct rt5514_dsp *rt5514_dsp = dev_get_drvdata(dev);
int irq = to_spi_device(dev)->irq;
@@ -490,7 +490,7 @@ static int __maybe_unused rt5514_resume(struct device *dev)
}
static const struct dev_pm_ops rt5514_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(rt5514_suspend, rt5514_resume)
+ SYSTEM_SLEEP_PM_OPS(rt5514_suspend, rt5514_resume)
};
static const struct of_device_id rt5514_of_match[] = {
@@ -502,7 +502,7 @@ MODULE_DEVICE_TABLE(of, rt5514_of_match);
static struct spi_driver rt5514_spi_driver = {
.driver = {
.name = "rt5514",
- .pm = &rt5514_pm_ops,
+ .pm = pm_ptr(&rt5514_pm_ops),
.of_match_table = of_match_ptr(rt5514_of_match),
},
.probe = rt5514_spi_probe,
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c
index 2b3c0f9e178c..ab9d81c32be8 100644
--- a/sound/soc/codecs/rt5514.c
+++ b/sound/soc/codecs/rt5514.c
@@ -1091,8 +1091,7 @@ static int rt5514_set_bias_level(struct snd_soc_component *component,
static int rt5514_probe(struct snd_soc_component *component)
{
struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component);
- struct platform_device *pdev = container_of(component->dev,
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(component->dev);
rt5514->mclk = devm_clk_get_optional(component->dev, "mclk");
if (IS_ERR(rt5514->mclk))
@@ -1207,15 +1206,15 @@ MODULE_DEVICE_TABLE(i2c, rt5514_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id rt5514_of_match[] = {
{ .compatible = "realtek,rt5514", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5514_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5514_acpi_match[] = {
- { "10EC5514", 0},
- {},
+ { "10EC5514" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5514_acpi_match);
#endif
@@ -1232,7 +1231,7 @@ static int rt5514_parse_dp(struct rt5514_priv *rt5514, struct device *dev)
return 0;
}
-static __maybe_unused int rt5514_i2c_resume(struct device *dev)
+static int rt5514_i2c_resume(struct device *dev)
{
struct rt5514_priv *rt5514 = dev_get_drvdata(dev);
unsigned int val;
@@ -1314,7 +1313,7 @@ static int rt5514_i2c_probe(struct i2c_client *i2c)
}
static const struct dev_pm_ops rt5514_i2_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume)
+ SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume)
};
static struct i2c_driver rt5514_i2c_driver = {
@@ -1322,7 +1321,7 @@ static struct i2c_driver rt5514_i2c_driver = {
.name = "rt5514",
.acpi_match_table = ACPI_PTR(rt5514_acpi_match),
.of_match_table = of_match_ptr(rt5514_of_match),
- .pm = &rt5514_i2_pm_ops,
+ .pm = pm_ptr(&rt5514_i2_pm_ops),
},
.probe = rt5514_i2c_probe,
.id_table = rt5514_i2c_id,
diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c
index 34461c462009..1ec486707ff9 100644
--- a/sound/soc/codecs/rt5616.c
+++ b/sound/soc/codecs/rt5616.c
@@ -1015,10 +1015,10 @@ static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5616->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5616_I2S_MS_S;
rt5616->master[dai->id] = 0;
break;
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 12df0c4f2097..d523477c5102 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1411,10 +1411,10 @@ static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
dev_dbg(component->dev, "enter %s\n", __func__);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5631->master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
iface |= RT5631_SDP_MODE_SEL_SLAVE;
rt5631->master = 0;
break;
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index 855139348edb..21a18012b4c0 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -1773,10 +1773,10 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
int dai_sel;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5640->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5640_I2S_MS_S;
rt5640->master[dai->id] = 0;
break;
@@ -2963,19 +2963,19 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
static const struct of_device_id rt5640_of_match[] = {
{ .compatible = "realtek,rt5639", },
{ .compatible = "realtek,rt5640", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5640_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5640_acpi_match[] = {
- { "INT33CA", 0 },
- { "10EC3276", 0 },
- { "10EC5640", 0 },
- { "10EC5642", 0 },
- { "INTCCFFD", 0 },
- { },
+ { "10EC3276" },
+ { "10EC5640" },
+ { "10EC5642" },
+ { "INT33CA" },
+ { "INTCCFFD" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 51187b1e0ed2..343e3bcef0ca 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -2841,10 +2841,10 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5645->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5645_I2S_MS_S;
rt5645->master[dai->id] = 0;
break;
@@ -3660,12 +3660,12 @@ MODULE_DEVICE_TABLE(of, rt5645_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5645_acpi_match[] = {
- { "10EC5645", 0 },
- { "10EC5648", 0 },
- { "10EC5650", 0 },
- { "10EC5640", 0 },
- { "10EC3270", 0 },
- {},
+ { "10EC3270" },
+ { "10EC5640" },
+ { "10EC5645" },
+ { "10EC5648" },
+ { "10EC5650" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
#endif
@@ -4314,7 +4314,7 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c)
gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0);
}
-static int __maybe_unused rt5645_sys_suspend(struct device *dev)
+static int rt5645_sys_suspend(struct device *dev)
{
struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
@@ -4327,7 +4327,7 @@ static int __maybe_unused rt5645_sys_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt5645_sys_resume(struct device *dev)
+static int rt5645_sys_resume(struct device *dev)
{
struct rt5645_priv *rt5645 = dev_get_drvdata(dev);
@@ -4342,7 +4342,7 @@ static int __maybe_unused rt5645_sys_resume(struct device *dev)
}
static const struct dev_pm_ops rt5645_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume)
+ SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume)
};
static struct i2c_driver rt5645_i2c_driver = {
@@ -4350,7 +4350,7 @@ static struct i2c_driver rt5645_i2c_driver = {
.name = "rt5645",
.of_match_table = of_match_ptr(rt5645_of_match),
.acpi_match_table = ACPI_PTR(rt5645_acpi_match),
- .pm = &rt5645_pm,
+ .pm = pm_ptr(&rt5645_pm),
},
.probe = rt5645_i2c_probe,
.remove = rt5645_i2c_remove,
diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c
index 00421a1f54bf..9eeeba8cd6ff 100644
--- a/sound/soc/codecs/rt5651.c
+++ b/sound/soc/codecs/rt5651.c
@@ -1352,10 +1352,10 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5651->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5651_I2S_MS_S;
rt5651->master[dai->id] = 0;
break;
@@ -2184,16 +2184,16 @@ static const struct regmap_config rt5651_regmap = {
#if defined(CONFIG_OF)
static const struct of_device_id rt5651_of_match[] = {
{ .compatible = "realtek,rt5651", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5651_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5651_acpi_match[] = {
- { "10EC5651", 0 },
- { "10EC5640", 0 },
- { },
+ { "10EC5640" },
+ { "10EC5651" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c
index a2652fa6e1d7..31b47db7b4f7 100644
--- a/sound/soc/codecs/rt5659.c
+++ b/sound/soc/codecs/rt5659.c
@@ -3363,10 +3363,10 @@ static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5659->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5659_I2S_MS_S;
rt5659->master[dai->id] = 0;
break;
@@ -4315,16 +4315,16 @@ static void rt5659_i2c_shutdown(struct i2c_client *client)
static const struct of_device_id rt5659_of_match[] = {
{ .compatible = "realtek,rt5658", },
{ .compatible = "realtek,rt5659", },
- { },
+ { }
};
MODULE_DEVICE_TABLE(of, rt5659_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5659_acpi_match[] = {
- { "10EC5658", 0, },
- { "10EC5659", 0, },
- { },
+ { "10EC5658" },
+ { "10EC5659" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c
index 3ac41d2c279b..82b92e83be4c 100644
--- a/sound/soc/codecs/rt5660.c
+++ b/sound/soc/codecs/rt5660.c
@@ -905,11 +905,11 @@ static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5660->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5660_I2S_MS_S;
rt5660->master[dai->id] = 0;
break;
@@ -1232,16 +1232,16 @@ MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id);
#ifdef CONFIG_OF
static const struct of_device_id rt5660_of_match[] = {
{ .compatible = "realtek,rt5660", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5660_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5660_acpi_match[] = {
- { "10EC5660", 0 },
- { "10EC3277", 0 },
- { },
+ { "10EC3277" },
+ { "10EC5660" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c
index 9d32debd3689..45057562c0c8 100644
--- a/sound/soc/codecs/rt5663.c
+++ b/sound/soc/codecs/rt5663.c
@@ -2814,9 +2814,9 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5663_I2S_MS_S;
break;
default:
@@ -3315,15 +3315,15 @@ MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id rt5663_of_match[] = {
{ .compatible = "realtek,rt5663", },
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5663_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5663_acpi_match[] = {
- { "10EC5663", 0},
- {},
+ { "10EC5663" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c
index 47df14ba5278..e0d1991cffdb 100644
--- a/sound/soc/codecs/rt5665.c
+++ b/sound/soc/codecs/rt5665.c
@@ -4219,10 +4219,10 @@ static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5665->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5665_I2S_MS_S;
rt5665->master[dai->id] = 0;
break;
@@ -4949,16 +4949,16 @@ static void rt5665_i2c_shutdown(struct i2c_client *client)
static const struct of_device_id rt5665_of_match[] = {
{.compatible = "realtek,rt5665"},
{.compatible = "realtek,rt5666"},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5665_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5665_acpi_match[] = {
- {"10EC5665", 0,},
- {"10EC5666", 0,},
- {},
+ { "10EC5665" },
+ { "10EC5666" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c
index 494ca3ce9b96..f626453f332b 100644
--- a/sound/soc/codecs/rt5668.c
+++ b/sound/soc/codecs/rt5668.c
@@ -2010,10 +2010,10 @@ static int rt5668_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0, tdm_ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5668->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
rt5668->master[dai->id] = 0;
break;
default:
@@ -2598,15 +2598,15 @@ static void rt5668_i2c_shutdown(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id rt5668_of_match[] = {
{.compatible = "realtek,rt5668b"},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5668_of_match);
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5668_acpi_match[] = {
- {"10EC5668", 0,},
- {},
+ { "10EC5668" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5668_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 30bf96c35b58..efd26082f19a 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -2439,10 +2439,10 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5670->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5670_I2S_MS_S;
rt5670->master[dai->id] = 0;
break;
@@ -2880,10 +2880,10 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5670_acpi_match[] = {
- { "10EC5670", 0},
- { "10EC5672", 0},
- { "10EC5640", 0}, /* quirk */
- { },
+ { "10EC5640" }, /* quirk */
+ { "10EC5670" },
+ { "10EC5672" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
#endif
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
index d91a2184f67c..abe0a5a95770 100644
--- a/sound/soc/codecs/rt5677-spi.c
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -617,7 +617,8 @@ static int rt5677_spi_probe(struct spi_device *spi)
#ifdef CONFIG_ACPI
static const struct acpi_device_id rt5677_spi_acpi_id[] = {
- { "RT5677AA", 0 },
+ { "10EC5677" },
+ { "RT5677AA" },
{ }
};
MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id);
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 0e70a3ab42b5..6e4774148566 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -4377,10 +4377,10 @@ static int rt5677_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5677->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg_val |= RT5677_I2S_MS_S;
rt5677->master[dai->id] = 0;
break;
@@ -5201,6 +5201,7 @@ static const struct of_device_id rt5677_of_match[] = {
MODULE_DEVICE_TABLE(of, rt5677_of_match);
static const struct acpi_device_id rt5677_acpi_match[] = {
+ { "10EC5677", RT5677 },
{ "RT5677CE", RT5677 },
{ }
};
diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c
index ff9e14fad0cd..bba987308e15 100644
--- a/sound/soc/codecs/rt5682-i2c.c
+++ b/sound/soc/codecs/rt5682-i2c.c
@@ -186,6 +186,12 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
return -ENODEV;
}
+ regmap_read(rt5682->regmap, RT5682_INT_DEVICE_ID, &val);
+ if (val == 0x6956) {
+ dev_dbg(&i2c->dev, "ALC5682I-VE device\n");
+ rt5682->ve_ic = true;
+ }
+
mutex_init(&rt5682->calibrate_mutex);
rt5682_calibrate(rt5682);
@@ -307,13 +313,13 @@ static void rt5682_i2c_remove(struct i2c_client *client)
static const struct of_device_id rt5682_of_match[] = {
{.compatible = "realtek,rt5682i"},
- {},
+ { }
};
MODULE_DEVICE_TABLE(of, rt5682_of_match);
static const struct acpi_device_id rt5682_acpi_match[] = {
- {"10EC5682", 0,},
- {},
+ { "10EC5682" },
+ { }
};
MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match);
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index 5edf11e136b4..aa229894129b 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -709,7 +709,7 @@ static const struct sdw_device_id rt5682_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt5682_id);
-static int __maybe_unused rt5682_dev_suspend(struct device *dev)
+static int rt5682_dev_suspend(struct device *dev)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
@@ -725,7 +725,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt5682_dev_system_suspend(struct device *dev)
+static int rt5682_dev_system_suspend(struct device *dev)
{
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -753,7 +753,7 @@ static int __maybe_unused rt5682_dev_system_suspend(struct device *dev)
return rt5682_dev_suspend(dev);
}
-static int __maybe_unused rt5682_dev_resume(struct device *dev)
+static int rt5682_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt5682_priv *rt5682 = dev_get_drvdata(dev);
@@ -791,14 +791,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt5682_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume)
- SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume)
+ RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL)
};
static struct sdw_driver rt5682_sdw_driver = {
.driver = {
.name = "rt5682",
- .pm = &rt5682_pm,
+ .pm = pm_ptr(&rt5682_pm),
},
.probe = rt5682_sdw_probe,
.remove = rt5682_sdw_remove,
diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c
index aa163ec40862..7c88370e2dee 100644
--- a/sound/soc/codecs/rt5682.c
+++ b/sound/soc/codecs/rt5682.c
@@ -395,6 +395,7 @@ bool rt5682_volatile_register(struct device *dev, unsigned int reg)
case RT5682_4BTN_IL_CMD_1:
case RT5682_AJD1_CTRL:
case RT5682_HP_CALIB_CTRL_1:
+ case RT5682_INT_DEVICE_ID:
case RT5682_DEVICE_ID:
case RT5682_I2C_MODE:
case RT5682_HP_CALIB_CTRL_10:
@@ -419,6 +420,7 @@ bool rt5682_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case RT5682_RESET:
+ case RT5682_INT_DEVICE_ID:
case RT5682_VERSION_ID:
case RT5682_VENDOR_ID:
case RT5682_DEVICE_ID:
@@ -2223,10 +2225,10 @@ static int rt5682_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0, tdm_ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5682->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
rt5682->master[dai->id] = 0;
break;
default:
@@ -3139,7 +3141,10 @@ void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0100);
regmap_write(rt5682->regmap, RT5682_HP_IMP_SENS_CTRL_19, 0x3800);
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x3000);
- regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005);
+ if (rt5682->ve_ic)
+ regmap_write(rt5682->regmap, RT5682_CHOP_ADC, 0x7005);
+ else
+ regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x7005);
regmap_write(rt5682->regmap, RT5682_STO1_ADC_MIXER, 0x686c);
regmap_write(rt5682->regmap, RT5682_CAL_REC, 0x0d0d);
regmap_write(rt5682->regmap, RT5682_HP_CALIB_CTRL_2, 0x0321);
@@ -3168,7 +3173,10 @@ void rt5682_calibrate(struct rt5682_priv *rt5682)
regmap_write(rt5682->regmap, RT5682_GLB_CLK, 0x0000);
regmap_write(rt5682->regmap, RT5682_PWR_DIG_1, 0x0000);
regmap_write(rt5682->regmap, RT5682_CHOP_DAC, 0x2000);
- regmap_write(rt5682->regmap, RT5682_CALIB_ADC_CTRL, 0x2005);
+ if (rt5682->ve_ic)
+ regmap_write(rt5682->regmap, RT5682_CHOP_ADC, 0x2005);
+ else
+ 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);
diff --git a/sound/soc/codecs/rt5682.h b/sound/soc/codecs/rt5682.h
index b2d9e87af259..de43a5d99403 100644
--- a/sound/soc/codecs/rt5682.h
+++ b/sound/soc/codecs/rt5682.h
@@ -22,6 +22,7 @@
/* Info */
#define RT5682_RESET 0x0000
+#define RT5682_INT_DEVICE_ID 0x00f9
#define RT5682_VERSION_ID 0x00fd
#define RT5682_VENDOR_ID 0x00fe
#define RT5682_DEVICE_ID 0x00ff
@@ -1446,6 +1447,7 @@ struct rt5682_priv {
bool hw_init;
bool first_hw_init;
bool is_sdw;
+ bool ve_ic;
#ifdef CONFIG_COMMON_CLK
struct clk_hw dai_clks_hw[RT5682_DAI_NUM_CLKS];
diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c
index ce2e88e066f3..73c4b3c31f8c 100644
--- a/sound/soc/codecs/rt5682s.c
+++ b/sound/soc/codecs/rt5682s.c
@@ -2132,10 +2132,10 @@ static int rt5682s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int reg_val = 0, tdm_ctrl = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
rt5682s->master[dai->id] = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
rt5682s->master[dai->id] = 0;
break;
default:
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 24cb895b759f..44543c0da177 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -475,7 +475,7 @@ static const struct sdw_device_id rt700_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt700_id);
-static int __maybe_unused rt700_dev_suspend(struct device *dev)
+static int rt700_dev_suspend(struct device *dev)
{
struct rt700_priv *rt700 = dev_get_drvdata(dev);
@@ -490,7 +490,7 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt700_dev_system_suspend(struct device *dev)
+static int rt700_dev_system_suspend(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt700_priv *rt700 = dev_get_drvdata(dev);
@@ -520,7 +520,7 @@ static int __maybe_unused rt700_dev_system_suspend(struct device *dev)
#define RT700_PROBE_TIMEOUT 5000
-static int __maybe_unused rt700_dev_resume(struct device *dev)
+static int rt700_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt700_priv *rt700 = dev_get_drvdata(dev);
@@ -551,14 +551,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt700_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume)
- SET_RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume)
+ RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL)
};
static struct sdw_driver rt700_sdw_driver = {
.driver = {
.name = "rt700",
- .pm = &rt700_pm,
+ .pm = pm_ptr(&rt700_pm),
},
.probe = rt700_sdw_probe,
.remove = rt700_sdw_remove,
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index f5933d2e085e..adf05f64259b 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -380,7 +380,7 @@ static const struct sdw_device_id rt711_sdca_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt711_sdca_id);
-static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev)
+static int rt711_sdca_dev_suspend(struct device *dev)
{
struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev);
@@ -396,7 +396,7 @@ static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev)
+static int rt711_sdca_dev_system_suspend(struct device *dev)
{
struct rt711_sdca_priv *rt711_sdca = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -428,7 +428,7 @@ static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev)
#define RT711_PROBE_TIMEOUT 5000
-static int __maybe_unused rt711_sdca_dev_resume(struct device *dev)
+static int rt711_sdca_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev);
@@ -467,14 +467,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt711_sdca_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume)
- SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL)
};
static struct sdw_driver rt711_sdca_sdw_driver = {
.driver = {
.name = "rt711-sdca",
- .pm = &rt711_sdca_pm,
+ .pm = pm_ptr(&rt711_sdca_pm),
},
.probe = rt711_sdca_sdw_probe,
.remove = rt711_sdca_sdw_remove,
diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c
index dfda6bb5c6f8..93a5a89a96b1 100644
--- a/sound/soc/codecs/rt711-sdw.c
+++ b/sound/soc/codecs/rt711-sdw.c
@@ -482,7 +482,7 @@ static const struct sdw_device_id rt711_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt711_id);
-static int __maybe_unused rt711_dev_suspend(struct device *dev)
+static int rt711_dev_suspend(struct device *dev)
{
struct rt711_priv *rt711 = dev_get_drvdata(dev);
@@ -498,7 +498,7 @@ static int __maybe_unused rt711_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt711_dev_system_suspend(struct device *dev)
+static int rt711_dev_system_suspend(struct device *dev)
{
struct rt711_priv *rt711 = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -528,7 +528,7 @@ static int __maybe_unused rt711_dev_system_suspend(struct device *dev)
#define RT711_PROBE_TIMEOUT 5000
-static int __maybe_unused rt711_dev_resume(struct device *dev)
+static int rt711_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt711_priv *rt711 = dev_get_drvdata(dev);
@@ -564,14 +564,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt711_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume)
- SET_RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume)
+ RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL)
};
static struct sdw_driver rt711_sdw_driver = {
.driver = {
.name = "rt711",
- .pm = &rt711_pm,
+ .pm = pm_ptr(&rt711_pm),
},
.probe = rt711_sdw_probe,
.remove = rt711_sdw_remove,
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index ee5435f3a80a..db011da63bd9 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -884,7 +884,7 @@ static const struct sdw_device_id rt712_sdca_dmic_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt712_sdca_dmic_id);
-static int __maybe_unused rt712_sdca_dmic_dev_suspend(struct device *dev)
+static int rt712_sdca_dmic_dev_suspend(struct device *dev)
{
struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(dev);
@@ -897,7 +897,7 @@ static int __maybe_unused rt712_sdca_dmic_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt712_sdca_dmic_dev_system_suspend(struct device *dev)
+static int rt712_sdca_dmic_dev_system_suspend(struct device *dev)
{
struct rt712_sdca_dmic_priv *rt712_sdca = dev_get_drvdata(dev);
@@ -909,7 +909,7 @@ static int __maybe_unused rt712_sdca_dmic_dev_system_suspend(struct device *dev)
#define RT712_PROBE_TIMEOUT 5000
-static int __maybe_unused rt712_sdca_dmic_dev_resume(struct device *dev)
+static int rt712_sdca_dmic_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(dev);
@@ -941,8 +941,8 @@ regmap_sync:
}
static const struct dev_pm_ops rt712_sdca_dmic_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt712_sdca_dmic_dev_system_suspend, rt712_sdca_dmic_dev_resume)
- SET_RUNTIME_PM_OPS(rt712_sdca_dmic_dev_suspend, rt712_sdca_dmic_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt712_sdca_dmic_dev_system_suspend, rt712_sdca_dmic_dev_resume)
+ RUNTIME_PM_OPS(rt712_sdca_dmic_dev_suspend, rt712_sdca_dmic_dev_resume, NULL)
};
@@ -978,7 +978,7 @@ static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave)
static struct sdw_driver rt712_sdca_dmic_sdw_driver = {
.driver = {
.name = "rt712-sdca-dmic",
- .pm = &rt712_sdca_dmic_pm,
+ .pm = pm_ptr(&rt712_sdca_dmic_pm),
},
.probe = rt712_sdca_dmic_sdw_probe,
.remove = rt712_sdca_dmic_sdw_remove,
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index b584a3f854b8..ea07131edfa2 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -400,7 +400,7 @@ static const struct sdw_device_id rt712_sdca_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt712_sdca_id);
-static int __maybe_unused rt712_sdca_dev_suspend(struct device *dev)
+static int rt712_sdca_dev_suspend(struct device *dev)
{
struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
@@ -416,7 +416,7 @@ static int __maybe_unused rt712_sdca_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt712_sdca_dev_system_suspend(struct device *dev)
+static int rt712_sdca_dev_system_suspend(struct device *dev)
{
struct rt712_sdca_priv *rt712_sdca = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -448,7 +448,7 @@ static int __maybe_unused rt712_sdca_dev_system_suspend(struct device *dev)
#define RT712_PROBE_TIMEOUT 5000
-static int __maybe_unused rt712_sdca_dev_resume(struct device *dev)
+static int rt712_sdca_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
@@ -488,14 +488,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt712_sdca_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt712_sdca_dev_system_suspend, rt712_sdca_dev_resume)
- SET_RUNTIME_PM_OPS(rt712_sdca_dev_suspend, rt712_sdca_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt712_sdca_dev_system_suspend, rt712_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt712_sdca_dev_suspend, rt712_sdca_dev_resume, NULL)
};
static struct sdw_driver rt712_sdca_sdw_driver = {
.driver = {
.name = "rt712-sdca",
- .pm = &rt712_sdca_pm,
+ .pm = pm_ptr(&rt712_sdca_pm),
},
.probe = rt712_sdca_sdw_probe,
.remove = rt712_sdca_sdw_remove,
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index 78dbf9eed494..19d99b9d4ab2 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -652,6 +652,61 @@ static int rt712_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol,
return 1;
}
+static int rt712_sdca_set_fu05_playback_ctl(struct rt712_sdca_priv *rt712)
+{
+ int err;
+ unsigned int ch_01, ch_02;
+
+ ch_01 = (rt712->fu05_dapm_mute || rt712->fu05_mixer_l_mute) ? 0x01 : 0x00;
+ ch_02 = (rt712->fu05_dapm_mute || rt712->fu05_mixer_r_mute) ? 0x01 : 0x00;
+
+ err = regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
+ RT712_SDCA_CTL_FU_MUTE, CH_01), ch_01);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(rt712->regmap,
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
+ RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int rt712_sdca_fu05_playback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+
+ ucontrol->value.integer.value[0] = !rt712->fu05_mixer_l_mute;
+ ucontrol->value.integer.value[1] = !rt712->fu05_mixer_r_mute;
+ return 0;
+}
+
+static int rt712_sdca_fu05_playback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+ int err;
+
+ if (rt712->fu05_mixer_l_mute == !ucontrol->value.integer.value[0] &&
+ rt712->fu05_mixer_r_mute == !ucontrol->value.integer.value[1])
+ return 0;
+
+ rt712->fu05_mixer_l_mute = !ucontrol->value.integer.value[0];
+ rt712->fu05_mixer_r_mute = !ucontrol->value.integer.value[1];
+
+ err = rt712_sdca_set_fu05_playback_ctl(rt712);
+ if (err < 0)
+ return err;
+
+ return 1;
+}
+
static const DECLARE_TLV_DB_SCALE(out_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, 0, 1000, 0);
@@ -674,6 +729,8 @@ static const struct snd_kcontrol_new rt712_sdca_controls[] = {
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02),
8, 3, 0,
rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, boost_vol_tlv),
+ SOC_DOUBLE_EXT("FU05 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
+ rt712_sdca_fu05_playback_get, rt712_sdca_fu05_playback_put),
};
static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = {
@@ -766,28 +823,15 @@ static int rt712_sdca_fu05_event(struct snd_soc_dapm_widget *w,
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
- unsigned char unmute = 0x0, mute = 0x1;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_01),
- unmute);
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_02),
- unmute);
+ rt712->fu05_dapm_mute = false;
+ rt712_sdca_set_fu05_playback_ctl(rt712);
break;
case SND_SOC_DAPM_PRE_PMD:
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_01),
- mute);
- regmap_write(rt712->regmap,
- SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05,
- RT712_SDCA_CTL_FU_MUTE, CH_02),
- mute);
+ rt712->fu05_dapm_mute = true;
+ rt712_sdca_set_fu05_playback_ctl(rt712);
break;
}
return 0;
@@ -1640,6 +1684,8 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap,
rt712->fu1e_dapm_mute = true;
rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] =
rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true;
+ rt712->fu05_dapm_mute = true;
+ rt712->fu05_mixer_l_mute = rt712->fu05_mixer_r_mute = false;
/* JD source uses JD1 in default */
rt712->jd_src = RT712_JD1;
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index a08491496d90..7ab7d5feb50a 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -42,6 +42,9 @@ struct rt712_sdca_priv {
bool fu0f_mixer_r_mute;
bool fu1e_dapm_mute;
bool fu1e_mixer_mute[4];
+ bool fu05_dapm_mute;
+ bool fu05_mixer_l_mute;
+ bool fu05_mixer_r_mute;
};
struct rt712_dmic_kctrl_priv {
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index c8dabb9b16b5..ce7d8955efc3 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -205,7 +205,7 @@ static const struct sdw_device_id rt715_sdca_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt715_sdca_id);
-static int __maybe_unused rt715_dev_suspend(struct device *dev)
+static int rt715_dev_suspend(struct device *dev)
{
struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
@@ -222,7 +222,7 @@ static int __maybe_unused rt715_dev_suspend(struct device *dev)
#define RT715_PROBE_TIMEOUT 5000
-static int __maybe_unused rt715_dev_resume(struct device *dev)
+static int rt715_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev);
@@ -263,14 +263,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt715_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
- SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
+ RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
};
static struct sdw_driver rt715_sdw_driver = {
.driver = {
.name = "rt715-sdca",
- .pm = &rt715_pm,
+ .pm = pm_ptr(&rt715_pm),
},
.probe = rt715_sdca_sdw_probe,
.remove = rt715_sdca_sdw_remove,
diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c
index 7e10fd913812..7fb02654c16b 100644
--- a/sound/soc/codecs/rt715-sdca.c
+++ b/sound/soc/codecs/rt715-sdca.c
@@ -427,14 +427,6 @@ static int rt715_sdca_fu_info(struct snd_kcontrol *kcontrol,
.private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, \
xshift, xinvert)}
-#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
- xhandler_get, xhandler_put) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = snd_soc_info_volsw, \
- .get = xhandler_get, .put = xhandler_put, \
- .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
- xmax, xinvert) }
-
#define RT715_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
xhandler_put, tlv_array, xcount, xmax) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index ec255ada44e0..a3df4bbedf86 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -372,47 +372,6 @@ static const struct regmap_config rt715_sdw_regmap = {
.use_single_write = true,
};
-int hda_to_sdw(unsigned int nid, unsigned int verb, unsigned int payload,
- unsigned int *sdw_addr_h, unsigned int *sdw_data_h,
- unsigned int *sdw_addr_l, unsigned int *sdw_data_l)
-{
- unsigned int offset_h, offset_l, e_verb;
-
- if (((verb & 0xff) != 0) || verb == 0xf00) { /* 12 bits command */
- if (verb == 0x7ff) /* special case */
- offset_h = 0;
- else
- offset_h = 0x3000;
-
- if (verb & 0x800) /* get command */
- e_verb = (verb - 0xf00) | 0x80;
- else /* set command */
- e_verb = (verb - 0x700);
-
- *sdw_data_h = payload; /* 7 bits payload */
- *sdw_addr_l = *sdw_data_l = 0;
- } else { /* 4 bits command */
- if ((verb & 0x800) == 0x800) { /* read */
- offset_h = 0x9000;
- offset_l = 0xa000;
- } else { /* write */
- offset_h = 0x7000;
- offset_l = 0x8000;
- }
- e_verb = verb >> 8;
- *sdw_data_h = (payload >> 8); /* 16 bits payload [15:8] */
- *sdw_addr_l = (e_verb << 8) | nid | 0x80; /* 0x80: valid bit */
- *sdw_addr_l += offset_l;
- *sdw_data_l = payload & 0xff;
- }
-
- *sdw_addr_h = (e_verb << 8) | nid;
- *sdw_addr_h += offset_h;
-
- return 0;
-}
-EXPORT_SYMBOL(hda_to_sdw);
-
static int rt715_update_status(struct sdw_slave *slave,
enum sdw_slave_status status)
{
@@ -526,7 +485,7 @@ static const struct sdw_device_id rt715_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt715_id);
-static int __maybe_unused rt715_dev_suspend(struct device *dev)
+static int rt715_dev_suspend(struct device *dev)
{
struct rt715_priv *rt715 = dev_get_drvdata(dev);
@@ -540,7 +499,7 @@ static int __maybe_unused rt715_dev_suspend(struct device *dev)
#define RT715_PROBE_TIMEOUT 5000
-static int __maybe_unused rt715_dev_resume(struct device *dev)
+static int rt715_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt715_priv *rt715 = dev_get_drvdata(dev);
@@ -571,14 +530,14 @@ regmap_sync:
}
static const struct dev_pm_ops rt715_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
- SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume)
+ RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL)
};
static struct sdw_driver rt715_sdw_driver = {
.driver = {
.name = "rt715",
- .pm = &rt715_pm,
+ .pm = pm_ptr(&rt715_pm),
},
.probe = rt715_sdw_probe,
.remove = rt715_sdw_remove,
diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c
index 299c9b12377c..2cf461852091 100644
--- a/sound/soc/codecs/rt715.c
+++ b/sound/soc/codecs/rt715.c
@@ -486,14 +486,6 @@ static int rt715_vol_info(struct snd_kcontrol *kcontrol,
return 0;
}
-#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\
- xhandler_get, xhandler_put) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = snd_soc_info_volsw, \
- .get = xhandler_get, .put = xhandler_put, \
- .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
- xmax, xinvert) }
-
#define RT715_MAIN_SWITCH_EXT(xname, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = rt715_switch_info, \
diff --git a/sound/soc/codecs/rt715.h b/sound/soc/codecs/rt715.h
index 6e37bf64e12f..a0c56aa1003a 100644
--- a/sound/soc/codecs/rt715.h
+++ b/sound/soc/codecs/rt715.h
@@ -220,8 +220,5 @@ int rt715_io_init(struct device *dev, struct sdw_slave *slave);
int rt715_init(struct device *dev, struct regmap *sdw_regmap,
struct regmap *regmap, struct sdw_slave *slave);
-int hda_to_sdw(unsigned int nid, unsigned int verb, unsigned int payload,
- unsigned int *sdw_addr_h, unsigned int *sdw_data_h,
- unsigned int *sdw_addr_l, unsigned int *sdw_data_l);
int rt715_clock_config(struct device *dev);
#endif /* __RT715_H__ */
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index c71453da088a..582b47d69278 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -437,7 +437,7 @@ static const struct sdw_device_id rt721_sdca_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt721_sdca_id);
-static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev)
+static int rt721_sdca_dev_suspend(struct device *dev)
{
struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
@@ -453,7 +453,7 @@ static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev)
+static int rt721_sdca_dev_system_suspend(struct device *dev)
{
struct rt721_sdca_priv *rt721_sdca = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -485,7 +485,7 @@ static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev)
#define RT721_PROBE_TIMEOUT 5000
-static int __maybe_unused rt721_sdca_dev_resume(struct device *dev)
+static int rt721_sdca_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev);
@@ -524,15 +524,15 @@ regmap_sync:
}
static const struct dev_pm_ops rt721_sdca_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume)
- SET_RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL)
};
static struct sdw_driver rt721_sdca_sdw_driver = {
.driver = {
.name = "rt721-sdca",
.owner = THIS_MODULE,
- .pm = &rt721_sdca_pm,
+ .pm = pm_ptr(&rt721_sdca_pm),
},
.probe = rt721_sdca_sdw_probe,
.remove = rt721_sdca_sdw_remove,
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 25fc13687bc8..11e2e8f68a98 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -16,7 +16,7 @@
#include "rt722-sdca.h"
#include "rt722-sdca-sdw.h"
-static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
+static int rt722_sdca_mbq_size(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0x2f01 ... 0x2f0a:
@@ -28,36 +28,52 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
0):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
0):
- case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
- 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
- RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
- case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
- return true;
- default:
- return false;
- }
-}
-
-static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case 0x2f01:
- case 0x2f54:
- case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE,
0):
- case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
- 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
- RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05,
+ RT722_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D,
+ RT722_SDCA_CTL_SELECTED_MODE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
+ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F,
+ RT722_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_01) ...
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E,
+ RT722_SDCA_CTL_FU_MUTE, CH_04):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26,
+ RT722_SDCA_CTL_VENDOR_DEF, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
+ SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_L) ...
+ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06,
+ RT722_SDCA_CTL_FU_MUTE, CH_R):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
+ RT722_SDCA_CTL_VENDOR_DEF, CH_08):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23,
+ RT722_SDCA_CTL_REQ_POWER_STATE, 0):
+ case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31,
+ RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
- return true;
- default:
- return false;
- }
-}
-
-static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int reg)
-{
- switch (reg) {
+ return 1;
case 0x2000000 ... 0x2000024:
case 0x2000029 ... 0x200004a:
case 0x2000051 ... 0x2000052:
@@ -74,6 +90,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5600000 ... 0x5600007:
case 0x5700000 ... 0x5700004:
case 0x5800000 ... 0x5800004:
+ case 0x5810000:
case 0x5b00003:
case 0x5c00011:
case 0x5d00006:
@@ -81,11 +98,16 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
case 0x5f00030:
case 0x6100000 ... 0x6100051:
case 0x6100055 ... 0x6100057:
+ case 0x6100060:
case 0x6100062:
case 0x6100064 ... 0x6100065:
case 0x6100067:
case 0x6100070 ... 0x610007c:
case 0x6100080:
+ case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_01) ...
+ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN,
+ CH_04):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
CH_01):
case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
@@ -108,15 +130,32 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re
RT722_SDCA_CTL_FU_CH_GAIN, CH_L):
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44,
RT722_SDCA_CTL_FU_CH_GAIN, CH_R):
- return true;
+ return 2;
default:
- return false;
+ return 0;
}
}
-static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int reg)
+static struct regmap_sdw_mbq_cfg rt722_mbq_config = {
+ .mbq_size = rt722_sdca_mbq_size,
+};
+
+static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg)
+{
+ return rt722_sdca_mbq_size(dev, reg) > 0;
+}
+
+static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case 0x2f01:
+ case 0x2f54:
+ case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE,
+ 0):
+ case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER,
+ 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01,
+ RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+ case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2:
case 0x2000000:
case 0x200000d:
case 0x2000019:
@@ -135,7 +174,7 @@ static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int re
static const struct regmap_config rt722_sdca_regmap = {
.reg_bits = 32,
- .val_bits = 8,
+ .val_bits = 16,
.readable_reg = rt722_sdca_readable_register,
.volatile_reg = rt722_sdca_volatile_register,
.max_register = 0x44ffffff,
@@ -146,20 +185,6 @@ static const struct regmap_config rt722_sdca_regmap = {
.use_single_write = true,
};
-static const struct regmap_config rt722_sdca_mbq_regmap = {
- .name = "sdw-mbq",
- .reg_bits = 32,
- .val_bits = 16,
- .readable_reg = rt722_sdca_mbq_readable_register,
- .volatile_reg = rt722_sdca_mbq_volatile_register,
- .max_register = 0x41000312,
- .reg_defaults = rt722_sdca_mbq_defaults,
- .num_reg_defaults = ARRAY_SIZE(rt722_sdca_mbq_defaults),
- .cache_type = REGCACHE_MAPLE,
- .use_single_read = true,
- .use_single_write = true,
-};
-
static int rt722_sdca_update_status(struct sdw_slave *slave,
enum sdw_slave_status status)
{
@@ -203,6 +228,8 @@ static int rt722_sdca_read_prop(struct sdw_slave *slave)
unsigned long addr;
struct sdw_dpn_prop *dpn;
+ sdw_slave_read_lane_mapping(slave);
+
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
@@ -369,18 +396,14 @@ static const struct sdw_slave_ops rt722_sdca_slave_ops = {
static int rt722_sdca_sdw_probe(struct sdw_slave *slave,
const struct sdw_device_id *id)
{
- struct regmap *regmap, *mbq_regmap;
+ struct regmap *regmap;
/* Regmap Initialization */
- mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt722_sdca_mbq_regmap);
- if (IS_ERR(mbq_regmap))
- return PTR_ERR(mbq_regmap);
-
- regmap = devm_regmap_init_sdw(slave, &rt722_sdca_regmap);
+ regmap = devm_regmap_init_sdw_mbq_cfg(slave, &rt722_sdca_regmap, &rt722_mbq_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- return rt722_sdca_init(&slave->dev, regmap, mbq_regmap, slave);
+ return rt722_sdca_init(&slave->dev, regmap, slave);
}
static int rt722_sdca_sdw_remove(struct sdw_slave *slave)
@@ -407,7 +430,7 @@ static const struct sdw_device_id rt722_sdca_id[] = {
};
MODULE_DEVICE_TABLE(sdw, rt722_sdca_id);
-static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev)
+static int rt722_sdca_dev_suspend(struct device *dev)
{
struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
@@ -418,12 +441,11 @@ static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev)
cancel_delayed_work_sync(&rt722->jack_btn_check_work);
regcache_cache_only(rt722->regmap, true);
- regcache_cache_only(rt722->mbq_regmap, true);
return 0;
}
-static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev)
+static int rt722_sdca_dev_system_suspend(struct device *dev)
{
struct rt722_sdca_priv *rt722_sdca = dev_get_drvdata(dev);
struct sdw_slave *slave = dev_to_sdw_dev(dev);
@@ -455,7 +477,7 @@ static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev)
#define RT722_PROBE_TIMEOUT 5000
-static int __maybe_unused rt722_sdca_dev_resume(struct device *dev)
+static int rt722_sdca_dev_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
@@ -488,20 +510,18 @@ regmap_sync:
slave->unattach_request = 0;
regcache_cache_only(rt722->regmap, false);
regcache_sync(rt722->regmap);
- regcache_cache_only(rt722->mbq_regmap, false);
- regcache_sync(rt722->mbq_regmap);
return 0;
}
static const struct dev_pm_ops rt722_sdca_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume)
- SET_RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume)
+ RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL)
};
static struct sdw_driver rt722_sdca_sdw_driver = {
.driver = {
.name = "rt722-sdca",
- .pm = &rt722_sdca_pm,
+ .pm = pm_ptr(&rt722_sdca_pm),
},
.probe = rt722_sdca_sdw_probe,
.remove = rt722_sdca_sdw_remove,
diff --git a/sound/soc/codecs/rt722-sdca-sdw.h b/sound/soc/codecs/rt722-sdca-sdw.h
index 5b43e86f75d1..80b014456940 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.h
+++ b/sound/soc/codecs/rt722-sdca-sdw.h
@@ -31,50 +31,9 @@ static const struct reg_default rt722_sdca_reg_defaults[] = {
{ 0x2f5b, 0x07 },
{ 0x2f5c, 0x27 },
{ 0x2f5d, 0x07 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
- 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
- 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE,
- 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE,
- 0), 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
- 0), 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
- 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0),
- 0x00 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
- 0x09 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R),
- 0x01 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
- 0x03 },
- { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
-};
-
-static const struct reg_default rt722_sdca_mbq_defaults[] = {
{ 0x200003c, 0xc214 },
{ 0x2000046, 0x8004 },
+ { 0x5810000, 0x702d },
{ 0x6100006, 0x0005 },
{ 0x6100010, 0x2630 },
{ 0x6100011, 0x152f },
@@ -86,27 +45,34 @@ static const struct reg_default rt722_sdca_mbq_defaults[] = {
{ 0x6100028, 0x2a2a },
{ 0x6100029, 0x4141 },
{ 0x6100055, 0x0000 },
- { 0x5810000, 0x702d },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
CH_L), 0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME,
CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
CH_L), 0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME,
CH_R), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE,
+ 0), 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE,
+ 0), 0x03 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN,
CH_L), 0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN,
CH_R), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
- CH_01), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
- CH_02), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
- CH_03), 0x0000 },
- { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
- CH_04), 0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_01),
0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_02),
@@ -115,10 +81,41 @@ static const struct reg_default rt722_sdca_mbq_defaults[] = {
0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_04),
0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_01), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_02), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_03), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME,
+ CH_04), 0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
+ 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX,
+ 0), 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0),
+ 0x00 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L),
+ 0x01 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R),
+ 0x01 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L),
0x0000 },
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R),
0x0000 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0),
+ 0x03 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+ 0x09 },
+ { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
};
#endif /* __RT722_SDW_H__ */
diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c
index e17a142d03b9..f093ce841b3f 100644
--- a/sound/soc/codecs/rt722-sdca.c
+++ b/sound/soc/codecs/rt722-sdca.c
@@ -25,11 +25,13 @@
#include "rt722-sdca.h"
+#define RT722_NID_ADDR(nid, reg) ((nid) << 20 | (reg))
+
int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
unsigned int nid, unsigned int reg, unsigned int value)
{
- struct regmap *regmap = rt722->mbq_regmap;
- unsigned int addr = (nid << 20) | reg;
+ struct regmap *regmap = rt722->regmap;
+ unsigned int addr = RT722_NID_ADDR(nid, reg);
int ret;
ret = regmap_write(regmap, addr, value);
@@ -45,8 +47,8 @@ int rt722_sdca_index_read(struct rt722_sdca_priv *rt722,
unsigned int nid, unsigned int reg, unsigned int *value)
{
int ret;
- struct regmap *regmap = rt722->mbq_regmap;
- unsigned int addr = (nid << 20) | reg;
+ struct regmap *regmap = rt722->regmap;
+ unsigned int addr = RT722_NID_ADDR(nid, reg);
ret = regmap_read(regmap, addr, value);
if (ret < 0)
@@ -361,8 +363,8 @@ static int rt722_sdca_set_gain_put(struct snd_kcontrol *kcontrol,
strstr(ucontrol->id.name, "FU0F Capture Volume"))
adc_vol_flag = 1;
- regmap_read(rt722->mbq_regmap, mc->reg, &lvalue);
- regmap_read(rt722->mbq_regmap, mc->rreg, &rvalue);
+ regmap_read(rt722->regmap, mc->reg, &lvalue);
+ regmap_read(rt722->regmap, mc->rreg, &rvalue);
/* L Channel */
gain_l_val = ucontrol->value.integer.value[0];
@@ -402,13 +404,13 @@ static int rt722_sdca_set_gain_put(struct snd_kcontrol *kcontrol,
return 0;
/* Lch*/
- regmap_write(rt722->mbq_regmap, mc->reg, gain_l_val);
+ regmap_write(rt722->regmap, mc->reg, gain_l_val);
/* Rch */
- regmap_write(rt722->mbq_regmap, mc->rreg, gain_r_val);
+ regmap_write(rt722->regmap, mc->rreg, gain_r_val);
- regmap_read(rt722->mbq_regmap, mc->reg, &read_l);
- regmap_read(rt722->mbq_regmap, mc->rreg, &read_r);
+ regmap_read(rt722->regmap, mc->reg, &read_l);
+ regmap_read(rt722->regmap, mc->rreg, &read_r);
if (read_r == gain_r_val && read_l == gain_l_val)
return changed;
@@ -431,8 +433,8 @@ static int rt722_sdca_set_gain_get(struct snd_kcontrol *kcontrol,
strstr(ucontrol->id.name, "FU0F Capture Volume"))
adc_vol_flag = 1;
- regmap_read(rt722->mbq_regmap, mc->reg, &read_l);
- regmap_read(rt722->mbq_regmap, mc->rreg, &read_r);
+ regmap_read(rt722->regmap, mc->reg, &read_l);
+ regmap_read(rt722->regmap, mc->rreg, &read_r);
if (mc->shift == 8) /* boost gain */
ctl_l = read_l / tendB;
@@ -604,7 +606,7 @@ static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
/* check all channels */
for (i = 0; i < p->count; i++) {
- regmap_read(rt722->mbq_regmap, p->reg_base + i, &regvalue);
+ regmap_read(rt722->regmap, p->reg_base + i, &regvalue);
if (!adc_vol_flag) /* boost gain */
ctl = regvalue / boost_step;
@@ -637,7 +639,7 @@ static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
/* check all channels */
for (i = 0; i < p->count; i++) {
- regmap_read(rt722->mbq_regmap, p->reg_base + i, &regvalue[i]);
+ regmap_read(rt722->regmap, p->reg_base + i, &regvalue[i]);
gain_val[i] = ucontrol->value.integer.value[i];
if (gain_val[i] > p->max)
@@ -658,7 +660,7 @@ static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
return 0;
for (i = 0; i < p->count; i++) {
- err = regmap_write(rt722->mbq_regmap, p->reg_base + i, gain_val[i]);
+ err = regmap_write(rt722->regmap, p->reg_base + i, gain_val[i]);
if (err < 0)
dev_err(&rt722->slave->dev, "%s: %#08x can't be set\n",
__func__, p->reg_base + i);
@@ -739,77 +741,6 @@ static const struct snd_kcontrol_new rt722_sdca_controls[] = {
4, 3, boost_vol_tlv),
};
-static int rt722_sdca_adc_mux_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
- struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
- unsigned int val = 0, mask_sft;
-
- if (strstr(ucontrol->id.name, "ADC 22 Mux"))
- mask_sft = 12;
- else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
- mask_sft = 4;
- else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
- mask_sft = 0;
- else
- return -EINVAL;
-
- rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL,
- RT722_HDA_LEGACY_MUX_CTL0, &val);
-
- ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7;
-
- return 0;
-}
-
-static int rt722_sdca_adc_mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component =
- snd_soc_dapm_kcontrol_component(kcontrol);
- struct snd_soc_dapm_context *dapm =
- snd_soc_dapm_kcontrol_dapm(kcontrol);
- struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int *item = ucontrol->value.enumerated.item;
- unsigned int val, val2 = 0, change, mask_sft;
-
- if (item[0] >= e->items)
- return -EINVAL;
-
- if (strstr(ucontrol->id.name, "ADC 22 Mux"))
- mask_sft = 12;
- else if (strstr(ucontrol->id.name, "ADC 24 Mux"))
- mask_sft = 4;
- else if (strstr(ucontrol->id.name, "ADC 25 Mux"))
- mask_sft = 0;
- else
- return -EINVAL;
-
- val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
-
- rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL,
- RT722_HDA_LEGACY_MUX_CTL0, &val2);
- val2 = (0x7 << mask_sft) & val2;
-
- if (val == val2)
- change = 0;
- else
- change = 1;
-
- if (change)
- rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL,
- RT722_HDA_LEGACY_MUX_CTL0, 0x7 << mask_sft,
- val << mask_sft);
-
- snd_soc_dapm_mux_update_power(dapm, kcontrol,
- item[0], e, NULL);
-
- return change;
-}
-
static const char * const adc22_mux_text[] = {
"MIC2",
"LINE1",
@@ -821,26 +752,26 @@ static const char * const adc07_10_mux_text[] = {
"DMIC2",
};
-static SOC_ENUM_SINGLE_DECL(
- rt722_adc22_enum, SND_SOC_NOPM, 0, adc22_mux_text);
+static SOC_ENUM_SINGLE_DECL(rt722_adc22_enum,
+ RT722_NID_ADDR(RT722_VENDOR_HDA_CTL, RT722_HDA_LEGACY_MUX_CTL0),
+ 12, adc22_mux_text);
-static SOC_ENUM_SINGLE_DECL(
- rt722_adc24_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+static SOC_ENUM_SINGLE_DECL(rt722_adc24_enum,
+ RT722_NID_ADDR(RT722_VENDOR_HDA_CTL, RT722_HDA_LEGACY_MUX_CTL0),
+ 4, adc07_10_mux_text);
-static SOC_ENUM_SINGLE_DECL(
- rt722_adc25_enum, SND_SOC_NOPM, 0, adc07_10_mux_text);
+static SOC_ENUM_SINGLE_DECL(rt722_adc25_enum,
+ RT722_NID_ADDR(RT722_VENDOR_HDA_CTL, RT722_HDA_LEGACY_MUX_CTL0),
+ 0, adc07_10_mux_text);
static const struct snd_kcontrol_new rt722_sdca_adc22_mux =
- SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt722_adc22_enum,
- rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+ SOC_DAPM_ENUM("ADC 22 Mux", rt722_adc22_enum);
static const struct snd_kcontrol_new rt722_sdca_adc24_mux =
- SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt722_adc24_enum,
- rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+ SOC_DAPM_ENUM("ADC 24 Mux", rt722_adc24_enum);
static const struct snd_kcontrol_new rt722_sdca_adc25_mux =
- SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt722_adc25_enum,
- rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put);
+ SOC_DAPM_ENUM("ADC 25 Mux", rt722_adc25_enum);
static int rt722_sdca_fu42_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
@@ -1335,8 +1266,7 @@ static struct snd_soc_dai_driver rt722_sdca_dai[] = {
}
};
-int rt722_sdca_init(struct device *dev, struct regmap *regmap,
- struct regmap *mbq_regmap, struct sdw_slave *slave)
+int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave)
{
struct rt722_sdca_priv *rt722;
@@ -1347,7 +1277,6 @@ int rt722_sdca_init(struct device *dev, struct regmap *regmap,
dev_set_drvdata(dev, rt722);
rt722->slave = slave;
rt722->regmap = regmap;
- rt722->mbq_regmap = mbq_regmap;
mutex_init(&rt722->calibrate_mutex);
mutex_init(&rt722->disable_irq_lock);
@@ -1521,8 +1450,6 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt722->first_hw_init) {
regcache_cache_only(rt722->regmap, false);
regcache_cache_bypass(rt722->regmap, true);
- regcache_cache_only(rt722->mbq_regmap, false);
- regcache_cache_bypass(rt722->mbq_regmap, true);
} else {
/*
* PM runtime is only enabled when a Slave reports as Attached
@@ -1550,8 +1477,6 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
if (rt722->first_hw_init) {
regcache_cache_bypass(rt722->regmap, false);
regcache_mark_dirty(rt722->regmap);
- regcache_cache_bypass(rt722->mbq_regmap, false);
- regcache_mark_dirty(rt722->mbq_regmap);
} else
rt722->first_hw_init = true;
diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h
index 2464361a7958..04c3b4232ef3 100644
--- a/sound/soc/codecs/rt722-sdca.h
+++ b/sound/soc/codecs/rt722-sdca.h
@@ -17,7 +17,6 @@
struct rt722_sdca_priv {
struct regmap *regmap;
- struct regmap *mbq_regmap;
struct snd_soc_component *component;
struct sdw_slave *slave;
struct sdw_bus_params params;
@@ -229,8 +228,7 @@ enum rt722_sdca_jd_src {
};
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave);
-int rt722_sdca_init(struct device *dev, struct regmap *regmap,
- struct regmap *mbq_regmap, struct sdw_slave *slave);
+int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave);
int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,
unsigned int nid, unsigned int reg, unsigned int value);
int rt722_sdca_index_read(struct rt722_sdca_priv *rt722,
diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c
index 733a7d130a95..97f56af25577 100644
--- a/sound/soc/codecs/rt9120.c
+++ b/sound/soc/codecs/rt9120.c
@@ -590,7 +590,7 @@ static void rt9120_remove(struct i2c_client *i2c)
pm_runtime_set_suspended(&i2c->dev);
}
-static int __maybe_unused rt9120_runtime_suspend(struct device *dev)
+static int rt9120_runtime_suspend(struct device *dev)
{
struct rt9120_data *data = dev_get_drvdata(dev);
@@ -603,7 +603,7 @@ static int __maybe_unused rt9120_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rt9120_runtime_resume(struct device *dev)
+static int rt9120_runtime_resume(struct device *dev)
{
struct rt9120_data *data = dev_get_drvdata(dev);
@@ -618,7 +618,7 @@ static int __maybe_unused rt9120_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops rt9120_pm_ops = {
- SET_RUNTIME_PM_OPS(rt9120_runtime_suspend, rt9120_runtime_resume, NULL)
+ RUNTIME_PM_OPS(rt9120_runtime_suspend, rt9120_runtime_resume, NULL)
};
static const struct of_device_id __maybe_unused rt9120_device_table[] = {
@@ -631,7 +631,7 @@ static struct i2c_driver rt9120_driver = {
.driver = {
.name = "rt9120",
.of_match_table = rt9120_device_table,
- .pm = &rt9120_pm_ops,
+ .pm = pm_ptr(&rt9120_pm_ops),
},
.probe = rt9120_probe,
.remove = rt9120_remove,
diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c
index aa3eadecd974..391cc03d687f 100644
--- a/sound/soc/codecs/rtq9128.c
+++ b/sound/soc/codecs/rtq9128.c
@@ -729,7 +729,7 @@ static int rtq9128_probe(struct i2c_client *i2c)
return devm_snd_soc_register_component(dev, &rtq9128_comp_driver, &rtq9128_dai, 1);
}
-static int __maybe_unused rtq9128_pm_runtime_suspend(struct device *dev)
+static int rtq9128_pm_runtime_suspend(struct device *dev)
{
struct rtq9128_data *data = dev_get_drvdata(dev);
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -746,7 +746,7 @@ static int __maybe_unused rtq9128_pm_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rtq9128_pm_runtime_resume(struct device *dev)
+static int rtq9128_pm_runtime_resume(struct device *dev)
{
struct rtq9128_data *data = dev_get_drvdata(dev);
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -764,8 +764,8 @@ static int __maybe_unused rtq9128_pm_runtime_resume(struct device *dev)
return regcache_sync(regmap);
}
-static const struct dev_pm_ops __maybe_unused rtq9128_pm_ops = {
- SET_RUNTIME_PM_OPS(rtq9128_pm_runtime_suspend, rtq9128_pm_runtime_resume, NULL)
+static const struct dev_pm_ops rtq9128_pm_ops = {
+ RUNTIME_PM_OPS(rtq9128_pm_runtime_suspend, rtq9128_pm_runtime_resume, NULL)
};
static const struct of_device_id rtq9128_device_table[] = {
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 7aa89e34657e..2cc8efe3d896 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -806,9 +806,9 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
* - clock and frame master
*/
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
i2sctl |= SGTL5000_I2S_MASTER;
sgtl5000->master = 1;
break;
diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c
index f2cea6186d98..f5c303d4bb62 100644
--- a/sound/soc/codecs/sma1307.c
+++ b/sound/soc/codecs/sma1307.c
@@ -1019,14 +1019,9 @@ static const struct snd_kcontrol_new sma1307_aif_out1_source_control = {
.private_value = (unsigned long)&sma1307_aif_out_source_enum
};
-static const struct snd_kcontrol_new sma1307_sdo_control = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Switch",
- .info = snd_soc_info_volsw,
- .get = sma1307_dapm_sdo_enable_get,
- .put = sma1307_dapm_sdo_enable_put,
- .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, 0, 1, 0, 0)
-};
+static const struct snd_kcontrol_new sma1307_sdo_control =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM, 0, 1, 0,
+ sma1307_dapm_sdo_enable_get, sma1307_dapm_sdo_enable_put);
static const struct snd_kcontrol_new sma1307_enable_control =
SOC_DAPM_SINGLE("Switch", SMA1307_00_SYSTEM_CTRL, 0, 1, 0);
@@ -1728,6 +1723,11 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
}
data = 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);
@@ -1741,6 +1741,12 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
sma1307->set.header = devm_kzalloc(sma1307->dev,
sma1307->set.header_size,
GFP_KERNEL);
+ if (!sma1307->set.header) {
+ kfree(data);
+ sma1307->set.status = false;
+ return;
+ }
+
memcpy(sma1307->set.header, data,
sma1307->set.header_size * sizeof(int));
@@ -1756,6 +1762,13 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
sma1307->set.def
= devm_kzalloc(sma1307->dev,
sma1307->set.def_size * sizeof(int), GFP_KERNEL);
+ if (!sma1307->set.def) {
+ kfree(data);
+ kfree(sma1307->set.header);
+ sma1307->set.status = false;
+ return;
+ }
+
memcpy(sma1307->set.def,
&data[sma1307->set.header_size],
sma1307->set.def_size * sizeof(int));
@@ -1768,6 +1781,16 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil
= devm_kzalloc(sma1307->dev,
sma1307->set.mode_size * 2 * sizeof(int),
GFP_KERNEL);
+ if (!sma1307->set.mode_set[i]) {
+ kfree(data);
+ kfree(sma1307->set.header);
+ kfree(sma1307->set.def);
+ for (int j = 0; j < i; j++)
+ kfree(sma1307->set.mode_set[j]);
+ sma1307->set.status = false;
+ return;
+ }
+
for (int j = 0; j < sma1307->set.mode_size; j++) {
sma1307->set.mode_set[i][2 * j]
= data[offset + ((num_mode + 1) * j)];
@@ -2011,8 +2034,8 @@ static void sma1307_i2c_remove(struct i2c_client *client)
}
static const struct i2c_device_id sma1307_i2c_id[] = {
- { "sma1307a", 0 },
- { "sma1307aq", 0 },
+ { "sma1307a" },
+ { "sma1307aq" },
{ }
};
diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c
index db4e280dd055..5a3489475225 100644
--- a/sound/soc/codecs/src4xxx.c
+++ b/sound/soc/codecs/src4xxx.c
@@ -158,11 +158,11 @@ static int src4xxx_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int ctrl;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ctrl = SRC4XXX_BUS_MASTER;
src4xxx->master[dai->id] = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
ctrl = 0;
src4xxx->master[dai->id] = false;
break;
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c
index 596096466cd4..49c74cba17c7 100644
--- a/sound/soc/codecs/ssm2602-i2c.c
+++ b/sound/soc/codecs/ssm2602-i2c.c
@@ -13,8 +13,6 @@
#include "ssm2602.h"
-static const struct i2c_device_id ssm2602_i2c_id[];
-
/*
* ssm2602 2 wire address is determined by GPIO5
* state during powerup.
@@ -23,8 +21,7 @@ static const struct i2c_device_id ssm2602_i2c_id[];
*/
static int ssm2602_i2c_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_match_id(ssm2602_i2c_id, client);
- return ssm2602_probe(&client->dev, id->driver_data,
+ return ssm2602_probe(&client->dev, (uintptr_t)i2c_get_match_data(client),
devm_regmap_init_i2c(client, &ssm2602_regmap_config));
}
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 684d52ec6600..b56dd279d90a 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -138,7 +138,6 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = {
{"ASI OUT", NULL, "DMIC"}
};
-#ifdef CONFIG_PM
static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown)
{
u8 cfg1_reg = 0;
@@ -152,7 +151,6 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown)
snd_soc_component_update_bits(tas2552->component, TAS2552_CFG_1, TAS2552_SWS,
cfg1_reg);
}
-#endif
static int tas2552_setup_pll(struct snd_soc_component *component,
struct snd_pcm_hw_params *params)
@@ -480,7 +478,6 @@ static int tas2552_mute(struct snd_soc_dai *dai, int mute, int direction)
return 0;
}
-#ifdef CONFIG_PM
static int tas2552_runtime_suspend(struct device *dev)
{
struct tas2552_data *tas2552 = dev_get_drvdata(dev);
@@ -508,11 +505,9 @@ static int tas2552_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops tas2552_pm = {
- SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume, NULL)
};
static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = {
@@ -768,7 +763,7 @@ static struct i2c_driver tas2552_i2c_driver = {
.driver = {
.name = "tas2552",
.of_match_table = of_match_ptr(tas2552_of_match),
- .pm = &tas2552_pm,
+ .pm = pm_ptr(&tas2552_pm),
},
.probe = tas2552_probe,
.remove = tas2552_i2c_remove,
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index 54561ae598b8..8e00dcc09d0c 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -513,17 +513,9 @@ static const struct snd_kcontrol_new vsense_switch =
static const struct snd_kcontrol_new tas2562_snd_controls[] = {
SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 1, 0x1c, 0,
tas2562_dac_tlv),
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Digital Volume Control",
- .index = 0,
- .tlv.p = dvc_tlv,
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_soc_info_volsw,
- .get = tas2562_volume_control_get,
- .put = tas2562_volume_control_put,
- .private_value = SOC_SINGLE_VALUE(TAS2562_DVC_CFG1, 0, 110, 0, 0),
- },
+ SOC_SINGLE_EXT_TLV("Digital Volume Control", TAS2562_DVC_CFG1, 0, 110, 0,
+ tas2562_volume_control_get, tas2562_volume_control_put,
+ dvc_tlv),
};
static const struct snd_soc_dapm_widget tas2110_dapm_widgets[] = {
@@ -731,16 +723,14 @@ static int tas2562_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct tas2562_data *data;
int ret;
- const struct i2c_device_id *id;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- id = i2c_match_id(tas2562_id, client);
data->client = client;
data->dev = &client->dev;
- data->model_id = id->driver_data;
+ data->model_id = (uintptr_t)i2c_get_match_data(client);
tas2562_parse_dt(data);
diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c
index d482cd194c08..08aa7ee34256 100644
--- a/sound/soc/codecs/tas2764.c
+++ b/sound/soc/codecs/tas2764.c
@@ -14,6 +14,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
@@ -23,6 +24,11 @@
#include "tas2764.h"
+enum tas2764_devid {
+ DEVID_TAS2764 = 0,
+ DEVID_SN012776 = 1
+};
+
struct tas2764_priv {
struct snd_soc_component *component;
struct gpio_desc *reset_gpio;
@@ -30,7 +36,8 @@ struct tas2764_priv {
struct regmap *regmap;
struct device *dev;
int irq;
-
+ enum tas2764_devid devid;
+
int v_sense_slot;
int i_sense_slot;
@@ -142,6 +149,8 @@ static int tas2764_codec_suspend(struct snd_soc_component *component)
regcache_cache_only(tas2764->regmap, true);
regcache_mark_dirty(tas2764->regmap);
+ usleep_range(6000, 7000);
+
return 0;
}
@@ -180,33 +189,6 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new tas2764_asi1_mux =
SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
-static int tas2764_dac_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 tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
- int ret;
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- tas2764->dac_powered = true;
- ret = tas2764_update_pwr_ctrl(tas2764);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- tas2764->dac_powered = false;
- ret = tas2764_update_pwr_ctrl(tas2764);
- break;
- default:
- dev_err(tas2764->dev, "Unsupported event\n");
- return -EINVAL;
- }
-
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static const struct snd_kcontrol_new isense_switch =
SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1);
static const struct snd_kcontrol_new vsense_switch =
@@ -219,8 +201,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = {
1, &isense_switch),
SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN,
1, &vsense_switch),
- SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("OUT"),
SND_SOC_DAPM_SIGGEN("VMON"),
SND_SOC_DAPM_SIGGEN("IMON")
@@ -241,9 +222,34 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction)
{
struct tas2764_priv *tas2764 =
snd_soc_component_get_drvdata(dai->component);
+ int ret;
+
+ if (!mute) {
+ tas2764->dac_powered = true;
+ ret = tas2764_update_pwr_ctrl(tas2764);
+ if (ret)
+ return ret;
+ }
tas2764->unmuted = !mute;
- return tas2764_update_pwr_ctrl(tas2764);
+ ret = tas2764_update_pwr_ctrl(tas2764);
+ if (ret)
+ return ret;
+
+ if (mute) {
+ /* Wait for ramp-down */
+ usleep_range(6000, 7000);
+
+ tas2764->dac_powered = false;
+ ret = tas2764_update_pwr_ctrl(tas2764);
+ if (ret)
+ return ret;
+
+ /* Wait a bit after shutdown */
+ usleep_range(2000, 3000);
+ }
+
+ return 0;
}
static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth)
@@ -365,7 +371,7 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_component *component = dai->component;
struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
- u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0;
+ u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0, asi_cfg_4 = 0;
int ret;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -374,12 +380,14 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
fallthrough;
case SND_SOC_DAIFMT_NB_NF:
asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
+ asi_cfg_4 = TAS2764_TDM_CFG4_TX_FALLING;
break;
case SND_SOC_DAIFMT_IB_IF:
asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
fallthrough;
case SND_SOC_DAIFMT_IB_NF:
asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
+ asi_cfg_4 = TAS2764_TDM_CFG4_TX_RISING;
break;
}
@@ -389,6 +397,12 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
if (ret < 0)
return ret;
+ ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG4,
+ TAS2764_TDM_CFG4_TX_MASK,
+ asi_cfg_4);
+ if (ret < 0)
+ return ret;
+
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
@@ -526,10 +540,16 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = {
},
};
+static uint8_t sn012776_bop_presets[] = {
+ 0x01, 0x32, 0x02, 0x22, 0x83, 0x2d, 0x80, 0x02, 0x06,
+ 0x32, 0x46, 0x30, 0x02, 0x06, 0x38, 0x40, 0x30, 0x02,
+ 0x06, 0x3e, 0x37, 0x30, 0xff, 0xe6
+};
+
static int tas2764_codec_probe(struct snd_soc_component *component)
{
struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
- int ret;
+ int ret, i;
tas2764->component = component;
@@ -578,6 +598,27 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
if (ret < 0)
return ret;
+ switch (tas2764->devid) {
+ case DEVID_SN012776:
+ ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
+ TAS2764_PWR_CTRL_BOP_SRC,
+ TAS2764_PWR_CTRL_BOP_SRC);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(sn012776_bop_presets); i++) {
+ ret = snd_soc_component_write(component,
+ TAS2764_BOP_CFG0 + i,
+ sn012776_bop_presets[i]);
+
+ if (ret < 0)
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
return 0;
}
@@ -593,12 +634,21 @@ static SOC_ENUM_SINGLE_DECL(
tas2764_hpf_enum, TAS2764_DC_BLK0,
TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts);
+static const char * const tas2764_oce_texts[] = {
+ "Disable", "Retry",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ tas2764_oce_enum, TAS2764_MISC_CFG1,
+ TAS2764_MISC_CFG1_OCE_RETRY_SHIFT, tas2764_oce_texts);
+
static const struct snd_kcontrol_new tas2764_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
TAS2764_DVC_MAX, 1, tas2764_playback_volume),
SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
tas2764_digital_tlv),
SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum),
+ SOC_ENUM("OCE Handling", tas2764_oce_enum),
};
static const struct snd_soc_component_driver soc_component_driver_tas2764 = {
@@ -626,6 +676,7 @@ static const struct reg_default tas2764_reg_defaults[] = {
{ TAS2764_TDM_CFG2, 0x0a },
{ TAS2764_TDM_CFG3, 0x10 },
{ TAS2764_TDM_CFG5, 0x42 },
+ { TAS2764_INT_CLK_CFG, 0x19 },
};
static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
@@ -643,6 +694,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = {
static bool tas2764_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
+ case TAS2764_SW_RST:
case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4:
case TAS2764_INT_CLK_CFG:
return true;
@@ -707,6 +759,8 @@ static int tas2764_i2c_probe(struct i2c_client *client)
if (!tas2764)
return -ENOMEM;
+ tas2764->devid = (enum tas2764_devid)of_device_get_match_data(&client->dev);
+
tas2764->dev = &client->dev;
tas2764->irq = client->irq;
i2c_set_clientdata(client, tas2764);
@@ -743,7 +797,8 @@ MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id);
#if defined(CONFIG_OF)
static const struct of_device_id tas2764_of_match[] = {
- { .compatible = "ti,tas2764" },
+ { .compatible = "ti,tas2764", .data = (void *)DEVID_TAS2764 },
+ { .compatible = "ti,sn012776", .data = (void *)DEVID_SN012776 },
{},
};
MODULE_DEVICE_TABLE(of, tas2764_of_match);
diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h
index 168af772a898..3251dc0106e0 100644
--- a/sound/soc/codecs/tas2764.h
+++ b/sound/soc/codecs/tas2764.h
@@ -25,10 +25,11 @@
/* Power Control */
#define TAS2764_PWR_CTRL TAS2764_REG(0X0, 0x02)
-#define TAS2764_PWR_CTRL_MASK GENMASK(1, 0)
+#define TAS2764_PWR_CTRL_MASK GENMASK(2, 0)
#define TAS2764_PWR_CTRL_ACTIVE 0x0
#define TAS2764_PWR_CTRL_MUTE BIT(0)
#define TAS2764_PWR_CTRL_SHUTDOWN BIT(1)
+#define TAS2764_PWR_CTRL_BOP_SRC BIT(7)
#define TAS2764_VSENSE_POWER_EN 3
#define TAS2764_ISENSE_POWER_EN 4
@@ -43,6 +44,10 @@
#define TAS2764_CHNL_0 TAS2764_REG(0X0, 0x03)
+/* Miscellaneous */
+#define TAS2764_MISC_CFG1 TAS2764_REG(0x0, 0x06)
+#define TAS2764_MISC_CFG1_OCE_RETRY_SHIFT 5
+
/* TDM Configuration Reg0 */
#define TAS2764_TDM_CFG0 TAS2764_REG(0X0, 0x08)
#define TAS2764_TDM_CFG0_SMP_MASK BIT(5)
@@ -79,6 +84,12 @@
#define TAS2764_TDM_CFG3_RXS_SHIFT 0x4
#define TAS2764_TDM_CFG3_MASK GENMASK(3, 0)
+/* TDM Configuration Reg4 */
+#define TAS2764_TDM_CFG4 TAS2764_REG(0X0, 0x0d)
+#define TAS2764_TDM_CFG4_TX_MASK BIT(0)
+#define TAS2764_TDM_CFG4_TX_RISING 0x0
+#define TAS2764_TDM_CFG4_TX_FALLING BIT(0)
+
/* TDM Configuration Reg5 */
#define TAS2764_TDM_CFG5 TAS2764_REG(0X0, 0x0e)
#define TAS2764_TDM_CFG5_VSNS_MASK BIT(6)
@@ -110,4 +121,6 @@
#define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c)
#define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2)
+#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d)
+
#endif /* __TAS2764__ */
diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c
index 9f93b230652a..7f219df8be70 100644
--- a/sound/soc/codecs/tas2770.c
+++ b/sound/soc/codecs/tas2770.c
@@ -189,6 +189,31 @@ static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction)
return tas2770_update_pwr_ctrl(tas2770);
}
+static int tas2770_set_ivsense_transmit(struct tas2770_priv *tas2770,
+ int i_slot, int v_slot)
+{
+ struct snd_soc_component *component = tas2770->component;
+ int ret;
+
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG5,
+ TAS2770_TDM_CFG_REG5_VSNS_MASK |
+ TAS2770_TDM_CFG_REG5_50_MASK,
+ TAS2770_TDM_CFG_REG5_VSNS_ENABLE |
+ v_slot);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG6,
+ TAS2770_TDM_CFG_REG6_ISNS_MASK |
+ TAS2770_TDM_CFG_REG6_50_MASK,
+ TAS2770_TDM_CFG_REG6_ISNS_ENABLE |
+ i_slot);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
{
int ret;
@@ -199,19 +224,16 @@ static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,
TAS2770_TDM_CFG_REG2_RXW_MASK,
TAS2770_TDM_CFG_REG2_RXW_16BITS);
- tas2770->v_sense_slot = tas2770->i_sense_slot + 2;
break;
case SNDRV_PCM_FORMAT_S24_LE:
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,
TAS2770_TDM_CFG_REG2_RXW_MASK,
TAS2770_TDM_CFG_REG2_RXW_24BITS);
- tas2770->v_sense_slot = tas2770->i_sense_slot + 4;
break;
case SNDRV_PCM_FORMAT_S32_LE:
ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2,
TAS2770_TDM_CFG_REG2_RXW_MASK,
TAS2770_TDM_CFG_REG2_RXW_32BITS);
- tas2770->v_sense_slot = tas2770->i_sense_slot + 4;
break;
default:
@@ -221,22 +243,6 @@ static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth)
if (ret < 0)
return ret;
- ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG5,
- TAS2770_TDM_CFG_REG5_VSNS_MASK |
- TAS2770_TDM_CFG_REG5_50_MASK,
- TAS2770_TDM_CFG_REG5_VSNS_ENABLE |
- tas2770->v_sense_slot);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG6,
- TAS2770_TDM_CFG_REG6_ISNS_MASK |
- TAS2770_TDM_CFG_REG6_50_MASK,
- TAS2770_TDM_CFG_REG6_ISNS_ENABLE |
- tas2770->i_sense_slot);
- if (ret < 0)
- return ret;
-
return 0;
}
@@ -491,6 +497,7 @@ static int tas2770_codec_probe(struct snd_soc_component *component)
{
struct tas2770_priv *tas2770 =
snd_soc_component_get_drvdata(component);
+ int ret;
tas2770->component = component;
@@ -502,11 +509,19 @@ static int tas2770_codec_probe(struct snd_soc_component *component)
tas2770_reset(tas2770);
regmap_reinit_cache(tas2770->regmap, &tas2770_i2c_regmap);
+ if (tas2770->i_sense_slot != -1 && tas2770->v_sense_slot != -1) {
+ ret = tas2770_set_ivsense_transmit(tas2770, tas2770->i_sense_slot,
+ tas2770->v_sense_slot);
+
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
static DECLARE_TLV_DB_SCALE(tas2770_digital_tlv, 1100, 50, 0);
-static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -12750, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2770_playback_volume, -10050, 50, 0);
static const struct snd_kcontrol_new tas2770_snd_controls[] = {
SOC_SINGLE_TLV("Speaker Playback Volume", TAS2770_PLAY_CFG_REG2,
@@ -629,7 +644,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770)
dev_info(tas2770->dev, "Property %s is missing setting default slot\n",
"ti,imon-slot-no");
- tas2770->i_sense_slot = 0;
+ tas2770->i_sense_slot = -1;
}
rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
@@ -638,7 +653,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770)
dev_info(tas2770->dev, "Property %s is missing setting default slot\n",
"ti,vmon-slot-no");
- tas2770->v_sense_slot = 2;
+ tas2770->v_sense_slot = -1;
}
tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH);
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index 61d9c220b6a4..13a197468193 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -2,9 +2,10 @@
//
// tas2781-fmwlib.c -- TASDEVICE firmware support
//
-// Copyright 2023 - 2024 Texas Instruments, Inc.
+// Copyright 2023 - 2025 Texas Instruments, Inc.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
+// Author: Baojun Xu <baojun.xu@ti.com>
#include <linux/crc8.h>
#include <linux/firmware.h>
@@ -389,10 +390,10 @@ static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw,
int i, n = ARRAY_SIZE(non_ppc3_mapping_table);
unsigned char dev_idx = 0;
- if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) {
+ if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) {
p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table;
n = ARRAY_SIZE(ppc3_tas2781_mapping_table);
- } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) {
+ } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) {
p = (struct blktyp_devidx_map *)ppc3_mapping_table;
n = ARRAY_SIZE(ppc3_mapping_table);
}
@@ -559,6 +560,124 @@ out:
return offset;
}
+static void fct_param_address_parser(struct cali_reg *r,
+ struct tasdevice_fw *tas_fmw, const unsigned char *data)
+{
+ struct fct_param_address *p = &tas_fmw->fct_par_addr;
+ unsigned int i;
+
+ /*
+ * Calibration parameters locations and data schema in dsp firmware.
+ * The number of items are flexible, but not more than 20. The dsp tool
+ * will reseve 20*24-byte space for fct params. In some cases, the
+ * number of fct param is less than 20, the data will be saved from the
+ * beginning, the rest part will be stuffed with zero.
+ *
+ * fct_param_num (not more than 20)
+ * for (i = 0; i < fct_param_num; i++) {
+ * Alias of fct param (20 bytes)
+ * Book (1 byte)
+ * Page (1 byte)
+ * Offset (1 byte)
+ * CoeffLength (1 byte) = 0x1
+ * }
+ * if (20 - fct_param_num)
+ * 24*(20 - fct_param_num) pieces of '0' as stuffing
+ *
+ * As follow:
+ * umg_SsmKEGCye = Book, Page, Offset, CoeffLength
+ * iks_E0 = Book, Page, Offset, CoeffLength
+ * yep_LsqM0 = Book, Page, Offset, CoeffLength
+ * oyz_U0_ujx = Book, Page, Offset, CoeffLength
+ * iks_GC_GMgq = Book, Page, Offset, CoeffLength
+ * gou_Yao = Book, Page, Offset, CoeffLength
+ * kgd_Wsc_Qsbp = Book, Page, Offset, CoeffLength
+ * yec_CqseSsqs = Book, Page, Offset, CoeffLength
+ * iks_SogkGgog2 = Book, Page, Offset, CoeffLength
+ * yec_Sae_Y = Book, Page, Offset, CoeffLength
+ * Re_Int = Book, Page, Offset, CoeffLength
+ * SigFlag = Book, Page, Offset, CoeffLength
+ * a1_Int = Book, Page, Offset, CoeffLength
+ * a2_Int = Book, Page, Offset, CoeffLength
+ */
+ for (i = 0; i < 20; i++) {
+ const unsigned char *dat = &data[24 * i];
+
+ /*
+ * check whether current fct param is empty.
+ */
+ if (dat[23] != 1)
+ break;
+
+ if (!strncmp(dat, "umg_SsmKEGCye", 20))
+ r->pow_reg = TASDEVICE_REG(dat[20], dat[21], dat[22]);
+ /* high 32-bit of real-time spk impedance */
+ else if (!strncmp(dat, "iks_E0", 20))
+ r->r0_reg = TASDEVICE_REG(dat[20], dat[21], dat[22]);
+ /* inverse of real-time spk impedance */
+ else if (!strncmp(dat, "yep_LsqM0", 20))
+ r->invr0_reg =
+ TASDEVICE_REG(dat[20], dat[21], dat[22]);
+ /* low 32-bit of real-time spk impedance */
+ else if (!strncmp(dat, "oyz_U0_ujx", 20))
+ r->r0_low_reg =
+ TASDEVICE_REG(dat[20], dat[21], dat[22]);
+ /* Delta Thermal Limit */
+ else if (!strncmp(dat, "iks_GC_GMgq", 20))
+ r->tlimit_reg =
+ TASDEVICE_REG(dat[20], dat[21], dat[22]);
+ /* Thermal data for PG 1.0 device */
+ else if (!strncmp(dat, "gou_Yao", 20))
+ memcpy(p->thr, &dat[20], 3);
+ /* Pilot tone enable flag, usually the sine wave */
+ else if (!strncmp(dat, "kgd_Wsc_Qsbp", 20))
+ memcpy(p->plt_flg, &dat[20], 3);
+ /* Pilot tone gain for calibration */
+ else if (!strncmp(dat, "yec_CqseSsqs", 20))
+ memcpy(p->sin_gn, &dat[20], 3);
+ /* Pilot tone gain for calibration, useless in PG 2.0 */
+ else if (!strncmp(dat, "iks_SogkGgog2", 20))
+ memcpy(p->sin_gn2, &dat[20], 3);
+ /* Thermal data for PG 2.0 device */
+ else if (!strncmp(dat, "yec_Sae_Y", 20))
+ memcpy(p->thr2, &dat[20], 3);
+ /* Spk Equivalent Resistance in fixed-point format */
+ else if (!strncmp(dat, "Re_Int", 20))
+ memcpy(p->r0_reg, &dat[20], 3);
+ /* Check whether the spk connection is open */
+ else if (!strncmp(dat, "SigFlag", 20))
+ memcpy(p->tf_reg, &dat[20], 3);
+ /* check spk resonant frequency */
+ else if (!strncmp(dat, "a1_Int", 20))
+ memcpy(p->a1_reg, &dat[20], 3);
+ /* check spk resonant frequency */
+ else if (!strncmp(dat, "a2_Int", 20))
+ memcpy(p->a2_reg, &dat[20], 3);
+ }
+}
+
+static int fw_parse_fct_param_address(struct tasdevice_priv *tas_priv,
+ struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+ struct calidata *cali_data = &tas_priv->cali_data;
+ struct cali_reg *r = &cali_data->cali_reg_array;
+ const unsigned char *data = fmw->data;
+
+ if (offset + 520 > fmw->size) {
+ dev_err(tas_priv->dev, "%s: File Size error\n", __func__);
+ return -EINVAL;
+ }
+
+ /* skip reserved part */
+ offset += 40;
+
+ fct_param_address_parser(r, tas_fmw, &data[offset]);
+
+ offset += 480;
+
+ return offset;
+}
+
static int fw_parse_variable_header_kernel(
struct tasdevice_priv *tas_priv, const struct firmware *fmw,
int offset)
@@ -1496,7 +1615,7 @@ static int tasdev_block_chksum(struct tasdevice_priv *tas_priv,
unsigned int nr_value;
int ret;
- ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_I2CChecksum,
+ ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG,
&nr_value);
if (ret < 0) {
dev_err(tas_priv->dev, "%s: Chn %d\n", __func__, chn);
@@ -1540,7 +1659,7 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv,
while (block->nr_retry > 0) {
if (block->is_pchksum_present) {
ret = tasdevice_dev_write(tas_priv, chn,
- TASDEVICE_I2CChecksum, 0);
+ TASDEVICE_CHECKSUM_REG, 0);
if (ret < 0)
break;
}
@@ -1686,13 +1805,29 @@ static int tasdevice_load_block(struct tasdevice_priv *tas_priv,
return rc;
}
+static void dspbin_type_check(struct tasdevice_priv *tas_priv,
+ unsigned int ppcver)
+{
+ if (ppcver >= PPC3_VERSION_TAS2781_ALPHA_MIN) {
+ if (ppcver >= PPC3_VERSION_TAS2781_BETA_MIN)
+ tas_priv->dspbin_typ = TASDEV_BETA;
+ else if (ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN)
+ tas_priv->dspbin_typ = TASDEV_BASIC;
+ else
+ tas_priv->dspbin_typ = TASDEV_ALPHA;
+ }
+ if (tas_priv->dspbin_typ != TASDEV_BASIC)
+ tas_priv->fw_parse_fct_param_address =
+ fw_parse_fct_param_address;
+}
+
static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
unsigned int drv_ver, unsigned int ppcver)
{
int rc = 0;
if (drv_ver == 0x100) {
- if (ppcver >= PPC3_VERSION) {
+ if (ppcver >= PPC3_VERSION_BASE) {
tas_priv->fw_parse_variable_header =
fw_parse_variable_header_kernel;
tas_priv->fw_parse_program_data =
@@ -1701,6 +1836,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
fw_parse_configuration_data_kernel;
tas_priv->tasdevice_load_block =
tasdevice_load_block_kernel;
+ dspbin_type_check(tas_priv, ppcver);
} else {
switch (ppcver) {
case 0x00:
@@ -1716,7 +1852,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
default:
dev_err(tas_priv->dev,
"%s: PPCVer must be 0x0 or 0x%02x",
- __func__, PPC3_VERSION);
+ __func__, PPC3_VERSION_BASE);
dev_err(tas_priv->dev, " Current:0x%02x\n",
ppcver);
rc = -EINVAL;
@@ -1952,28 +2088,25 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
struct tasdevice_fw_fixed_hdr *fw_fixed_hdr;
struct tasdevice_fw *tas_fmw;
int offset = 0;
- int ret = 0;
+ int ret;
if (!fmw || !fmw->data) {
dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n",
__func__, tas_priv->coef_binaryname);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
tas_priv->fmw = kzalloc(sizeof(struct tasdevice_fw), GFP_KERNEL);
- if (!tas_priv->fmw) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!tas_priv->fmw)
+ return -ENOMEM;
+
tas_fmw = tas_priv->fmw;
tas_fmw->dev = tas_priv->dev;
offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset);
- if (offset == -EINVAL) {
- ret = -EINVAL;
- goto out;
- }
+ if (offset == -EINVAL)
+ return -EINVAL;
+
fw_fixed_hdr = &(tas_fmw->fw_hdr.fixed_hdr);
/* Support different versions of firmware */
switch (fw_fixed_hdr->drv_ver) {
@@ -2006,28 +2139,32 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw,
ret = dspfw_default_callback(tas_priv,
fw_fixed_hdr->drv_ver, fw_fixed_hdr->ppcver);
if (ret)
- goto out;
+ return ret;
break;
}
offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset);
- if (offset < 0) {
- ret = offset;
- goto out;
- }
+ if (offset < 0)
+ return offset;
+
offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw,
offset);
- if (offset < 0) {
- ret = offset;
- goto out;
- }
+ if (offset < 0)
+ return offset;
+
offset = tas_priv->fw_parse_configuration_data(tas_priv,
tas_fmw, fmw, offset);
if (offset < 0)
- ret = offset;
+ return offset;
-out:
- return ret;
+ if (tas_priv->fw_parse_fct_param_address) {
+ offset = tas_priv->fw_parse_fct_param_address(tas_priv,
+ tas_fmw, fmw, offset);
+ if (offset < 0)
+ return offset;
+ }
+
+ return 0;
}
int tasdevice_dsp_parser(void *context)
diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c
index 728bf78ae71f..b950914b7d48 100644
--- a/sound/soc/codecs/tas2781-i2c.c
+++ b/sound/soc/codecs/tas2781-i2c.c
@@ -2,7 +2,7 @@
//
// ALSA SoC Texas Instruments TAS2563/TAS2781 Audio Smart Amplifier
//
-// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
+// Copyright (C) 2022 - 2025 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2563/TAS2781 driver implements a flexible and configurable
@@ -349,13 +349,31 @@ static int calib_data_get(struct tasdevice_priv *tas_priv, int reg,
return rc;
}
+static int partial_cali_data_update(int *reg, int j)
+{
+ switch (tas2781_cali_start_reg[j].reg) {
+ case 0:
+ return reg[0];
+ case TAS2781_PRM_PLT_FLAG_REG:
+ return reg[1];
+ case TAS2781_PRM_SINEGAIN_REG:
+ return reg[2];
+ case TAS2781_PRM_SINEGAIN2_REG:
+ return reg[3];
+ default:
+ return 0;
+ }
+}
+
static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
int *reg, unsigned char *dat)
{
struct tasdevice *tasdev = tas_priv->tasdevice;
struct bulk_reg_val *p = tasdev[i].cali_data_backup;
+ struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp;
const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
- int j;
+ unsigned char val[4];
+ int j, r;
if (p == NULL)
return;
@@ -370,30 +388,23 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
tasdevice_dev_read(tas_priv, i, p[j].reg,
(int *)&p[j].val[0]);
} else {
- switch (tas2781_cali_start_reg[j].reg) {
- case 0: {
- if (!reg[0])
- continue;
- p[j].reg = reg[0];
+ if (!tas_priv->dspbin_typ) {
+ r = partial_cali_data_update(reg, j);
+ if (r)
+ p[j].reg = r;
}
- break;
- case TAS2781_PRM_PLT_FLAG_REG:
- p[j].reg = reg[1];
- break;
- case TAS2781_PRM_SINEGAIN_REG:
- p[j].reg = reg[2];
- break;
- case TAS2781_PRM_SINEGAIN2_REG:
- p[j].reg = reg[3];
- break;
- }
- tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
- p[j].val, 4);
+
+ if (p[j].reg)
+ tasdevice_dev_bulk_read(tas_priv, i, p[j].reg,
+ p[j].val, 4);
}
}
+ if (tas_priv->dspbin_typ == TASDEV_ALPHA)
+ tasdevice_dev_bulk_read(tas_priv, i, t->reg, t->val, 4);
+
/* Update the setting for calibration */
- for (j = 0; j < sum - 2; j++) {
+ for (j = 0; j < sum - 4; j++) {
if (p[j].val_len == 1) {
if (p[j].is_locked)
tasdevice_dev_write(tas_priv, i,
@@ -401,17 +412,33 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i,
TAS2781_TEST_PAGE_UNLOCK);
tasdevice_dev_write(tas_priv, i, p[j].reg,
tas2781_cali_start_reg[j].val[0]);
- } else {
- if (!p[j].reg)
- continue;
- tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
- (unsigned char *)
- tas2781_cali_start_reg[j].val, 4);
}
}
- tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, &dat[1], 4);
- tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg, &dat[5], 4);
+ if (tas_priv->dspbin_typ == TASDEV_ALPHA) {
+ val[0] = 0x00;
+ val[1] = 0x00;
+ val[2] = 0x21;
+ val[3] = 0x8e;
+ } else {
+ val[0] = tas2781_cali_start_reg[j].val[0];
+ val[1] = tas2781_cali_start_reg[j].val[1];
+ val[2] = tas2781_cali_start_reg[j].val[2];
+ val[3] = tas2781_cali_start_reg[j].val[3];
+ }
+ tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, val, 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg,
+ (unsigned char *)tas2781_cali_start_reg[j + 1].val, 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 2].reg, &dat[1], 4);
+ tasdevice_dev_bulk_write(tas_priv, i, p[j + 3].reg, &dat[5], 4);
+ if (tas_priv->dspbin_typ == TASDEV_ALPHA) {
+ val[0] = 0x00;
+ val[1] = 0x00;
+ val[2] = 0x2a;
+ val[3] = 0x0b;
+
+ tasdevice_dev_bulk_read(tas_priv, i, t->reg, val, 4);
+ }
}
static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol,
@@ -452,14 +479,15 @@ static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol,
return 1;
}
-static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv)
+static void tas2781_calib_stop_put(struct tasdevice_priv *priv)
{
const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
int i, j;
- for (i = 0; i < tas_priv->ndev; i++) {
- struct tasdevice *tasdev = tas_priv->tasdevice;
+ for (i = 0; i < priv->ndev; i++) {
+ struct tasdevice *tasdev = priv->tasdevice;
struct bulk_reg_val *p = tasdev[i].cali_data_backup;
+ struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp;
if (p == NULL)
continue;
@@ -467,18 +495,21 @@ static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv)
for (j = 0; j < sum; j++) {
if (p[j].val_len == 1) {
if (p[j].is_locked)
- tasdevice_dev_write(tas_priv, i,
+ tasdevice_dev_write(priv, i,
TAS2781_TEST_UNLOCK_REG,
TAS2781_TEST_PAGE_UNLOCK);
- tasdevice_dev_write(tas_priv, i, p[j].reg,
+ tasdevice_dev_write(priv, i, p[j].reg,
p[j].val[0]);
} else {
if (!p[j].reg)
continue;
- tasdevice_dev_bulk_write(tas_priv, i, p[j].reg,
+ tasdevice_dev_bulk_write(priv, i, p[j].reg,
p[j].val, 4);
}
}
+
+ if (priv->dspbin_typ == TASDEV_ALPHA)
+ tasdevice_dev_bulk_write(priv, i, t->reg, t->val, 4);
}
}
@@ -489,14 +520,11 @@ static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
const int sum = ARRAY_SIZE(tas2563_cali_start_reg);
- int rc = 1;
int i, j;
guard(mutex)(&tas_priv->codec_lock);
- if (tas_priv->chip_id != TAS2563) {
- rc = -1;
- goto out;
- }
+ if (tas_priv->chip_id != TAS2563)
+ return -1;
for (i = 0; i < tas_priv->ndev; i++) {
struct tasdevice *tasdev = tas_priv->tasdevice;
@@ -523,8 +551,8 @@ static int tas2563_calib_start_put(struct snd_kcontrol *kcontrol,
q[j].val, 4);
}
}
-out:
- return rc;
+
+ return 1;
}
static void tas2563_calib_stop_put(struct tasdevice_priv *tas_priv)
@@ -576,7 +604,7 @@ static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
struct cali_reg *p = &cali_data->cali_reg_array;
unsigned char *src = ucontrol->value.bytes.data;
unsigned char *dst = cali_data->data;
- int rc = 1, i = 0;
+ int i = 0;
int j;
guard(mutex)(&priv->codec_lock);
@@ -593,19 +621,23 @@ static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol,
i += 2;
priv->is_user_space_calidata = true;
- p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
- p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
- i += 3;
+ if (priv->dspbin_typ == TASDEV_BASIC) {
+ p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]);
+ i += 3;
+ } else {
+ i += 15;
+ }
memcpy(dst, &src[i], cali_data->total_sz);
- return rc;
+ return 1;
}
static int tas2781_latch_reg_get(struct snd_kcontrol *kcontrol,
@@ -649,12 +681,19 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
- unsigned int reg;
+ unsigned int reg = TAS2781_RUNTIME_RE_REG_TF;
+
+ if (tas_priv->chip_id == TAS2781) {
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
- if (tas_priv->chip_id == TAS2781)
reg = TAS2781_RUNTIME_RE_REG_TF;
- else
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->tf_reg[0], p->tf_reg[1],
+ p->tf_reg[2]);
+ } else {
reg = TAS2563_RUNTIME_RE_REG_TF;
+ }
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
@@ -669,12 +708,19 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
- unsigned int reg;
+ unsigned int reg = TAS2781_RUNTIME_RE_REG;
- if (tas_priv->chip_id == TAS2781)
- reg = TAS2781_RUNTIME_RE_REG;
- else
+ if (tas_priv->chip_id == TAS2781) {
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
+
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->r0_reg[0], p->r0_reg[1],
+ p->r0_reg[2]);
+ } else {
reg = TAS2563_RUNTIME_RE_REG;
+ }
+
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
return calib_data_get(tas_priv, reg, &dst[1]);
@@ -708,11 +754,16 @@ static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg = TASDEVICE_XM_A1_REG;
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->a1_reg[0], p->a1_reg[1], p->a1_reg[2]);
+
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
return calib_data_get(tas_priv, reg, &dst[1]);
@@ -723,11 +774,16 @@ static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp);
+ struct tasdevice_fw *tas_fmw = tas_priv->fmw;
+ struct fct_param_address *p = &(tas_fmw->fct_par_addr);
struct soc_bytes_ext *bytes_ext =
(struct soc_bytes_ext *) kcontrol->private_value;
unsigned char *dst = ucontrol->value.bytes.data;
unsigned int reg = TASDEVICE_XM_A2_REG;
+ if (tas_priv->dspbin_typ)
+ reg = TASDEVICE_REG(p->a2_reg[0], p->a2_reg[1], p->a2_reg[2]);
+
guard(mutex)(&tas_priv->codec_lock);
dst[0] = bytes_ext->max;
return calib_data_get(tas_priv, reg, &dst[1]);
@@ -1115,25 +1171,21 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
char *conf_name, *prog_name;
int nr_controls = 4;
int mix_index = 0;
- int ret;
/* Alloc kcontrol via devm_kzalloc, which don't manually
* free the kcontrol
*/
dsp_ctrls = devm_kcalloc(tas_priv->dev, nr_controls,
sizeof(dsp_ctrls[0]), GFP_KERNEL);
- if (!dsp_ctrls) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!dsp_ctrls)
+ return -ENOMEM;
/* Create mixer items for selecting the active Program and Config */
prog_name = devm_kstrdup(tas_priv->dev, "Speaker Program Id",
GFP_KERNEL);
- if (!prog_name) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!prog_name)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = prog_name;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_programs;
@@ -1143,10 +1195,9 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
conf_name = devm_kstrdup(tas_priv->dev, "Speaker Config Id",
GFP_KERNEL);
- if (!conf_name) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!conf_name)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = conf_name;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_configurations;
@@ -1156,10 +1207,9 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
active_dev_num = devm_kstrdup(tas_priv->dev, "Activate Tasdevice Num",
GFP_KERNEL);
- if (!active_dev_num) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!active_dev_num)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = active_dev_num;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_active_num;
@@ -1168,27 +1218,64 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv)
mix_index++;
chip_id = devm_kstrdup(tas_priv->dev, "Tasdevice Chip Id", GFP_KERNEL);
- if (!chip_id) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!chip_id)
+ return -ENOMEM;
+
dsp_ctrls[mix_index].name = chip_id;
dsp_ctrls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
dsp_ctrls[mix_index].info = tasdevice_info_chip_id;
dsp_ctrls[mix_index].get = tasdevice_get_chip_id;
mix_index++;
- ret = snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
+ return snd_soc_add_component_controls(tas_priv->codec, dsp_ctrls,
nr_controls < mix_index ? nr_controls : mix_index);
+}
-out:
- return ret;
+static void cali_reg_update(struct bulk_reg_val *p,
+ struct fct_param_address *t)
+{
+ const int sum = ARRAY_SIZE(tas2781_cali_start_reg);
+ int reg, j;
+
+ for (j = 0; j < sum; j++) {
+ switch (tas2781_cali_start_reg[j].reg) {
+ case 0:
+ reg = TASDEVICE_REG(t->thr[0], t->thr[1], t->thr[2]);
+ break;
+ case TAS2781_PRM_PLT_FLAG_REG:
+ reg = TASDEVICE_REG(t->plt_flg[0], t->plt_flg[1],
+ t->plt_flg[2]);
+ break;
+ case TAS2781_PRM_SINEGAIN_REG:
+ reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1],
+ t->sin_gn[2]);
+ break;
+ case TAS2781_PRM_SINEGAIN2_REG:
+ reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1],
+ t->sin_gn[2]);
+ break;
+ default:
+ reg = 0;
+ break;
+ }
+ if (reg)
+ p[j].reg = reg;
+ }
+}
+
+static void alpa_cali_update(struct bulk_reg_val *p,
+ struct fct_param_address *t)
+{
+ p->is_locked = false;
+ p->reg = TASDEVICE_REG(t->thr2[0], t->thr2[1], t->thr2[2]);
+ p->val_len = 4;
}
static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
{
struct calidata *cali_data = &priv->cali_data;
struct tasdevice *tasdev = priv->tasdevice;
+ struct tasdevice_fw *fmw = priv->fmw;
struct soc_bytes_ext *ext_cali_data;
struct snd_kcontrol_new *cali_ctrls;
unsigned int nctrls;
@@ -1204,14 +1291,25 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
}
if (priv->chip_id == TAS2781) {
+ struct fct_param_address *t = &(fmw->fct_par_addr);
+
cali_ctrls = (struct snd_kcontrol_new *)tas2781_cali_controls;
nctrls = ARRAY_SIZE(tas2781_cali_controls);
for (i = 0; i < priv->ndev; i++) {
- tasdev[i].cali_data_backup =
+ struct bulk_reg_val *p;
+
+ p = tasdev[i].cali_data_backup =
kmemdup(tas2781_cali_start_reg,
sizeof(tas2781_cali_start_reg), GFP_KERNEL);
if (!tasdev[i].cali_data_backup)
return -ENOMEM;
+ if (priv->dspbin_typ) {
+ cali_reg_update(p, t);
+ if (priv->dspbin_typ == TASDEV_ALPHA) {
+ p = &tasdev[i].alp_cali_bckp;
+ alpa_cali_update(p, t);
+ }
+ }
}
} else {
cali_ctrls = (struct snd_kcontrol_new *)tas2563_cali_controls;
@@ -1273,8 +1371,6 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv)
(cali_data->cali_dat_sz_per_dev + 1) + 1 + 15 + 1;
priv->cali_data.total_sz = priv->ndev *
(cali_data->cali_dat_sz_per_dev + 1);
- priv->cali_data.data = devm_kzalloc(priv->dev,
- ext_cali_data->max, GFP_KERNEL);
cali_ctrls[i].name = cali_name;
cali_ctrls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
cali_ctrls[i].info = snd_soc_bytes_info_ext;
@@ -1469,7 +1565,6 @@ static int tasdevice_hw_params(struct snd_pcm_substream *substream,
unsigned int slot_width;
unsigned int fsrate;
int bclk_rate;
- int rc = 0;
fsrate = params_rate(params);
switch (fsrate) {
@@ -1479,8 +1574,7 @@ static int tasdevice_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(tas_priv->dev, "%s: incorrect sample rate = %u\n",
__func__, fsrate);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
slot_width = params_width(params);
@@ -1493,20 +1587,17 @@ static int tasdevice_hw_params(struct snd_pcm_substream *substream,
default:
dev_err(tas_priv->dev, "%s: incorrect slot width = %u\n",
__func__, slot_width);
- rc = -EINVAL;
- goto out;
+ return -EINVAL;
}
bclk_rate = snd_soc_params_to_bclk(params);
if (bclk_rate < 0) {
dev_err(tas_priv->dev, "%s: incorrect bclk rate = %d\n",
__func__, bclk_rate);
- rc = bclk_rate;
- goto out;
+ return bclk_rate;
}
-out:
- return rc;
+ return 0;
}
static int tasdevice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
@@ -1663,7 +1754,6 @@ static void tasdevice_parse_dt(struct tasdevice_priv *tas_priv)
static int tasdevice_i2c_probe(struct i2c_client *i2c)
{
- const struct i2c_device_id *id = i2c_match_id(tasdevice_id, i2c);
const struct acpi_device_id *acpi_id;
struct tasdevice_priv *tas_priv;
int ret;
@@ -1685,7 +1775,7 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c)
tas_priv->chip_id = acpi_id->driver_data;
tas_priv->isacpi = true;
} else {
- tas_priv->chip_id = id ? id->driver_data : 0;
+ tas_priv->chip_id = (uintptr_t)i2c_get_match_data(i2c);
tas_priv->isacpi = false;
}
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c
index 6dd6c0896eff..f0361822061f 100644
--- a/sound/soc/codecs/tas5720.c
+++ b/sound/soc/codecs/tas5720.c
@@ -43,7 +43,6 @@ static const char * const tas5720_supply_names[] = {
struct tas5720_data {
struct snd_soc_component *component;
struct regmap *regmap;
- struct i2c_client *tas5720_client;
enum tas572x_type devtype;
struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES];
struct delayed_work fault_check_work;
@@ -729,7 +728,6 @@ static int tas5720_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct tas5720_data *data;
const struct regmap_config *regmap_config;
- const struct i2c_device_id *id;
int ret;
int i;
@@ -737,11 +735,9 @@ static int tas5720_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
- id = i2c_match_id(tas5720_id, client);
- data->tas5720_client = client;
- data->devtype = id->driver_data;
+ data->devtype = (uintptr_t)i2c_get_match_data(client);
- switch (id->driver_data) {
+ switch (data->devtype) {
case TAS5720:
regmap_config = &tas5720_regmap_config;
break;
@@ -774,7 +770,7 @@ static int tas5720_probe(struct i2c_client *client)
dev_set_drvdata(dev, data);
- switch (id->driver_data) {
+ switch (data->devtype) {
case TAS5720:
ret = devm_snd_soc_register_component(&client->dev,
&soc_component_dev_tas5720,
diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c
index 868e8a91e05b..191e067ed1c9 100644
--- a/sound/soc/codecs/tlv320adc3xxx.c
+++ b/sound/soc/codecs/tlv320adc3xxx.c
@@ -1401,7 +1401,6 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct adc3xxx *adc3xxx = NULL;
- const struct i2c_device_id *id;
int ret;
adc3xxx = devm_kzalloc(dev, sizeof(struct adc3xxx), GFP_KERNEL);
@@ -1466,8 +1465,7 @@ static int adc3xxx_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, adc3xxx);
- id = i2c_match_id(adc3xxx_i2c_id, i2c);
- adc3xxx->type = id->driver_data;
+ adc3xxx->type = (uintptr_t)i2c_get_match_data(i2c);
/* Reset codec chip */
gpiod_set_value_cansleep(adc3xxx->rst_pin, 1);
@@ -1495,8 +1493,7 @@ static void adc3xxx_i2c_remove(struct i2c_client *client)
{
struct adc3xxx *adc3xxx = i2c_get_clientdata(client);
- if (adc3xxx->mclk)
- clk_disable_unprepare(adc3xxx->mclk);
+ clk_disable_unprepare(adc3xxx->mclk);
adc3xxx_free_gpio(adc3xxx);
snd_soc_unregister_component(&client->dev);
}
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index d81ab9c25c29..4b3f9128ec37 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -1736,12 +1736,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c)
{
struct aic31xx_priv *aic31xx;
unsigned int micbias_value = MICBIAS_2_0V;
- const struct i2c_device_id *id = i2c_match_id(aic31xx_i2c_id, i2c);
int i, ret;
- dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
- id->name, (int)id->driver_data);
-
aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
if (!aic31xx)
return -ENOMEM;
@@ -1758,7 +1754,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c)
aic31xx->dev = &i2c->dev;
aic31xx->irq = i2c->irq;
- aic31xx->codec_type = id->driver_data;
+ aic31xx->codec_type = (uintptr_t)i2c_get_match_data(i2c);
dev_set_drvdata(aic31xx->dev, aic31xx);
diff --git a/sound/soc/codecs/tlv320aic3x-i2c.c b/sound/soc/codecs/tlv320aic3x-i2c.c
index bb33fd3dfb4f..0b585925c1ac 100644
--- a/sound/soc/codecs/tlv320aic3x-i2c.c
+++ b/sound/soc/codecs/tlv320aic3x-i2c.c
@@ -31,14 +31,13 @@ static int aic3x_i2c_probe(struct i2c_client *i2c)
{
struct regmap *regmap;
struct regmap_config config;
- const struct i2c_device_id *id = i2c_match_id(aic3x_i2c_id, i2c);
config = aic3x_regmap;
config.reg_bits = 8;
config.val_bits = 8;
regmap = devm_regmap_init_i2c(i2c, &config);
- return aic3x_probe(&i2c->dev, regmap, id->driver_data);
+ return aic3x_probe(&i2c->dev, regmap, (uintptr_t)i2c_get_match_data(i2c));
}
static void aic3x_i2c_remove(struct i2c_client *i2c)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index fa46f51d4341..423b9264a205 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1477,10 +1477,8 @@ static int dac33_i2c_probe(struct i2c_client *client)
if (dac33 == NULL)
return -ENOMEM;
- dac33->reg_cache = devm_kmemdup(&client->dev,
- dac33_reg,
- ARRAY_SIZE(dac33_reg) * sizeof(u8),
- GFP_KERNEL);
+ dac33->reg_cache = devm_kmemdup_array(&client->dev, dac33_reg, ARRAY_SIZE(dac33_reg),
+ sizeof(dac33_reg[0]), GFP_KERNEL);
if (!dac33->reg_cache)
return -ENOMEM;
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 5bc486283fde..b5472fa1bdda 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -222,7 +222,6 @@ static int tpa6130a2_probe(struct i2c_client *client)
struct tpa6130a2_data *data;
struct tpa6130a2_platform_data *pdata = client->dev.platform_data;
struct device_node *np = client->dev.of_node;
- const struct i2c_device_id *id;
const char *regulator;
unsigned int version;
int ret;
@@ -251,8 +250,7 @@ static int tpa6130a2_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
- id = i2c_match_id(tpa6130a2_id, client);
- data->id = id->driver_data;
+ data->id = (uintptr_t)i2c_get_match_data(client);
if (data->power_gpio >= 0) {
ret = devm_gpio_request(dev, data->power_gpio,
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
index b9eb59e3bfa0..5ce0db9326fd 100644
--- a/sound/soc/codecs/ts3a227e.c
+++ b/sound/soc/codecs/ts3a227e.c
@@ -399,7 +399,6 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int ts3a227e_suspend(struct device *dev)
{
struct ts3a227e *ts3a227e = dev_get_drvdata(dev);
@@ -419,10 +418,9 @@ static int ts3a227e_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops ts3a227e_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume)
+ SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume)
};
static const struct i2c_device_id ts3a227e_i2c_ids[] = {
@@ -450,7 +448,7 @@ MODULE_DEVICE_TABLE(acpi, ts3a227e_acpi_match);
static struct i2c_driver ts3a227e_driver = {
.driver = {
.name = "ts3a227e",
- .pm = &ts3a227e_pm,
+ .pm = pm_ptr(&ts3a227e_pm),
.of_match_table = of_match_ptr(ts3a227e_of_match),
.acpi_match_table = ACPI_PTR(ts3a227e_acpi_match),
},
diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c
index 850e5de9271e..da2f3cb1cd13 100644
--- a/sound/soc/codecs/tscs454.c
+++ b/sound/soc/codecs/tscs454.c
@@ -10,6 +10,7 @@
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <linux/string_choices.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -737,9 +738,7 @@ static int pll_power_event(struct snd_soc_dapm_widget *w,
ret = snd_soc_component_update_bits(component, R_PLLCTL, msk, val);
if (ret < 0) {
dev_err(component->dev, "Failed to %s PLL %d (%d)\n",
- enable ? "enable" : "disable",
- pll1 ? 1 : 2,
- ret);
+ str_enable_disable(enable), pll1 ? 1 : 2, ret);
return ret;
}
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index e3782762139f..609886461805 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -2049,7 +2049,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_CBP_CFP:
format &= ~(TWL4030_VIF_SLAVE_EN);
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
format |= TWL4030_VIF_SLAVE_EN;
break;
default:
diff --git a/sound/soc/codecs/uda1342.c b/sound/soc/codecs/uda1342.c
index 3d49a7869948..b0b29012842d 100644
--- a/sound/soc/codecs/uda1342.c
+++ b/sound/soc/codecs/uda1342.c
@@ -319,7 +319,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(uda1342_pm_ops,
uda1342_suspend, uda1342_resume, NULL);
static const struct i2c_device_id uda1342_i2c_id[] = {
- { "uda1342", 0 },
+ { "uda1342" },
{ }
};
MODULE_DEVICE_TABLE(i2c, uda1342_i2c_id);
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 4f8fdd574585..c179d865b938 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -766,10 +766,8 @@ static int uda1380_i2c_probe(struct i2c_client *i2c)
return ret;
}
- uda1380->reg_cache = devm_kmemdup(&i2c->dev,
- uda1380_reg,
- ARRAY_SIZE(uda1380_reg) * sizeof(u16),
- GFP_KERNEL);
+ uda1380->reg_cache = devm_kmemdup_array(&i2c->dev, uda1380_reg, ARRAY_SIZE(uda1380_reg),
+ sizeof(uda1380_reg[0]), GFP_KERNEL);
if (!uda1380->reg_cache)
return -ENOMEM;
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index a2521e16c099..7cef43bb2a88 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -159,6 +159,8 @@
{"AMIC MUX" #id, "ADC5", "ADC5"}, \
{"AMIC MUX" #id, "ADC6", "ADC6"}
+#define NUM_CODEC_DAIS 7
+
enum {
WCD9335_RX0 = 0,
WCD9335_RX1,
diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c
index 910852eb9698..dd0cda394bf1 100644
--- a/sound/soc/codecs/wcd934x.c
+++ b/sound/soc/codecs/wcd934x.c
@@ -23,6 +23,8 @@
#include "wcd-clsh-v2.h"
#include "wcd-mbhc-v2.h"
+#include <dt-bindings/sound/qcom,wcd934x.h>
+
#define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
@@ -307,6 +309,7 @@
{"SLIM TX" #id, NULL, "CDC_IF TX" #id " MUX"}
#define WCD934X_MAX_MICBIAS MIC_BIAS_4
+#define NUM_CODEC_DAIS 9
enum {
SIDO_SOURCE_INTERNAL,
@@ -435,19 +438,6 @@ enum {
};
enum {
- AIF1_PB = 0,
- AIF1_CAP,
- AIF2_PB,
- AIF2_CAP,
- AIF3_PB,
- AIF3_CAP,
- AIF4_PB,
- AIF4_VIFEED,
- AIF4_MAD_TX,
- NUM_CODEC_DAIS,
-};
-
-enum {
INTn_1_INP_SEL_ZERO = 0,
INTn_1_INP_SEL_DEC0,
INTn_1_INP_SEL_DEC1,
diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c
index 0c33f7f3dc25..1bfe7383b311 100644
--- a/sound/soc/codecs/wcd937x-sdw.c
+++ b/sound/soc/codecs/wcd937x-sdw.c
@@ -19,7 +19,7 @@
#include <sound/soc.h>
#include "wcd937x.h"
-static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = {
+static struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)),
WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)),
WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)),
@@ -30,7 +30,7 @@ static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = {
WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)),
};
-static const struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = {
+static struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = {
WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)),
WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)),
WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)),
@@ -1019,14 +1019,16 @@ static int wcd9370_probe(struct sdw_slave *pdev,
{
struct device *dev = &pdev->dev;
struct wcd937x_sdw_priv *wcd;
- int ret;
+ u8 master_ch_mask[WCD937X_MAX_SWR_CH_IDS];
+ int master_ch_mask_size = 0;
+ int ret, i;
wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
if (!wcd)
return -ENOMEM;
/* Port map index starts at 0, however the data port for this codec start at index 1 */
- if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) {
+ if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) {
wcd->is_tx = true;
ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping",
&pdev->m_port_map[1],
@@ -1048,10 +1050,36 @@ static int wcd9370_probe(struct sdw_slave *pdev,
SDW_SCP_INT1_PARITY;
pdev->prop.lane_control_support = true;
pdev->prop.simple_clk_stop_capable = true;
+
+ memset(master_ch_mask, 0, WCD937X_MAX_SWR_CH_IDS);
+
if (wcd->is_tx) {
- pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS - 1, 0);
+ master_ch_mask_size = of_property_count_u8_elems(dev->of_node,
+ "qcom,tx-channel-mapping");
+
+ if (master_ch_mask_size)
+ ret = of_property_read_u8_array(dev->of_node, "qcom,tx-channel-mapping",
+ master_ch_mask, master_ch_mask_size);
+ } else {
+ master_ch_mask_size = of_property_count_u8_elems(dev->of_node,
+ "qcom,rx-channel-mapping");
+
+ if (master_ch_mask_size)
+ ret = of_property_read_u8_array(dev->of_node, "qcom,rx-channel-mapping",
+ master_ch_mask, master_ch_mask_size);
+ }
+
+ if (ret < 0)
+ dev_info(dev, "Static channel mapping not specified using device channel maps\n");
+
+ if (wcd->is_tx) {
+ pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS, 0);
pdev->prop.src_dpn_prop = wcd937x_dpn_prop;
wcd->ch_info = &wcd937x_sdw_tx_ch_info[0];
+
+ for (i = 0; i < master_ch_mask_size; i++)
+ wcd->ch_info[i].master_ch_mask = WCD937X_SWRM_CH_MASK(master_ch_mask[i]);
+
pdev->prop.wake_capable = true;
wcd->regmap = devm_regmap_init_sdw(pdev, &wcd937x_regmap_config);
@@ -1065,6 +1093,9 @@ static int wcd9370_probe(struct sdw_slave *pdev,
pdev->prop.sink_ports = GENMASK(WCD937X_MAX_SWR_PORTS - 1, 0);
pdev->prop.sink_dpn_prop = wcd937x_dpn_prop;
wcd->ch_info = &wcd937x_sdw_rx_ch_info[0];
+
+ for (i = 0; i < master_ch_mask_size; i++)
+ wcd->ch_info[i].master_ch_mask = WCD937X_SWRM_CH_MASK(master_ch_mask[i]);
}
@@ -1093,7 +1124,7 @@ static const struct sdw_device_id wcd9370_slave_id[] = {
};
MODULE_DEVICE_TABLE(sdw, wcd9370_slave_id);
-static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev)
+static int wcd937x_sdw_runtime_suspend(struct device *dev)
{
struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
@@ -1105,7 +1136,7 @@ static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev)
+static int wcd937x_sdw_runtime_resume(struct device *dev)
{
struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev);
@@ -1118,7 +1149,7 @@ static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops wcd937x_sdw_pm_ops = {
- SET_RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL)
};
static struct sdw_driver wcd9370_codec_driver = {
@@ -1128,7 +1159,7 @@ static struct sdw_driver wcd9370_codec_driver = {
.id_table = wcd9370_slave_id,
.driver = {
.name = "wcd9370-codec",
- .pm = &wcd937x_sdw_pm_ops,
+ .pm = pm_ptr(&wcd937x_sdw_pm_ops),
}
};
module_sdw_driver(wcd9370_codec_driver);
diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c
index c9d5e67bf66e..dd2045a5d26d 100644
--- a/sound/soc/codecs/wcd937x.c
+++ b/sound/soc/codecs/wcd937x.c
@@ -1197,13 +1197,21 @@ static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch
const struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id];
u8 port_num = ch_info->port_num;
u8 ch_mask = ch_info->ch_mask;
+ u8 mstr_port_num, mstr_ch_mask;
+ struct sdw_slave *sdev = wcd->sdev;
port_config->num = port_num;
- if (enable)
+ mstr_port_num = sdev->m_port_map[port_num];
+ mstr_ch_mask = ch_info->master_ch_mask;
+
+ if (enable) {
port_config->ch_mask |= ch_mask;
- else
+ wcd->master_channel_map[mstr_port_num] |= mstr_ch_mask;
+ } else {
port_config->ch_mask &= ~ch_mask;
+ wcd->master_channel_map[mstr_port_num] &= ~mstr_ch_mask;
+ }
return 0;
}
@@ -2472,7 +2480,7 @@ static const struct irq_domain_ops wcd_domain_ops = {
static int wcd937x_irq_init(struct wcd937x_priv *wcd, struct device *dev)
{
- wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL);
+ wcd->virq = irq_domain_create_linear(NULL, 1, &wcd_domain_ops, NULL);
if (!(wcd->virq)) {
dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
return -EINVAL;
@@ -2563,6 +2571,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
ARRAY_SIZE(wcd9375_dapm_widgets));
if (ret < 0) {
dev_err(component->dev, "Failed to add snd_ctls\n");
+ wcd_clsh_ctrl_free(wcd937x->clsh_info);
return ret;
}
@@ -2570,6 +2579,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component)
ARRAY_SIZE(wcd9375_audio_map));
if (ret < 0) {
dev_err(component->dev, "Failed to add routes\n");
+ wcd_clsh_ctrl_free(wcd937x->clsh_info);
return ret;
}
}
@@ -2689,10 +2699,51 @@ static int wcd937x_codec_set_sdw_stream(struct snd_soc_dai *dai,
return 0;
}
+static int wcd937x_get_channel_map(const struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev);
+ struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id];
+ int i;
+
+ switch (dai->id) {
+ case AIF1_PB:
+ if (!rx_slot || !rx_num) {
+ dev_err(dai->dev, "Invalid rx_slot %p or rx_num %p\n",
+ rx_slot, rx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < SDW_MAX_PORTS; i++)
+ rx_slot[i] = wcd->master_channel_map[i];
+
+ *rx_num = i;
+ break;
+ case AIF1_CAP:
+ if (!tx_slot || !tx_num) {
+ dev_err(dai->dev, "Invalid tx_slot %p or tx_num %p\n",
+ tx_slot, tx_num);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < SDW_MAX_PORTS; i++)
+ tx_slot[i] = wcd->master_channel_map[i];
+
+ *tx_num = i;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops wcd937x_sdw_dai_ops = {
.hw_params = wcd937x_codec_hw_params,
.hw_free = wcd937x_codec_free,
.set_stream = wcd937x_codec_set_sdw_stream,
+ .get_channel_map = wcd937x_get_channel_map,
};
static struct snd_soc_dai_driver wcd937x_dais[] = {
diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h
index 4afa48dcaf74..4ef57c496c37 100644
--- a/sound/soc/codecs/wcd937x.h
+++ b/sound/soc/codecs/wcd937x.h
@@ -489,6 +489,7 @@
#define WCD937X_MAX_MICBIAS 3
#define WCD937X_MAX_BULK_SUPPLY 4
#define WCD937X_MAX_SWR_CH_IDS 15
+#define WCD937X_SWRM_CH_MASK(ch_idx) BIT(ch_idx - 1)
enum wcd937x_tx_sdw_ports {
WCD937X_ADC_1_PORT = 1,
@@ -510,12 +511,14 @@ enum wcd937x_rx_sdw_ports {
struct wcd937x_sdw_ch_info {
int port_num;
unsigned int ch_mask;
+ unsigned int master_ch_mask;
};
#define WCD_SDW_CH(id, pn, cmask) \
[id] = { \
.port_num = pn, \
.ch_mask = cmask, \
+ .master_ch_mask = cmask, \
}
struct wcd937x_priv;
@@ -524,9 +527,11 @@ struct wcd937x_sdw_priv {
struct sdw_stream_config sconfig;
struct sdw_stream_runtime *sruntime;
struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS];
- const struct wcd937x_sdw_ch_info *ch_info;
+ struct wcd937x_sdw_ch_info *ch_info;
bool port_enable[WCD937X_MAX_SWR_CH_IDS];
+ unsigned int master_channel_map[SDW_MAX_PORTS];
int active_ports;
+ int num_ports;
bool is_tx;
struct wcd937x_priv *wcd937x;
struct irq_domain *slave_irq;
diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c
index 7da8a10bd0a9..cabddadc90ef 100644
--- a/sound/soc/codecs/wcd938x-sdw.c
+++ b/sound/soc/codecs/wcd938x-sdw.c
@@ -1229,7 +1229,7 @@ static int wcd9380_probe(struct sdw_slave *pdev,
* Port map index starts with 0, however the data port for this codec
* are from index 1
*/
- if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) {
+ if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) {
wcd->is_tx = true;
ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping",
&pdev->m_port_map[1],
@@ -1311,7 +1311,7 @@ static const struct sdw_device_id wcd9380_slave_id[] = {
};
MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id);
-static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev)
+static int wcd938x_sdw_runtime_suspend(struct device *dev)
{
struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
@@ -1323,7 +1323,7 @@ static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev)
+static int wcd938x_sdw_runtime_resume(struct device *dev)
{
struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev);
@@ -1338,7 +1338,7 @@ static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops wcd938x_sdw_pm_ops = {
- SET_RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL)
};
@@ -1349,7 +1349,7 @@ static struct sdw_driver wcd9380_codec_driver = {
.id_table = wcd9380_slave_id,
.driver = {
.name = "wcd9380-codec",
- .pm = &wcd938x_sdw_pm_ops,
+ .pm = pm_ptr(&wcd938x_sdw_pm_ops),
}
};
module_sdw_driver(wcd9380_codec_driver);
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c
index f2a4f3262bdb..1ae498c32391 100644
--- a/sound/soc/codecs/wcd938x.c
+++ b/sound/soc/codecs/wcd938x.c
@@ -70,13 +70,8 @@
#define WCD_MBHC_HS_V_MAX 1600
#define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
- .put = wcd938x_ear_pa_put_gain, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, snd_soc_get_volsw, \
+ wcd938x_ear_pa_put_gain, tlv_array)
enum {
WCD9380 = 0,
@@ -3030,7 +3025,7 @@ static const struct irq_domain_ops wcd_domain_ops = {
static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev)
{
- wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL);
+ wcd->virq = irq_domain_create_linear(NULL, 1, &wcd_domain_ops, NULL);
if (!(wcd->virq)) {
dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
return -EINVAL;
diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c
index fca95777a75a..f7a9323a9fea 100644
--- a/sound/soc/codecs/wcd939x-sdw.c
+++ b/sound/soc/codecs/wcd939x-sdw.c
@@ -1429,7 +1429,7 @@ static int wcd9390_probe(struct sdw_slave *pdev, const struct sdw_device_id *id)
* Port map index starts with 0, however the data port for this codec
* are from index 1
*/
- if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) {
+ if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) {
wcd->is_tx = true;
ret = of_property_read_u32_array(dev->of_node,
"qcom,tx-port-mapping",
@@ -1507,7 +1507,7 @@ static const struct sdw_device_id wcd9390_slave_id[] = {
};
MODULE_DEVICE_TABLE(sdw, wcd9390_slave_id);
-static int __maybe_unused wcd939x_sdw_runtime_suspend(struct device *dev)
+static int wcd939x_sdw_runtime_suspend(struct device *dev)
{
struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
@@ -1519,7 +1519,7 @@ static int __maybe_unused wcd939x_sdw_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wcd939x_sdw_runtime_resume(struct device *dev)
+static int wcd939x_sdw_runtime_resume(struct device *dev)
{
struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev);
@@ -1532,7 +1532,7 @@ static int __maybe_unused wcd939x_sdw_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops wcd939x_sdw_pm_ops = {
- SET_RUNTIME_PM_OPS(wcd939x_sdw_runtime_suspend, wcd939x_sdw_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wcd939x_sdw_runtime_suspend, wcd939x_sdw_runtime_resume, NULL)
};
static struct sdw_driver wcd9390_codec_driver = {
@@ -1542,7 +1542,7 @@ static struct sdw_driver wcd9390_codec_driver = {
.id_table = wcd9390_slave_id,
.driver = {
.name = "wcd9390-codec",
- .pm = &wcd939x_sdw_pm_ops,
+ .pm = pm_ptr(&wcd939x_sdw_pm_ops),
}
};
module_sdw_driver(wcd9390_codec_driver);
diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c
index 4a417a92514d..0a87a79772da 100644
--- a/sound/soc/codecs/wcd939x.c
+++ b/sound/soc/codecs/wcd939x.c
@@ -2975,7 +2975,7 @@ static const struct irq_domain_ops wcd_domain_ops = {
static int wcd939x_irq_init(struct wcd939x_priv *wcd, struct device *dev)
{
- wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL);
+ wcd->virq = irq_domain_create_linear(NULL, 1, &wcd_domain_ops, NULL);
if (!(wcd->virq)) {
dev_err(dev, "%s: Failed to add IRQ domain\n", __func__);
return -EINVAL;
diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c
index edd2cb185c42..9e67fbfc2cca 100644
--- a/sound/soc/codecs/wm0010.c
+++ b/sound/soc/codecs/wm0010.c
@@ -920,7 +920,7 @@ static int wm0010_spi_probe(struct spi_device *spi)
if (ret) {
dev_err(wm0010->dev, "Failed to set IRQ %d as wake source: %d\n",
irq, ret);
- return ret;
+ goto free_irq;
}
if (spi->max_speed_hz)
@@ -932,9 +932,18 @@ static int wm0010_spi_probe(struct spi_device *spi)
&soc_component_dev_wm0010, wm0010_dai,
ARRAY_SIZE(wm0010_dai));
if (ret < 0)
- return ret;
+ goto disable_irq_wake;
return 0;
+
+disable_irq_wake:
+ irq_set_irq_wake(wm0010->irq, 0);
+
+free_irq:
+ if (wm0010->irq)
+ free_irq(wm0010->irq, wm0010);
+
+ return ret;
}
static void wm0010_spi_remove(struct spi_device *spi)
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 841247173d98..87418c838ca0 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1576,15 +1576,15 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
bclk |= WM2200_AIF1_BCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
lrclk |= WM2200_AIF1TX_LRCLK_MSTR;
bclk |= WM2200_AIF1_BCLK_MSTR;
break;
@@ -2429,7 +2429,6 @@ static void wm2200_i2c_remove(struct i2c_client *i2c)
wm2200->core_supplies);
}
-#ifdef CONFIG_PM
static int wm2200_runtime_suspend(struct device *dev)
{
struct wm2200_priv *wm2200 = dev_get_drvdata(dev);
@@ -2466,11 +2465,9 @@ static int wm2200_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops wm2200_pm = {
- SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume, NULL)
};
static const struct i2c_device_id wm2200_i2c_id[] = {
@@ -2482,7 +2479,7 @@ MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id);
static struct i2c_driver wm2200_i2c_driver = {
.driver = {
.name = "wm2200",
- .pm = &wm2200_pm,
+ .pm = pm_ptr(&wm2200_pm),
},
.probe = wm2200_i2c_probe,
.remove = wm2200_i2c_remove,
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index 11bbc94a282c..d9e5762324df 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1303,15 +1303,15 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
bclk |= WM5100_AIF1_BCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
lrclk |= WM5100_AIF1TX_LRCLK_MSTR;
bclk |= WM5100_AIF1_BCLK_MSTR;
break;
@@ -2625,7 +2625,6 @@ static void wm5100_i2c_remove(struct i2c_client *i2c)
gpiod_set_value_cansleep(wm5100->ldo_ena, 0);
}
-#ifdef CONFIG_PM
static int wm5100_runtime_suspend(struct device *dev)
{
struct wm5100_priv *wm5100 = dev_get_drvdata(dev);
@@ -2662,11 +2661,9 @@ static int wm5100_runtime_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops wm5100_pm = {
- SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume, NULL)
};
static const struct i2c_device_id wm5100_i2c_id[] = {
@@ -2678,7 +2675,7 @@ MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id);
static struct i2c_driver wm5100_i2c_driver = {
.driver = {
.name = "wm5100",
- .pm = &wm5100_pm,
+ .pm = pm_ptr(&wm5100_pm),
},
.probe = wm5100_i2c_probe,
.remove = wm5100_i2c_remove,
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 502196253d42..212eca675f27 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -302,7 +302,7 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
} else {
wseq = wm5110_no_dre_left_enable;
nregs = ARRAY_SIZE(wm5110_no_dre_left_enable);
- priv->out_up_delay += 10;
+ priv->out_up_delay += 10000;
}
break;
case ARIZONA_OUT1R_ENA_SHIFT:
@@ -312,7 +312,7 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w)
} else {
wseq = wm5110_no_dre_right_enable;
nregs = ARRAY_SIZE(wm5110_no_dre_right_enable);
- priv->out_up_delay += 10;
+ priv->out_up_delay += 10000;
}
break;
default:
@@ -338,7 +338,7 @@ static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG1, 0);
- priv->out_down_delay += 27;
+ priv->out_down_delay += 27000;
}
break;
case ARIZONA_OUT1R_ENA_SHIFT:
@@ -350,7 +350,7 @@ static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w)
snd_soc_component_update_bits(component,
ARIZONA_SPARE_TRIGGERS,
ARIZONA_WS_TRG2, 0);
- priv->out_down_delay += 27;
+ priv->out_down_delay += 27000;
}
break;
default:
@@ -477,7 +477,7 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol,
*/
snd_soc_dapm_mutex_lock(dapm);
- ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
+ ret = snd_soc_get_volsw(kcontrol, ucontrol);
snd_soc_dapm_mutex_unlock(dapm);
@@ -497,7 +497,7 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol,
*/
snd_soc_dapm_mutex_lock(dapm);
- ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
snd_soc_dapm_mutex_unlock(dapm);
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 66bd281095e1..b1fe6f4e0c10 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -846,12 +846,12 @@ static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
master |= WM8350_BCLK_MSTR;
dac_lrc |= WM8350_DACLRC_ENA;
adc_lrc |= WM8350_ADCLRC_ENA;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 19ce839f6ef7..5ad6d5b63ffc 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -986,10 +986,10 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
audio3 &= ~WM8400_AIF_MSTR1;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
audio3 |= WM8400_AIF_MSTR1;
break;
default:
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 4a31d6f89502..79adbcc90d4a 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -389,10 +389,10 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
clk |= 0x0001;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 138eba7e577a..6671e13c320c 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -264,10 +264,10 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aifctrl1 |= WM8523_AIF_MSTR;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c
index fa9942a08927..403e513f3fa8 100644
--- a/sound/soc/codecs/wm8524.c
+++ b/sound/soc/codecs/wm8524.c
@@ -139,7 +139,7 @@ static int wm8524_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
SND_SOC_DAIFMT_MASTER_MASK);
if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS)) {
+ SND_SOC_DAIFMT_CBC_CFC)) {
dev_err(codec_dai->dev, "Invalid DAI format\n");
return -EINVAL;
}
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 73a8edc797fb..ba4a08456e78 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -614,10 +614,10 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai,
aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
aifa &= ~WM8580_AIF_MS;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aifa |= WM8580_AIF_MS;
break;
default:
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index a1c99bbf5aa1..481088987742 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -243,10 +243,10 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
iface |= 0x0040;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 2cbd6b189416..ea0a588da40f 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -128,7 +128,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* The hardware only support full slave mode */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index efdc242c2ede..f7e48f27649d 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -404,10 +404,10 @@ static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
u16 af = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
af |= WM8737_MS;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 4863d6ac461b..4dfbb33edb09 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -308,7 +308,7 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* check master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index cae97fa3bcb0..312be0721b5d 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -522,10 +522,10 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
iface = 0x0040;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 38b76b7275e5..43cc368cf3f3 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -963,12 +963,12 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_component *component,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ioctl |= 0x2;
fallthrough;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
voice |= 0x0040;
break;
default:
@@ -1089,12 +1089,12 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_component *component,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ioctl |= 0x1;
fallthrough;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
hifi |= 0x0040;
break;
default:
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c
index 38376b605201..5685c3bb5555 100644
--- a/sound/soc/codecs/wm8770.c
+++ b/sound/soc/codecs/wm8770.c
@@ -349,10 +349,10 @@ static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
component = dai->component;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
master = 0x100;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
master = 0;
break;
default:
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 166e00fcd11d..7b73c825aed4 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -182,9 +182,9 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
iface = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
master = 0;
break;
default:
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
index e80dad87219b..3380d7301b17 100644
--- a/sound/soc/codecs/wm8804-i2c.c
+++ b/sound/soc/codecs/wm8804-i2c.c
@@ -56,7 +56,7 @@ MODULE_DEVICE_TABLE(acpi, wm8804_acpi_match);
static struct i2c_driver wm8804_i2c_driver = {
.driver = {
.name = "wm8804",
- .pm = &wm8804_pm,
+ .pm = pm_ptr(&wm8804_pm),
.of_match_table = of_match_ptr(wm8804_of_match),
.acpi_match_table = ACPI_PTR(wm8804_acpi_match),
},
diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c
index 628568724c20..cf74abfb1a2c 100644
--- a/sound/soc/codecs/wm8804-spi.c
+++ b/sound/soc/codecs/wm8804-spi.c
@@ -38,7 +38,7 @@ MODULE_DEVICE_TABLE(of, wm8804_of_match);
static struct spi_driver wm8804_spi_driver = {
.driver = {
.name = "wm8804",
- .pm = &wm8804_pm,
+ .pm = pm_ptr(&wm8804_pm),
.of_match_table = wm8804_of_match,
},
.probe = wm8804_spi_probe,
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index cfa78e4d8b73..48700cc25cb0 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -243,10 +243,10 @@ static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
snd_soc_component_update_bits(component, WM8804_AIFRX, 0x3, format);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
master = 0;
break;
default:
@@ -680,7 +680,6 @@ void wm8804_remove(struct device *dev)
}
EXPORT_SYMBOL_GPL(wm8804_remove);
-#if IS_ENABLED(CONFIG_PM)
static int wm8804_runtime_resume(struct device *dev)
{
struct wm8804_priv *wm8804 = dev_get_drvdata(dev);
@@ -713,12 +712,10 @@ static int wm8804_runtime_suspend(struct device *dev)
return 0;
}
-#endif
-const struct dev_pm_ops wm8804_pm = {
- SET_RUNTIME_PM_OPS(wm8804_runtime_suspend, wm8804_runtime_resume, NULL)
+EXPORT_GPL_DEV_PM_OPS(wm8804_pm) = {
+ RUNTIME_PM_OPS(wm8804_runtime_suspend, wm8804_runtime_resume, NULL)
};
-EXPORT_SYMBOL_GPL(wm8804_pm);
MODULE_DESCRIPTION("ASoC WM8804 driver");
MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index e44fdf97796f..6fb25588ca81 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -867,22 +867,22 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR;
aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR;
aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR;
aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR;
aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR;
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index c643b5377d3a..03902909f27e 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1229,15 +1229,15 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai,
WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
aif1 |= WM8903_LRCLK_DIR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
aif1 |= WM8903_BCLK_DIR;
break;
default:
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 829bf055622a..1de09ea646cf 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -844,6 +844,26 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static const char * const dmic_text[] = {
+ "DMIC1", "DMIC2"
+};
+
+static SOC_ENUM_SINGLE_DECL(dmic_enum, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_SRC_SHIFT, dmic_text);
+
+static const struct snd_kcontrol_new dmic_mux =
+ SOC_DAPM_ENUM("DMIC Mux", dmic_enum);
+
+static const char * const cin_text[] = {
+ "ADC", "DMIC"
+};
+
+static SOC_ENUM_SINGLE_DECL(cin_enum, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_ENA_SHIFT, cin_text);
+
+static const struct snd_kcontrol_new cin_mux =
+ SOC_DAPM_ENUM("Capture Input", cin_enum);
+
static const char *input_mode_text[] = {
"Single-Ended", "Differential Line", "Differential Mic"
};
@@ -963,6 +983,15 @@ SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0),
};
+static const struct snd_soc_dapm_widget wm8904_dmic_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &dmic_mux),
+};
+
+static const struct snd_soc_dapm_widget wm8904_cin_dapm_widgets[] = {
+SND_SOC_DAPM_MUX("Left Capture Input", SND_SOC_NOPM, 0, 0, &cin_mux),
+SND_SOC_DAPM_MUX("Right Capture Input", SND_SOC_NOPM, 0, 0, &cin_mux),
+};
+
static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
@@ -1101,12 +1130,45 @@ static const struct snd_soc_dapm_route adc_intercon[] = {
{ "AIFOUTR", NULL, "AIFOUTR Mux" },
{ "ADCL", NULL, "CLK_DSP" },
- { "ADCL", NULL, "Left Capture PGA" },
-
{ "ADCR", NULL, "CLK_DSP" },
+};
+
+/* No DMICs, always connect PGAs */
+static const struct snd_soc_dapm_route cin_nodmic_con[] = {
+ { "ADCL", NULL, "Left Capture PGA" },
{ "ADCR", NULL, "Right Capture PGA" },
};
+/* DMIC system in use: mux between ADC and DMICDAT1, 2 or both */
+static const struct snd_soc_dapm_route cin_adc_dmic_con[] = {
+ { "Left Capture Input", "ADC", "Left Capture PGA" },
+ { "Right Capture Input", "ADC", "Right Capture PGA" },
+
+ { "ADCL", NULL, "Left Capture Input" },
+ { "ADCR", NULL, "Right Capture Input" },
+};
+
+/* IN1L as DMICDAT1 */
+static const struct snd_soc_dapm_route cin_dmic1_con[] = {
+ { "Left Capture Input", "DMIC", "IN1L" },
+ { "Right Capture Input", "DMIC", "IN1L" },
+};
+
+/* IN1R as DMICDAT2 */
+static const struct snd_soc_dapm_route cin_dmic2_con[] = {
+ { "Left Capture Input", "DMIC", "IN1R" },
+ { "Right Capture Input", "DMIC", "IN1R" },
+};
+
+/* DMICDAT1 and DMICDAT2: mux between them, ADC still used for IN2 and IN3 */
+static const struct snd_soc_dapm_route cin_2dmics_con[] = {
+ { "DMIC Mux", "DMIC1", "IN1L" },
+ { "DMIC Mux", "DMIC2", "IN1R" },
+
+ { "Left Capture Input", "DMIC", "DMIC Mux" },
+ { "Right Capture Input", "DMIC", "DMIC Mux" },
+};
+
static const struct snd_soc_dapm_route dac_intercon[] = {
{ "DACL Mux", "Left", "AIFINL" },
{ "DACL Mux", "Right", "AIFINR" },
@@ -1424,15 +1486,15 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int aif3 = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
aif3 |= WM8904_LRCLK_DIR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
aif1 |= WM8904_BCLK_DIR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif1 |= WM8904_BCLK_DIR;
aif3 |= WM8904_LRCLK_DIR;
break;
@@ -2050,18 +2112,70 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *componen
"Failed to add ReTune Mobile control: %d\n", ret);
}
+static void wm8904_handle_dmic_pdata(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
+ struct wm8904_pdata *pdata = wm8904->pdata;
+ unsigned int dmic_src;
+
+ if (!pdata->in1l_as_dmicdat1 && !pdata->in1r_as_dmicdat2) {
+ snd_soc_dapm_add_routes(dapm, cin_nodmic_con,
+ ARRAY_SIZE(cin_nodmic_con));
+ snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_ENA_MASK, 0);
+ return;
+ }
+
+ /* Need a control and routing to switch between DMIC and ADC */
+ snd_soc_dapm_new_controls(dapm, wm8904_cin_dapm_widgets,
+ ARRAY_SIZE(wm8904_cin_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, cin_adc_dmic_con,
+ ARRAY_SIZE(cin_adc_dmic_con));
+
+ if (pdata->in1l_as_dmicdat1 && pdata->in1r_as_dmicdat2) {
+ /* Need a control and routing to mux between DMICDAT1 and 2 */
+ dev_dbg(component->dev, "DMICDAT1 and DMICDAT2 in use\n");
+ snd_soc_dapm_new_controls(dapm, wm8904_dmic_dapm_widgets,
+ ARRAY_SIZE(wm8904_dmic_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, cin_2dmics_con,
+ ARRAY_SIZE(cin_2dmics_con));
+ return;
+ }
+
+ /* Either DMICDAT1 or DMICDAT2 is in use, not both */
+ if (pdata->in1l_as_dmicdat1) {
+ dmic_src = 0;
+ snd_soc_dapm_add_routes(dapm, cin_dmic1_con,
+ ARRAY_SIZE(cin_dmic1_con));
+ } else {
+ dmic_src = 1;
+ snd_soc_dapm_add_routes(dapm, cin_dmic2_con,
+ ARRAY_SIZE(cin_dmic2_con));
+ }
+ dev_dbg(component->dev, "DMIC_SRC (0 or 1): %d\n", dmic_src);
+ snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0,
+ WM8904_DMIC_SRC_MASK,
+ dmic_src << WM8904_DMIC_SRC_SHIFT);
+}
+
static void wm8904_handle_pdata(struct snd_soc_component *component)
{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component);
struct wm8904_pdata *pdata = wm8904->pdata;
int ret, i;
if (!pdata) {
+ snd_soc_dapm_add_routes(dapm, cin_nodmic_con,
+ ARRAY_SIZE(cin_nodmic_con));
snd_soc_add_component_controls(component, wm8904_eq_controls,
- ARRAY_SIZE(wm8904_eq_controls));
+ ARRAY_SIZE(wm8904_eq_controls));
return;
}
+ wm8904_handle_dmic_pdata(component);
+
dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs);
if (pdata->num_drc_cfgs) {
@@ -2117,10 +2231,11 @@ static int wm8904_probe(struct snd_soc_component *component)
return -EINVAL;
}
- wm8904_handle_pdata(component);
-
wm8904_add_widgets(component);
+ /* This can add dependent widgets, so it is done after add_widgets */
+ wm8904_handle_pdata(component);
+
return 0;
}
@@ -2168,6 +2283,184 @@ static const struct of_device_id wm8904_of_match[] = {
MODULE_DEVICE_TABLE(of, wm8904_of_match);
#endif
+/**
+ * wm8904_read_cfg_reg_arr() - Reads a subarray from a DT u16 array
+ *
+ * @np: pointer to the device_node struct
+ * @regs_property: DT property of interest
+ * @size: size of subarrays within the array
+ * @idx: index of the subarray of interest
+ * @out: output
+ *
+ * Helper to read a subarray from a DT uint16-array,
+ * divided into equally sized arrays of size `size`
+ *
+ * Subset starts at `idx * size` and is of size `size`
+ *
+ * Return: 0 on success, negative error code otherwise
+ */
+static int wm8904_read_cfg_reg_arr(const struct device_node *np,
+ const char * const regs_property,
+ int size, int idx,
+ u16 * const out)
+{
+ int i, offset, ret;
+
+ offset = idx * size;
+
+ for (i = 0; i < size; i++) {
+ ret = of_property_read_u16_index(np, regs_property, i + offset, &out[i]);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int wm8904_parse_retune_cfg_regs(const struct device_node *np,
+ struct wm8904_pdata *pdata, int cfg_idx)
+{
+ return wm8904_read_cfg_reg_arr(np, "wlf,retune-mobile-cfg-regs",
+ WM8904_EQ_REGS, cfg_idx,
+ &pdata->retune_mobile_cfgs[cfg_idx].regs[0]);
+}
+
+static int wm8904_parse_drc_cfg_regs(const struct device_node *np,
+ struct wm8904_pdata *pdata, int cfg_idx)
+{
+ return wm8904_read_cfg_reg_arr(np, "wlf,drc-cfg-regs",
+ WM8904_DRC_REGS, cfg_idx,
+ &pdata->drc_cfgs[cfg_idx].regs[0]);
+}
+
+static int wm8904_parse_drc_cfg_from_of(struct i2c_client *i2c,
+ struct wm8904_pdata *pdata)
+{
+ const struct device_node *np = i2c->dev.of_node;
+ int i, n_cfgs;
+
+ n_cfgs = of_property_count_strings(np, "wlf,drc-cfg-names");
+ if (n_cfgs == -EINVAL)
+ return 0;
+
+ if (n_cfgs <= 0) {
+ dev_err(&i2c->dev, "Could not get wlf,drc-cfg-names length: %d",
+ n_cfgs);
+ return n_cfgs;
+ }
+
+ pdata->drc_cfgs = devm_kzalloc(&i2c->dev,
+ n_cfgs * sizeof(struct wm8904_drc_cfg),
+ GFP_KERNEL);
+ if (!pdata->drc_cfgs)
+ return -ENOMEM;
+
+ for (i = 0; i < n_cfgs; i++) {
+ if (wm8904_parse_drc_cfg_regs(np, pdata, i)) {
+ dev_err(&i2c->dev,
+ "Invalid 'wlf,drc-cfg-regs[%i,:]'\n", i);
+ return -EINVAL;
+ }
+
+ if (of_property_read_string_index(np, "wlf,drc-cfg-names", i,
+ &pdata->drc_cfgs[i].name)) {
+ dev_err(&i2c->dev,
+ "Invalid 'wlf,drc-cfg-names[%i]'\n", i);
+ return -EINVAL;
+ }
+ }
+
+ pdata->num_drc_cfgs = n_cfgs;
+ return 0;
+}
+
+static int wm8904_parse_retune_cfg_from_of(struct i2c_client *i2c,
+ struct wm8904_pdata *pdata)
+{
+ const struct device_node *np = i2c->dev.of_node;
+ int i, n_cfgs;
+
+ n_cfgs = of_property_count_strings(np, "wlf,retune-mobile-cfg-names");
+ if (n_cfgs == -EINVAL)
+ return 0;
+
+ if (n_cfgs <= 0) {
+ dev_err(&i2c->dev,
+ "Could not get wlf,retune-mobile-cfg-names length: %d",
+ n_cfgs);
+ return n_cfgs;
+ }
+
+ pdata->retune_mobile_cfgs = devm_kzalloc(&i2c->dev,
+ n_cfgs * sizeof(struct wm8904_retune_mobile_cfg),
+ GFP_KERNEL);
+ if (!pdata->retune_mobile_cfgs)
+ return -ENOMEM;
+
+ for (i = 0; i < n_cfgs; i++) {
+ if (wm8904_parse_retune_cfg_regs(np, pdata, i)) {
+ dev_err(&i2c->dev,
+ "Invalid 'wlf,retune-mobile-cfg-regs[%i,:]'\n", i);
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_index(np, "wlf,retune-mobile-cfg-hz", i,
+ &pdata->retune_mobile_cfgs[i].rate)) {
+ dev_err(&i2c->dev,
+ "Invalid 'wlf,retune-mobile-cfg-hz[%i]'\n", i);
+ return -EINVAL;
+ }
+
+ if (of_property_read_string_index(np, "wlf,retune-mobile-cfg-names", i,
+ &pdata->retune_mobile_cfgs[i].name)) {
+ dev_err(&i2c->dev,
+ "Invalid 'wlf,retune-mobile-cfg-names[%i]'\n", i);
+ return -EINVAL;
+ }
+ }
+
+ pdata->num_retune_mobile_cfgs = n_cfgs;
+ return 0;
+}
+
+static int wm8904_set_pdata_from_of(struct i2c_client *i2c,
+ struct wm8904_priv *wm8904)
+{
+ const struct device_node *np = i2c->dev.of_node;
+ struct wm8904_pdata *pdata;
+ int ret, i;
+
+ pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->in1l_as_dmicdat1 =
+ of_property_read_bool(np, "wlf,in1l-as-dmicdat1");
+
+ pdata->in1r_as_dmicdat2 =
+ of_property_read_bool(np, "wlf,in1r-as-dmicdat2");
+
+ /* If absent, default to 0xFFFF for GPIO config (i.e.: don't set) */
+ for (i = 0; i < WM8904_GPIO_REGS; i++)
+ pdata->gpio_cfg[i] = 0xFFFF;
+
+ of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_cfg,
+ ARRAY_SIZE(pdata->gpio_cfg));
+
+ of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->mic_cfg,
+ ARRAY_SIZE(pdata->mic_cfg));
+
+ ret = wm8904_parse_drc_cfg_from_of(i2c, pdata);
+ if (ret)
+ return ret;
+
+ ret = wm8904_parse_retune_cfg_from_of(i2c, pdata);
+ if (ret)
+ return ret;
+
+ wm8904->pdata = pdata;
+ return 0;
+}
+
static const struct i2c_device_id wm8904_i2c_id[];
static int wm8904_i2c_probe(struct i2c_client *i2c)
@@ -2196,22 +2489,20 @@ static int wm8904_i2c_probe(struct i2c_client *i2c)
return ret;
}
- if (i2c->dev.of_node) {
- const struct of_device_id *match;
+ wm8904->devtype = (uintptr_t)i2c_get_match_data(i2c);
- match = of_match_node(wm8904_of_match, i2c->dev.of_node);
- if (match == NULL)
- return -EINVAL;
- wm8904->devtype = (uintptr_t)match->data;
+ i2c_set_clientdata(i2c, wm8904);
+
+ if (i2c->dev.of_node) {
+ ret = wm8904_set_pdata_from_of(i2c, wm8904);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to set platform data from of: %d\n", ret);
+ return ret;
+ }
} else {
- const struct i2c_device_id *id =
- i2c_match_id(wm8904_i2c_id, i2c);
- wm8904->devtype = id->driver_data;
+ wm8904->pdata = i2c->dev.platform_data;
}
- i2c_set_clientdata(i2c, wm8904);
- wm8904->pdata = i2c->dev.platform_data;
-
for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++)
wm8904->supplies[i].supply = wm8904_supply_names[i];
@@ -2281,7 +2572,8 @@ static int wm8904_i2c_probe(struct i2c_client *i2c)
/* Apply configuration from the platform data. */
if (wm8904->pdata) {
for (i = 0; i < WM8904_GPIO_REGS; i++) {
- if (!wm8904->pdata->gpio_cfg[i])
+ /* 0xFFFF in this config means "don't touch" */
+ if (wm8904->pdata->gpio_cfg[i] == 0xffff)
continue;
regmap_update_bits(wm8904->regmap,
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 8a532f7d750c..401ee20897b1 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -343,10 +343,10 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai,
u16 clk = snd_soc_component_read(component, WM8940_CLOCK) & 0x1fe;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
clk |= 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index bae52a8a2e11..bca83410b432 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -671,9 +671,9 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u16 aif = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif |= WM8955_MS;
break;
default:
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 00858b9c9568..e6525b4cedfb 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -540,10 +540,10 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
iface |= 0x0040;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index d1c731e25777..1ec7c5e8fd69 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -627,10 +627,10 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
WM8961_MS | WM8961_FORMAT_MASK);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif |= WM8961_MS;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 08d164ce3e49..68f746626c33 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2762,10 +2762,10 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif0 |= WM8962_MSTR;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
@@ -3850,7 +3850,6 @@ static void wm8962_i2c_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
}
-#ifdef CONFIG_PM
static int wm8962_runtime_resume(struct device *dev)
{
struct wm8962_priv *wm8962 = dev_get_drvdata(dev);
@@ -3930,11 +3929,10 @@ static int wm8962_runtime_suspend(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops wm8962_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+ RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL)
};
static const struct i2c_device_id wm8962_i2c_id[] = {
@@ -3953,7 +3951,7 @@ static struct i2c_driver wm8962_i2c_driver = {
.driver = {
.name = "wm8962",
.of_match_table = wm8962_of_match,
- .pm = &wm8962_pm,
+ .pm = pm_ptr(&wm8962_pm),
},
.probe = wm8962_i2c_probe,
.remove = wm8962_i2c_remove,
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index b97c7d5bd4e7..62dcddeb78b3 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -452,10 +452,10 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
iface = 0x0040;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 0ee3655cad01..bdf437a5403f 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -454,10 +454,10 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
clk |= 0x0001;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 40d22b36b7a9..8c45ba6fc4c3 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -660,10 +660,10 @@ static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
clk |= 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
clk &= ~1;
break;
default:
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index 252b4a6cac04..6a83afe6400b 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -594,10 +594,10 @@ static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
WM8983_FMT_MASK, format << WM8983_FMT_SHIFT);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
master = 0;
break;
default:
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index 8606e0752a60..2e2d07193c41 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -688,10 +688,10 @@ static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
WM8985_FMT_MASK, format << WM8985_FMT_SHIFT);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
master = 1;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
master = 0;
break;
default:
@@ -1166,12 +1166,10 @@ static struct spi_driver wm8985_spi_driver = {
#endif
#if IS_ENABLED(CONFIG_I2C)
-static const struct i2c_device_id wm8985_i2c_id[];
static int wm8985_i2c_probe(struct i2c_client *i2c)
{
struct wm8985_priv *wm8985;
- const struct i2c_device_id *id = i2c_match_id(wm8985_i2c_id, i2c);
int ret;
wm8985 = devm_kzalloc(&i2c->dev, sizeof *wm8985, GFP_KERNEL);
@@ -1180,7 +1178,7 @@ static int wm8985_i2c_probe(struct i2c_client *i2c)
i2c_set_clientdata(i2c, wm8985);
- wm8985->dev_type = id->driver_data;
+ wm8985->dev_type = (uintptr_t)i2c_get_match_data(i2c);
wm8985->regmap = devm_regmap_init_i2c(i2c, &wm8985_regmap);
if (IS_ERR(wm8985->regmap)) {
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index f0e9d6e38dc0..cf6d642b7bfe 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -589,10 +589,10 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
iface = 0x0040;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
default:
return -EINVAL;
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 573bd3d487ba..89df406bf552 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -897,10 +897,10 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
audio3 &= ~WM8990_AIF_MSTR1;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
audio3 |= WM8990_AIF_MSTR1;
break;
default:
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index 3bd9b362051b..c3dd44c1dd0c 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -958,10 +958,10 @@ static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
audio3 &= ~WM8991_AIF_MSTR1;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
audio3 |= WM8991_AIF_MSTR1;
break;
default:
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index f257980f9b56..9be4f6cadba3 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1098,18 +1098,18 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
aif4 &= ~WM8993_LRCLK_DIR;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
wm8993->master = 0;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
aif4 |= WM8993_LRCLK_DIR;
wm8993->master = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
aif1 |= WM8993_BCLK_DIR;
wm8993->master = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif1 |= WM8993_BCLK_DIR;
aif4 |= WM8993_LRCLK_DIR;
wm8993->master = 1;
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index a4abe6e53bfc..240ec1bed234 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2783,9 +2783,9 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
ms = WM8994_AIF1_MSTR;
break;
default:
@@ -4662,7 +4662,6 @@ static void wm8994_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int wm8994_suspend(struct device *dev)
{
struct wm8994_priv *wm8994 = dev_get_drvdata(dev);
@@ -4687,16 +4686,15 @@ static int wm8994_resume(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops wm8994_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume)
+ SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume)
};
static struct platform_driver wm8994_codec_driver = {
.driver = {
.name = "wm8994-codec",
- .pm = &wm8994_pm_ops,
+ .pm = pm_ptr(&wm8994_pm_ops),
},
.probe = wm8994_probe,
.remove = wm8994_remove,
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 1f9a9b636935..a88170a3ed91 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -1448,9 +1448,9 @@ static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
master = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
master = WM8995_AIF1_MSTR;
break;
default:
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 5c06cea09bd1..c2af8d7ecdd8 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1672,16 +1672,16 @@ static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
bclk |= WM8996_AIF1_BCLK_MSTR;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
bclk |= WM8996_AIF1_BCLK_MSTR;
lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR;
lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR;
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index cb9d040b34d6..94d8571360c4 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -907,18 +907,18 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
wm9081->master = 0;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
aif2 |= WM9081_LRCLK_DIR;
wm9081->master = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
aif2 |= WM9081_BCLK_DIR;
wm9081->master = 1;
break;
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR;
wm9081->master = 1;
break;
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index e63921de0c37..8ff4b5f13b3a 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -275,13 +275,9 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
return 0;
}
-#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \
- .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \
- (xmixer << 8) | xshift, 1, 0, 0) \
-}
+#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) \
+ SOC_SINGLE_EXT(xname, SND_SOC_NOPM, ((xmixer) << 8) | (xshift), \
+ 1, 0, wm9712_hp_mixer_get, wm9712_hp_mixer_put)
/* Left Headphone Mixers */
static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index 64b69316e4c7..5f1b0f5c1a58 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -284,13 +284,9 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
return 0;
}
-#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_volsw, \
- .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \
- .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \
- xshift, xmixer, 1, 0, 0) \
-}
+#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) \
+ SOC_DOUBLE_EXT(xname, SND_SOC_NOPM, xshift, xmixer, 1, 0, \
+ wm9713_hp_mixer_get, wm9713_hp_mixer_put)
/* Left Headphone Mixers */
static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = {
@@ -944,19 +940,19 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* clock masters */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
reg |= 0x4000;
gpio |= 0x0010;
break;
- case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBP_CFC:
reg |= 0x6000;
gpio |= 0x0018;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
reg |= 0x2000;
gpio |= 0x001a;
break;
- case SND_SOC_DAIFMT_CBS_CFM:
+ case SND_SOC_DAIFMT_CBC_CFP:
gpio |= 0x0012;
break;
}
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 0c881846f485..196ddb224e6d 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -14,6 +14,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/mfd/wm8994/registers.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -674,7 +675,7 @@ void wm_hubs_update_class_w(struct snd_soc_component *component)
if (hubs->check_class_w_digital && !hubs->check_class_w_digital(component))
enable = false;
- dev_vdbg(component->dev, "Class W %s\n", enable ? "enabled" : "disabled");
+ dev_vdbg(component->dev, "Class W %s\n", str_enabled_disabled(enable));
snd_soc_component_update_bits(component, WM8993_CLASS_W_0,
WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index dd2d6661adc7..6627d2da3722 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -199,13 +199,8 @@
#define WSA881X_PROBE_TIMEOUT 1000
#define WSA881X_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
- SNDRV_CTL_ELEM_ACCESS_READWRITE,\
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
- .put = wsa881x_put_pa_gain, \
- .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+ SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \
+ snd_soc_get_volsw, wsa881x_put_pa_gain, tlv_array)
static struct reg_default wsa881x_defaults[] = {
{ WSA881X_CHIP_ID0, 0x00 },
@@ -1174,7 +1169,7 @@ static int wsa881x_probe(struct sdw_slave *pdev,
ARRAY_SIZE(wsa881x_dais));
}
-static int __maybe_unused wsa881x_runtime_suspend(struct device *dev)
+static int wsa881x_runtime_suspend(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
@@ -1187,7 +1182,7 @@ static int __maybe_unused wsa881x_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wsa881x_runtime_resume(struct device *dev)
+static int wsa881x_runtime_resume(struct device *dev)
{
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -1211,7 +1206,7 @@ static int __maybe_unused wsa881x_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops wsa881x_pm_ops = {
- SET_RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL)
};
static const struct sdw_device_id wsa881x_slave_id[] = {
@@ -1227,7 +1222,7 @@ static struct sdw_driver wsa881x_codec_driver = {
.id_table = wsa881x_slave_id,
.driver = {
.name = "wsa881x-codec",
- .pm = &wsa881x_pm_ops,
+ .pm = pm_ptr(&wsa881x_pm_ops),
}
};
module_sdw_driver(wsa881x_codec_driver);
diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c
index 47da5674d7c9..d259e1d4d83d 100644
--- a/sound/soc/codecs/wsa883x.c
+++ b/sound/soc/codecs/wsa883x.c
@@ -6,6 +6,7 @@
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
+#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -156,8 +157,28 @@
#define WSA883X_PA_FSM_ERR_COND (WSA883X_DIG_CTRL_BASE + 0x0014)
#define WSA883X_PA_FSM_MSK (WSA883X_DIG_CTRL_BASE + 0x0015)
#define WSA883X_PA_FSM_BYP (WSA883X_DIG_CTRL_BASE + 0x0016)
+#define WSA883X_PA_FSM_BYP_DC_CAL_EN_MASK 0x01
+#define WSA883X_PA_FSM_BYP_DC_CAL_EN_SHIFT 0
+#define WSA883X_PA_FSM_BYP_CLK_WD_EN_MASK 0x02
+#define WSA883X_PA_FSM_BYP_CLK_WD_EN_SHIFT 1
+#define WSA883X_PA_FSM_BYP_BG_EN_MASK 0x04
+#define WSA883X_PA_FSM_BYP_BG_EN_SHIFT 2
+#define WSA883X_PA_FSM_BYP_BOOST_EN_MASK 0x08
+#define WSA883X_PA_FSM_BYP_BOOST_EN_SHIFT 3
+#define WSA883X_PA_FSM_BYP_PA_EN_MASK 0x10
+#define WSA883X_PA_FSM_BYP_PA_EN_SHIFT 4
+#define WSA883X_PA_FSM_BYP_D_UNMUTE_MASK 0x20
+#define WSA883X_PA_FSM_BYP_D_UNMUTE_SHIFT 5
+#define WSA883X_PA_FSM_BYP_SPKR_PROT_EN_MASK 0x40
+#define WSA883X_PA_FSM_BYP_SPKR_PROT_EN_SHIFT 6
+#define WSA883X_PA_FSM_BYP_TSADC_EN_MASK 0x80
+#define WSA883X_PA_FSM_BYP_TSADC_EN_SHIFT 7
#define WSA883X_PA_FSM_DBG (WSA883X_DIG_CTRL_BASE + 0x0017)
#define WSA883X_TADC_VALUE_CTL (WSA883X_DIG_CTRL_BASE + 0x0020)
+#define WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK 0x01
+#define WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_SHIFT 0
+#define WSA883X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_MASK 0x02
+#define WSA883X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_SHIFT 1
#define WSA883X_TEMP_DETECT_CTL (WSA883X_DIG_CTRL_BASE + 0x0021)
#define WSA883X_TEMP_MSB (WSA883X_DIG_CTRL_BASE + 0x0022)
#define WSA883X_TEMP_LSB (WSA883X_DIG_CTRL_BASE + 0x0023)
@@ -427,6 +448,17 @@
SNDRV_PCM_FMTBIT_S24_LE |\
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+/* Two-point trimming for temperature calibration */
+#define WSA883X_T1_TEMP -10L
+#define WSA883X_T2_TEMP 150L
+
+/*
+ * Device will report senseless data in many cases, so discard any measurements
+ * outside of valid range.
+ */
+#define WSA883X_LOW_TEMP_THRESHOLD 5
+#define WSA883X_HIGH_TEMP_THRESHOLD 45
+
struct wsa883x_priv {
struct regmap *regmap;
struct device *dev;
@@ -441,6 +473,13 @@ struct wsa883x_priv {
int active_ports;
int dev_mode;
int comp_offset;
+ /*
+ * Protects temperature reading code (related to speaker protection) and
+ * fields: temperature and pa_on.
+ */
+ struct mutex sp_lock;
+ unsigned int temperature;
+ bool pa_on;
};
enum {
@@ -1186,6 +1225,10 @@ 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);
+
switch (wsa883x->dev_mode) {
case RECEIVER:
snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE,
@@ -1235,6 +1278,9 @@ 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);
break;
}
return 0;
@@ -1367,6 +1413,140 @@ static struct snd_soc_dai_driver wsa883x_dais[] = {
},
};
+static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
+{
+ unsigned int d1_msb = 0, d1_lsb = 0, d2_msb = 0, d2_lsb = 0;
+ unsigned int dmeas_msb = 0, dmeas_lsb = 0;
+ int d1, d2, dmeas;
+ unsigned int mask;
+ int ret, range;
+ long val;
+
+ guard(mutex)(&wsa883x->sp_lock);
+
+ if (wsa883x->pa_on) {
+ /*
+ * Reading temperature is possible only when Power Amplifier is
+ * off. Report last cached data.
+ */
+ *temp = wsa883x->temperature * 1000;
+ return 0;
+ }
+
+ ret = pm_runtime_resume_and_get(wsa883x->dev);
+ if (ret < 0)
+ return ret;
+
+ mask = WSA883X_PA_FSM_BYP_DC_CAL_EN_MASK |
+ WSA883X_PA_FSM_BYP_CLK_WD_EN_MASK |
+ WSA883X_PA_FSM_BYP_BG_EN_MASK |
+ WSA883X_PA_FSM_BYP_D_UNMUTE_MASK |
+ WSA883X_PA_FSM_BYP_SPKR_PROT_EN_MASK |
+ WSA883X_PA_FSM_BYP_TSADC_EN_MASK;
+
+ /*
+ * Here and further do not care about read or update failures.
+ * For example, before turning the amplifier on for the first
+ * time, reading WSA883X_TEMP_DIN_MSB will always return 0.
+ * Instead, check if returned value is within reasonable
+ * thresholds.
+ */
+ regmap_update_bits(wsa883x->regmap, WSA883X_PA_FSM_BYP, mask, mask);
+
+ regmap_update_bits(wsa883x->regmap, WSA883X_TADC_VALUE_CTL,
+ WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK,
+ FIELD_PREP(WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x0));
+
+ regmap_read(wsa883x->regmap, WSA883X_TEMP_MSB, &dmeas_msb);
+ regmap_read(wsa883x->regmap, WSA883X_TEMP_LSB, &dmeas_lsb);
+
+ regmap_update_bits(wsa883x->regmap, WSA883X_TADC_VALUE_CTL,
+ WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK,
+ FIELD_PREP(WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x1));
+
+ regmap_read(wsa883x->regmap, WSA883X_OTP_REG_1, &d1_msb);
+ regmap_read(wsa883x->regmap, WSA883X_OTP_REG_2, &d1_lsb);
+ regmap_read(wsa883x->regmap, WSA883X_OTP_REG_3, &d2_msb);
+ regmap_read(wsa883x->regmap, WSA883X_OTP_REG_4, &d2_lsb);
+
+ regmap_update_bits(wsa883x->regmap, WSA883X_PA_FSM_BYP, mask, 0x0);
+
+ dmeas = (((dmeas_msb & 0xff) << 0x8) | (dmeas_lsb & 0xff)) >> 0x6;
+ d1 = (((d1_msb & 0xff) << 0x8) | (d1_lsb & 0xff)) >> 0x6;
+ d2 = (((d2_msb & 0xff) << 0x8) | (d2_lsb & 0xff)) >> 0x6;
+
+ if (d1 == d2) {
+ /* Incorrect data in OTP? */
+ ret = -EINVAL;
+ goto out;
+ }
+
+ val = WSA883X_T1_TEMP + (((dmeas - d1) * (WSA883X_T2_TEMP - WSA883X_T1_TEMP)) / (d2 - d1));
+ range = WSA883X_HIGH_TEMP_THRESHOLD - WSA883X_LOW_TEMP_THRESHOLD;
+ if (in_range(val, WSA883X_LOW_TEMP_THRESHOLD, range)) {
+ wsa883x->temperature = val;
+ *temp = val * 1000;
+ ret = 0;
+ } else {
+ ret = -EAGAIN;
+ }
+out:
+ pm_runtime_mark_last_busy(wsa883x->dev);
+ pm_runtime_put_autosuspend(wsa883x->dev);
+
+ return ret;
+}
+
+static umode_t wsa883x_hwmon_is_visible(const void *data,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ if (type != hwmon_temp)
+ return 0;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ return 0444;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int wsa883x_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *temp)
+{
+ int ret;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ ret = wsa883x_get_temp(dev_get_drvdata(dev), temp);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct hwmon_channel_info *const wsa883x_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL
+};
+
+static const struct hwmon_ops wsa883x_hwmon_ops = {
+ .is_visible = wsa883x_hwmon_is_visible,
+ .read = wsa883x_hwmon_read,
+};
+
+static const struct hwmon_chip_info wsa883x_hwmon_chip_info = {
+ .ops = &wsa883x_hwmon_ops,
+ .info = wsa883x_hwmon_info,
+};
+
static int wsa883x_probe(struct sdw_slave *pdev,
const struct sdw_device_id *id)
{
@@ -1402,6 +1582,7 @@ static int wsa883x_probe(struct sdw_slave *pdev,
wsa883x->sconfig.bps = 1;
wsa883x->sconfig.direction = SDW_DATA_DIR_RX;
wsa883x->sconfig.type = SDW_STREAM_PDM;
+ mutex_init(&wsa883x->sp_lock);
/**
* Port map index starts with 0, however the data port for this codec
@@ -1424,6 +1605,19 @@ static int wsa883x_probe(struct sdw_slave *pdev,
"regmap_init failed\n");
goto err;
}
+
+ if (IS_REACHABLE(CONFIG_HWMON)) {
+ struct device *hwmon;
+
+ hwmon = devm_hwmon_device_register_with_info(dev, "wsa883x",
+ wsa883x,
+ &wsa883x_hwmon_chip_info,
+ NULL);
+ if (IS_ERR(hwmon))
+ return dev_err_probe(dev, PTR_ERR(hwmon),
+ "Failed to register hwmon sensor\n");
+ }
+
pm_runtime_set_autosuspend_delay(dev, 3000);
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
@@ -1442,7 +1636,7 @@ err:
}
-static int __maybe_unused wsa883x_runtime_suspend(struct device *dev)
+static int wsa883x_runtime_suspend(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -1452,7 +1646,7 @@ static int __maybe_unused wsa883x_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wsa883x_runtime_resume(struct device *dev)
+static int wsa883x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -1463,7 +1657,7 @@ static int __maybe_unused wsa883x_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops wsa883x_pm_ops = {
- SET_RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL)
};
static const struct sdw_device_id wsa883x_swr_id[] = {
@@ -1476,7 +1670,7 @@ MODULE_DEVICE_TABLE(sdw, wsa883x_swr_id);
static struct sdw_driver wsa883x_codec_driver = {
.driver = {
.name = "wsa883x-codec",
- .pm = &wsa883x_pm_ops,
+ .pm = pm_ptr(&wsa883x_pm_ops),
.suppress_bind_attrs = true,
},
.probe = wsa883x_probe,
diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c
index 86df5152c547..8051483aa1ac 100644
--- a/sound/soc/codecs/wsa884x.c
+++ b/sound/soc/codecs/wsa884x.c
@@ -1875,7 +1875,7 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
* Reading temperature is possible only when Power Amplifier is
* off. Report last cached data.
*/
- *temp = wsa884x->temperature;
+ *temp = wsa884x->temperature * 1000;
return 0;
}
@@ -1934,7 +1934,7 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
if ((val > WSA884X_LOW_TEMP_THRESHOLD) &&
(val < WSA884X_HIGH_TEMP_THRESHOLD)) {
wsa884x->temperature = val;
- *temp = val;
+ *temp = val * 1000;
ret = 0;
} else {
ret = -EAGAIN;
@@ -2136,7 +2136,7 @@ static int wsa884x_probe(struct sdw_slave *pdev,
ARRAY_SIZE(wsa884x_dais));
}
-static int __maybe_unused wsa884x_runtime_suspend(struct device *dev)
+static int wsa884x_runtime_suspend(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -2146,7 +2146,7 @@ static int __maybe_unused wsa884x_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wsa884x_runtime_resume(struct device *dev)
+static int wsa884x_runtime_resume(struct device *dev)
{
struct regmap *regmap = dev_get_regmap(dev, NULL);
@@ -2157,7 +2157,7 @@ static int __maybe_unused wsa884x_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops wsa884x_pm_ops = {
- SET_RUNTIME_PM_OPS(wsa884x_runtime_suspend, wsa884x_runtime_resume, NULL)
+ RUNTIME_PM_OPS(wsa884x_runtime_suspend, wsa884x_runtime_resume, NULL)
};
static const struct sdw_device_id wsa884x_swr_id[] = {
@@ -2169,7 +2169,7 @@ MODULE_DEVICE_TABLE(sdw, wsa884x_swr_id);
static struct sdw_driver wsa884x_codec_driver = {
.driver = {
.name = "wsa884x-codec",
- .pm = &wsa884x_pm_ops,
+ .pm = pm_ptr(&wsa884x_pm_ops),
},
.probe = wsa884x_probe,
.ops = &wsa884x_slave_ops,
diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c
index 57b789d7fbed..4c4171bb3fbb 100644
--- a/sound/soc/dwc/dwc-i2s.c
+++ b/sound/soc/dwc/dwc-i2s.c
@@ -478,7 +478,6 @@ static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
.set_tdm_slot = dw_i2s_set_tdm_slot,
};
-#ifdef CONFIG_PM
static int dw_i2s_runtime_suspend(struct device *dev)
{
struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev);
@@ -501,6 +500,7 @@ static int dw_i2s_runtime_resume(struct device *dev)
return 0;
}
+#ifdef CONFIG_PM
static int dw_i2s_suspend(struct snd_soc_component *component)
{
struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component);
@@ -1084,7 +1084,7 @@ MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
#endif
static const struct dev_pm_ops dwc_pm_ops = {
- SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
+ RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL)
};
static struct platform_driver dw_i2s_driver = {
@@ -1093,7 +1093,7 @@ static struct platform_driver dw_i2s_driver = {
.driver = {
.name = "designware-i2s",
.of_match_table = of_match_ptr(dw_i2s_of_match),
- .pm = &dwc_pm_ops,
+ .pm = pm_ptr(&dwc_pm_ops),
},
};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 678540b78280..c4cf3cff58de 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -6,8 +6,11 @@ comment "Common SoC Audio options for Freescale CPUs:"
config SND_SOC_FSL_ASRC
tristate "Asynchronous Sample Rate Converter (ASRC) module support"
depends on HAS_DMA
+ select DMA_SHARED_BUFFER
select REGMAP_MMIO
select SND_SOC_GENERIC_DMAENGINE_PCM
+ select SND_COMPRESS_ACCEL
+ select SND_COMPRESS_OFFLOAD
help
Say Y if you want to add Asynchronous Sample Rate Converter (ASRC)
support for the Freescale CPUs.
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index ad97244b5cc3..d656a9ab54e3 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
# Freescale SSI/DMA/SAI/SPDIF Support
snd-soc-fsl-audmix-y := fsl_audmix.o
snd-soc-fsl-asoc-card-y := fsl-asoc-card.o
-snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o
+snd-soc-fsl-asrc-y := fsl_asrc.o fsl_asrc_dma.o fsl_asrc_m2m.o
snd-soc-fsl-lpc3xxx-y := lpc3xxx-pcm.o lpc3xxx-i2s.o
snd-soc-fsl-sai-y := fsl_sai.o
snd-soc-fsl-ssi-y := fsl_ssi.o
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 02e1594e8223..ab583b432c60 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -759,7 +759,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
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_CBS_CFS;
+ 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;
@@ -818,7 +818,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
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_CBM_CFM;
+ 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")) {
@@ -932,7 +932,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
if (!asrc_pdev)
priv->card.num_dapm_routes /= 2;
- if (of_property_read_bool(np, "audio-routing")) {
+ if (of_property_present(np, "audio-routing")) {
ret = snd_soc_of_parse_audio_routing(&priv->card, "audio-routing");
if (ret) {
dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c
index bd5c46d763c0..677529916dc0 100644
--- a/sound/soc/fsl/fsl_asrc.c
+++ b/sound/soc/fsl/fsl_asrc.c
@@ -1063,6 +1063,139 @@ static int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
return REG_ASRDx(dir, index);
}
+/* Get sample numbers in FIFO */
+static unsigned int fsl_asrc_get_output_fifo_size(struct fsl_asrc_pair *pair)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ enum asrc_pair_index index = pair->index;
+ u32 val;
+
+ regmap_read(asrc->regmap, REG_ASRFST(index), &val);
+
+ val &= ASRFSTi_OUTPUT_FIFO_MASK;
+
+ return val >> ASRFSTi_OUTPUT_FIFO_SHIFT;
+}
+
+static int fsl_asrc_m2m_prepare(struct fsl_asrc_pair *pair)
+{
+ struct fsl_asrc_pair_priv *pair_priv = pair->private;
+ struct fsl_asrc *asrc = pair->asrc;
+ struct device *dev = &asrc->pdev->dev;
+ struct asrc_config config;
+ int ret;
+
+ /* fill config */
+ config.pair = pair->index;
+ config.channel_num = pair->channels;
+ config.input_sample_rate = pair->rate[IN];
+ config.output_sample_rate = pair->rate[OUT];
+ config.input_format = pair->sample_format[IN];
+ config.output_format = pair->sample_format[OUT];
+ config.inclk = INCLK_NONE;
+ config.outclk = OUTCLK_ASRCK1_CLK;
+
+ pair_priv->config = &config;
+ ret = fsl_asrc_config_pair(pair, true);
+ if (ret) {
+ dev_err(dev, "failed to config pair: %d\n", ret);
+ return ret;
+ }
+
+ pair->first_convert = 1;
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_start(struct fsl_asrc_pair *pair)
+{
+ if (pair->first_convert) {
+ fsl_asrc_start_pair(pair);
+ pair->first_convert = 0;
+ }
+ /*
+ * Clear DMA request during the stall state of ASRC:
+ * During STALL state, the remaining in input fifo would never be
+ * smaller than the input threshold while the output fifo would not
+ * be bigger than output one. Thus the DMA request would be cleared.
+ */
+ fsl_asrc_set_watermarks(pair, ASRC_FIFO_THRESHOLD_MIN,
+ ASRC_FIFO_THRESHOLD_MAX);
+
+ /* Update the real input threshold to raise DMA request */
+ fsl_asrc_set_watermarks(pair, ASRC_M2M_INPUTFIFO_WML,
+ ASRC_M2M_OUTPUTFIFO_WML);
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_stop(struct fsl_asrc_pair *pair)
+{
+ if (!pair->first_convert) {
+ fsl_asrc_stop_pair(pair);
+ pair->first_convert = 1;
+ }
+
+ return 0;
+}
+
+/* calculate capture data length according to output data length and sample rate */
+static int fsl_asrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buffer_length)
+{
+ unsigned int in_width, out_width;
+ unsigned int channels = pair->channels;
+ unsigned int in_samples, out_samples;
+ unsigned int out_length;
+
+ in_width = snd_pcm_format_physical_width(pair->sample_format[IN]) / 8;
+ out_width = snd_pcm_format_physical_width(pair->sample_format[OUT]) / 8;
+
+ in_samples = input_buffer_length / in_width / channels;
+ out_samples = pair->rate[OUT] * in_samples / pair->rate[IN];
+ out_length = (out_samples - ASRC_OUTPUT_LAST_SAMPLE) * out_width * channels;
+
+ return out_length;
+}
+
+static int fsl_asrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ struct fsl_asrc_priv *asrc_priv = asrc->private;
+ int wml = (dir == IN) ? ASRC_M2M_INPUTFIFO_WML : ASRC_M2M_OUTPUTFIFO_WML;
+
+ if (!asrc_priv->soc->use_edma)
+ return wml * pair->channels;
+ else
+ return 1;
+}
+
+static int fsl_asrc_m2m_get_cap(struct fsl_asrc_m2m_cap *cap)
+{
+ cap->fmt_in = FSL_ASRC_FORMATS;
+ cap->fmt_out = FSL_ASRC_FORMATS | SNDRV_PCM_FMTBIT_S8;
+
+ cap->rate_in = supported_asrc_rate;
+ cap->rate_in_count = ARRAY_SIZE(supported_asrc_rate);
+ cap->rate_out = supported_asrc_rate;
+ cap->rate_out_count = ARRAY_SIZE(supported_asrc_rate);
+ cap->chan_min = 1;
+ cap->chan_max = 10;
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_pair_resume(struct fsl_asrc_pair *pair)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ int i;
+
+ for (i = 0; i < pair->channels * 4; i++)
+ regmap_write(asrc->regmap, REG_ASRDI(pair->index), 0);
+
+ pair->first_convert = 1;
+ return 0;
+}
+
static int fsl_asrc_runtime_resume(struct device *dev);
static int fsl_asrc_runtime_suspend(struct device *dev);
@@ -1147,6 +1280,15 @@ static int fsl_asrc_probe(struct platform_device *pdev)
asrc->get_fifo_addr = fsl_asrc_get_fifo_addr;
asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv);
+ asrc->m2m_prepare = fsl_asrc_m2m_prepare;
+ asrc->m2m_start = fsl_asrc_m2m_start;
+ asrc->m2m_stop = fsl_asrc_m2m_stop;
+ asrc->get_output_fifo_size = fsl_asrc_get_output_fifo_size;
+ asrc->m2m_calc_out_len = fsl_asrc_m2m_calc_out_len;
+ asrc->m2m_get_maxburst = fsl_asrc_m2m_get_maxburst;
+ asrc->m2m_pair_resume = fsl_asrc_m2m_pair_resume;
+ asrc->m2m_get_cap = fsl_asrc_m2m_get_cap;
+
if (of_device_is_compatible(np, "fsl,imx35-asrc")) {
asrc_priv->clk_map[IN] = input_clk_map_imx35;
asrc_priv->clk_map[OUT] = output_clk_map_imx35;
@@ -1242,6 +1384,12 @@ static int fsl_asrc_probe(struct platform_device *pdev)
goto err_pm_get_sync;
}
+ ret = fsl_asrc_m2m_init(asrc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to init m2m device %d\n", ret);
+ return ret;
+ }
+
return 0;
err_pm_get_sync:
@@ -1254,6 +1402,10 @@ err_pm_disable:
static void fsl_asrc_remove(struct platform_device *pdev)
{
+ struct fsl_asrc *asrc = dev_get_drvdata(&pdev->dev);
+
+ fsl_asrc_m2m_exit(asrc);
+
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
fsl_asrc_runtime_suspend(&pdev->dev);
@@ -1355,10 +1507,29 @@ static int fsl_asrc_runtime_suspend(struct device *dev)
return 0;
}
+static int fsl_asrc_suspend(struct device *dev)
+{
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
+ int ret;
+
+ fsl_asrc_m2m_suspend(asrc);
+ ret = pm_runtime_force_suspend(dev);
+ return ret;
+}
+
+static int fsl_asrc_resume(struct device *dev)
+{
+ struct fsl_asrc *asrc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ fsl_asrc_m2m_resume(asrc);
+ return ret;
+}
+
static const struct dev_pm_ops fsl_asrc_pm = {
- SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume)
};
static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = {
@@ -1396,7 +1567,7 @@ static struct platform_driver fsl_asrc_driver = {
.driver = {
.name = "fsl-asrc",
.of_match_table = fsl_asrc_ids,
- .pm = &fsl_asrc_pm,
+ .pm = pm_ptr(&fsl_asrc_pm),
},
};
module_platform_driver(fsl_asrc_driver);
diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h
index 86d2422ad606..1c492eb237f5 100644
--- a/sound/soc/fsl/fsl_asrc.h
+++ b/sound/soc/fsl/fsl_asrc.h
@@ -12,6 +12,8 @@
#include "fsl_asrc_common.h"
+#define ASRC_M2M_INPUTFIFO_WML 0x4
+#define ASRC_M2M_OUTPUTFIFO_WML 0x2
#define ASRC_DMA_BUFFER_NUM 2
#define ASRC_INPUTFIFO_THRESHOLD 32
#define ASRC_OUTPUTFIFO_THRESHOLD 32
diff --git a/sound/soc/fsl/fsl_asrc_common.h b/sound/soc/fsl/fsl_asrc_common.h
index 7e1c13ca37f1..0cd595b0f629 100644
--- a/sound/soc/fsl/fsl_asrc_common.h
+++ b/sound/soc/fsl/fsl_asrc_common.h
@@ -22,6 +22,26 @@ enum asrc_pair_index {
#define PAIR_CTX_NUM 0x4
/**
+ * struct fsl_asrc_m2m_cap - capability data
+ * @fmt_in: input sample format
+ * @fmt_out: output sample format
+ * @chan_min: minimum channel number
+ * @chan_max: maximum channel number
+ * @rate_in: minimum rate
+ * @rate_out: maximum rete
+ */
+struct fsl_asrc_m2m_cap {
+ u64 fmt_in;
+ u64 fmt_out;
+ int chan_min;
+ int chan_max;
+ const unsigned int *rate_in;
+ int rate_in_count;
+ const unsigned int *rate_out;
+ int rate_out_count;
+};
+
+/**
* fsl_asrc_pair: ASRC Pair common data
*
* @asrc: pointer to its parent module
@@ -34,6 +54,14 @@ enum asrc_pair_index {
* @pos: hardware pointer position
* @req_dma_chan: flag to release dev_to_dev chan
* @private: pair private area
+ * @complete: dma task complete
+ * @sample_format: format of m2m
+ * @rate: rate of m2m
+ * @buf_len: buffer length of m2m
+ * @dma_buffer: buffer pointers
+ * @first_convert: start of conversion
+ * @ratio_mod_flag: flag for new ratio modifier
+ * @ratio_mod: ratio modification
*/
struct fsl_asrc_pair {
struct fsl_asrc *asrc;
@@ -49,6 +77,16 @@ struct fsl_asrc_pair {
bool req_dma_chan;
void *private;
+
+ /* used for m2m */
+ struct completion complete[2];
+ snd_pcm_format_t sample_format[2];
+ unsigned int rate[2];
+ unsigned int buf_len[2];
+ struct snd_dma_buffer dma_buffer[2];
+ unsigned int first_convert;
+ bool ratio_mod_flag;
+ unsigned int ratio_mod;
};
/**
@@ -62,6 +100,7 @@ struct fsl_asrc_pair {
* @mem_clk: clock source to access register
* @ipg_clk: clock source to drive peripheral
* @spba_clk: SPBA clock (optional, depending on SoC design)
+ * @card: compress sound card
* @lock: spin lock for resource protection
* @pair: pair pointers
* @channel_avail: non-occupied channel numbers
@@ -72,6 +111,17 @@ struct fsl_asrc_pair {
* @request_pair: function pointer
* @release_pair: function pointer
* @get_fifo_addr: function pointer
+ * @m2m_get_cap: function pointer
+ * @m2m_prepare: function pointer
+ * @m2m_start: function pointer
+ * @m2m_unprepare: function pointer
+ * @m2m_stop: function pointer
+ * @m2m_calc_out_len: function pointer
+ * @m2m_get_maxburst: function pointer
+ * @m2m_pair_suspend: function pointer
+ * @m2m_pair_resume: function pointer
+ * @m2m_set_ratio_mod: function pointer
+ * @get_output_fifo_size: function pointer
* @pair_priv_size: size of pair private struct.
* @private: private data structure
*/
@@ -84,6 +134,7 @@ struct fsl_asrc {
struct clk *mem_clk;
struct clk *ipg_clk;
struct clk *spba_clk;
+ struct snd_card *card;
spinlock_t lock; /* spin lock for resource protection */
struct fsl_asrc_pair *pair[PAIR_CTX_NUM];
@@ -97,6 +148,20 @@ struct fsl_asrc {
int (*request_pair)(int channels, struct fsl_asrc_pair *pair);
void (*release_pair)(struct fsl_asrc_pair *pair);
int (*get_fifo_addr)(u8 dir, enum asrc_pair_index index);
+ int (*m2m_get_cap)(struct fsl_asrc_m2m_cap *cap);
+
+ int (*m2m_prepare)(struct fsl_asrc_pair *pair);
+ int (*m2m_start)(struct fsl_asrc_pair *pair);
+ int (*m2m_unprepare)(struct fsl_asrc_pair *pair);
+ int (*m2m_stop)(struct fsl_asrc_pair *pair);
+
+ int (*m2m_calc_out_len)(struct fsl_asrc_pair *pair, int input_buffer_length);
+ int (*m2m_get_maxburst)(u8 dir, struct fsl_asrc_pair *pair);
+ int (*m2m_pair_suspend)(struct fsl_asrc_pair *pair);
+ int (*m2m_pair_resume)(struct fsl_asrc_pair *pair);
+ int (*m2m_set_ratio_mod)(struct fsl_asrc_pair *pair, int val);
+
+ unsigned int (*get_output_fifo_size)(struct fsl_asrc_pair *pair);
size_t pair_priv_size;
void *private;
@@ -105,4 +170,9 @@ struct fsl_asrc {
#define DRV_NAME "fsl-asrc-dai"
extern struct snd_soc_component_driver fsl_asrc_component;
+int fsl_asrc_m2m_init(struct fsl_asrc *asrc);
+void fsl_asrc_m2m_exit(struct fsl_asrc *asrc);
+int fsl_asrc_m2m_resume(struct fsl_asrc *asrc);
+int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc);
+
#endif /* _FSL_ASRC_COMMON_H */
diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
new file mode 100644
index 000000000000..f46881f71e43
--- /dev/null
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -0,0 +1,729 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
+// Copyright (C) 2019-2024 NXP
+//
+// Freescale ASRC Memory to Memory (M2M) driver
+
+#include <linux/dma/imx-dma.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <sound/asound.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/initval.h>
+
+#include "fsl_asrc_common.h"
+
+#define DIR_STR(dir) (dir) == IN ? "in" : "out"
+
+#define ASRC_xPUT_DMA_CALLBACK(dir) \
+ (((dir) == IN) ? asrc_input_dma_callback \
+ : asrc_output_dma_callback)
+
+/* Maximum output and capture buffer size */
+#define ASRC_M2M_BUFFER_SIZE (512 * 1024)
+
+/* Maximum output and capture period size */
+#define ASRC_M2M_PERIOD_SIZE (48 * 1024)
+
+/* dma complete callback */
+static void asrc_input_dma_callback(void *data)
+{
+ struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data;
+
+ complete(&pair->complete[IN]);
+}
+
+/* dma complete callback */
+static void asrc_output_dma_callback(void *data)
+{
+ struct fsl_asrc_pair *pair = (struct fsl_asrc_pair *)data;
+
+ complete(&pair->complete[OUT]);
+}
+
+/**
+ *asrc_read_last_fifo: read all the remaining data from FIFO
+ *@pair: Structure pointer of fsl_asrc_pair
+ *@dma_vaddr: virtual address of capture buffer
+ *@length: payload length of capture buffer
+ */
+static void asrc_read_last_fifo(struct fsl_asrc_pair *pair, void *dma_vaddr, u32 *length)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ enum asrc_pair_index index = pair->index;
+ u32 i, reg, size, t_size = 0, width;
+ u32 *reg32 = NULL;
+ u16 *reg16 = NULL;
+ u8 *reg24 = NULL;
+
+ width = snd_pcm_format_physical_width(pair->sample_format[OUT]);
+ if (width == 32)
+ reg32 = dma_vaddr + *length;
+ else if (width == 16)
+ reg16 = dma_vaddr + *length;
+ else
+ reg24 = dma_vaddr + *length;
+retry:
+ size = asrc->get_output_fifo_size(pair);
+ if (size + *length > ASRC_M2M_BUFFER_SIZE)
+ goto end;
+
+ for (i = 0; i < size * pair->channels; i++) {
+ regmap_read(asrc->regmap, asrc->get_fifo_addr(OUT, index), &reg);
+ if (reg32) {
+ *reg32++ = reg;
+ } else if (reg16) {
+ *reg16++ = (u16)reg;
+ } else {
+ *reg24++ = (u8)reg;
+ *reg24++ = (u8)(reg >> 8);
+ *reg24++ = (u8)(reg >> 16);
+ }
+ }
+ t_size += size;
+
+ /* In case there is data left in FIFO */
+ if (size)
+ goto retry;
+end:
+ /* Update payload length */
+ if (reg32)
+ *length += t_size * pair->channels * 4;
+ else if (reg16)
+ *length += t_size * pair->channels * 2;
+ else
+ *length += t_size * pair->channels * 3;
+}
+
+/* config dma channel */
+static int asrc_dmaconfig(struct fsl_asrc_pair *pair,
+ struct dma_chan *chan,
+ u32 dma_addr, dma_addr_t buf_addr, u32 buf_len,
+ int dir, int width)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ struct device *dev = &asrc->pdev->dev;
+ struct dma_slave_config slave_config;
+ enum dma_slave_buswidth buswidth;
+ unsigned int sg_len, max_period_size;
+ struct scatterlist *sg;
+ int ret, i;
+
+ switch (width) {
+ case 8:
+ buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ break;
+ case 16:
+ buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ break;
+ case 24:
+ buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES;
+ break;
+ case 32:
+ buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ break;
+ default:
+ dev_err(dev, "invalid word width\n");
+ return -EINVAL;
+ }
+
+ memset(&slave_config, 0, sizeof(slave_config));
+ if (dir == IN) {
+ slave_config.direction = DMA_MEM_TO_DEV;
+ slave_config.dst_addr = dma_addr;
+ slave_config.dst_addr_width = buswidth;
+ slave_config.dst_maxburst = asrc->m2m_get_maxburst(IN, pair);
+ } else {
+ slave_config.direction = DMA_DEV_TO_MEM;
+ slave_config.src_addr = dma_addr;
+ slave_config.src_addr_width = buswidth;
+ slave_config.src_maxburst = asrc->m2m_get_maxburst(OUT, pair);
+ }
+
+ ret = dmaengine_slave_config(chan, &slave_config);
+ if (ret) {
+ dev_err(dev, "failed to config dmaengine for %s task: %d\n",
+ DIR_STR(dir), ret);
+ return -EINVAL;
+ }
+
+ max_period_size = rounddown(ASRC_M2M_PERIOD_SIZE, width * pair->channels / 8);
+ /* scatter gather mode */
+ sg_len = buf_len / max_period_size;
+ if (buf_len % max_period_size)
+ sg_len += 1;
+
+ sg = kmalloc_array(sg_len, sizeof(*sg), GFP_KERNEL);
+ if (!sg)
+ return -ENOMEM;
+
+ sg_init_table(sg, sg_len);
+ for (i = 0; i < (sg_len - 1); i++) {
+ sg_dma_address(&sg[i]) = buf_addr + i * max_period_size;
+ sg_dma_len(&sg[i]) = max_period_size;
+ }
+ sg_dma_address(&sg[i]) = buf_addr + i * max_period_size;
+ sg_dma_len(&sg[i]) = buf_len - i * max_period_size;
+
+ pair->desc[dir] = dmaengine_prep_slave_sg(chan, sg, sg_len,
+ slave_config.direction,
+ DMA_PREP_INTERRUPT);
+ kfree(sg);
+ if (!pair->desc[dir]) {
+ dev_err(dev, "failed to prepare dmaengine for %s task\n", DIR_STR(dir));
+ return -EINVAL;
+ }
+
+ pair->desc[dir]->callback = ASRC_xPUT_DMA_CALLBACK(dir);
+ pair->desc[dir]->callback_param = pair;
+
+ return 0;
+}
+
+/* main function of converter */
+static int asrc_m2m_device_run(struct fsl_asrc_pair *pair, struct snd_compr_task_runtime *task)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ struct device *dev = &asrc->pdev->dev;
+ enum asrc_pair_index index = pair->index;
+ struct snd_dma_buffer *src_buf, *dst_buf;
+ unsigned int in_buf_len;
+ unsigned int out_dma_len;
+ unsigned int width;
+ u32 fifo_addr;
+ int ret = 0;
+
+ /* set ratio mod */
+ if (asrc->m2m_set_ratio_mod) {
+ if (pair->ratio_mod_flag) {
+ asrc->m2m_set_ratio_mod(pair, pair->ratio_mod);
+ pair->ratio_mod_flag = false;
+ }
+ }
+
+ src_buf = &pair->dma_buffer[IN];
+ dst_buf = &pair->dma_buffer[OUT];
+
+ width = snd_pcm_format_physical_width(pair->sample_format[IN]);
+ fifo_addr = asrc->paddr + asrc->get_fifo_addr(IN, index);
+
+ in_buf_len = task->input_size;
+
+ if (in_buf_len < width * pair->channels / 8 ||
+ in_buf_len > ASRC_M2M_BUFFER_SIZE ||
+ in_buf_len % (width * pair->channels / 8)) {
+ dev_err(dev, "out buffer size is error: [%d]\n", in_buf_len);
+ ret = -EINVAL;
+ goto end;
+ }
+
+ /* dma config for output dma channel */
+ ret = asrc_dmaconfig(pair,
+ pair->dma_chan[IN],
+ fifo_addr,
+ src_buf->addr,
+ in_buf_len, IN, width);
+ if (ret) {
+ dev_err(dev, "out dma config error\n");
+ goto end;
+ }
+
+ width = snd_pcm_format_physical_width(pair->sample_format[OUT]);
+ fifo_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
+ out_dma_len = asrc->m2m_calc_out_len(pair, in_buf_len);
+ if (out_dma_len > 0 && out_dma_len <= ASRC_M2M_BUFFER_SIZE) {
+ /* dma config for capture dma channel */
+ ret = asrc_dmaconfig(pair,
+ pair->dma_chan[OUT],
+ fifo_addr,
+ dst_buf->addr,
+ out_dma_len, OUT, width);
+ if (ret) {
+ dev_err(dev, "cap dma config error\n");
+ goto end;
+ }
+ } else if (out_dma_len > ASRC_M2M_BUFFER_SIZE) {
+ dev_err(dev, "cap buffer size error\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ reinit_completion(&pair->complete[IN]);
+ reinit_completion(&pair->complete[OUT]);
+
+ /* Submit DMA request */
+ dmaengine_submit(pair->desc[IN]);
+ dma_async_issue_pending(pair->desc[IN]->chan);
+ if (out_dma_len > 0) {
+ dmaengine_submit(pair->desc[OUT]);
+ dma_async_issue_pending(pair->desc[OUT]->chan);
+ }
+
+ asrc->m2m_start(pair);
+
+ if (!wait_for_completion_interruptible_timeout(&pair->complete[IN], 10 * HZ)) {
+ dev_err(dev, "out DMA task timeout\n");
+ ret = -ETIMEDOUT;
+ goto end;
+ }
+
+ if (out_dma_len > 0) {
+ if (!wait_for_completion_interruptible_timeout(&pair->complete[OUT], 10 * HZ)) {
+ dev_err(dev, "cap DMA task timeout\n");
+ ret = -ETIMEDOUT;
+ goto end;
+ }
+ }
+
+ /* read the last words from FIFO */
+ asrc_read_last_fifo(pair, dst_buf->area, &out_dma_len);
+ /* update payload length for capture */
+ task->output_size = out_dma_len;
+end:
+ return ret;
+}
+
+static int fsl_asrc_m2m_comp_open(struct snd_compr_stream *stream)
+{
+ struct fsl_asrc *asrc = stream->private_data;
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct device *dev = &asrc->pdev->dev;
+ struct fsl_asrc_pair *pair;
+ int size, ret;
+
+ pair = kzalloc(sizeof(*pair) + asrc->pair_priv_size, GFP_KERNEL);
+ if (!pair)
+ return -ENOMEM;
+
+ pair->private = (void *)pair + sizeof(struct fsl_asrc_pair);
+ pair->asrc = asrc;
+
+ init_completion(&pair->complete[IN]);
+ init_completion(&pair->complete[OUT]);
+
+ runtime->private_data = pair;
+
+ size = ASRC_M2M_BUFFER_SIZE;
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &pair->dma_buffer[IN]);
+ if (ret)
+ goto error_alloc_in_buf;
+
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &pair->dma_buffer[OUT]);
+ if (ret)
+ goto error_alloc_out_buf;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to power up asrc\n");
+ goto err_pm_runtime;
+ }
+
+ return 0;
+
+err_pm_runtime:
+ snd_dma_free_pages(&pair->dma_buffer[OUT]);
+error_alloc_out_buf:
+ snd_dma_free_pages(&pair->dma_buffer[IN]);
+error_alloc_in_buf:
+ kfree(pair);
+ return ret;
+}
+
+static int fsl_asrc_m2m_comp_release(struct snd_compr_stream *stream)
+{
+ struct fsl_asrc *asrc = stream->private_data;
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct fsl_asrc_pair *pair = runtime->private_data;
+ struct device *dev = &asrc->pdev->dev;
+
+ pm_runtime_put_sync(dev);
+
+ snd_dma_free_pages(&pair->dma_buffer[IN]);
+ snd_dma_free_pages(&pair->dma_buffer[OUT]);
+
+ kfree(runtime->private_data);
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_comp_set_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct fsl_asrc *asrc = stream->private_data;
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct fsl_asrc_pair *pair = runtime->private_data;
+ struct fsl_asrc_m2m_cap cap;
+ int ret, i;
+
+ ret = asrc->m2m_get_cap(&cap);
+ 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;
+ 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;
+ else
+ return -EINVAL;
+
+ /* check input rate is in scope */
+ for (i = 0; i < cap.rate_in_count; i++)
+ if (params->codec.sample_rate == cap.rate_in[i]) {
+ pair->rate[IN] = params->codec.sample_rate;
+ break;
+ }
+ if (i == cap.rate_in_count)
+ return -EINVAL;
+
+ /* check output rate is in scope */
+ for (i = 0; i < cap.rate_out_count; i++)
+ if (params->codec.options.src_d.out_sample_rate == cap.rate_out[i]) {
+ pair->rate[OUT] = params->codec.options.src_d.out_sample_rate;
+ break;
+ }
+ if (i == cap.rate_out_count)
+ return -EINVAL;
+
+ if (params->codec.ch_in != params->codec.ch_out ||
+ params->codec.ch_in < cap.chan_min ||
+ params->codec.ch_in > cap.chan_max)
+ return -EINVAL;
+
+ pair->channels = params->codec.ch_in;
+ pair->buf_len[IN] = params->buffer.fragment_size;
+ pair->buf_len[OUT] = params->buffer.fragment_size;
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+ struct snd_dma_buffer *dmab = dmabuf->priv;
+
+ return snd_dma_buffer_mmap(dmab, vma);
+}
+
+static struct sg_table *fsl_asrc_m2m_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction direction)
+{
+ struct snd_dma_buffer *dmab = attachment->dmabuf->priv;
+ struct sg_table *sgt;
+
+ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt)
+ return NULL;
+
+ if (dma_get_sgtable(attachment->dev, sgt, dmab->area, dmab->addr, dmab->bytes) < 0)
+ goto free;
+
+ if (dma_map_sgtable(attachment->dev, sgt, direction, 0))
+ goto free;
+
+ return sgt;
+
+free:
+ sg_free_table(sgt);
+ kfree(sgt);
+ return NULL;
+}
+
+static void fsl_asrc_m2m_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *table,
+ enum dma_data_direction direction)
+{
+ dma_unmap_sgtable(attachment->dev, table, direction, 0);
+}
+
+static void fsl_asrc_m2m_release(struct dma_buf *dmabuf)
+{
+ /* buffer is released by fsl_asrc_m2m_comp_release() */
+}
+
+static const struct dma_buf_ops fsl_asrc_m2m_dma_buf_ops = {
+ .mmap = fsl_asrc_m2m_mmap,
+ .map_dma_buf = fsl_asrc_m2m_map_dma_buf,
+ .unmap_dma_buf = fsl_asrc_m2m_unmap_dma_buf,
+ .release = fsl_asrc_m2m_release,
+};
+
+static int fsl_asrc_m2m_comp_task_create(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info_in);
+ DEFINE_DMA_BUF_EXPORT_INFO(exp_info_out);
+ struct fsl_asrc *asrc = stream->private_data;
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct fsl_asrc_pair *pair = runtime->private_data;
+ struct device *dev = &asrc->pdev->dev;
+ int ret;
+
+ exp_info_in.ops = &fsl_asrc_m2m_dma_buf_ops;
+ exp_info_in.size = ASRC_M2M_BUFFER_SIZE;
+ exp_info_in.flags = O_RDWR;
+ exp_info_in.priv = &pair->dma_buffer[IN];
+ task->input = dma_buf_export(&exp_info_in);
+ if (IS_ERR(task->input)) {
+ ret = PTR_ERR(task->input);
+ return ret;
+ }
+
+ exp_info_out.ops = &fsl_asrc_m2m_dma_buf_ops;
+ exp_info_out.size = ASRC_M2M_BUFFER_SIZE;
+ exp_info_out.flags = O_RDWR;
+ exp_info_out.priv = &pair->dma_buffer[OUT];
+ task->output = dma_buf_export(&exp_info_out);
+ if (IS_ERR(task->output)) {
+ ret = PTR_ERR(task->output);
+ return ret;
+ }
+
+ /* Request asrc pair/context */
+ ret = asrc->request_pair(pair->channels, pair);
+ if (ret) {
+ dev_err(dev, "failed to request pair: %d\n", ret);
+ goto err_request_pair;
+ }
+
+ ret = asrc->m2m_prepare(pair);
+ if (ret) {
+ dev_err(dev, "failed to start pair part one: %d\n", ret);
+ goto err_start_part_one;
+ }
+
+ /* Request dma channels */
+ pair->dma_chan[IN] = asrc->get_dma_channel(pair, IN);
+ if (!pair->dma_chan[IN]) {
+ dev_err(dev, "[ctx%d] failed to get input DMA channel\n", pair->index);
+ ret = -EBUSY;
+ goto err_dma_channel_in;
+ }
+
+ pair->dma_chan[OUT] = asrc->get_dma_channel(pair, OUT);
+ if (!pair->dma_chan[OUT]) {
+ dev_err(dev, "[ctx%d] failed to get output DMA channel\n", pair->index);
+ ret = -EBUSY;
+ goto err_dma_channel_out;
+ }
+
+ return 0;
+
+err_dma_channel_out:
+ dma_release_channel(pair->dma_chan[IN]);
+err_dma_channel_in:
+ if (asrc->m2m_unprepare)
+ asrc->m2m_unprepare(pair);
+err_start_part_one:
+ asrc->release_pair(pair);
+err_request_pair:
+ return ret;
+}
+
+static int fsl_asrc_m2m_comp_task_start(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct fsl_asrc_pair *pair = runtime->private_data;
+
+ return asrc_m2m_device_run(pair, task);
+}
+
+static int fsl_asrc_m2m_comp_task_stop(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ return 0;
+}
+
+static int fsl_asrc_m2m_comp_task_free(struct snd_compr_stream *stream,
+ struct snd_compr_task_runtime *task)
+{
+ struct fsl_asrc *asrc = stream->private_data;
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct fsl_asrc_pair *pair = runtime->private_data;
+
+ /* Stop & release pair/context */
+ if (asrc->m2m_stop)
+ asrc->m2m_stop(pair);
+
+ if (asrc->m2m_unprepare)
+ asrc->m2m_unprepare(pair);
+ asrc->release_pair(pair);
+
+ /* Release dma channel */
+ if (pair->dma_chan[IN])
+ dma_release_channel(pair->dma_chan[IN]);
+ if (pair->dma_chan[OUT])
+ dma_release_channel(pair->dma_chan[OUT]);
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_get_caps(struct snd_compr_stream *cstream,
+ struct snd_compr_caps *caps)
+{
+ caps->num_codecs = 1;
+ caps->min_fragment_size = 4096;
+ caps->max_fragment_size = 4096;
+ caps->min_fragments = 1;
+ caps->max_fragments = 1;
+ caps->codecs[0] = SND_AUDIOCODEC_PCM;
+
+ return 0;
+}
+
+static int fsl_asrc_m2m_fill_codec_caps(struct fsl_asrc *asrc,
+ struct snd_compr_codec_caps *codec)
+{
+ struct fsl_asrc_m2m_cap cap;
+ snd_pcm_format_t k;
+ int j = 0;
+ int ret;
+
+ ret = asrc->m2m_get_cap(&cap);
+ if (ret)
+ return -EINVAL;
+
+ pcm_for_each_format(k) {
+ if (pcm_format_to_bits(k) & cap.fmt_in) {
+ codec->descriptor[j].max_ch = cap.chan_max;
+ memcpy(codec->descriptor[j].sample_rates,
+ 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].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 =
+ cap.rate_out[cap.rate_out_count - 1];
+ j++;
+ }
+ }
+
+ codec->codec = SND_AUDIOCODEC_PCM;
+ codec->num_descriptors = j;
+ return 0;
+}
+
+static int fsl_asrc_m2m_get_codec_caps(struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec)
+{
+ struct fsl_asrc *asrc = stream->private_data;
+
+ return fsl_asrc_m2m_fill_codec_caps(asrc, codec);
+}
+
+static struct snd_compr_ops fsl_asrc_m2m_compr_ops = {
+ .open = fsl_asrc_m2m_comp_open,
+ .free = fsl_asrc_m2m_comp_release,
+ .set_params = fsl_asrc_m2m_comp_set_params,
+ .get_caps = fsl_asrc_m2m_get_caps,
+ .get_codec_caps = fsl_asrc_m2m_get_codec_caps,
+ .task_create = fsl_asrc_m2m_comp_task_create,
+ .task_start = fsl_asrc_m2m_comp_task_start,
+ .task_stop = fsl_asrc_m2m_comp_task_stop,
+ .task_free = fsl_asrc_m2m_comp_task_free,
+};
+
+int fsl_asrc_m2m_suspend(struct fsl_asrc *asrc)
+{
+ struct fsl_asrc_pair *pair;
+ int i;
+
+ for (i = 0; i < PAIR_CTX_NUM; i++) {
+ pair = asrc->pair[i];
+ if (!pair || !pair->dma_buffer[IN].area || !pair->dma_buffer[OUT].area)
+ continue;
+ if (!completion_done(&pair->complete[IN])) {
+ if (pair->dma_chan[IN])
+ dmaengine_terminate_all(pair->dma_chan[IN]);
+ asrc_input_dma_callback((void *)pair);
+ }
+ if (!completion_done(&pair->complete[OUT])) {
+ if (pair->dma_chan[OUT])
+ dmaengine_terminate_all(pair->dma_chan[OUT]);
+ asrc_output_dma_callback((void *)pair);
+ }
+
+ if (asrc->m2m_pair_suspend)
+ asrc->m2m_pair_suspend(pair);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_asrc_m2m_suspend);
+
+int fsl_asrc_m2m_resume(struct fsl_asrc *asrc)
+{
+ struct fsl_asrc_pair *pair;
+ int i;
+
+ for (i = 0; i < PAIR_CTX_NUM; i++) {
+ pair = asrc->pair[i];
+ if (!pair)
+ continue;
+ if (asrc->m2m_pair_resume)
+ asrc->m2m_pair_resume(pair);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(fsl_asrc_m2m_resume);
+
+int fsl_asrc_m2m_init(struct fsl_asrc *asrc)
+{
+ struct device *dev = &asrc->pdev->dev;
+ struct snd_card *card;
+ struct snd_compr *compr;
+ int ret;
+
+ ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (ret < 0)
+ return ret;
+
+ strscpy(card->driver, "fsl-asrc-m2m", sizeof(card->driver));
+ strscpy(card->shortname, "ASRC-M2M", sizeof(card->shortname));
+ strscpy(card->longname, "ASRC-M2M", sizeof(card->shortname));
+
+ asrc->card = card;
+
+ compr = devm_kzalloc(dev, sizeof(*compr), GFP_KERNEL);
+ if (!compr) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ compr->ops = &fsl_asrc_m2m_compr_ops;
+ compr->private_data = asrc;
+
+ ret = snd_compress_new(card, 0, SND_COMPRESS_ACCEL, "ASRC M2M", compr);
+ if (ret < 0)
+ goto err;
+
+ ret = snd_card_register(card);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ snd_card_free(card);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fsl_asrc_m2m_init);
+
+void fsl_asrc_m2m_exit(struct fsl_asrc *asrc)
+{
+ struct snd_card *card = asrc->card;
+
+ snd_card_free(card);
+}
+EXPORT_SYMBOL_GPL(fsl_asrc_m2m_exit);
+
+MODULE_IMPORT_NS("DMA_BUF");
+MODULE_AUTHOR("Shengjiu Wang <Shengjiu.Wang@nxp.com>");
+MODULE_DESCRIPTION("Freescale ASRC M2M driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c
index bde642318835..da401561e2de 100644
--- a/sound/soc/fsl/fsl_aud2htx.c
+++ b/sound/soc/fsl/fsl_aud2htx.c
@@ -290,8 +290,7 @@ static int fsl_aud2htx_runtime_resume(struct device *dev)
static const struct dev_pm_ops fsl_aud2htx_pm_ops = {
RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend, fsl_aud2htx_runtime_resume,
NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_aud2htx_driver = {
diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c
index 3cd9a66b70a1..7981d598ba13 100644
--- a/sound/soc/fsl/fsl_audmix.c
+++ b/sound/soc/fsl/fsl_audmix.c
@@ -488,11 +488,17 @@ static int fsl_audmix_probe(struct platform_device *pdev)
goto err_disable_pm;
}
- priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
- if (IS_ERR(priv->pdev)) {
- ret = PTR_ERR(priv->pdev);
- dev_err(dev, "failed to register platform: %d\n", ret);
- goto err_disable_pm;
+ /*
+ * If dais property exist, then register the imx-audmix card driver.
+ * otherwise, it should be linked by audio graph card.
+ */
+ if (of_find_property(pdev->dev.of_node, "dais", NULL)) {
+ priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0);
+ if (IS_ERR(priv->pdev)) {
+ ret = PTR_ERR(priv->pdev);
+ dev_err(dev, "failed to register platform: %d\n", ret);
+ goto err_disable_pm;
+ }
}
return 0;
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index d22f0621c465..f404a39009e1 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -1861,6 +1861,224 @@ static int fsl_easrc_get_fifo_addr(u8 dir, enum asrc_pair_index index)
return REG_EASRC_FIFO(dir, index);
}
+/* Get sample numbers in FIFO */
+static unsigned int fsl_easrc_get_output_fifo_size(struct fsl_asrc_pair *pair)
+{
+ struct fsl_asrc *asrc = pair->asrc;
+ enum asrc_pair_index index = pair->index;
+ u32 val;
+
+ regmap_read(asrc->regmap, REG_EASRC_SFS(index), &val);
+ val &= EASRC_SFS_NSGO_MASK;
+
+ return val >> EASRC_SFS_NSGO_SHIFT;
+}
+
+static int fsl_easrc_m2m_prepare(struct fsl_asrc_pair *pair)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+ struct fsl_asrc *asrc = pair->asrc;
+ struct device *dev = &asrc->pdev->dev;
+ int ret;
+
+ ctx_priv->in_params.sample_rate = pair->rate[IN];
+ ctx_priv->in_params.sample_format = pair->sample_format[IN];
+ ctx_priv->out_params.sample_rate = pair->rate[OUT];
+ ctx_priv->out_params.sample_format = pair->sample_format[OUT];
+
+ ctx_priv->in_params.fifo_wtmk = FSL_EASRC_INPUTFIFO_WML;
+ ctx_priv->out_params.fifo_wtmk = FSL_EASRC_OUTPUTFIFO_WML;
+ /* Fill the right half of the re-sampler with zeros */
+ ctx_priv->rs_init_mode = 0x2;
+ /* Zero fill the right half of the prefilter */
+ ctx_priv->pf_init_mode = 0x2;
+
+ ret = fsl_easrc_set_ctx_format(pair,
+ &ctx_priv->in_params.sample_format,
+ &ctx_priv->out_params.sample_format);
+ if (ret) {
+ dev_err(dev, "failed to set context format: %d\n", ret);
+ return ret;
+ }
+
+ ret = fsl_easrc_config_context(asrc, pair->index);
+ if (ret) {
+ dev_err(dev, "failed to config context %d\n", ret);
+ return ret;
+ }
+
+ ctx_priv->in_params.iterations = 1;
+ ctx_priv->in_params.group_len = pair->channels;
+ ctx_priv->in_params.access_len = pair->channels;
+ ctx_priv->out_params.iterations = 1;
+ ctx_priv->out_params.group_len = pair->channels;
+ ctx_priv->out_params.access_len = pair->channels;
+
+ ret = fsl_easrc_set_ctx_organziation(pair);
+ if (ret) {
+ dev_err(dev, "failed to set fifo organization\n");
+ return ret;
+ }
+
+ /* The context start flag */
+ pair->first_convert = 1;
+ return 0;
+}
+
+static int fsl_easrc_m2m_start(struct fsl_asrc_pair *pair)
+{
+ /* start context once */
+ if (pair->first_convert) {
+ fsl_easrc_start_context(pair);
+ pair->first_convert = 0;
+ }
+
+ return 0;
+}
+
+static int fsl_easrc_m2m_stop(struct fsl_asrc_pair *pair)
+{
+ /* Stop pair/context */
+ if (!pair->first_convert) {
+ fsl_easrc_stop_context(pair);
+ pair->first_convert = 1;
+ }
+
+ return 0;
+}
+
+/* calculate capture data length according to output data length and sample rate */
+static int fsl_easrc_m2m_calc_out_len(struct fsl_asrc_pair *pair, int input_buffer_length)
+{
+ struct fsl_asrc *easrc = pair->asrc;
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+ unsigned int in_rate = ctx_priv->in_params.norm_rate;
+ unsigned int out_rate = ctx_priv->out_params.norm_rate;
+ unsigned int channels = pair->channels;
+ unsigned int in_samples, out_samples;
+ unsigned int in_width, out_width;
+ unsigned int out_length;
+ unsigned int frac_bits;
+ u64 val1, val2;
+
+ switch (easrc_priv->rs_num_taps) {
+ case EASRC_RS_32_TAPS:
+ /* integer bits = 5; */
+ frac_bits = 39;
+ break;
+ case EASRC_RS_64_TAPS:
+ /* integer bits = 6; */
+ frac_bits = 38;
+ break;
+ case EASRC_RS_128_TAPS:
+ /* integer bits = 7; */
+ frac_bits = 37;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val1 = (u64)in_rate << frac_bits;
+ do_div(val1, out_rate);
+ val1 += (s64)ctx_priv->ratio_mod << (frac_bits - 31);
+
+ in_width = snd_pcm_format_physical_width(ctx_priv->in_params.sample_format) / 8;
+ out_width = snd_pcm_format_physical_width(ctx_priv->out_params.sample_format) / 8;
+
+ ctx_priv->in_filled_len += input_buffer_length;
+ if (ctx_priv->in_filled_len <= ctx_priv->in_filled_sample * in_width * channels) {
+ out_length = 0;
+ } else {
+ in_samples = ctx_priv->in_filled_len / (in_width * channels) -
+ ctx_priv->in_filled_sample;
+
+ /* right shift 12 bit to make ratio in 32bit space */
+ val2 = (u64)in_samples << (frac_bits - 12);
+ val1 = val1 >> 12;
+ do_div(val2, val1);
+ out_samples = val2;
+
+ out_length = out_samples * out_width * channels;
+ ctx_priv->in_filled_len = ctx_priv->in_filled_sample * in_width * channels;
+ }
+
+ return out_length;
+}
+
+static int fsl_easrc_m2m_get_maxburst(u8 dir, struct fsl_asrc_pair *pair)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+
+ if (dir == IN)
+ return ctx_priv->in_params.fifo_wtmk * pair->channels;
+ else
+ return ctx_priv->out_params.fifo_wtmk * pair->channels;
+}
+
+static int fsl_easrc_m2m_pair_suspend(struct fsl_asrc_pair *pair)
+{
+ fsl_easrc_stop_context(pair);
+
+ return 0;
+}
+
+static int fsl_easrc_m2m_pair_resume(struct fsl_asrc_pair *pair)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+
+ pair->first_convert = 1;
+ ctx_priv->in_filled_len = 0;
+
+ return 0;
+}
+
+/* val is Q31 */
+static int fsl_easrc_m2m_set_ratio_mod(struct fsl_asrc_pair *pair, int val)
+{
+ struct fsl_easrc_ctx_priv *ctx_priv = pair->private;
+ struct fsl_asrc *easrc = pair->asrc;
+ struct fsl_easrc_priv *easrc_priv = easrc->private;
+ unsigned int frac_bits;
+
+ ctx_priv->ratio_mod += val;
+
+ switch (easrc_priv->rs_num_taps) {
+ case EASRC_RS_32_TAPS:
+ /* integer bits = 5; */
+ frac_bits = 39;
+ break;
+ case EASRC_RS_64_TAPS:
+ /* integer bits = 6; */
+ frac_bits = 38;
+ break;
+ case EASRC_RS_128_TAPS:
+ /* integer bits = 7; */
+ frac_bits = 37;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val <<= (frac_bits - 31);
+ regmap_write(easrc->regmap, REG_EASRC_RUC(pair->index), EASRC_RSUC_RS_RM(val));
+
+ return 0;
+}
+
+static int fsl_easrc_m2m_get_cap(struct fsl_asrc_m2m_cap *cap)
+{
+ cap->fmt_in = FSL_EASRC_FORMATS;
+ cap->fmt_out = FSL_EASRC_FORMATS | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
+ cap->rate_in = easrc_rates;
+ cap->rate_in_count = ARRAY_SIZE(easrc_rates);
+ cap->rate_out = easrc_rates;
+ cap->rate_out_count = ARRAY_SIZE(easrc_rates);
+ cap->chan_min = 1;
+ cap->chan_max = 32;
+ return 0;
+}
+
static const struct of_device_id fsl_easrc_dt_ids[] = {
{ .compatible = "fsl,imx8mn-easrc",},
{}
@@ -1926,6 +2144,16 @@ static int fsl_easrc_probe(struct platform_device *pdev)
easrc->release_pair = fsl_easrc_release_context;
easrc->get_fifo_addr = fsl_easrc_get_fifo_addr;
easrc->pair_priv_size = sizeof(struct fsl_easrc_ctx_priv);
+ easrc->m2m_prepare = fsl_easrc_m2m_prepare;
+ easrc->m2m_start = fsl_easrc_m2m_start;
+ easrc->m2m_stop = fsl_easrc_m2m_stop;
+ easrc->get_output_fifo_size = fsl_easrc_get_output_fifo_size;
+ easrc->m2m_calc_out_len = fsl_easrc_m2m_calc_out_len;
+ easrc->m2m_get_maxburst = fsl_easrc_m2m_get_maxburst;
+ easrc->m2m_pair_suspend = fsl_easrc_m2m_pair_suspend;
+ easrc->m2m_pair_resume = fsl_easrc_m2m_pair_resume;
+ easrc->m2m_set_ratio_mod = fsl_easrc_m2m_set_ratio_mod;
+ easrc->m2m_get_cap = fsl_easrc_m2m_get_cap;
easrc_priv->rs_num_taps = EASRC_RS_32_TAPS;
easrc_priv->const_coeff = 0x3FF0000000000000;
@@ -1976,6 +2204,12 @@ static int fsl_easrc_probe(struct platform_device *pdev)
goto err_pm_disable;
}
+ ret = fsl_asrc_m2m_init(easrc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to init m2m device %d\n", ret);
+ return ret;
+ }
+
return 0;
err_pm_disable:
@@ -1985,6 +2219,10 @@ err_pm_disable:
static void fsl_easrc_remove(struct platform_device *pdev)
{
+ struct fsl_asrc *easrc = dev_get_drvdata(&pdev->dev);
+
+ fsl_asrc_m2m_exit(easrc);
+
pm_runtime_disable(&pdev->dev);
}
@@ -2085,10 +2323,29 @@ disable_mem_clk:
return ret;
}
+static int fsl_easrc_suspend(struct device *dev)
+{
+ struct fsl_asrc *easrc = dev_get_drvdata(dev);
+ int ret;
+
+ fsl_asrc_m2m_suspend(easrc);
+ ret = pm_runtime_force_suspend(dev);
+ return ret;
+}
+
+static int fsl_easrc_resume(struct device *dev)
+{
+ struct fsl_asrc *easrc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ fsl_asrc_m2m_resume(easrc);
+ return ret;
+}
+
static const struct dev_pm_ops fsl_easrc_pm_ops = {
RUNTIME_PM_OPS(fsl_easrc_runtime_suspend, fsl_easrc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SYSTEM_SLEEP_PM_OPS(fsl_easrc_suspend, fsl_easrc_resume)
};
static struct platform_driver fsl_easrc_driver = {
diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h
index 7c70dac52713..c9f770862662 100644
--- a/sound/soc/fsl/fsl_easrc.h
+++ b/sound/soc/fsl/fsl_easrc.h
@@ -601,6 +601,8 @@ struct fsl_easrc_slot {
* @out_missed_sample: sample missed in output
* @st1_addexp: exponent added for stage1
* @st2_addexp: exponent added for stage2
+ * @ratio_mod: update ratio
+ * @in_filled_len: input filled length
*/
struct fsl_easrc_ctx_priv {
struct fsl_easrc_io_params in_params;
@@ -618,6 +620,8 @@ struct fsl_easrc_ctx_priv {
int out_missed_sample;
int st1_addexp;
int st2_addexp;
+ int ratio_mod;
+ unsigned int in_filled_len;
};
/**
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index 0b247f16a163..cde0b0c6c1ef 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -1189,11 +1189,8 @@ static int fsl_esai_runtime_suspend(struct device *dev)
}
static const struct dev_pm_ops fsl_esai_pm_ops = {
- SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend,
- fsl_esai_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_esai_runtime_suspend, fsl_esai_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_esai_driver = {
@@ -1201,7 +1198,7 @@ static struct platform_driver fsl_esai_driver = {
.remove = fsl_esai_remove,
.driver = {
.name = "fsl-esai-dai",
- .pm = &fsl_esai_pm_ops,
+ .pm = pm_ptr(&fsl_esai_pm_ops),
.of_match_table = fsl_esai_dt_ids,
},
};
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
index 8c15389c9a04..aabd90a8b3ec 100644
--- a/sound/soc/fsl/fsl_micfil.c
+++ b/sound/soc/fsl/fsl_micfil.c
@@ -19,6 +19,7 @@
#include <linux/dma/imx-dma.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/core.h>
@@ -35,6 +36,15 @@
#define MICFIL_AUDIO_PLL2 1
#define MICFIL_CLK_EXT3 2
+static const unsigned int fsl_micfil_rates[] = {
+ 8000, 11025, 16000, 22050, 32000, 44100, 48000,
+};
+
+static const struct snd_pcm_hw_constraint_list fsl_micfil_rate_constraints = {
+ .count = ARRAY_SIZE(fsl_micfil_rates),
+ .list = fsl_micfil_rates,
+};
+
enum quality {
QUALITY_HIGH,
QUALITY_MEDIUM,
@@ -69,6 +79,7 @@ struct fsl_micfil {
struct fsl_micfil_verid verid;
struct fsl_micfil_param param;
bool mclk_flag; /* mclk enable flag */
+ bool dec_bypass;
};
struct fsl_micfil_soc_data {
@@ -80,6 +91,7 @@ struct fsl_micfil_soc_data {
bool use_verid;
bool volume_sx;
u64 formats;
+ int fifo_offset;
};
static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
@@ -89,6 +101,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.volume_sx = true,
+ .fifo_offset = 0,
};
static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
@@ -98,6 +111,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
.dataline = 0xf,
.formats = SNDRV_PCM_FMTBIT_S32_LE,
.volume_sx = false,
+ .fifo_offset = 0,
};
static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
@@ -109,12 +123,26 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
.use_edma = true,
.use_verid = true,
.volume_sx = false,
+ .fifo_offset = 0,
+};
+
+static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
+ .imx = true,
+ .fifos = 8,
+ .fifo_depth = 32,
+ .dataline = 0xf,
+ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_BE,
+ .use_edma = true,
+ .use_verid = true,
+ .volume_sx = false,
+ .fifo_offset = -4,
};
static const struct of_device_id fsl_micfil_dt_ids[] = {
{ .compatible = "fsl,imx8mm-micfil", .data = &fsl_micfil_imx8mm },
{ .compatible = "fsl,imx8mp-micfil", .data = &fsl_micfil_imx8mp },
{ .compatible = "fsl,imx93-micfil", .data = &fsl_micfil_imx93 },
+ { .compatible = "fsl,imx943-micfil", .data = &fsl_micfil_imx943 },
{}
};
MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids);
@@ -157,6 +185,8 @@ static int micfil_set_quality(struct fsl_micfil *micfil)
case QUALITY_VLOW2:
qsel = MICFIL_QSEL_VLOW2_QUALITY;
break;
+ default:
+ return -EINVAL;
}
return regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
@@ -486,29 +516,12 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
- unsigned int rates[MICFIL_NUM_RATES] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
- int i, j, k = 0;
- u64 clk_rate;
if (!micfil) {
dev_err(dai->dev, "micfil dai priv_data not set\n");
return -EINVAL;
}
- micfil->constraint_rates.list = micfil->constraint_rates_list;
- micfil->constraint_rates.count = 0;
-
- for (j = 0; j < MICFIL_NUM_RATES; j++) {
- for (i = 0; i < MICFIL_CLK_SRC_NUM; i++) {
- clk_rate = clk_get_rate(micfil->clk_src[i]);
- if (clk_rate != 0 && do_div(clk_rate, rates[j]) == 0) {
- micfil->constraint_rates_list[k++] = rates[j];
- micfil->constraint_rates.count++;
- break;
- }
- }
- }
-
if (micfil->constraint_rates.count > 0)
snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
@@ -713,14 +726,14 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd,
if (ret)
return ret;
- if (micfil->vad_enabled)
+ if (micfil->vad_enabled && !micfil->dec_bypass)
fsl_micfil_hwvad_enable(micfil);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- if (micfil->vad_enabled)
+ if (micfil->vad_enabled && !micfil->dec_bypass)
fsl_micfil_hwvad_disable(micfil);
/* Disable the module */
@@ -767,8 +780,9 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
{
struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
unsigned int channels = params_channels(params);
+ snd_pcm_format_t format = params_format(params);
unsigned int rate = params_rate(params);
- int clk_div = 8;
+ int clk_div = 8, mclk_rate, div_multiply_k;
int osr = MICFIL_OSR_DEFAULT;
int ret;
@@ -790,7 +804,39 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
micfil->mclk_flag = true;
- ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8);
+ /* floor(K * CLKDIV) */
+ switch (micfil->quality) {
+ case QUALITY_HIGH:
+ div_multiply_k = clk_div >> 1;
+ break;
+ case QUALITY_LOW:
+ case QUALITY_VLOW1:
+ div_multiply_k = clk_div << 1;
+ break;
+ case QUALITY_VLOW2:
+ div_multiply_k = clk_div << 2;
+ break;
+ case QUALITY_MEDIUM:
+ case QUALITY_VLOW0:
+ default:
+ div_multiply_k = clk_div;
+ break;
+ }
+
+ if (format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
+ micfil->dec_bypass = true;
+ /*
+ * According to equation 29 in RM:
+ * MCLK_CLK_ROOT = PDM CLK rate * 2 * floor(K * CLKDIV)
+ * PDM CLK rate = rate * physical bit width (32)
+ */
+ mclk_rate = rate * div_multiply_k * 32 * 2;
+ } else {
+ micfil->dec_bypass = false;
+ mclk_rate = rate * clk_div * osr * 8;
+ }
+
+ ret = clk_set_rate(micfil->mclk, mclk_rate);
if (ret)
return ret;
@@ -798,10 +844,14 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream,
if (ret)
return ret;
+ regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
+ MICFIL_CTRL2_DEC_BYPASS,
+ micfil->dec_bypass ? MICFIL_CTRL2_DEC_BYPASS : 0);
+
ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
MICFIL_CTRL2_CLKDIV | MICFIL_CTRL2_CICOSR,
FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) |
- FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr));
+ FIELD_PREP(MICFIL_CTRL2_CICOSR, 32 - osr));
/* Configure CIC OSR in VADCICOSR */
regmap_update_bits(micfil->regmap, REG_MICFIL_VAD0_CTRL1,
@@ -940,9 +990,39 @@ static const struct reg_default fsl_micfil_reg_defaults[] = {
{REG_MICFIL_VAD0_ZCD, 0x00000004},
};
+static const struct reg_default fsl_micfil_reg_defaults_v2[] = {
+ {REG_MICFIL_CTRL1, 0x00000000},
+ {REG_MICFIL_CTRL2, 0x00000000},
+ {REG_MICFIL_STAT, 0x00000000},
+ {REG_MICFIL_FIFO_CTRL, 0x0000001F},
+ {REG_MICFIL_FIFO_STAT, 0x00000000},
+ {REG_MICFIL_DATACH0 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH1 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH2 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH3 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH4 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH5 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH6 - 0x4, 0x00000000},
+ {REG_MICFIL_DATACH7 - 0x4, 0x00000000},
+ {REG_MICFIL_DC_CTRL, 0x00000000},
+ {REG_MICFIL_OUT_CTRL, 0x00000000},
+ {REG_MICFIL_OUT_STAT, 0x00000000},
+ {REG_MICFIL_VAD0_CTRL1, 0x00000000},
+ {REG_MICFIL_VAD0_CTRL2, 0x000A0000},
+ {REG_MICFIL_VAD0_STAT, 0x00000000},
+ {REG_MICFIL_VAD0_SCONFIG, 0x00000000},
+ {REG_MICFIL_VAD0_NCONFIG, 0x80000000},
+ {REG_MICFIL_VAD0_NDATA, 0x00000000},
+ {REG_MICFIL_VAD0_ZCD, 0x00000004},
+};
+
static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg)
{
struct fsl_micfil *micfil = dev_get_drvdata(dev);
+ int ofs = micfil->soc->fifo_offset;
+
+ if (reg >= (REG_MICFIL_DATACH0 + ofs) && reg <= (REG_MICFIL_DATACH7 + ofs))
+ return true;
switch (reg) {
case REG_MICFIL_CTRL1:
@@ -950,14 +1030,6 @@ static bool fsl_micfil_readable_reg(struct device *dev, unsigned int reg)
case REG_MICFIL_STAT:
case REG_MICFIL_FIFO_CTRL:
case REG_MICFIL_FIFO_STAT:
- case REG_MICFIL_DATACH0:
- case REG_MICFIL_DATACH1:
- case REG_MICFIL_DATACH2:
- case REG_MICFIL_DATACH3:
- case REG_MICFIL_DATACH4:
- case REG_MICFIL_DATACH5:
- case REG_MICFIL_DATACH6:
- case REG_MICFIL_DATACH7:
case REG_MICFIL_DC_CTRL:
case REG_MICFIL_OUT_CTRL:
case REG_MICFIL_OUT_STAT:
@@ -1011,17 +1083,15 @@ static bool fsl_micfil_writeable_reg(struct device *dev, unsigned int reg)
static bool fsl_micfil_volatile_reg(struct device *dev, unsigned int reg)
{
+ struct fsl_micfil *micfil = dev_get_drvdata(dev);
+ int ofs = micfil->soc->fifo_offset;
+
+ if (reg >= (REG_MICFIL_DATACH0 + ofs) && reg <= (REG_MICFIL_DATACH7 + ofs))
+ return true;
+
switch (reg) {
case REG_MICFIL_STAT:
case REG_MICFIL_FIFO_STAT:
- case REG_MICFIL_DATACH0:
- case REG_MICFIL_DATACH1:
- case REG_MICFIL_DATACH2:
- case REG_MICFIL_DATACH3:
- case REG_MICFIL_DATACH4:
- case REG_MICFIL_DATACH5:
- case REG_MICFIL_DATACH6:
- case REG_MICFIL_DATACH7:
case REG_MICFIL_OUT_STAT:
case REG_MICFIL_VERID:
case REG_MICFIL_PARAM:
@@ -1047,6 +1117,20 @@ static const struct regmap_config fsl_micfil_regmap_config = {
.cache_type = REGCACHE_MAPLE,
};
+static const struct regmap_config fsl_micfil_regmap_config_v2 = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+
+ .max_register = REG_MICFIL_VAD0_ZCD,
+ .reg_defaults = fsl_micfil_reg_defaults_v2,
+ .num_reg_defaults = ARRAY_SIZE(fsl_micfil_reg_defaults_v2),
+ .readable_reg = fsl_micfil_readable_reg,
+ .volatile_reg = fsl_micfil_volatile_reg,
+ .writeable_reg = fsl_micfil_writeable_reg,
+ .cache_type = REGCACHE_MAPLE,
+};
+
/* END OF REGMAP */
static irqreturn_t micfil_isr(int irq, void *devid)
@@ -1239,14 +1323,26 @@ static int fsl_micfil_probe(struct platform_device *pdev)
if (IS_ERR(micfil->clk_src[MICFIL_CLK_EXT3]))
micfil->clk_src[MICFIL_CLK_EXT3] = NULL;
+ fsl_asoc_constrain_rates(&micfil->constraint_rates,
+ &fsl_micfil_rate_constraints,
+ micfil->clk_src[MICFIL_AUDIO_PLL1],
+ micfil->clk_src[MICFIL_AUDIO_PLL2],
+ micfil->clk_src[MICFIL_CLK_EXT3],
+ micfil->constraint_rates_list);
+
/* init regmap */
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(regs))
return PTR_ERR(regs);
- micfil->regmap = devm_regmap_init_mmio(&pdev->dev,
- regs,
- &fsl_micfil_regmap_config);
+ if (of_device_is_compatible(np, "fsl,imx943-micfil"))
+ micfil->regmap = devm_regmap_init_mmio(&pdev->dev,
+ regs,
+ &fsl_micfil_regmap_config_v2);
+ else
+ micfil->regmap = devm_regmap_init_mmio(&pdev->dev,
+ regs,
+ &fsl_micfil_regmap_config);
if (IS_ERR(micfil->regmap)) {
dev_err(&pdev->dev, "failed to init MICFIL regmap: %ld\n",
PTR_ERR(micfil->regmap));
@@ -1315,7 +1411,7 @@ static int fsl_micfil_probe(struct platform_device *pdev)
}
micfil->dma_params_rx.chan_name = "rx";
- micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0;
+ micfil->dma_params_rx.addr = res->start + REG_MICFIL_DATACH0 + micfil->soc->fifo_offset;
micfil->dma_params_rx.maxburst = MICFIL_DMA_MAXBURST_RX;
platform_set_drvdata(pdev, micfil);
@@ -1416,11 +1512,8 @@ static int fsl_micfil_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops fsl_micfil_pm_ops = {
- SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend,
- fsl_micfil_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, fsl_micfil_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_micfil_driver = {
@@ -1428,7 +1521,7 @@ static struct platform_driver fsl_micfil_driver = {
.remove = fsl_micfil_remove,
.driver = {
.name = "fsl-micfil-dai",
- .pm = &fsl_micfil_pm_ops,
+ .pm = pm_ptr(&fsl_micfil_pm_ops),
.of_match_table = fsl_micfil_dt_ids,
},
};
diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h
index b7798a7cbf2a..fdfe4e7125bc 100644
--- a/sound/soc/fsl/fsl_micfil.h
+++ b/sound/soc/fsl/fsl_micfil.h
@@ -53,6 +53,7 @@
#define MICFIL_CTRL1_CHEN(ch) BIT(ch)
/* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */
+#define MICFIL_CTRL2_DEC_BYPASS BIT(31)
#define MICFIL_CTRL2_QSEL_SHIFT 25
#define MICFIL_CTRL2_QSEL GENMASK(27, 25)
#define MICFIL_QSEL_MEDIUM_QUALITY 0
@@ -62,7 +63,7 @@
#define MICFIL_QSEL_VLOW1_QUALITY 5
#define MICFIL_QSEL_VLOW2_QUALITY 4
-#define MICFIL_CTRL2_CICOSR GENMASK(19, 16)
+#define MICFIL_CTRL2_CICOSR GENMASK(20, 16)
#define MICFIL_CTRL2_CLKDIV GENMASK(7, 0)
/* MICFIL Status Register -- REG_MICFIL_STAT 0x08 */
diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c
index 0513e9e8402e..e34e5ea98de5 100644
--- a/sound/soc/fsl/fsl_mqs.c
+++ b/sound/soc/fsl/fsl_mqs.c
@@ -410,12 +410,40 @@ static const struct fsl_mqs_soc_data fsl_mqs_imx95_netc_data = {
.div_shift = 9,
};
+static const struct fsl_mqs_soc_data fsl_mqs_imx943_aon_data = {
+ .type = TYPE_REG_SM,
+ .ctrl_off = 0x88,
+ .en_mask = BIT(1),
+ .en_shift = 1,
+ .rst_mask = BIT(2),
+ .rst_shift = 2,
+ .osr_mask = BIT(3),
+ .osr_shift = 3,
+ .div_mask = GENMASK(15, 8),
+ .div_shift = 8,
+};
+
+static const struct fsl_mqs_soc_data fsl_mqs_imx943_wakeup_data = {
+ .type = TYPE_REG_GPR,
+ .ctrl_off = 0x10,
+ .en_mask = BIT(1),
+ .en_shift = 1,
+ .rst_mask = BIT(2),
+ .rst_shift = 2,
+ .osr_mask = BIT(3),
+ .osr_shift = 3,
+ .div_mask = GENMASK(15, 8),
+ .div_shift = 8,
+};
+
static const struct of_device_id fsl_mqs_dt_ids[] = {
{ .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data },
{ .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data },
{ .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data },
{ .compatible = "fsl,imx95-aonmix-mqs", .data = &fsl_mqs_imx95_aon_data },
{ .compatible = "fsl,imx95-netcmix-mqs", .data = &fsl_mqs_imx95_netc_data },
+ { .compatible = "fsl,imx943-aonmix-mqs", .data = &fsl_mqs_imx943_aon_data },
+ { .compatible = "fsl,imx943-wakeupmix-mqs", .data = &fsl_mqs_imx943_wakeup_data },
{}
};
MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids);
diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c
index e257b8adafe0..b2979290c973 100644
--- a/sound/soc/fsl/fsl_qmc_audio.c
+++ b/sound/soc/fsl/fsl_qmc_audio.c
@@ -892,7 +892,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts;
}
qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts,
- count > 1 ? true : false);
+ count > 1);
qmc_soc_dai_driver->capture.channels_min = 0;
qmc_soc_dai_driver->capture.channels_max = 0;
@@ -901,7 +901,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node *
qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts;
}
qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts,
- count > 1 ? true : false);
+ count > 1);
qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate);
qmc_soc_dai_driver->playback.rate_min = tx_fs_rate;
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 634168d2bb6e..ed2b4780c470 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -885,7 +885,7 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
sai->dma_params_rx.maxburst);
ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
+ SNDRV_PCM_HW_PARAM_RATE, &sai->constraint_rates);
return ret;
}
@@ -994,10 +994,10 @@ static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
{
.name = "sai-tx",
.playback = {
- .stream_name = "CPU-Playback",
+ .stream_name = "SAI-Playback",
.channels_min = 1,
.channels_max = 32,
- .rate_min = 8000,
+ .rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
@@ -1007,7 +1007,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
{
.name = "sai-rx",
.capture = {
- .stream_name = "CPU-Capture",
+ .stream_name = "SAI-Capture",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
@@ -1442,6 +1442,11 @@ static int fsl_sai_probe(struct platform_device *pdev)
fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk,
&sai->pll11k_clk);
+ fsl_asoc_constrain_rates(&sai->constraint_rates,
+ &fsl_sai_rate_constraints,
+ sai->pll8k_clk, sai->pll11k_clk, NULL,
+ sai->constraint_rates_list);
+
/* Use Multi FIFO mode depending on the support from SDMA script */
ret = of_property_read_u32_array(np, "dmas", dmas, 4);
if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI)
@@ -1812,10 +1817,8 @@ disable_bus_clk:
}
static const struct dev_pm_ops fsl_sai_pm_ops = {
- SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend,
- fsl_sai_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(fsl_sai_runtime_suspend, fsl_sai_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_sai_driver = {
@@ -1823,7 +1826,7 @@ static struct platform_driver fsl_sai_driver = {
.remove = fsl_sai_remove,
.driver = {
.name = "fsl-sai",
- .pm = &fsl_sai_pm_ops,
+ .pm = pm_ptr(&fsl_sai_pm_ops),
.of_match_table = fsl_sai_ids,
},
};
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index 9c4d19fe22c6..0e25e2fc7ce0 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -9,6 +9,7 @@
#include <linux/dma/imx-dma.h>
#include <sound/dmaengine_pcm.h>
+#define FAL_SAI_NUM_RATES 20
#define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE |\
@@ -309,6 +310,8 @@ struct fsl_sai {
struct pinctrl *pinctrl;
struct pinctrl_state *pins_state;
struct sdma_peripheral_config audio_config[2];
+ struct snd_pcm_hw_constraint_list constraint_rates;
+ unsigned int constraint_rates_list[FAL_SAI_NUM_RATES];
};
#define TX 1
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
index a5ab27c2f711..d69a6b9795bf 100644
--- a/sound/soc/fsl/fsl_utils.c
+++ b/sound/soc/fsl/fsl_utils.c
@@ -152,6 +152,51 @@ void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
}
EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks);
+/**
+ * fsl_asoc_constrain_rates - constrain rates according to clocks
+ *
+ * @target_constr: target constraint
+ * @original_constr: original constraint
+ * @pll8k_clk: PLL clock pointer for 8kHz
+ * @pll11k_clk: PLL clock pointer for 11kHz
+ * @ext_clk: External clock pointer
+ * @target_rates: target rates array
+ *
+ * This function constrain rates according to clocks
+ */
+void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
+ const struct snd_pcm_hw_constraint_list *original_constr,
+ struct clk *pll8k_clk, struct clk *pll11k_clk,
+ struct clk *ext_clk, int *target_rates)
+{
+ int i, j, k = 0;
+ u64 clk_rate[3];
+
+ *target_constr = *original_constr;
+ if (pll8k_clk || pll11k_clk || ext_clk) {
+ target_constr->list = target_rates;
+ target_constr->count = 0;
+ for (i = 0; i < original_constr->count; i++) {
+ clk_rate[0] = clk_get_rate(pll8k_clk);
+ clk_rate[1] = clk_get_rate(pll11k_clk);
+ clk_rate[2] = clk_get_rate(ext_clk);
+ for (j = 0; j < 3; j++) {
+ if (clk_rate[j] != 0 &&
+ do_div(clk_rate[j], original_constr->list[i]) == 0) {
+ target_rates[k++] = original_constr->list[i];
+ target_constr->count++;
+ break;
+ }
+ }
+ }
+
+ /* protection for if there is no proper rate found*/
+ if (!target_constr->count)
+ *target_constr = *original_constr;
+ }
+}
+EXPORT_SYMBOL(fsl_asoc_constrain_rates);
+
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale ASoC utility code");
MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
index 4d5f3d93bc81..21b25a11ecda 100644
--- a/sound/soc/fsl/fsl_utils.h
+++ b/sound/soc/fsl/fsl_utils.h
@@ -26,4 +26,9 @@ void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk,
void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
struct clk *pll8k_clk,
struct clk *pll11k_clk, u64 ratio);
+
+void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
+ const struct snd_pcm_hw_constraint_list *original_constr,
+ struct clk *pll8k_clk, struct clk *pll11k_clk,
+ struct clk *ext_clk, int *target_rates);
#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c
index 9c184ab73468..83aea341c1b6 100644
--- a/sound/soc/fsl/fsl_xcvr.c
+++ b/sound/soc/fsl/fsl_xcvr.c
@@ -19,6 +19,7 @@
#include "imx-pcm.h"
#define FSL_XCVR_CAPDS_SIZE 256
+#define SPDIF_NUM_RATES 7
enum fsl_xcvr_pll_verison {
PLL_MX8MP,
@@ -37,6 +38,8 @@ struct fsl_xcvr {
const struct fsl_xcvr_soc_data *soc_data;
struct platform_device *pdev;
struct regmap *regmap;
+ struct regmap *regmap_phy;
+ struct regmap *regmap_pll;
struct clk *ipg_clk;
struct clk *pll_ipg_clk;
struct clk *phy_clk;
@@ -55,6 +58,8 @@ struct fsl_xcvr {
u8 cap_ds[FSL_XCVR_CAPDS_SIZE];
struct work_struct work_rst;
spinlock_t lock; /* Protect hw_reset and trigger */
+ struct snd_pcm_hw_constraint_list spdif_constr_rates;
+ u32 spdif_constr_rates_list[SPDIF_NUM_RATES];
};
static const struct fsl_xcvr_pll_conf {
@@ -257,7 +262,7 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
idx = BIT(phy ? 26 : 24);
tidx = BIT(phy ? 27 : 25);
- regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF);
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF | FSL_XCVR_PHY_AI_CTRL_AI_RWB);
regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg);
regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_WDATA, data);
regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);
@@ -271,6 +276,59 @@ static int fsl_xcvr_ai_write(struct fsl_xcvr *xcvr, u8 reg, u32 data, bool phy)
return ret;
}
+static int fsl_xcvr_ai_read(struct fsl_xcvr *xcvr, u8 reg, u32 *data, bool phy)
+{
+ struct device *dev = &xcvr->pdev->dev;
+ u32 val, idx, tidx;
+ int ret;
+
+ idx = BIT(phy ? 26 : 24);
+ tidx = BIT(phy ? 27 : 25);
+
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_CLR, 0xFF | FSL_XCVR_PHY_AI_CTRL_AI_RWB);
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET, reg | FSL_XCVR_PHY_AI_CTRL_AI_RWB);
+ regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_TOG, idx);
+
+ ret = regmap_read_poll_timeout(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL, val,
+ (val & idx) == ((val & tidx) >> 1),
+ 10, 10000);
+ if (ret)
+ dev_err(dev, "AI timeout: failed to read %s reg 0x%02x\n",
+ phy ? "PHY" : "PLL", reg);
+
+ regmap_read(xcvr->regmap, FSL_XCVR_PHY_AI_RDATA, data);
+
+ return ret;
+}
+
+static int fsl_xcvr_phy_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct fsl_xcvr *xcvr = context;
+
+ return fsl_xcvr_ai_read(xcvr, reg, val, 1);
+}
+
+static int fsl_xcvr_phy_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct fsl_xcvr *xcvr = context;
+
+ return fsl_xcvr_ai_write(xcvr, reg, val, 1);
+}
+
+static int fsl_xcvr_pll_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct fsl_xcvr *xcvr = context;
+
+ return fsl_xcvr_ai_read(xcvr, reg, val, 0);
+}
+
+static int fsl_xcvr_pll_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct fsl_xcvr *xcvr = context;
+
+ return fsl_xcvr_ai_write(xcvr, reg, val, 0);
+}
+
static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
{
struct device *dev = &xcvr->pdev->dev;
@@ -303,55 +361,55 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
switch (xcvr->soc_data->pll_ver) {
case PLL_MX8MP:
/* PLL: BANDGAP_SET: EN_VBG (enable bandgap) */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_BANDGAP_SET,
- FSL_XCVR_PLL_BANDGAP_EN_VBG, 0);
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_BANDGAP,
+ FSL_XCVR_PLL_BANDGAP_EN_VBG);
/* PLL: CTRL0: DIV_INTEGER */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi, 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0, fsl_xcvr_pll_cfg[i].mfi);
/* PLL: NUMERATOR: MFN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn, 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_NUM, fsl_xcvr_pll_cfg[i].mfn);
/* PLL: DENOMINATOR: MFD */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd, 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_DEN, fsl_xcvr_pll_cfg[i].mfd);
/* PLL: CTRL0_SET: HOLD_RING_OFF, POWER_UP */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP, 0);
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
+ FSL_XCVR_PLL_CTRL0_HROFF | FSL_XCVR_PLL_CTRL0_PWP);
udelay(25);
/* PLL: CTRL0: Clear Hold Ring Off */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_CLR,
- FSL_XCVR_PLL_CTRL0_HROFF, 0);
+ regmap_clear_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
+ FSL_XCVR_PLL_CTRL0_HROFF);
udelay(100);
if (tx) { /* TX is enabled for SPDIF only */
/* PLL: POSTDIV: PDIV0 */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
- FSL_XCVR_PLL_PDIVx(log2, 0), 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 0));
/* PLL: CTRL_SET: CLKMUX0_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_CM0_EN, 0);
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
+ FSL_XCVR_PLL_CTRL0_CM0_EN);
} else if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC RX */
/* PLL: POSTDIV: PDIV1 */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
- FSL_XCVR_PLL_PDIVx(log2, 1), 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 1));
/* PLL: CTRL_SET: CLKMUX1_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_CM1_EN, 0);
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
+ FSL_XCVR_PLL_CTRL0_CM1_EN);
} else { /* SPDIF / ARC RX */
/* PLL: POSTDIV: PDIV2 */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_PDIV,
- FSL_XCVR_PLL_PDIVx(log2, 2), 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_PLL_PDIV,
+ FSL_XCVR_PLL_PDIVx(log2, 2));
/* PLL: CTRL_SET: CLKMUX2_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PLL_CTRL0_SET,
- FSL_XCVR_PLL_CTRL0_CM2_EN, 0);
+ regmap_set_bits(xcvr->regmap_pll, FSL_XCVR_PLL_CTRL0,
+ FSL_XCVR_PLL_CTRL0_CM2_EN);
}
break;
case PLL_MX95:
val = fsl_xcvr_pll_cfg[i].mfi << FSL_XCVR_GP_PLL_DIV_MFI_SHIFT | div;
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DIV, val, 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_DIV, val);
val = fsl_xcvr_pll_cfg[i].mfn << FSL_XCVR_GP_PLL_NUMERATOR_MFN_SHIFT;
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_NUMERATOR, val, 0);
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_DENOMINATOR,
- fsl_xcvr_pll_cfg[i].mfd, 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_NUMERATOR, val);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_DENOMINATOR,
+ fsl_xcvr_pll_cfg[i].mfd);
val = FSL_XCVR_GP_PLL_CTRL_POWERUP | FSL_XCVR_GP_PLL_CTRL_CLKMUX_EN;
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_GP_PLL_CTRL, val, 0);
+ regmap_write(xcvr->regmap_pll, FSL_XCVR_GP_PLL_CTRL, val);
break;
default:
dev_err(dev, "Error for PLL version %d\n", xcvr->soc_data->pll_ver);
@@ -360,22 +418,22 @@ static int fsl_xcvr_en_phy_pll(struct fsl_xcvr *xcvr, u32 freq, bool tx)
if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
- FSL_XCVR_PHY_CTRL_TSDIFF_OE |
- FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
+ FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+ FSL_XCVR_PHY_CTRL_PHY_EN);
/* PHY: CTRL2_SET: EARC_TX_MODE */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
- FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL2,
+ FSL_XCVR_PHY_CTRL2_EARC_TXMS);
} else if (!tx) { /* SPDIF / ARC RX mode */
if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
/* PHY: CTRL_SET: SPDIF_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
- FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
+ FSL_XCVR_PHY_CTRL_SPDIF_EN);
else /* PHY: CTRL_SET: ARC RX setup */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
- FSL_XCVR_PHY_CTRL_PHY_EN |
- FSL_XCVR_PHY_CTRL_RX_CM_EN |
- fsl_xcvr_phy_arc_cfg[xcvr->arc_mode], 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
+ FSL_XCVR_PHY_CTRL_PHY_EN |
+ FSL_XCVR_PHY_CTRL_RX_CM_EN |
+ fsl_xcvr_phy_arc_cfg[xcvr->arc_mode]);
}
dev_dbg(dev, "PLL Fexp: %u, Fout: %u, mfi: %u, mfn: %u, mfd: %d, div: %u, pdiv0: %u\n",
@@ -416,17 +474,17 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
if (xcvr->mode == FSL_XCVR_MODE_EARC) { /* eARC mode */
/* PHY: CTRL_SET: TX_DIFF_OE, PHY_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
- FSL_XCVR_PHY_CTRL_TSDIFF_OE |
- FSL_XCVR_PHY_CTRL_PHY_EN, 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
+ FSL_XCVR_PHY_CTRL_TSDIFF_OE |
+ FSL_XCVR_PHY_CTRL_PHY_EN);
/* PHY: CTRL2_SET: EARC_TX_MODE */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL2_SET,
- FSL_XCVR_PHY_CTRL2_EARC_TXMS, 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL2,
+ FSL_XCVR_PHY_CTRL2_EARC_TXMS);
} else { /* SPDIF mode */
/* PHY: CTRL_SET: TX_CLK_AUD_SS | SPDIF_EN */
- fsl_xcvr_ai_write(xcvr, FSL_XCVR_PHY_CTRL_SET,
- FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
- FSL_XCVR_PHY_CTRL_SPDIF_EN, 1);
+ regmap_set_bits(xcvr->regmap_phy, FSL_XCVR_PHY_CTRL,
+ FSL_XCVR_PHY_CTRL_TX_CLK_AUD_SS |
+ FSL_XCVR_PHY_CTRL_SPDIF_EN);
}
dev_dbg(dev, "PLL Fexp: %u\n", freq);
@@ -448,7 +506,7 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
switch (xcvr->mode) {
case FSL_XCVR_MODE_SPDIF:
if (xcvr->soc_data->spdif_only && tx) {
- ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM);
if (ret < 0) {
@@ -466,8 +524,8 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
return ret;
}
- ret = regmap_write(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
- FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
+ ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
+ FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
if (ret < 0) {
dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret);
return ret;
@@ -484,11 +542,11 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
* Clear RX FIFO, flip RX FIFO bits,
* disable eARC related HW mode detects
*/
- ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
- FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
- FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
- FSL_XCVR_RX_DPTH_CTRL_COMP |
- FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+ ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
+ FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+ FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
+ FSL_XCVR_RX_DPTH_CTRL_COMP |
+ FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
if (ret < 0) {
dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
return ret;
@@ -505,18 +563,18 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
case FSL_XCVR_MODE_EARC:
if (!tx) {
/** Clear RX FIFO, flip RX FIFO bits */
- ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_SET,
- FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
- FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
+ ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
+ FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
+ FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
if (ret < 0) {
dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
return ret;
}
/** Enable eARC related HW mode detects */
- ret = regmap_write(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL_CLR,
- FSL_XCVR_RX_DPTH_CTRL_COMP |
- FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
+ ret = regmap_clear_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
+ FSL_XCVR_RX_DPTH_CTRL_COMP |
+ FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
if (ret < 0) {
dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret);
return ret;
@@ -585,8 +643,12 @@ static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
switch (xcvr->mode) {
case FSL_XCVR_MODE_SPDIF:
case FSL_XCVR_MODE_ARC:
- ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
- &fsl_xcvr_spdif_rates_constr);
+ if (xcvr->soc_data->spdif_only && tx)
+ ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
+ &xcvr->spdif_constr_rates);
+ else
+ ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
+ &fsl_xcvr_spdif_rates_constr);
break;
case FSL_XCVR_MODE_EARC:
ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
@@ -696,9 +758,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
}
fallthrough;
case FSL_XCVR_MODE_SPDIF:
- ret = regmap_write(xcvr->regmap,
- FSL_XCVR_TX_DPTH_CTRL_SET,
- FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+ ret = regmap_set_bits(xcvr->regmap,
+ FSL_XCVR_TX_DPTH_CTRL,
+ 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;
@@ -754,9 +816,9 @@ static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
if (tx) {
switch (xcvr->mode) {
case FSL_XCVR_MODE_SPDIF:
- ret = regmap_write(xcvr->regmap,
- FSL_XCVR_TX_DPTH_CTRL_CLR,
- FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
+ ret = regmap_clear_bits(xcvr->regmap,
+ FSL_XCVR_TX_DPTH_CTRL,
+ 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;
@@ -1169,6 +1231,7 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET:
case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG:
+ case FSL_XCVR_TX_DPTH_CTRL:
case FSL_XCVR_TX_DPTH_CTRL_SET:
case FSL_XCVR_TX_DPTH_CTRL_CLR:
case FSL_XCVR_TX_DPTH_CTRL_TOG:
@@ -1190,7 +1253,49 @@ static bool fsl_xcvr_writeable_reg(struct device *dev, unsigned int reg)
static bool fsl_xcvr_volatile_reg(struct device *dev, unsigned int reg)
{
- return fsl_xcvr_readable_reg(dev, reg);
+ switch (reg) {
+ case FSL_XCVR_EXT_STATUS:
+ case FSL_XCVR_EXT_ISR:
+ case FSL_XCVR_EXT_ISR_SET:
+ case FSL_XCVR_EXT_ISR_CLR:
+ case FSL_XCVR_EXT_ISR_TOG:
+ case FSL_XCVR_ISR:
+ case FSL_XCVR_ISR_SET:
+ case FSL_XCVR_ISR_CLR:
+ case FSL_XCVR_ISR_TOG:
+ case FSL_XCVR_PHY_AI_CTRL:
+ case FSL_XCVR_PHY_AI_CTRL_SET:
+ case FSL_XCVR_PHY_AI_CTRL_CLR:
+ case FSL_XCVR_PHY_AI_CTRL_TOG:
+ case FSL_XCVR_PHY_AI_RDATA:
+ case FSL_XCVR_RX_CS_DATA_0:
+ case FSL_XCVR_RX_CS_DATA_1:
+ case FSL_XCVR_RX_CS_DATA_2:
+ case FSL_XCVR_RX_CS_DATA_3:
+ case FSL_XCVR_RX_CS_DATA_4:
+ case FSL_XCVR_RX_CS_DATA_5:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR:
+ case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG:
+ case FSL_XCVR_RX_DPTH_TSCR:
+ case FSL_XCVR_RX_DPTH_BCR:
+ case FSL_XCVR_RX_DPTH_BCTR:
+ case FSL_XCVR_RX_DPTH_BCRR:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR:
+ case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG:
+ case FSL_XCVR_TX_DPTH_TSCR:
+ case FSL_XCVR_TX_DPTH_BCR:
+ case FSL_XCVR_TX_DPTH_BCTR:
+ case FSL_XCVR_TX_DPTH_BCRR:
+ case FSL_XCVR_DEBUG_REG_0:
+ case FSL_XCVR_DEBUG_REG_1:
+ return true;
+ default:
+ return false;
+ }
}
static const struct regmap_config fsl_xcvr_regmap_cfg = {
@@ -1206,6 +1311,49 @@ static const struct regmap_config fsl_xcvr_regmap_cfg = {
.cache_type = REGCACHE_FLAT,
};
+static const struct reg_default fsl_xcvr_phy_reg_defaults[] = {
+ { FSL_XCVR_PHY_CTRL, 0x58200804 },
+ { FSL_XCVR_PHY_STATUS, 0x00000000 },
+ { FSL_XCVR_PHY_ANALOG_TRIM, 0x00260F13 },
+ { FSL_XCVR_PHY_SLEW_RATE_TRIM, 0x00000411 },
+ { FSL_XCVR_PHY_DATA_TEST_DELAY, 0x00990000 },
+ { FSL_XCVR_PHY_TEST_CTRL, 0x00000000 },
+ { FSL_XCVR_PHY_DIFF_CDR_CTRL, 0x016D0009 },
+ { FSL_XCVR_PHY_CTRL2, 0x80000000 },
+};
+
+static const struct regmap_config fsl_xcvr_regmap_phy_cfg = {
+ .reg_bits = 8,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = FSL_XCVR_PHY_CTRL2_TOG,
+ .reg_defaults = fsl_xcvr_phy_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(fsl_xcvr_phy_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
+ .reg_read = fsl_xcvr_phy_reg_read,
+ .reg_write = fsl_xcvr_phy_reg_write,
+};
+
+static const struct regmap_config fsl_xcvr_regmap_pllv0_cfg = {
+ .reg_bits = 8,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = FSL_XCVR_PLL_STAT0_TOG,
+ .cache_type = REGCACHE_FLAT,
+ .reg_read = fsl_xcvr_pll_reg_read,
+ .reg_write = fsl_xcvr_pll_reg_write,
+};
+
+static const struct regmap_config fsl_xcvr_regmap_pllv1_cfg = {
+ .reg_bits = 8,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = FSL_XCVR_GP_PLL_STATUS_TOG,
+ .cache_type = REGCACHE_FLAT,
+ .reg_read = fsl_xcvr_pll_reg_read,
+ .reg_write = fsl_xcvr_pll_reg_write,
+};
+
static void reset_rx_work(struct work_struct *work)
{
struct fsl_xcvr *xcvr = container_of(work, struct fsl_xcvr, work_rst);
@@ -1405,6 +1553,15 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
fsl_asoc_get_pll_clocks(dev, &xcvr->pll8k_clk,
&xcvr->pll11k_clk);
+ if (xcvr->soc_data->spdif_only) {
+ if (!(xcvr->pll8k_clk || xcvr->pll11k_clk))
+ xcvr->pll8k_clk = xcvr->phy_clk;
+ fsl_asoc_constrain_rates(&xcvr->spdif_constr_rates,
+ &fsl_xcvr_spdif_rates_constr,
+ xcvr->pll8k_clk, xcvr->pll11k_clk, NULL,
+ xcvr->spdif_constr_rates_list);
+ }
+
xcvr->ram_addr = devm_platform_ioremap_resource_byname(pdev, "ram");
if (IS_ERR(xcvr->ram_addr))
return PTR_ERR(xcvr->ram_addr);
@@ -1421,6 +1578,40 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
return PTR_ERR(xcvr->regmap);
}
+ if (xcvr->soc_data->use_phy) {
+ xcvr->regmap_phy = devm_regmap_init(dev, NULL, xcvr,
+ &fsl_xcvr_regmap_phy_cfg);
+ if (IS_ERR(xcvr->regmap_phy)) {
+ dev_err(dev, "failed to init XCVR PHY regmap: %ld\n",
+ PTR_ERR(xcvr->regmap_phy));
+ return PTR_ERR(xcvr->regmap_phy);
+ }
+
+ switch (xcvr->soc_data->pll_ver) {
+ case PLL_MX8MP:
+ xcvr->regmap_pll = devm_regmap_init(dev, NULL, xcvr,
+ &fsl_xcvr_regmap_pllv0_cfg);
+ if (IS_ERR(xcvr->regmap_pll)) {
+ dev_err(dev, "failed to init XCVR PLL regmap: %ld\n",
+ PTR_ERR(xcvr->regmap_pll));
+ return PTR_ERR(xcvr->regmap_pll);
+ }
+ break;
+ case PLL_MX95:
+ xcvr->regmap_pll = devm_regmap_init(dev, NULL, xcvr,
+ &fsl_xcvr_regmap_pllv1_cfg);
+ if (IS_ERR(xcvr->regmap_pll)) {
+ dev_err(dev, "failed to init XCVR PLL regmap: %ld\n",
+ PTR_ERR(xcvr->regmap_pll));
+ return PTR_ERR(xcvr->regmap_pll);
+ }
+ break;
+ default:
+ dev_err(dev, "Error for PLL version %d\n", xcvr->soc_data->pll_ver);
+ return -EINVAL;
+ }
+ }
+
xcvr->reset = devm_reset_control_get_optional_exclusive(dev, NULL);
if (IS_ERR(xcvr->reset)) {
dev_err(dev, "failed to get XCVR reset control\n");
@@ -1454,6 +1645,10 @@ static int fsl_xcvr_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, xcvr);
pm_runtime_enable(dev);
regcache_cache_only(xcvr->regmap, true);
+ if (xcvr->soc_data->use_phy) {
+ regcache_cache_only(xcvr->regmap_phy, true);
+ regcache_cache_only(xcvr->regmap_pll, true);
+ }
/*
* Register platform component before registering cpu dai for there
@@ -1492,7 +1687,8 @@ static int fsl_xcvr_runtime_suspend(struct device *dev)
struct fsl_xcvr *xcvr = dev_get_drvdata(dev);
int ret;
- if (!xcvr->soc_data->spdif_only) {
+ if (!xcvr->soc_data->spdif_only &&
+ xcvr->mode == FSL_XCVR_MODE_EARC) {
/* Assert M0+ reset */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_CORE_RESET,
@@ -1502,6 +1698,10 @@ static int fsl_xcvr_runtime_suspend(struct device *dev)
}
regcache_cache_only(xcvr->regmap, true);
+ if (xcvr->soc_data->use_phy) {
+ regcache_cache_only(xcvr->regmap_phy, true);
+ regcache_cache_only(xcvr->regmap_pll, true);
+ }
clk_disable_unprepare(xcvr->spba_clk);
clk_disable_unprepare(xcvr->phy_clk);
@@ -1546,6 +1746,12 @@ static int fsl_xcvr_runtime_resume(struct device *dev)
goto stop_phy_clk;
}
+ ret = reset_control_deassert(xcvr->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert M0+ reset.\n");
+ goto stop_spba_clk;
+ }
+
regcache_cache_only(xcvr->regmap, false);
regcache_mark_dirty(xcvr->regmap);
ret = regcache_sync(xcvr->regmap);
@@ -1555,31 +1761,49 @@ static int fsl_xcvr_runtime_resume(struct device *dev)
goto stop_spba_clk;
}
- if (xcvr->soc_data->spdif_only)
- return 0;
+ if (xcvr->soc_data->use_phy) {
+ ret = regmap_write(xcvr->regmap, FSL_XCVR_PHY_AI_CTRL_SET,
+ FSL_XCVR_PHY_AI_CTRL_AI_RESETN);
+ if (ret < 0) {
+ dev_err(dev, "Error while release PHY reset: %d\n", ret);
+ goto stop_spba_clk;
+ }
- ret = reset_control_deassert(xcvr->reset);
- if (ret) {
- dev_err(dev, "failed to deassert M0+ reset.\n");
- goto stop_spba_clk;
- }
+ regcache_cache_only(xcvr->regmap_phy, false);
+ regcache_mark_dirty(xcvr->regmap_phy);
+ ret = regcache_sync(xcvr->regmap_phy);
+ if (ret) {
+ dev_err(dev, "failed to sync phy regcache.\n");
+ goto stop_spba_clk;
+ }
- ret = fsl_xcvr_load_firmware(xcvr);
- if (ret) {
- dev_err(dev, "failed to load firmware.\n");
- goto stop_spba_clk;
+ regcache_cache_only(xcvr->regmap_pll, false);
+ regcache_mark_dirty(xcvr->regmap_pll);
+ ret = regcache_sync(xcvr->regmap_pll);
+ if (ret) {
+ dev_err(dev, "failed to sync pll regcache.\n");
+ goto stop_spba_clk;
+ }
}
- /* Release M0+ reset */
- ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
- FSL_XCVR_EXT_CTRL_CORE_RESET, 0);
- if (ret < 0) {
- dev_err(dev, "M0+ core release failed: %d\n", ret);
- goto stop_spba_clk;
- }
+ if (xcvr->mode == FSL_XCVR_MODE_EARC) {
+ ret = fsl_xcvr_load_firmware(xcvr);
+ if (ret) {
+ dev_err(dev, "failed to load firmware.\n");
+ goto stop_spba_clk;
+ }
+
+ /* Release M0+ reset */
+ ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
+ FSL_XCVR_EXT_CTRL_CORE_RESET, 0);
+ if (ret < 0) {
+ dev_err(dev, "M0+ core release failed: %d\n", ret);
+ goto stop_spba_clk;
+ }
- /* Let M0+ core complete firmware initialization */
- msleep(50);
+ /* Let M0+ core complete firmware initialization */
+ msleep(50);
+ }
return 0;
@@ -1597,8 +1821,7 @@ stop_ipg_clk:
static const struct dev_pm_ops fsl_xcvr_pm_ops = {
RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend, fsl_xcvr_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver fsl_xcvr_driver = {
diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h
index c72cb05184df..dade3945cc0c 100644
--- a/sound/soc/fsl/fsl_xcvr.h
+++ b/sound/soc/fsl/fsl_xcvr.h
@@ -234,6 +234,7 @@
#define FSL_XCVR_TX_DPTH_CTRL_TM_NO_PRE_BME GENMASK(31, 30)
#define FSL_XCVR_PHY_AI_CTRL_AI_RESETN BIT(15)
+#define FSL_XCVR_PHY_AI_CTRL_AI_RWB BIT(31)
#define FSL_XCVR_PLL_CTRL0 0x00
#define FSL_XCVR_PLL_CTRL0_SET 0x04
@@ -241,13 +242,25 @@
#define FSL_XCVR_PLL_NUM 0x20
#define FSL_XCVR_PLL_DEN 0x30
#define FSL_XCVR_PLL_PDIV 0x40
+#define FSL_XCVR_PLL_BANDGAP 0x50
#define FSL_XCVR_PLL_BANDGAP_SET 0x54
+#define FSL_XCVR_PLL_STAT0 0x60
+#define FSL_XCVR_PLL_STAT0_TOG 0x6c
+
#define FSL_XCVR_PHY_CTRL 0x00
#define FSL_XCVR_PHY_CTRL_SET 0x04
#define FSL_XCVR_PHY_CTRL_CLR 0x08
+#define FSL_XCVR_PHY_CTRL_TOG 0x0c
+#define FSL_XCVR_PHY_STATUS 0x10
+#define FSL_XCVR_PHY_ANALOG_TRIM 0x20
+#define FSL_XCVR_PHY_SLEW_RATE_TRIM 0x30
+#define FSL_XCVR_PHY_DATA_TEST_DELAY 0x40
+#define FSL_XCVR_PHY_TEST_CTRL 0x50
+#define FSL_XCVR_PHY_DIFF_CDR_CTRL 0x60
#define FSL_XCVR_PHY_CTRL2 0x70
#define FSL_XCVR_PHY_CTRL2_SET 0x74
#define FSL_XCVR_PHY_CTRL2_CLR 0x78
+#define FSL_XCVR_PHY_CTRL2_TOG 0x7c
#define FSL_XCVR_PLL_BANDGAP_EN_VBG BIT(0)
#define FSL_XCVR_PLL_CTRL0_HROFF BIT(13)
diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c
index 231400661c90..dac5d4ddacd6 100644
--- a/sound/soc/fsl/imx-audmix.c
+++ b/sound/soc/fsl/imx-audmix.c
@@ -23,7 +23,6 @@ struct imx_audmix {
struct snd_soc_card card;
struct platform_device *audmix_pdev;
struct platform_device *out_pdev;
- struct clk *cpu_mclk;
int num_dai;
struct snd_soc_dai_link *dai;
int num_dai_conf;
@@ -32,34 +31,11 @@ struct imx_audmix {
struct snd_soc_dapm_route *dapm_routes;
};
-static const u32 imx_audmix_rates[] = {
- 8000, 12000, 16000, 24000, 32000, 48000, 64000, 96000,
-};
-
-static const struct snd_pcm_hw_constraint_list imx_audmix_rate_constraints = {
- .count = ARRAY_SIZE(imx_audmix_rates),
- .list = imx_audmix_rates,
-};
-
static int imx_audmix_fe_startup(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
- struct imx_audmix *priv = snd_soc_card_get_drvdata(rtd->card);
struct snd_pcm_runtime *runtime = substream->runtime;
- struct device *dev = rtd->card->dev;
- unsigned long clk_rate = clk_get_rate(priv->cpu_mclk);
int ret;
- if (clk_rate % 24576000 == 0) {
- ret = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- &imx_audmix_rate_constraints);
- if (ret < 0)
- return ret;
- } else {
- dev_warn(dev, "mclk may be not supported %lu\n", clk_rate);
- }
-
ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
1, 8);
if (ret < 0)
@@ -143,8 +119,8 @@ static const struct snd_soc_ops imx_audmix_be_ops = {
static const char *name[][3] = {
{"HiFi-AUDMIX-FE-0", "HiFi-AUDMIX-FE-1", "HiFi-AUDMIX-FE-2"},
{"sai-tx", "sai-tx", "sai-rx"},
- {"AUDMIX-Playback-0", "AUDMIX-Playback-1", "CPU-Capture"},
- {"CPU-Playback", "CPU-Playback", "AUDMIX-Capture-0"},
+ {"AUDMIX-Playback-0", "AUDMIX-Playback-1", "SAI-Capture"},
+ {"SAI-Playback", "SAI-Playback", "AUDMIX-Capture-0"},
};
static int imx_audmix_probe(struct platform_device *pdev)
@@ -323,13 +299,6 @@ static int imx_audmix_probe(struct platform_device *pdev)
}
put_device(&cpu_pdev->dev);
- priv->cpu_mclk = devm_clk_get(&cpu_pdev->dev, "mclk1");
- if (IS_ERR(priv->cpu_mclk)) {
- ret = PTR_ERR(priv->cpu_mclk);
- dev_err(&cpu_pdev->dev, "failed to get DAI mclk1: %d\n", ret);
- return ret;
- }
-
priv->audmix_pdev = audmix_pdev;
priv->out_pdev = cpu_pdev;
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 43e14f2eca8d..cc2918ee2cf5 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -237,7 +237,7 @@ static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
child);
continue;
}
- if (!of_property_read_bool(child, "fsl,port-config")) {
+ if (!of_property_present(child, "fsl,port-config")) {
dev_warn(&pdev->dev, "child node \"%pOF\" does not have property fsl,port-config\n",
child);
continue;
diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c
index 95a57fda0250..905294682996 100644
--- a/sound/soc/fsl/imx-card.c
+++ b/sound/soc/fsl/imx-card.c
@@ -518,6 +518,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
struct snd_soc_dai_link *link;
struct dai_link_data *link_data;
struct of_phandle_args args;
+ bool playback_only, capture_only;
int ret, num_links;
u32 asrc_fmt = 0;
u32 width;
@@ -529,7 +530,7 @@ static int imx_card_parse_of(struct imx_card_data *data)
}
/* DAPM routes */
- if (of_property_read_bool(dev->of_node, "audio-routing")) {
+ if (of_property_present(dev->of_node, "audio-routing")) {
ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret)
return ret;
@@ -679,6 +680,10 @@ static int imx_card_parse_of(struct imx_card_data *data)
link->ops = &imx_aif_ops;
}
+ graph_util_parse_link_direction(np, &playback_only, &capture_only);
+ link->playback_only = playback_only;
+ link->capture_only = capture_only;
+
/* Get dai fmt */
ret = simple_util_parse_daifmt(dev, np, codec,
NULL, &link->dai_fmt);
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 3391430e4253..83de3ae33691 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -185,8 +185,7 @@ static int snd_imx_open(struct snd_soc_component *component,
atomic_set(&iprtd->playing, 0);
atomic_set(&iprtd->capturing, 0);
- hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- iprtd->hrt.function = snd_hrtimer_callback;
+ hrtimer_setup(&iprtd->hrt, snd_hrtimer_callback, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
diff --git a/sound/soc/fsl/imx-rpmsg.c b/sound/soc/fsl/imx-rpmsg.c
index ce98d2288193..7cd3aa4c8706 100644
--- a/sound/soc/fsl/imx-rpmsg.c
+++ b/sound/soc/fsl/imx-rpmsg.c
@@ -218,7 +218,7 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
if (ret)
goto fail;
- if (of_property_read_bool(np, "audio-routing")) {
+ if (of_property_present(np, "audio-routing")) {
ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
if (ret) {
dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 7655425a3deb..a8a3bad3df00 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -20,6 +20,13 @@
#define DPCM_SELECTABLE 1
+#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret)
+static inline int _graph_ret(struct simple_util_priv *priv,
+ const char *func, int ret)
+{
+ return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
+}
+
#define ep_to_port(ep) of_get_parent(ep)
static struct device_node *port_to_ports(struct device_node *port)
{
@@ -81,18 +88,14 @@ static void graph_parse_convert(struct device *dev,
struct simple_util_data *adata)
{
struct device_node *top = dev->of_node;
- struct device_node *port = ep_to_port(ep);
- struct device_node *ports = port_to_ports(port);
- struct device_node *node = of_graph_get_port_parent(ep);
+ struct device_node *port __free(device_node) = ep_to_port(ep);
+ struct device_node *ports __free(device_node) = port_to_ports(port);
+ struct device_node *node __free(device_node) = of_graph_get_port_parent(ep);
simple_util_parse_convert(top, NULL, adata);
simple_util_parse_convert(ports, NULL, adata);
simple_util_parse_convert(port, NULL, adata);
simple_util_parse_convert(ep, NULL, adata);
-
- of_node_put(port);
- of_node_put(ports);
- of_node_put(node);
}
static int graph_parse_node(struct simple_util_priv *priv,
@@ -115,19 +118,17 @@ static int graph_parse_node(struct simple_util_priv *priv,
dai = simple_props_to_dai_codec(dai_props, 0);
}
- ret = graph_util_parse_dai(dev, ep, dlc, cpu);
+ ret = graph_util_parse_dai(priv, ep, dlc, cpu);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_tdm(ep, dai);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_clk(dev, ep, dai, dlc);
- if (ret < 0)
- return ret;
-
- return 0;
+end:
+ return graph_ret(priv, ret);
}
static int graph_link_init(struct simple_util_priv *priv,
@@ -140,10 +141,10 @@ static int graph_link_init(struct simple_util_priv *priv,
struct device_node *top = dev->of_node;
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
- struct device_node *port_cpu = ep_to_port(ep_cpu);
- struct device_node *port_codec = ep_to_port(ep_codec);
- struct device_node *ports_cpu = port_to_ports(port_cpu);
- struct device_node *ports_codec = port_to_ports(port_codec);
+ struct device_node *port_cpu __free(device_node) = ep_to_port(ep_cpu);
+ struct device_node *port_codec __free(device_node) = ep_to_port(ep_codec);
+ struct device_node *ports_cpu __free(device_node) = port_to_ports(port_cpu);
+ struct device_node *ports_codec __free(device_node) = port_to_ports(port_codec);
enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT;
bool playback_only = 0, capture_only = 0;
@@ -152,7 +153,7 @@ static int graph_link_init(struct simple_util_priv *priv,
ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec,
NULL, &dai_link->dai_fmt);
if (ret < 0)
- goto init_end;
+ goto end;
graph_util_parse_link_direction(top, &playback_only, &capture_only);
graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only);
@@ -187,14 +188,9 @@ static int graph_link_init(struct simple_util_priv *priv,
if (priv->ops)
dai_link->ops = priv->ops;
- ret = simple_util_set_dailink_name(dev, dai_link, name);
-init_end:
- of_node_put(ports_cpu);
- of_node_put(ports_codec);
- of_node_put(port_cpu);
- of_node_put(port_codec);
-
- return ret;
+ ret = simple_util_set_dailink_name(priv, dai_link, name);
+end:
+ return graph_ret(priv, ret);
}
static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
@@ -226,7 +222,7 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
ret = graph_parse_node(priv, cpu_ep, li, &is_single_links);
if (ret)
- return ret;
+ goto end;
snprintf(dai_name, sizeof(dai_name),
"fe.%pOFP.%s", cpus->of_node, cpus->dai_name);
@@ -250,8 +246,6 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
} else {
struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0);
struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, 0);
- struct device_node *port;
- struct device_node *ports;
/* CPU is dummy */
@@ -261,20 +255,18 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
ret = graph_parse_node(priv, codec_ep, li, NULL);
if (ret < 0)
- return ret;
+ goto end;
snprintf(dai_name, sizeof(dai_name),
"be.%pOFP.%s", codecs->of_node, codecs->dai_name);
/* check "prefix" from top node */
- port = ep_to_port(ep);
- ports = port_to_ports(port);
+ struct device_node *port __free(device_node) = ep_to_port(ep);
+ struct device_node *ports __free(device_node) = port_to_ports(port);
+
snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix");
snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix");
-
- of_node_put(ports);
- of_node_put(port);
}
graph_parse_convert(dev, ep, &dai_props->adata);
@@ -282,8 +274,8 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
li->link++;
-
- return ret;
+end:
+ return graph_ret(priv, ret);
}
static int graph_dai_link_of(struct simple_util_priv *priv,
@@ -303,11 +295,11 @@ static int graph_dai_link_of(struct simple_util_priv *priv,
ret = graph_parse_node(priv, cpu_ep, li, &is_single_links);
if (ret < 0)
- return ret;
+ goto end;
ret = graph_parse_node(priv, codec_ep, li, NULL);
if (ret < 0)
- return ret;
+ goto end;
snprintf(dai_name, sizeof(dai_name),
"%s-%s", cpus->dai_name, codecs->dai_name);
@@ -317,11 +309,11 @@ static int graph_dai_link_of(struct simple_util_priv *priv,
ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
if (ret < 0)
- return ret;
+ goto end;
li->link++;
-
- return 0;
+end:
+ return graph_ret(priv, ret);
}
static inline bool parse_as_dpcm_link(struct simple_util_priv *priv,
@@ -361,8 +353,6 @@ static int __graph_for_each_link(struct simple_util_priv *priv,
struct device *dev = simple_priv_to_dev(priv);
struct device_node *node = dev->of_node;
struct device_node *cpu_port;
- struct device_node *codec_ep;
- struct device_node *codec_port;
struct device_node *codec_port_old = NULL;
struct simple_util_data adata;
int rc, ret = 0;
@@ -374,8 +364,8 @@ static int __graph_for_each_link(struct simple_util_priv *priv,
/* loop for all CPU endpoint */
for_each_of_graph_port_endpoint(cpu_port, cpu_ep) {
/* get codec */
- codec_ep = of_graph_get_remote_endpoint(cpu_ep);
- codec_port = ep_to_port(codec_ep);
+ struct device_node *codec_ep __free(device_node) = of_graph_get_remote_endpoint(cpu_ep);
+ struct device_node *codec_port __free(device_node) = ep_to_port(codec_ep);
/* get convert-xxx property */
memset(&adata, 0, sizeof(adata));
@@ -399,17 +389,14 @@ static int __graph_for_each_link(struct simple_util_priv *priv,
ret = func_noml(priv, cpu_ep, codec_ep, li);
}
- of_node_put(codec_ep);
- of_node_put(codec_port);
-
if (ret < 0)
- return ret;
+ goto end;
codec_port_old = codec_port;
}
}
-
- return 0;
+end:
+ return graph_ret(priv, ret);
}
static int graph_for_each_link(struct simple_util_priv *priv,
@@ -442,7 +429,7 @@ static int graph_for_each_link(struct simple_util_priv *priv,
break;
}
- return ret;
+ return graph_ret(priv, ret);
}
static int graph_count_noml(struct simple_util_priv *priv,
@@ -451,11 +438,10 @@ static int graph_count_noml(struct simple_util_priv *priv,
struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
+ int ret = -EINVAL;
- if (li->link >= SNDRV_MAX_LINKS) {
- dev_err(dev, "too many links\n");
- return -EINVAL;
- }
+ if (li->link >= SNDRV_MAX_LINKS)
+ goto end;
/*
* DON'T REMOVE platforms
@@ -470,8 +456,9 @@ static int graph_count_noml(struct simple_util_priv *priv,
li->link += 1; /* 1xCPU-Codec */
dev_dbg(dev, "Count As Normal\n");
-
- return 0;
+ ret = 0;
+end:
+ return graph_ret(priv, ret);
}
static int graph_count_dpcm(struct simple_util_priv *priv,
@@ -480,11 +467,10 @@ static int graph_count_dpcm(struct simple_util_priv *priv,
struct link_info *li)
{
struct device *dev = simple_priv_to_dev(priv);
+ int ret = -EINVAL;
- if (li->link >= SNDRV_MAX_LINKS) {
- dev_err(dev, "too many links\n");
- return -EINVAL;
- }
+ if (li->link >= SNDRV_MAX_LINKS)
+ goto end;
if (li->cpu) {
/*
@@ -503,8 +489,9 @@ static int graph_count_dpcm(struct simple_util_priv *priv,
}
dev_dbg(dev, "Count As DPCM\n");
-
- return 0;
+ ret = 0;
+end:
+ return graph_ret(priv, ret);
}
static int graph_get_dais_count(struct simple_util_priv *priv,
@@ -564,40 +551,41 @@ static int graph_get_dais_count(struct simple_util_priv *priv,
int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
{
struct snd_soc_card *card = simple_priv_to_card(priv);
- int ret;
+ int ret = -ENOMEM;
struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
if (!li)
- return -ENOMEM;
+ goto end;
card->owner = THIS_MODULE;
card->dev = dev;
ret = graph_get_dais_count(priv, li);
if (ret < 0)
- return ret;
+ goto end;
+ ret = -EINVAL;
if (!li->link)
- return -EINVAL;
+ goto end;
ret = simple_util_init_priv(priv, li);
if (ret < 0)
- return ret;
+ 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);
- return ret;
+ goto end;
}
ret = simple_util_parse_widgets(card, NULL);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_routing(card, NULL);
if (ret < 0)
- return ret;
+ goto end;
memset(li, 0, sizeof(*li));
ret = graph_for_each_link(priv, li,
@@ -606,7 +594,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
if (ret < 0)
goto err;
- ret = simple_util_parse_card_name(card, NULL);
+ ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -619,10 +607,9 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
goto err;
return 0;
-
err:
simple_util_clean_reference(card);
-
+end:
return dev_err_probe(dev, ret, "parse error\n");
}
EXPORT_SYMBOL_GPL(audio_graph_parse_of);
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
deleted file mode 100644
index 9efd31206c9b..000000000000
--- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi
+++ /dev/null
@@ -1,702 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * audio-graph-card2-custom-sample.dtsi
- *
- * Copyright (C) 2020 Renesas Electronics Corp.
- * Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This sample indicates how to use audio-graph-card2 and its
- * custom driver. "audio-graph-card2-custom-sample" is the custome driver
- * which is using audio-graph-card2.
- *
- * You can easily use this sample by adding below line on your DT file,
- * and add new CONFIG to your .config.
- *
- * #include "../../../../../sound/soc/generic/audio-graph-card2-custom-sample.dtsi"
- *
- * CONFIG_SND_AUDIO_GRAPH_CARD2
- * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE
- * CONFIG_SND_TEST_COMPONENT
- *
- *
- * You can indicate more detail each device behavior as debug if you modify
- * "compatible" on each test-component. see below
- *
- * test_cpu {
- * - compatible = "test-cpu";
- * + compatible = "test-cpu-verbose";
- * ...
- * };
- *
- * test_codec {
- * - compatible = "test-codec";
- * + compatible = "test-codec-verbose";
- * ...
- * };
- *
- *
- * Below sample doesn't use "format" property,
- * because test-component driver (test-cpu/test-codec) is supporting
- * snd_soc_dai_ops :: .auto_selectable_formats.
- * see
- * snd_soc_runtime_get_dai_fmt()
- * linux/sound/soc/generic/test-component.c :: test_dai_formats
- */
-/ {
- /*
- * @ : used at links
- *
- * [Normal]
- * cpu0 <-@-----------------> codec0
- *
- * [Semi-Multi]
- *
- * CPU:Codec = 1:N
- *
- * +-+
- * cpu7 <-@------->| |-> codec12
- * | |-> codec13
- * +-+
- *
- * [Multi-CPU/Codec-0]
- * +-+ +-+
- * cpu1 <--| |<-@--------->| |-> codec1
- * cpu2 <--| | | |-> codec2
- * +-+ +-+
- *
- * [Multi-CPU/Codec-1]
- *
- * +-+ +-+
- * | |<-@--------->| |
- * | | | |
- * cpu8 <--| |<----------->| |-> codec14
- * cpu9 <--| |<---+------->| |-> codec15
- * +-+ \------>| |-> codec16
- * +-+
- *
- * [Multi-CPU/Codec-2]
- *
- * +-+ +-+
- * | |<-@--------->| |
- * | | | |
- * cpu10 <-| |<----------->| |-> codec17
- * cpu11 <-| |<-----+----->| |-> codec18
- * cpu12 <-| |<----/ +-+
- * +-+
- *
- * [DPCM]
- *
- * CPU3/CPU4 are converting rate to 44100
- *
- * FE BE
- * ****
- * cpu3 <-@--* *--@-> codec3
- * cpu4 <-@--* * (44.1kHz)
- * ****
- *
- * [DPCM-Multi]
- *
- * --NOTE--
- * Multi-FE is not supported by ASoC.
- *
- * FE BE
- * **** +-+
- * cpu5 <-@--* *--@-> | | -> codec4
- * cpu6 <-@--* * | | -> codec5
- * **** +-+
- *
- * [Codec2Codec]
- * +-@-> codec6
- * |
- * +---> codec7
- *
- * [Codec2Codec-Multi]
- *
- * --NOTE--
- * Multi connect N:M is not supported by ASoC.
- *
- * +-+
- * +-@->| |-> codec8
- * | | |-> codec9
- * | +-+
- * | +-+
- * +--->| |-> codec10
- * | |-> codec11
- * +-+
- */
- audio-graph-card2-custom-sample {
- /*
- * You can use audio-graph-card2 directly by using
- *
- * compatible = "audio-graph-card2";
- */
- compatible = "audio-graph-card2-custom-sample";
-
- /* for [DPCM] */
- /* BE FE */
- routing = "TC DAI3 Playback", "DAI3 Playback",
- "TC DAI3 Playback", "DAI4 Playback",
- "DAI3 Capture", "TC DAI3 Capture",
- "DAI4 Capture", "TC DAI3 Capture",
- /* for [DPCM-Multi] */
- /* BE FE */
- "TC DAI4 Playback", "DAI5 Playback",
- "TC DAI5 Playback", "DAI5 Playback",
- "TC DAI4 Playback", "DAI6 Playback",
- "TC DAI5 Playback", "DAI6 Playback",
- "DAI5 Capture", "TC DAI4 Capture",
- "DAI5 Capture", "TC DAI5 Capture",
- "DAI6 Capture", "TC DAI4 Capture",
- "DAI6 Capture", "TC DAI5 Capture",
- /* for [Codec2Codec] */
- "TC OUT", "TC DAI7 Playback",
- "TC DAI6 Capture", "TC IN",
- /* for [Codec2Codec-Multi] */
- "TC OUT", "TC DAI10 Playback",
- "TC DAI8 Capture", "TC IN",
- "TC OUT", "TC DAI11 Playback",
- "TC DAI9 Capture", "TC IN";
-
- links = <
- /*
- * [Normal]: cpu side only
- * cpu0/codec0
- */
- &cpu0
-
- /*
- * [Semi-Multi]
- * cpu7/codec12/codec13
- */
- &sm0
-
- /*
- * [Multi-CPU/Codec-0]: cpu side only
- * cpu1/cpu2/codec1/codec2
- */
- &mcpu0
-
- /*
- * [Multi-CPU/Codec-1]: cpu side only
- * cpu8/cpu9/codec14/codec15/codec16
- *
- * Because it will reach to the maximum of sound minor number,
- * disable it so far.
- * If you want to try it, please disable some other one instead.
- */
- //&mcpu1
-
- /*
- * [Multi-CPU/Codec-2]: cpu side only
- * cpu10/cpu11/cpu12/codec17/codec18
- *
- * Because it will reach to the maximum of sound minor number,
- * disable it so far.
- * If you want to try it, please disable some other one instead.
- */
- //&mcpu2
-
- /*
- * [DPCM]: both FE / BE
- * cpu3/cpu4/codec3
- */
- &fe00 &fe01 &be0
-
- /*
- * [DPCM-Multi]: both FE / BE
- * cpu5/cpu6/codec4/codec5
- */
- &fe10 &fe11 &be1
-
- /*
- * [Codec2Codec]: cpu side only
- * codec6/codec7
- */
- &c2c
-
- /*
- * [Codec2Codec-Multi]: cpu side only
- * codec8/codec9/codec10/codec11
- */
- &c2c_m
- >;
-
- multi {
- #address-cells = <1>;
- #size-cells = <0>;
-
- /*
- * [Multi-CPU-0]
- *
- * +---+ +---+
- * cpu1 <--|A X|<-@------->|x a|-> codec1
- * cpu2 <--|B | | b|-> codec2
- * +---+ +---+
- */
- ports@0 {
- reg = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
- mcpu0: port@0 { reg = <0>; mcpu00_ep: endpoint { remote-endpoint = <&mcodec00_ep>; };};/* (X) to pair */
- port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; };};/* (A) Multi Element */
- port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; };};/* (B) Multi Element */
- };
-
- /*
- * [Multi-Codec-0]
- *
- * +---+ +---+
- * cpu1 <--|A X|<-@------->|x a|-> codec1
- * cpu2 <--|B | | b|-> codec2
- * +---+ +---+
- */
- ports@1 {
- reg = <1>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mcodec00_ep: endpoint { remote-endpoint = <&mcpu00_ep>; };};/* (x) to pair */
- port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; };};/* (a) Multi Element */
- port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; };};/* (b) Multi Element */
- };
-
- /*
- * [DPCM-Multi]::BE
- *
- * FE BE
- * **** +---+
- * cpu5 <-@--* *-----@--->|x a|-> codec4
- * cpu6 <-@--* * | b|-> codec5
- * **** +---+
- */
- ports@2 {
- reg = <2>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; };};/* (x) to pair */
- port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; };};/* (a) Multi Element */
- port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; };};/* (b) Multi Element */
- };
-
- /*
- * [Codec2Codec-Multi]::CPU
- *
- * +---+
- * +-@->|X A|-> codec8
- * | | B|-> codec9
- * | +---+
- * | +---+
- * +--->|x a|-> codec10
- * | b|-> codec11
- * +---+
- */
- ports@3 {
- reg = <3>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */
- port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; };};/* (A) Multi Element */
- port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; };};/* (B) Multi Element */
- };
-
- /*
- * [Codec2Codec-Multi]::Codec
- *
- * +---+
- * +-@->|X A|-> codec8
- * | | B|-> codec9
- * | +---+
- * | +---+
- * +--->|x a|-> codec10
- * | b|-> codec11
- * +---+
- */
- ports@4 {
- reg = <4>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */
- port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; };};/* (a) Multi Element */
- port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; };};/* (b) Multi Element */
- };
-
- /*
- * [Semi-Multi]
- *
- * +---+
- * cpu7 <-@------->|X A|-> codec12
- * | B|-> codec13
- * +---+
- */
- ports@5 {
- reg = <5>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; };};/* (X) to pair */
- port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */
- port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */
- };
-
- /*
- * [Multi-CPU-1]
- *
- * +---+ +---+
- * | X|<-@------->|x |
- * | | | |
- * cpu8 <--|A 1|<--------->|3 a|-> codec14
- * cpu9 <--|B 2|<---+----->|4 b|-> codec15
- * +---+ \---->|5 c|-> codec16
- * +---+
- */
- ports@6 {
- reg = <6>;
- #address-cells = <1>;
- #size-cells = <0>;
- mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; };}; /* (X) to pair */
- port@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- mcpu11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu8_ep>; }; /* (A) Multi Element */
- mcpu11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec11_ep_0>; }; /* (1) connected Codec */
- };
- port@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- mcpu12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu9_ep>; }; /* (B) Multi Element */
- mcpu12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec12_ep_0>; }; /* (2) connected Codec */
- mcpu12_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec13_ep_0>; }; /* (2) connected Codec */
- };
- };
-
- /*
- * [Multi-Codec-1]
- *
- * +---+ +---+
- * | X|<-@------->|x |
- * | | | |
- * cpu8 <--|A 1|<--------->|3 a|-> codec14
- * cpu9 <--|B 2|<---+----->|4 b|-> codec15
- * +---+ \---->|5 c|-> codec16
- * +---+
- */
- ports@7 {
- reg = <7>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; };}; /* (x) to pair */
- port@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- mcodec11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec14_ep>; }; /* (a) Multi Element */
- mcodec11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu11_ep_0>; }; /* (3) connected CPU */
- };
- port@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- mcodec12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec15_ep>; }; /* (b) Multi Element */
- mcodec12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_0>; }; /* (4) connected CPU */
- };
- port@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- mcodec13_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec16_ep>; }; /* (c) Multi Element */
- mcodec13_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_1>; }; /* (5) connected CPU */
- };
- };
-
- /*
- * [Multi-CPU-2]
- *
- * +---+ +---+
- * | X|<-@------->|x |
- * | | | |
- * cpu10 <-|A 1|<--------->|4 a|-> codec17
- * cpu11 <-|B 2|<-----+--->|5 b|-> codec18
- * cpu12 <-|C 3|<----/ +---+
- * +---+
- */
- ports@8 {
- reg = <8>;
- #address-cells = <1>;
- #size-cells = <0>;
- mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; };}; /* (X) to pair */
- port@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- mcpu21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu10_ep>; }; /* (A) Multi Element */
- mcpu21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec21_ep_0>; }; /* (1) connected Codec */
- };
- port@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- mcpu22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu11_ep>; }; /* (B) Multi Element */
- mcpu22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_0>; }; /* (2) connected Codec */
- };
- port@3 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <3>;
- mcpu23_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu12_ep>; }; /* (C) Multi Element */
- mcpu23_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_1>; }; /* (3) connected Codec */
- };
- };
-
- /*
- * [Multi-Codec-2]
- *
- * +---+ +---+
- * | X|<-@------->|x |
- * | | | |
- * cpu10 <-|A 1|<--------->|4 a|-> codec17
- * cpu11 <-|B 2|<-----+--->|5 b|-> codec18
- * cpu12 <-|C 3|<----/ +---+
- * +---+
- */
- ports@9 {
- reg = <9>;
- #address-cells = <1>;
- #size-cells = <0>;
- port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; };}; /* (x) to pair */
- port@1 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <1>;
- mcodec21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec17_ep>; }; /* (a) Multi Element */
- mcodec21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu21_ep_0>; }; /* (4) connected CPU */
- };
- port@2 {
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <2>;
- mcodec22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec18_ep>; }; /* (b) Multi Element */
- mcodec22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu22_ep_0>; }; /* (5) connected CPU */
- mcodec22_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu23_ep_0>; }; /* (5) connected CPU */
- };
- };
- };
-
- dpcm {
- #address-cells = <1>;
- #size-cells = <0>;
-
- ports@0 {
- reg = <0>;
-
- #address-cells = <1>;
- #size-cells = <0>;
- /*
- * [DPCM]::FE
- *
- * FE BE
- * ****
- * cpu3 <-@(fe00)--* *--(be0)@--> codec3
- * cpu4 <-@(fe01)--* * (44.1kHz)
- * ****
- */
- fe00: port@0 { reg = <0>; fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; };
- fe01: port@1 { reg = <1>; fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; };
-
- /*
- * [DPCM-Multi]::FE
- *
- * FE BE
- * **** +-+
- * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4
- * cpu6 <-@(fe11)--* * | |-> codec5
- * **** +-+
- */
- fe10: port@2 { reg = <2>; fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; };
- fe11: port@3 { reg = <3>; fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; };
- };
-
- ports@1 {
- reg = <1>;
-
- #address-cells = <1>;
- #size-cells = <0>;
- /*
- * [DPCM]::BE
- *
- * FE BE
- * ****
- * cpu3 <-@(fe00)--* *--(be0)@--> codec3
- * cpu4 <-@(fe01)--* * (44.1kHz)
- * ****
- */
- be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; };
-
- /*
- * [DPCM-Multi]::BE
- *
- * FE BE
- * **** +-+
- * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4
- * cpu6 <-@(fe11)--* * | |-> codec5
- * **** +-+
- */
- be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; };
- };
- };
-
- codec2codec {
- #address-cells = <1>;
- #size-cells = <0>;
- /*
- * [Codec2Codec]
- *
- * +-@(c2c)-> codec6
- * |
- * +--------> codec7
- */
- ports@0 {
- reg = <0>;
-
- #address-cells = <1>;
- #size-cells = <0>;
-
- /* use default settings */
- c2c: port@0 { reg = <0>; c2cf_ep: endpoint { remote-endpoint = <&codec6_ep>; }; };
- port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; };
- };
-
- /*
- * [Codec2Codec-Multi]
- *
- * +-+
- * +-@(c2c_m)-->| |-> codec8
- * | | |-> codec9
- * | +-+
- * | +-+
- * +----------->| |-> codec10
- * | |-> codec11
- * +-+
- */
- ports@1 {
- reg = <1>;
-
- #address-cells = <1>;
- #size-cells = <0>;
-
- /* use original settings */
- rate = <48000>;
- c2c_m: port@0 { reg = <0>; c2cmf_ep: endpoint { remote-endpoint = <&mc2c0_ep>; }; };
- port@1 { reg = <1>; c2cmb_ep: endpoint { remote-endpoint = <&mc2c1_ep>; }; };
- };
- };
- };
-
- test_cpu {
- /*
- * update compatible to indicate more detail behaviour
- * if you want. see test-compatible for more detail.
- *
- * ex)
- * - compatible = "test-cpu";
- * + compatible = "test-cpu-verbose";
- */
- compatible = "test-cpu";
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- bitclock-master;
- frame-master;
- /* [Normal] */
- cpu0: port@0 { reg = <0>; cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
-
- /* [Multi-CPU-0] */
- port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu01_ep>; }; };
- port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu02_ep>; }; };
-
- /* [DPCM]::FE */
- port@3 { reg = <3>; cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; };
- port@4 { reg = <4>; cpu4_ep: endpoint { remote-endpoint = <&fe01_ep>; }; };
-
- /* [DPCM-Multi]::FE */
- port@5 { reg = <5>; cpu5_ep: endpoint { remote-endpoint = <&fe10_ep>; }; };
- port@6 { reg = <6>; cpu6_ep: endpoint { remote-endpoint = <&fe11_ep>; }; };
-
- /* [Semi-Multi] */
- sm0: port@7 { reg = <7>; cpu7_ep: endpoint { remote-endpoint = <&smcodec0_ep>; }; };
-
- /* [Multi-CPU-1] */
- port@8 { reg = <8>; cpu8_ep: endpoint { remote-endpoint = <&mcpu11_ep>; }; };
- port@9 { reg = <9>; cpu9_ep: endpoint { remote-endpoint = <&mcpu12_ep>; }; };
- /* [Multi-CPU-2] */
- port@a { reg = <10>; cpu10_ep: endpoint { remote-endpoint = <&mcpu21_ep>; }; };
- port@b { reg = <11>; cpu11_ep: endpoint { remote-endpoint = <&mcpu22_ep>; }; };
- port@c { reg = <12>; cpu12_ep: endpoint { remote-endpoint = <&mcpu23_ep>; }; };
- };
- };
-
- test_codec {
- /*
- * update compatible to indicate more detail behaviour
- * if you want. see test-compatible for more detail.
- *
- * ex)
- * - compatible = "test-codec";
- * + compatible = "test-codec-verbose";
- */
- compatible = "test-codec";
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- /*
- * prefix can be added to *component*,
- * see audio-graph-card2::routing
- */
- prefix = "TC";
-
- /* [Normal] */
- port@0 { reg = <0>; codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; };
-
- /* [Multi-Codec-0] */
- port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec01_ep>; }; };
- port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec02_ep>; }; };
-
- /* [DPCM]::BE */
- port@3 {
- convert-rate = <44100>;
- reg = <3>; codec3_ep: endpoint { remote-endpoint = <&be00_ep>; };
- };
-
- /* [DPCM-Multi]::BE */
- port@4 { reg = <4>; codec4_ep: endpoint { remote-endpoint = <&mbe1_ep>; }; };
- port@5 { reg = <5>; codec5_ep: endpoint { remote-endpoint = <&mbe2_ep>; }; };
-
- /* [Codec2Codec] */
- port@6 { bitclock-master;
- frame-master;
- reg = <6>; codec6_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; };
- port@7 { reg = <7>; codec7_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; };
-
- /* [Codec2Codec-Multi] */
- port@8 { bitclock-master;
- frame-master;
- reg = <8>; codec8_ep: endpoint { remote-endpoint = <&mc2c00_ep>; }; };
- port@9 { reg = <9>; codec9_ep: endpoint { remote-endpoint = <&mc2c01_ep>; }; };
- port@a { reg = <10>; codec10_ep: endpoint { remote-endpoint = <&mc2c10_ep>; }; };
- port@b { reg = <11>; codec11_ep: endpoint { remote-endpoint = <&mc2c11_ep>; }; };
-
- /* [Semi-Multi] */
- port@c { reg = <12>; codec12_ep: endpoint { remote-endpoint = <&smcodec1_ep>; }; };
- port@d { reg = <13>; codec13_ep: endpoint { remote-endpoint = <&smcodec2_ep>; }; };
-
- /* [Multi-Codec-1] */
- port@e { reg = <14>; codec14_ep: endpoint { remote-endpoint = <&mcodec11_ep>; }; };
- port@f { reg = <15>; codec15_ep: endpoint { remote-endpoint = <&mcodec12_ep>; }; };
- port@10 { reg = <16>; codec16_ep: endpoint { remote-endpoint = <&mcodec13_ep>; }; };
- /* [Multi-Codec-2] */
- port@11 { reg = <17>; codec17_ep: endpoint { remote-endpoint = <&mcodec21_ep>; }; };
- port@12 { reg = <18>; codec18_ep: endpoint { remote-endpoint = <&mcodec22_ep>; }; };
- };
- };
-};
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample1.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample1.dtsi
new file mode 100644
index 000000000000..12d40e05de46
--- /dev/null
+++ b/sound/soc/generic/audio-graph-card2-custom-sample1.dtsi
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * audio-graph-card2-custom-sample1.dtsi
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ * Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This sample indicates how to use audio-graph-card2 and its
+ * custom driver. "audio-graph-card2-custom-sample" is the custome driver
+ * which is using audio-graph-card2.
+ *
+ * You can easily use this sample by adding below line on your DT file,
+ * and add new CONFIG to your .config.
+ *
+ * #include "../../../../../sound/soc/generic/audio-graph-card2-custom-sample1.dtsi"
+ *
+ * CONFIG_SND_AUDIO_GRAPH_CARD2
+ * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE
+ * CONFIG_SND_TEST_COMPONENT
+ *
+ *
+ * You can indicate more detail each device behavior as debug if you modify
+ * "compatible" on each test-component. see below
+ *
+ * test_cpu {
+ * - compatible = "test-cpu";
+ * + compatible = "test-cpu-verbose";
+ * ...
+ * };
+ *
+ * test_codec {
+ * - compatible = "test-codec";
+ * + compatible = "test-codec-verbose";
+ * ...
+ * };
+ *
+ *
+ * Below sample doesn't use "format" property,
+ * because test-component driver (test-cpu/test-codec) is supporting
+ * snd_soc_dai_ops :: .auto_selectable_formats.
+ * see
+ * snd_soc_runtime_get_dai_fmt()
+ * linux/sound/soc/generic/test-component.c :: test_dai_formats
+ */
+/ {
+ audio-graph-card2-custom-sample-1 {
+ /*
+ * You can use audio-graph-card2 directly by using
+ *
+ * compatible = "audio-graph-card2";
+ */
+ compatible = "audio-graph-card2-custom-sample";
+ label = "card2-custom-sample-1";
+
+ /*
+ * @ : used at links
+ */
+ links = <
+ /*
+ *
+ * [Normal]
+ *
+ * <cpu1_0>
+ * cpu1_0 <-@-----> codec1_0
+ */
+ &cpu1_0 /* CPU side only */
+
+ /*
+ * [Semi-Multi]
+ *
+ * CPU:Codec = 1:N
+ *
+ * <sm> +-+
+ * cpu1_1 <--@---->| |-> codec1_1
+ * | |-> codec1_2
+ * +-+
+ */
+ &sm /* CPU side only */
+
+ /*
+ * [Multi-CPU/Codec-A]
+ *
+ * +-+ <mcpuA> +-+
+ * cpu1_2 <-| |<---@------>| |-> codec1_3
+ * cpu1_3 <-| | | |-> codec1_4
+ * +-+ +-+
+ */
+ &mcpuA /* CPU side only */
+
+ /*
+ * [Multi-CPU/Codec-B]
+ *
+ * +-+ <mcpuB> +-+
+ * | |<---@------>| |
+ * | | | |
+ * cpu1_4 <-| |<---------->| |-> codec1_5
+ * cpu1_5 <-| |<---+------>| |-> codec1_6
+ * +-+ \----->| |-> codec1_7
+ * +-+
+ */
+ &mcpuB /* CPU side only */
+
+ /*
+ * [Multi-CPU/Codec-C]
+ *
+ * +-+ <mcpuC> +-+
+ * | |<---@------>| |
+ * | | | |
+ * cpu1_6 <-| |<---------->| |-> codec1_8
+ * cpu1_7 <-| |<-----+---->| |-> codec1_9
+ * cpu1_8 <-| |<----/ +-+
+ * +-+
+ */
+ &mcpuC /* CPU side only */
+ >;
+
+ multi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /*
+ * [Semi-Multi]
+ *
+ * <sm> +---+
+ * cpu1_1 <---@--->|X A|-> codec1_1
+ * | B|-> codec1_2
+ * +---+
+ */
+ ports@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; smcodec_ep: endpoint { remote-endpoint = <&cpu1_1_ep>; };};/* (X) to pair */
+ port@1 { reg = <1>; smcodec_A_ep: endpoint { remote-endpoint = <&codec1_1_ep>; };};/* (A) Multi Element */
+ port@2 { reg = <2>; smcodec_B_ep: endpoint { remote-endpoint = <&codec1_2_ep>; };};/* (B) Multi Element */
+ };
+
+ /*
+ * [Multi-CPU-A]
+ *
+ * +---+ <mcpuA> +---+
+ * cpu1_2 <-|A X|<---@---->|x a|-> codec1_3
+ * cpu1_3 <-|B | | b|-> codec1_4
+ * +---+ +---+
+ */
+ ports@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mcpuA: port@0 { reg = <0>; mcpu_A_ep: endpoint { remote-endpoint = <&mcodec_A_ep>; };}; /* (X) to pair */
+ port@1 { reg = <1>; mcpu_AA_ep: endpoint { remote-endpoint = <&cpu1_2_ep>; };}; /* (A) Multi Element */
+ port@2 { reg = <2>; mcpu_AB_ep: endpoint { remote-endpoint = <&cpu1_3_ep>; };}; /* (B) Multi Element */
+ };
+
+ /*
+ * [Multi-Codec-A]
+ *
+ * +---+ <mcpuA> +---+
+ * cpu1_2 <-|A X|<-@------>|x a|-> codec1_3
+ * cpu1_3 <-|B | | b|-> codec1_4
+ * +---+ +---+
+ */
+ ports@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; mcodec_A_ep: endpoint { remote-endpoint = <&mcpu_A_ep>; };}; /* (x) to pair */
+ port@1 { reg = <1>; mcodec_Aa_ep: endpoint { remote-endpoint = <&codec1_3_ep>; };}; /* (a) Multi Element */
+ port@2 { reg = <2>; mcodec_Ab_ep: endpoint { remote-endpoint = <&codec1_4_ep>; };}; /* (b) Multi Element */
+ };
+
+ /*
+ * [Multi-CPU-B]
+ *
+ * +---+ <mcpuB> +---+
+ * | X|<---@---->|x |
+ * | | | |
+ * cpu1_4 <-|A 1|<-------->|3 a|-> codec1_5
+ * cpu1_5 <-|B 2|<---+---->|4 b|-> codec1_6
+ * +---+ \--->|5 c|-> codec1_7
+ * +---+
+ */
+ ports@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mcpuB: port@0 {
+ reg = <0>;
+ mcpu_BX_ep: endpoint { remote-endpoint = <&mcodec_Bx_ep>; }; /* (X) to pair */
+ };
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcpu_BA_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_4_ep>; }; /* (A) Multi Element */
+ mcpu_B1_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_B3_ep>; }; /* (1) connected Codec */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcpu_BB_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_5_ep>; }; /* (B) Multi Element */
+ mcpu_B2_0_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_B4_ep>; }; /* (2) connected Codec */
+ mcpu_B2_1_ep: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec_B5_ep>; }; /* (2) connected Codec */
+ };
+ };
+
+ /*
+ * [Multi-Codec-B]
+ *
+ * +---+ <mcpuB> +---+
+ * | X|<-@------>|x |
+ * | | | |
+ * cpu1_4 <-|A 1|<-------->|3 a|-> codec1_5
+ * cpu1_5 <-|B 2|<---+---->|4 b|-> codec1_6
+ * +---+ \--->|5 c|-> codec1_7
+ * +---+
+ */
+ ports@4 {
+ reg = <4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ mcodec_Bx_ep: endpoint { remote-endpoint = <&mcpu_BX_ep>; }; /* (x) to pair */
+ };
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcodec_Ba_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_5_ep>;}; /* (a) Multi Element */
+ mcodec_B3_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_B1_ep>; }; /* (3) connected CPU */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcodec_Bb_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_6_ep>; }; /* (b) Multi Element */
+ mcodec_B4_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_B2_0_ep>;}; /* (4) connected CPU */
+ };
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ mcodec_Bc_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_7_ep>; }; /* (c) Multi Element */
+ mcodec_B5_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_B2_1_ep>;}; /* (5) connected CPU */
+ };
+ };
+
+ /*
+ * [Multi-CPU-C]
+ *
+ * +---+ <mcpuC> +---+
+ * | X|<-@------>|x |
+ * | | | |
+ * cpu1_6 <-|A 1|<-------->|4 a|-> codec1_8
+ * cpu1_7 <-|B 2|<-----+-->|5 b|-> codec1_9
+ * cpu1_8 <-|C 3|<----/ +---+
+ * +---+
+ */
+ ports@5 {
+ reg = <5>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mcpuC: port@0 {
+ reg = <0>;
+ mcpu_CX_ep: endpoint { remote-endpoint = <&mcodec_Cx_ep>; }; /* (X) to pair */
+ };
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcpu_CA_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_6_ep>; }; /* (A) Multi Element */
+ mcpu_C1_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_C4_ep>; }; /* (1) connected Codec */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcpu_CB_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_7_ep>; }; /* (B) Multi Element */
+ mcpu_C2_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_C5_0_ep>; }; /* (2) connected Codec */
+ };
+ port@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ mcpu_CC_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_8_ep>; }; /* (C) Multi Element */
+ mcpu_C3_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_C5_1_ep>; }; /* (3) connected Codec */
+ };
+ };
+
+ /*
+ * [Multi-Codec-C]
+ *
+ * +---+ <mcpuC> +---+
+ * | X|<-@------>|x |
+ * | | | |
+ * cpu1_6 <-|A 1|<-------->|4 a|-> codec1_8
+ * cpu1_7 <-|B 2|<-----+-->|5 b|-> codec1_9
+ * cpu1_8 <-|C 3|<----/ +---+
+ * +---+
+ */
+ ports@6 {
+ reg = <6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ mcodec_Cx_ep: endpoint { remote-endpoint = <&mcpu_CX_ep>; }; /* (x) to pair */
+ };
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ mcodec_Ca_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_8_ep>;}; /* (a) Multi Element */
+ mcodec_C4_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_C1_ep>; }; /* (4) connected CPU */
+ };
+ port@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ mcodec_Cb_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_9_ep>;}; /* (b) Multi Element */
+ mcodec_C5_0_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_C2_ep>; }; /* (5) connected CPU */
+ mcodec_C5_1_ep: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu_C3_ep>; }; /* (5) connected CPU */
+ };
+ };
+ };
+ };
+
+ test_cpu_1 {
+ /*
+ * update compatible to indicate more detail behaviour
+ * if you want. see test-compatible for more detail.
+ *
+ * ex)
+ * - compatible = "test-cpu";
+ * + compatible = "test-cpu-verbose";
+ */
+ compatible = "test-cpu";
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bitclock-master;
+ frame-master;
+
+ /* [Normal] */
+ cpu1_0: port@0 { reg = <0>; cpu1_0_ep: endpoint { remote-endpoint = <&codec1_0_ep>;}; };
+ /* [Semi-Multi] */
+ sm: port@1 { reg = <1>; cpu1_1_ep: endpoint { remote-endpoint = <&smcodec_ep>; }; };
+ /* [Multi-CPU-A] */
+ port@2 { reg = <2>; cpu1_2_ep: endpoint { remote-endpoint = <&mcpu_AA_ep>; }; };
+ port@3 { reg = <3>; cpu1_3_ep: endpoint { remote-endpoint = <&mcpu_AB_ep>; }; };
+ /* [Multi-CPU-B] */
+ port@4 { reg = <4>; cpu1_4_ep: endpoint { remote-endpoint = <&mcpu_BA_ep>; }; };
+ port@5 { reg = <5>; cpu1_5_ep: endpoint { remote-endpoint = <&mcpu_BB_ep>; }; };
+ /* [Multi-CPU-C] */
+ port@6 { reg = <6>; cpu1_6_ep: endpoint { remote-endpoint = <&mcpu_CA_ep>; }; };
+ port@7 { reg = <7>; cpu1_7_ep: endpoint { remote-endpoint = <&mcpu_CB_ep>; }; };
+ port@8 { reg = <8>; cpu1_8_ep: endpoint { remote-endpoint = <&mcpu_CC_ep>; }; };
+ };
+ };
+
+ test_codec_1 {
+ /*
+ * update compatible to indicate more detail behaviour
+ * if you want. see test-compatible for more detail.
+ *
+ * ex)
+ * - compatible = "test-codec";
+ * + compatible = "test-codec-verbose";
+ */
+ compatible = "test-codec";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* [Normal] */
+ port@0 { reg = <0>; codec1_0_ep: endpoint { remote-endpoint = <&cpu1_0_ep>; }; };
+ /* [Semi-Multi] */
+ port@1 { reg = <1>; codec1_1_ep: endpoint { remote-endpoint = <&smcodec_A_ep>; }; };
+ port@2 { reg = <2>; codec1_2_ep: endpoint { remote-endpoint = <&smcodec_B_ep>; }; };
+ /* [Multi-Codec-0] */
+ port@3 { reg = <3>; codec1_3_ep: endpoint { remote-endpoint = <&mcodec_Aa_ep>; }; };
+ port@4 { reg = <4>; codec1_4_ep: endpoint { remote-endpoint = <&mcodec_Ab_ep>; }; };
+ /* [Multi-Codec-1] */
+ port@5 { reg = <5>; codec1_5_ep: endpoint { remote-endpoint = <&mcodec_Ba_ep>; }; };
+ port@6 { reg = <6>; codec1_6_ep: endpoint { remote-endpoint = <&mcodec_Bb_ep>; }; };
+ port@7 { reg = <7>; codec1_7_ep: endpoint { remote-endpoint = <&mcodec_Bc_ep>; }; };
+ /* [Multi-Codec-2] */
+ port@8 { reg = <8>; codec1_8_ep: endpoint { remote-endpoint = <&mcodec_Ca_ep>; }; };
+ port@9 { reg = <9>; codec1_9_ep: endpoint { remote-endpoint = <&mcodec_Cb_ep>; }; };
+ };
+ };
+};
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample2.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample2.dtsi
new file mode 100644
index 000000000000..1fb061a10ab1
--- /dev/null
+++ b/sound/soc/generic/audio-graph-card2-custom-sample2.dtsi
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * audio-graph-card2-custom-sample2.dtsi
+ *
+ * Copyright (C) 2020 Renesas Electronics Corp.
+ * Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This sample indicates how to use audio-graph-card2 and its
+ * custom driver. "audio-graph-card2-custom-sample" is the custome driver
+ * which is using audio-graph-card2.
+ *
+ * You can easily use this sample by adding below line on your DT file,
+ * and add new CONFIG to your .config.
+ *
+ * #include "../../../../../sound/soc/generic/audio-graph-card2-custom-sample2.dtsi"
+ *
+ * CONFIG_SND_AUDIO_GRAPH_CARD2
+ * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE
+ * CONFIG_SND_TEST_COMPONENT
+ *
+ *
+ * You can indicate more detail each device behavior as debug if you modify
+ * "compatible" on each test-component. see below
+ *
+ * test_cpu {
+ * - compatible = "test-cpu";
+ * + compatible = "test-cpu-verbose";
+ * ...
+ * };
+ *
+ * test_codec {
+ * - compatible = "test-codec";
+ * + compatible = "test-codec-verbose";
+ * ...
+ * };
+ *
+ *
+ * Below sample doesn't use "format" property,
+ * because test-component driver (test-cpu/test-codec) is supporting
+ * snd_soc_dai_ops :: .auto_selectable_formats.
+ * see
+ * snd_soc_runtime_get_dai_fmt()
+ * linux/sound/soc/generic/test-component.c :: test_dai_formats
+ */
+/ {
+ audio-graph-card2-custom-sample-2 {
+ /*
+ * You can use audio-graph-card2 directly by using
+ *
+ * compatible = "audio-graph-card2";
+ */
+ compatible = "audio-graph-card2-custom-sample";
+ label = "card2-custom-sample-2";
+
+ /* for [DPCM] */
+ /* BE FE */
+ routing = "TC DAI0 Playback", "DAI0 Playback",
+ "TC DAI0 Playback", "DAI1 Playback",
+ "DAI0 Capture", "TC DAI0 Capture",
+ "DAI1 Capture", "TC DAI0 Capture",
+ /* for [DPCM-Multi] */
+ /* BE FE */
+ "TC DAI1 Playback", "DAI2 Playback",
+ "TC DAI2 Playback", "DAI2 Playback",
+ "TC DAI1 Playback", "DAI3 Playback",
+ "TC DAI2 Playback", "DAI3 Playback",
+ "DAI2 Capture", "TC DAI1 Capture",
+ "DAI2 Capture", "TC DAI2 Capture",
+ "DAI3 Capture", "TC DAI1 Capture",
+ "DAI3 Capture", "TC DAI2 Capture",
+ /* for [Codec2Codec] */
+ "TC OUT", "TC DAI4 Playback",
+ "TC DAI3 Capture", "TC IN",
+ /* for [Codec2Codec-Multi] */
+ "TC OUT", "TC DAI7 Playback",
+ "TC DAI5 Capture", "TC IN",
+ "TC OUT", "TC DAI8 Playback",
+ "TC DAI6 Capture", "TC IN";
+
+ /*
+ * @ : used at links
+ */
+ links = <
+ /*
+ * [DPCM]
+ *
+ * cpu20/cpu21 are converting rate to 44.1kHz
+ *
+ * FE BE
+ * <feA> **** <beA>
+ * cpu2_0 <----@---* *------@---> codec2_0 (44.1kHz)
+ * cpu2_1 <----@---* *
+ * <feB> ****
+ */
+ &feA &feB &beA /* both FE / BE */
+
+ /*
+ * [DPCM-Multi]
+ *
+ * FE BE
+ * <feC> **** <beB> +-+
+ * cpu2_2 <----@---* *------@---> | | -> codec2_1
+ * cpu2_3 <----@---* * | | -> codec2_2
+ * <feD> **** +-+
+ */
+ &feC &feD &beB /* both FE / BE*/
+
+ /*
+ * [Codec2Codec]
+ *
+ * <c2c>
+ * +-@-> codec2_3
+ * |
+ * +---> codec2_4
+ */
+ &c2c /* CPU side only */
+
+ /*
+ * [Codec2Codec-Multi]
+ *
+ * --NOTE--
+ * Multi connect N:M is not supported by ASoC.
+ *
+ * <c2c_m> +-+
+ * +---@-->| |-> codec2_5
+ * | | |-> codec2_6
+ * | +-+
+ * | +-+
+ * +------>| |-> codec2_7
+ * | |-> codec2_8
+ * +-+
+ */
+ &c2c_m /* CPU side only */
+ >;
+
+ multi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /*
+ * [DPCM-Multi]::BE
+ *
+ * FE BE
+ * <feC> **** <beB> +---+
+ * cpu2_2 <----@---* *------@---> |x a| -> codec2_1
+ * cpu2_3 <----@---* * | b| -> codec2_2
+ * <feD> **** +---+
+ */
+ ports@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; mbe_x_ep: endpoint { remote-endpoint = <&beB_ep>; };};/* (x) to pair */
+ port@1 { reg = <1>; mbe_a_ep: endpoint { remote-endpoint = <&codec2_1_ep>; };};/* (a) Multi Element */
+ port@2 { reg = <2>; mbe_b_ep: endpoint { remote-endpoint = <&codec2_2_ep>; };};/* (b) Multi Element */
+ };
+
+ /*
+ * [Codec2Codec-Multi]::CPU
+ *
+ * <c2c_m> c2cmf +---+
+ * +---@---------->|X A|-> codec2_5
+ * | | B|-> codec2_6
+ * | +---+
+ * | c2cmb +---+
+ * +-------------->|x a|-> codec2_7
+ * | b|-> codec2_8
+ * +---+
+ */
+ ports@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; mc2c0X_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */
+ port@1 { reg = <1>; mc2c0A_ep: endpoint { remote-endpoint = <&codec2_5_ep>; };};/* (A) Multi Element */
+ port@2 { reg = <2>; mc2c0B_ep: endpoint { remote-endpoint = <&codec2_6_ep>; };};/* (B) Multi Element */
+ };
+
+ /*
+ * [Codec2Codec-Multi]::Codec
+ *
+ * <c2c_m> c2cmf +---+
+ * +---@---------->|X A|-> codec2_5
+ * | | B|-> codec2_6
+ * | +---+
+ * | c2cmb +---+
+ * +-------------->|x a|-> codec2_7
+ * | b|-> codec2_8
+ * +---+
+ */
+ ports@4 {
+ reg = <4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 { reg = <0>; mc2c1x_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */
+ port@1 { reg = <1>; mc2c1a_ep: endpoint { remote-endpoint = <&codec2_7_ep>; };};/* (a) Multi Element */
+ port@2 { reg = <2>; mc2c1b_ep: endpoint { remote-endpoint = <&codec2_8_ep>; };};/* (b) Multi Element */
+ };
+ };
+
+ dpcm {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FE part */
+ ports@0 {
+ reg = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /*
+ * [DPCM]::FE
+ *
+ * FE BE
+ * <feA> **** <beA>
+ * cpu2_0 <----@---* *------@---> codec2_0 (44.1kHz)
+ * cpu2_1 <----@---* *
+ * <feB> ****
+ */
+ feA: port@0 { reg = <0>; feA_ep: endpoint { remote-endpoint = <&cpu2_0_ep>; }; };
+ feB: port@1 { reg = <1>; feB_ep: endpoint { remote-endpoint = <&cpu2_1_ep>; }; };
+
+ /*
+ * [DPCM-Multi]::FE
+ *
+ * FE BE
+ * <feC> **** <beB> +-+
+ * cpu2_2 <----@---* *------@---> | | -> codec2_1
+ * cpu2_3 <----@---* * | | -> codec2_2
+ * <feD> **** +-+
+ */
+ feC: port@2 { reg = <2>; feC_ep: endpoint { remote-endpoint = <&cpu2_2_ep>; }; };
+ feD: port@3 { reg = <3>; feD_ep: endpoint { remote-endpoint = <&cpu2_3_ep>; }; };
+ };
+
+ /* BE part */
+ ports@1 {
+ reg = <1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /*
+ * [DPCM]::BE
+ *
+ * FE BE
+ * <feA> **** <beA>
+ * cpu2_0 <----@---* *------@---> codec2_0 (44.1kHz)
+ * cpu2_1 <----@---* *
+ * <feB> ****
+ */
+ beA: port@0 { reg = <0>; beA_ep: endpoint { remote-endpoint = <&codec2_0_ep>; }; };
+
+ /*
+ * [DPCM-Multi]::BE
+ *
+ * FE BE
+ * <feC> **** <beB> +-------+
+ * cpu2_2 <----@---* *------@---> |mbe_x | -> codec2_1
+ * cpu2_3 <----@---* * | | -> codec2_2
+ * <feD> **** +-------+
+ */
+ beB: port@1 { reg = <1>; beB_ep: endpoint { remote-endpoint = <&mbe_x_ep>; }; };
+ };
+ };
+
+ codec2codec {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ /*
+ * [Codec2Codec]
+ *
+ * <c2c>
+ * +-@--> codec2_3
+ * |
+ * +----> codec2_4
+ */
+ ports@0 {
+ reg = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* use default settings */
+ c2c: port@0 { reg = <0>; c2cf_ep: endpoint { remote-endpoint = <&codec2_3_ep>; }; };
+ port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec2_4_ep>; }; };
+ };
+
+ /*
+ * [Codec2Codec-Multi]
+ *
+ * <c2c_m> c2cmf +--------+
+ * +---@---------->|mc2c0X |-> codec2_5
+ * | | |-> codec2_6
+ * | +--------+
+ * | c2cmb +--------+
+ * +-------------->|mc2c1x |-> codec2_7
+ * | |-> codec2_8
+ * +--------+
+ */
+ ports@1 {
+ reg = <1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* use original settings */
+ rate = <48000>;
+ c2c_m: port@0 { reg = <0>; c2cmf_ep: endpoint { remote-endpoint = <&mc2c0X_ep>; }; };
+ port@1 { reg = <1>; c2cmb_ep: endpoint { remote-endpoint = <&mc2c1x_ep>; }; };
+ };
+ };
+ };
+
+ test_cpu_2 {
+ /*
+ * update compatible to indicate more detail behaviour
+ * if you want. see test-compatible for more detail.
+ *
+ * ex)
+ * - compatible = "test-cpu";
+ * + compatible = "test-cpu-verbose";
+ */
+ compatible = "test-cpu";
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bitclock-master;
+ frame-master;
+
+ /* [DPCM]::FE */
+ port@0 { reg = <0>; cpu2_0_ep: endpoint { remote-endpoint = <&feA_ep>; };};
+ port@1 { reg = <1>; cpu2_1_ep: endpoint { remote-endpoint = <&feB_ep>; };};
+ /* [DPCM-Multi]::FE */
+ port@2 { reg = <2>; cpu2_2_ep: endpoint { remote-endpoint = <&feC_ep>; };};
+ port@3 { reg = <3>; cpu2_3_ep: endpoint { remote-endpoint = <&feD_ep>; };};
+ };
+ };
+
+ test_codec_2 {
+ /*
+ * update compatible to indicate more detail behaviour
+ * if you want. see test-compatible for more detail.
+ *
+ * ex)
+ * - compatible = "test-codec";
+ * + compatible = "test-codec-verbose";
+ */
+ compatible = "test-codec";
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /*
+ * prefix can be added to *component*,
+ * see audio-graph-card2::routing
+ */
+ prefix = "TC";
+
+ /* [DPCM]::BE */
+ port@0 {
+ convert-rate = <44100>;
+ reg = <0>; codec2_0_ep: endpoint { remote-endpoint = <&beA_ep>; };
+ };
+ /* [DPCM-Multi]::BE */
+ port@1 { reg = <1>; codec2_1_ep: endpoint { remote-endpoint = <&mbe_a_ep>; };};
+ port@2 { reg = <2>; codec2_2_ep: endpoint { remote-endpoint = <&mbe_b_ep>; };};
+ /* [Codec2Codec] */
+ port@3 { bitclock-master;
+ frame-master;
+ reg = <3>; codec2_3_ep: endpoint { remote-endpoint = <&c2cf_ep>; };};
+ port@4 { reg = <4>; codec2_4_ep: endpoint { remote-endpoint = <&c2cb_ep>; };};
+ /* [Codec2Codec-Multi] */
+ port@5 { bitclock-master;
+ frame-master;
+ reg = <5>; codec2_5_ep: endpoint { remote-endpoint = <&mc2c0A_ep>; };};
+ port@6 { reg = <6>; codec2_6_ep: endpoint { remote-endpoint = <&mc2c0B_ep>; };};
+ port@7 { reg = <7>; codec2_7_ep: endpoint { remote-endpoint = <&mc2c1a_ep>; };};
+ port@8 { reg = <8>; codec2_8_ep: endpoint { remote-endpoint = <&mc2c1b_ep>; };};
+ };
+ };
+};
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 1f5c4e8ff1b9..5dcc78c551a2 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -234,6 +234,13 @@ enum graph_type {
#define GRAPH_NODENAME_DPCM "dpcm"
#define GRAPH_NODENAME_C2C "codec2codec"
+#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret)
+static inline int _graph_ret(struct simple_util_priv *priv,
+ const char *func, int ret)
+{
+ return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
+}
+
#define ep_to_port(ep) of_get_parent(ep)
static struct device_node *port_to_ports(struct device_node *port)
{
@@ -331,10 +338,9 @@ static int graph_lnk_is_multi(struct device_node *lnk)
return __graph_get_type(lnk) == GRAPH_MULTI;
}
-static struct device_node *graph_get_next_multi_ep(struct device_node **port)
+static struct device_node *graph_get_next_multi_ep(struct device_node **port, int idx)
{
- struct device_node *ports = port_to_ports(*port);
- struct device_node *ep = NULL;
+ struct device_node *ports __free(device_node) = port_to_ports(*port);
struct device_node *rep = NULL;
/*
@@ -352,15 +358,22 @@ static struct device_node *graph_get_next_multi_ep(struct device_node **port)
* port@1 { rep1 };
* };
*/
- *port = of_graph_get_next_port(ports, *port);
+
+ /*
+ * Don't use of_graph_get_next_port() here
+ *
+ * In overlay case, "port" are not necessarily in order. So we need to use
+ * of_graph_get_port_by_id() instead
+ */
+ of_node_put(*port);
+
+ *port = of_graph_get_port_by_id(ports, idx);
if (*port) {
- ep = of_graph_get_next_port_endpoint(*port, NULL);
+ struct device_node *ep __free(device_node) = of_graph_get_next_port_endpoint(*port, NULL);
+
rep = of_graph_get_remote_endpoint(ep);
}
- of_node_put(ep);
- of_node_put(ports);
-
return rep;
}
@@ -373,16 +386,13 @@ static const struct snd_soc_ops graph_ops = {
static void graph_parse_convert(struct device_node *ep,
struct simple_dai_props *props)
{
- struct device_node *port = ep_to_port(ep);
- struct device_node *ports = port_to_ports(port);
+ struct device_node *port __free(device_node) = ep_to_port(ep);
+ struct device_node *ports __free(device_node) = port_to_ports(port);
struct simple_util_data *adata = &props->adata;
simple_util_parse_convert(ports, NULL, adata);
simple_util_parse_convert(port, NULL, adata);
simple_util_parse_convert(ep, NULL, adata);
-
- of_node_put(port);
- of_node_put(ports);
}
static int __graph_parse_node(struct simple_util_priv *priv,
@@ -406,21 +416,21 @@ static int __graph_parse_node(struct simple_util_priv *priv,
dai = simple_props_to_dai_codec(dai_props, idx);
}
- ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links);
+ ret = graph_util_parse_dai(priv, ep, dlc, &is_single_links);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_tdm(ep, dai);
if (ret < 0)
- return ret;
+ goto end;
- ret = simple_util_parse_tdm_width_map(dev, ep, dai);
+ ret = simple_util_parse_tdm_width_map(priv, ep, dai);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_clk(dev, ep, dai, dlc);
if (ret < 0)
- return ret;
+ goto end;
/*
* set DAI Name
@@ -440,22 +450,22 @@ static int __graph_parse_node(struct simple_util_priv *priv,
case GRAPH_NORMAL:
/* run is_cpu only. see audio_graph2_link_normal() */
if (is_cpu)
- simple_util_set_dailink_name(dev, dai_link, "%s%s-%s%s",
+ simple_util_set_dailink_name(priv, dai_link, "%s%s-%s%s",
cpus->dai_name, cpu_multi,
codecs->dai_name, codec_multi);
break;
case GRAPH_DPCM:
if (is_cpu)
- simple_util_set_dailink_name(dev, dai_link, "fe.%pOFP.%s%s",
+ simple_util_set_dailink_name(priv, dai_link, "fe.%pOFP.%s%s",
cpus->of_node, cpus->dai_name, cpu_multi);
else
- simple_util_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s",
+ simple_util_set_dailink_name(priv, dai_link, "be.%pOFP.%s%s",
codecs->of_node, codecs->dai_name, codec_multi);
break;
case GRAPH_C2C:
/* run is_cpu only. see audio_graph2_link_c2c() */
if (is_cpu)
- simple_util_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s",
+ simple_util_set_dailink_name(priv, dai_link, "c2c.%s%s-%s%s",
cpus->dai_name, cpu_multi,
codecs->dai_name, codec_multi);
break;
@@ -471,14 +481,11 @@ static int __graph_parse_node(struct simple_util_priv *priv,
if (!is_cpu && gtype == GRAPH_DPCM) {
struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx);
- struct device_node *rport = ep_to_port(ep);
- struct device_node *rports = port_to_ports(rport);
+ struct device_node *rport __free(device_node) = ep_to_port(ep);
+ struct device_node *rports __free(device_node) = port_to_ports(rport);
snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
snd_soc_of_parse_node_prefix(rport, cconf, codecs->of_node, "prefix");
-
- of_node_put(rport);
- of_node_put(rports);
}
if (is_cpu) {
@@ -488,11 +495,12 @@ static int __graph_parse_node(struct simple_util_priv *priv,
simple_util_canonicalize_cpu(cpus, is_single_links);
simple_util_canonicalize_platform(platforms, cpus);
}
-
- return 0;
+end:
+ return graph_ret(priv, ret);
}
-static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
+static int graph_parse_node_multi_nm(struct simple_util_priv *priv,
+ struct snd_soc_dai_link *dai_link,
int *nm_idx, int cpu_idx,
struct device_node *mcpu_port)
{
@@ -526,25 +534,21 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
* };
* };
*/
- struct device_node *mcpu_ep = of_graph_get_next_port_endpoint(mcpu_port, NULL);
- struct device_node *mcpu_ports = port_to_ports(mcpu_port);
- struct device_node *mcpu_port_top = of_graph_get_next_port(mcpu_ports, NULL);
- struct device_node *mcpu_ep_top = of_graph_get_next_port_endpoint(mcpu_port_top, NULL);
- struct device_node *mcodec_ep_top = of_graph_get_remote_endpoint(mcpu_ep_top);
- struct device_node *mcodec_port_top = ep_to_port(mcodec_ep_top);
- struct device_node *mcodec_ports = port_to_ports(mcodec_port_top);
+ struct device_node *mcpu_ep __free(device_node) = of_graph_get_next_port_endpoint(mcpu_port, NULL);
+ struct device_node *mcpu_ports __free(device_node) = port_to_ports(mcpu_port);
+ struct device_node *mcpu_port_top __free(device_node) = of_graph_get_next_port(mcpu_ports, NULL);
+ struct device_node *mcpu_ep_top __free(device_node) = of_graph_get_next_port_endpoint(mcpu_port_top, NULL);
+ struct device_node *mcodec_ep_top __free(device_node) = of_graph_get_remote_endpoint(mcpu_ep_top);
+ struct device_node *mcodec_port_top __free(device_node) = ep_to_port(mcodec_ep_top);
+ struct device_node *mcodec_ports __free(device_node) = port_to_ports(mcodec_port_top);
int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
- int ret = 0;
+ int ret = -EINVAL;
- if (cpu_idx > dai_link->num_cpus) {
- ret = -EINVAL;
- goto mcpu_err;
- }
+ if (cpu_idx > dai_link->num_cpus)
+ goto end;
for_each_of_graph_port_endpoint(mcpu_port, mcpu_ep_n) {
- struct device_node *mcodec_ep_n;
- struct device_node *mcodec_port;
- int codec_idx;
+ int codec_idx = 0;
/* ignore 1st ep which is for element */
if (mcpu_ep_n == mcpu_ep)
@@ -553,16 +557,13 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
if (*nm_idx > nm_max)
break;
- mcodec_ep_n = of_graph_get_remote_endpoint(mcpu_ep_n);
- mcodec_port = ep_to_port(mcodec_ep_n);
+ struct device_node *mcodec_ep_n __free(device_node) = of_graph_get_remote_endpoint(mcpu_ep_n);
+ struct device_node *mcodec_port __free(device_node) = ep_to_port(mcodec_ep_n);
- if (mcodec_ports != port_to_ports(mcodec_port)) {
- ret = -EINVAL;
- goto mcpu_err;
- }
-
- codec_idx = 0;
ret = -EINVAL;
+ if (mcodec_ports != port_to_ports(mcodec_port))
+ break;
+
for_each_of_graph_port(mcodec_ports, mcodec_port_i) {
/* ignore 1st port which is for pair connection */
@@ -582,20 +583,11 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
}
codec_idx++;
}
- of_node_put(mcodec_port);
- of_node_put(mcodec_ep_n);
if (ret < 0)
break;
}
-mcpu_err:
- of_node_put(mcpu_ep);
- of_node_put(mcpu_port_top);
- of_node_put(mcpu_ep_top);
- of_node_put(mcodec_ep_top);
- of_node_put(mcodec_port_top);
- of_node_put(mcodec_ports);
-
- return ret;
+end:
+ return graph_ret(priv, ret);
}
static int graph_parse_node_multi(struct simple_util_priv *priv,
@@ -605,7 +597,6 @@ static int graph_parse_node_multi(struct simple_util_priv *priv,
{
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct device *dev = simple_priv_to_dev(priv);
- struct device_node *ep;
int ret = -ENOMEM;
int nm_idx = 0;
int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
@@ -640,18 +631,17 @@ static int graph_parse_node_multi(struct simple_util_priv *priv,
* };
* };
*/
- ep = graph_get_next_multi_ep(&port);
+ struct device_node *ep __free(device_node) = graph_get_next_multi_ep(&port, idx + 1);
if (!ep)
break;
ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, idx);
- of_node_put(ep);
if (ret < 0)
goto multi_err;
/* CPU:Codec = N:M */
if (is_cpu && dai_link->ch_maps) {
- ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port);
+ ret = graph_parse_node_multi_nm(priv, dai_link, &nm_idx, idx, port);
if (ret < 0)
goto multi_err;
}
@@ -661,35 +651,34 @@ static int graph_parse_node_multi(struct simple_util_priv *priv,
ret = -EINVAL;
multi_err:
- return ret;
+ return graph_ret(priv, ret);
}
static int graph_parse_node_single(struct simple_util_priv *priv,
enum graph_type gtype,
- struct device_node *port,
+ struct device_node *ep,
struct link_info *li, int is_cpu)
{
- struct device_node *ep = of_graph_get_next_port_endpoint(port, NULL);
- int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0);
-
- of_node_put(ep);
-
- return ret;
+ return graph_ret(priv, __graph_parse_node(priv, gtype, ep, li, is_cpu, 0));
}
static int graph_parse_node(struct simple_util_priv *priv,
enum graph_type gtype,
- struct device_node *port,
+ struct device_node *ep,
struct link_info *li, int is_cpu)
{
+ struct device_node *port __free(device_node) = ep_to_port(ep);
+ int ret;
+
if (graph_lnk_is_multi(port))
- return graph_parse_node_multi(priv, gtype, port, li, is_cpu);
+ ret = graph_parse_node_multi(priv, gtype, port, li, is_cpu);
else
- return graph_parse_node_single(priv, gtype, port, li, is_cpu);
+ ret = graph_parse_node_single(priv, gtype, ep, li, is_cpu);
+
+ return graph_ret(priv, ret);
}
-static void graph_parse_daifmt(struct device_node *node,
- unsigned int *daifmt, unsigned int *bit_frame)
+static void graph_parse_daifmt(struct device_node *node, unsigned int *daifmt)
{
unsigned int fmt;
@@ -714,16 +703,6 @@ static void graph_parse_daifmt(struct device_node *node,
* };
*/
- /*
- * clock_provider:
- *
- * It can be judged it is provider
- * if (A) or (B) or (C) has bitclock-master / frame-master flag.
- *
- * use "or"
- */
- *bit_frame |= snd_soc_daifmt_parse_clock_provider_as_bitmap(node, NULL);
-
#define update_daifmt(name) \
if (!(*daifmt & SND_SOC_DAIFMT_##name##_MASK) && \
(fmt & SND_SOC_DAIFMT_##name##_MASK)) \
@@ -741,51 +720,64 @@ static void graph_parse_daifmt(struct device_node *node,
update_daifmt(INV);
}
+static unsigned int graph_parse_bitframe(struct device_node *ep)
+{
+ struct device_node *port __free(device_node) = ep_to_port(ep);
+ struct device_node *ports __free(device_node) = port_to_ports(port);
+
+ return snd_soc_daifmt_clock_provider_from_bitmap(
+ snd_soc_daifmt_parse_clock_provider_as_bitmap(ep, NULL) |
+ snd_soc_daifmt_parse_clock_provider_as_bitmap(port, NULL) |
+ snd_soc_daifmt_parse_clock_provider_as_bitmap(ports, NULL));
+}
+
static void graph_link_init(struct simple_util_priv *priv,
struct device_node *lnk,
- struct device_node *port_cpu,
- struct device_node *port_codec,
+ struct device_node *ep_cpu,
+ struct device_node *ep_codec,
struct link_info *li,
int is_cpu_node)
{
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
- struct device_node *ep_cpu, *ep_codec;
- struct device_node *ports_cpu, *ports_codec;
- unsigned int daifmt = 0, daiclk = 0;
+ struct device_node *port_cpu = ep_to_port(ep_cpu);
+ struct device_node *port_codec = ep_to_port(ep_codec);
+ struct device_node *multi_cpu_port = NULL, *multi_codec_port = NULL;
+ struct snd_soc_dai_link_component *dlc;
+ unsigned int daifmt = 0;
bool playback_only = 0, capture_only = 0;
enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT;
- unsigned int bit_frame = 0;
+ int multi_cpu_port_idx = 1, multi_codec_port_idx = 1;
+ int i;
- of_node_get(port_cpu);
if (graph_lnk_is_multi(port_cpu)) {
- ep_cpu = graph_get_next_multi_ep(&port_cpu);
+ multi_cpu_port = port_cpu;
+ ep_cpu = graph_get_next_multi_ep(&multi_cpu_port, multi_cpu_port_idx++);
of_node_put(port_cpu);
port_cpu = ep_to_port(ep_cpu);
} else {
- ep_cpu = of_graph_get_next_port_endpoint(port_cpu, NULL);
+ of_node_get(ep_cpu);
}
- ports_cpu = port_to_ports(port_cpu);
+ struct device_node *ports_cpu __free(device_node) = port_to_ports(port_cpu);
- of_node_get(port_codec);
if (graph_lnk_is_multi(port_codec)) {
- ep_codec = graph_get_next_multi_ep(&port_codec);
+ multi_codec_port = port_codec;
+ ep_codec = graph_get_next_multi_ep(&multi_codec_port, multi_codec_port_idx++);
of_node_put(port_codec);
port_codec = ep_to_port(ep_codec);
} else {
- ep_codec = of_graph_get_next_port_endpoint(port_codec, NULL);
+ of_node_get(ep_codec);
}
- ports_codec = port_to_ports(port_codec);
-
+ struct device_node *ports_codec __free(device_node) = port_to_ports(port_codec);
- graph_parse_daifmt(ep_cpu, &daifmt, &bit_frame);
- graph_parse_daifmt(ep_codec, &daifmt, &bit_frame);
- graph_parse_daifmt(port_cpu, &daifmt, &bit_frame);
- graph_parse_daifmt(port_codec, &daifmt, &bit_frame);
- graph_parse_daifmt(ports_cpu, &daifmt, &bit_frame);
- graph_parse_daifmt(ports_codec, &daifmt, &bit_frame);
- graph_parse_daifmt(lnk, &daifmt, &bit_frame);
+ graph_parse_daifmt(ep_cpu, &daifmt);
+ graph_parse_daifmt(ep_codec, &daifmt);
+ graph_parse_daifmt(port_cpu, &daifmt);
+ graph_parse_daifmt(port_codec, &daifmt);
+ graph_parse_daifmt(ports_cpu, &daifmt);
+ graph_parse_daifmt(ports_codec, &daifmt);
+ graph_parse_daifmt(lnk, &daifmt);
graph_util_parse_link_direction(lnk, &playback_only, &capture_only);
graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only);
@@ -811,14 +803,21 @@ static void graph_link_init(struct simple_util_priv *priv,
graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop);
graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop);
- /*
- * convert bit_frame
- * We need to flip clock_provider if it was CPU node,
- * because it is Codec base.
- */
- daiclk = snd_soc_daifmt_clock_provider_from_bitmap(bit_frame);
- if (is_cpu_node)
- daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk);
+ for_each_link_cpus(dai_link, i, dlc) {
+ dlc->ext_fmt = graph_parse_bitframe(ep_cpu);
+
+ if (multi_cpu_port)
+ ep_cpu = graph_get_next_multi_ep(&multi_cpu_port, multi_cpu_port_idx++);
+ }
+
+ for_each_link_codecs(dai_link, i, dlc) {
+ dlc->ext_fmt = graph_parse_bitframe(ep_codec);
+
+ if (multi_codec_port)
+ ep_codec = graph_get_next_multi_ep(&multi_codec_port, multi_codec_port_idx++);
+ }
+
+ /*** Don't use port_cpu / port_codec after here ***/
dai_link->playback_only = playback_only;
dai_link->capture_only = capture_only;
@@ -826,14 +825,12 @@ static void graph_link_init(struct simple_util_priv *priv,
dai_link->trigger_start = trigger_start;
dai_link->trigger_stop = trigger_stop;
- dai_link->dai_fmt = daifmt | daiclk;
+ dai_link->dai_fmt = daifmt;
dai_link->init = simple_util_dai_init;
dai_link->ops = &graph_ops;
if (priv->ops)
dai_link->ops = priv->ops;
- of_node_put(ports_cpu);
- of_node_put(ports_codec);
of_node_put(port_cpu);
of_node_put(port_codec);
of_node_put(ep_cpu);
@@ -845,8 +842,8 @@ int audio_graph2_link_normal(struct simple_util_priv *priv,
struct link_info *li)
{
struct device_node *cpu_port = lnk;
- struct device_node *cpu_ep = of_graph_get_next_port_endpoint(cpu_port, NULL);
- struct device_node *codec_port = of_graph_get_remote_port(cpu_ep);
+ struct device_node *cpu_ep __free(device_node) = of_graph_get_next_port_endpoint(cpu_port, NULL);
+ struct device_node *codec_ep __free(device_node) = of_graph_get_remote_endpoint(cpu_ep);
int ret;
/*
@@ -854,23 +851,21 @@ int audio_graph2_link_normal(struct simple_util_priv *priv,
* see
* __graph_parse_node() :: DAI Naming
*/
- ret = graph_parse_node(priv, GRAPH_NORMAL, codec_port, li, 0);
+ ret = graph_parse_node(priv, GRAPH_NORMAL, codec_ep, li, 0);
if (ret < 0)
- goto err;
+ goto end;
/*
* call CPU, and set DAI Name
*/
- ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_port, li, 1);
+ ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_ep, li, 1);
if (ret < 0)
- goto err;
+ goto end;
- graph_link_init(priv, lnk, cpu_port, codec_port, li, 1);
-err:
- of_node_put(codec_port);
- of_node_put(cpu_ep);
+ graph_link_init(priv, lnk, cpu_ep, codec_ep, li, 1);
- return ret;
+end:
+ return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph2_link_normal);
@@ -878,17 +873,17 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ep = of_graph_get_next_port_endpoint(lnk, NULL);
- struct device_node *rep = of_graph_get_remote_endpoint(ep);
- struct device_node *cpu_port = NULL;
- struct device_node *codec_port = NULL;
+ struct device_node *ep __free(device_node) = of_graph_get_next_port_endpoint(lnk, NULL);
+ struct device_node *rep __free(device_node) = of_graph_get_remote_endpoint(ep);
+ struct device_node *cpu_ep = NULL;
+ struct device_node *codec_ep = NULL;
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
int is_cpu = graph_util_is_ports0(lnk);
int ret;
if (is_cpu) {
- cpu_port = of_graph_get_remote_port(ep); /* rport */
+ cpu_ep = rep;
/*
* dpcm {
@@ -917,12 +912,12 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
dai_link->dynamic = 1;
dai_link->dpcm_merged_format = 1;
- ret = graph_parse_node(priv, GRAPH_DPCM, cpu_port, li, 1);
+ ret = graph_parse_node(priv, GRAPH_DPCM, cpu_ep, li, 1);
if (ret)
- goto err;
+ return ret;
} else {
- codec_port = of_graph_get_remote_port(ep); /* rport */
+ codec_ep = rep;
/*
* dpcm {
@@ -953,22 +948,17 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv,
dai_link->no_pcm = 1;
dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
- ret = graph_parse_node(priv, GRAPH_DPCM, codec_port, li, 0);
+ ret = graph_parse_node(priv, GRAPH_DPCM, codec_ep, li, 0);
if (ret < 0)
- goto err;
+ return ret;
}
graph_parse_convert(ep, dai_props); /* at node of <dpcm> */
graph_parse_convert(rep, dai_props); /* at node of <CPU/Codec> */
- graph_link_init(priv, lnk, cpu_port, codec_port, li, is_cpu);
-err:
- of_node_put(ep);
- of_node_put(rep);
- of_node_put(cpu_port);
- of_node_put(codec_port);
+ graph_link_init(priv, lnk, cpu_ep, codec_ep, li, is_cpu);
- return ret;
+ return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm);
@@ -977,9 +967,9 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
struct link_info *li)
{
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
- struct device_node *port0, *port1, *ports;
- struct device_node *codec0_port, *codec1_port;
- struct device_node *ep0, *ep1;
+ struct device_node *port0 = lnk;
+ struct device_node *ports __free(device_node) = port_to_ports(port0);
+ struct device_node *port1 __free(device_node) = of_graph_get_next_port(ports, port0);
u32 val = 0;
int ret = -EINVAL;
@@ -999,10 +989,6 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
* };
* };
*/
- of_node_get(lnk);
- port0 = lnk;
- ports = port_to_ports(port0);
- port1 = of_graph_get_next_port(ports, port0);
/*
* Card2 can use original Codec2Codec settings if DT has.
@@ -1018,8 +1004,13 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
struct snd_soc_pcm_stream *c2c_conf;
c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL);
- if (!c2c_conf)
- goto err1;
+ if (!c2c_conf) {
+ /*
+ * Clang doesn't allow to use "goto end" before calling __free(),
+ * because it bypasses the initialization. Use graph_ret() directly.
+ */
+ return graph_ret(priv, -ENOMEM);
+ }
c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */
c2c_conf->rates = SNDRV_PCM_RATE_8000_384000;
@@ -1032,40 +1023,31 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv,
dai_link->num_c2c_params = 1;
}
- ep0 = of_graph_get_next_port_endpoint(port0, NULL);
- ep1 = of_graph_get_next_port_endpoint(port1, NULL);
+ struct device_node *ep0 __free(device_node) = of_graph_get_next_port_endpoint(port0, NULL);
+ struct device_node *ep1 __free(device_node) = of_graph_get_next_port_endpoint(port1, NULL);
- codec0_port = of_graph_get_remote_port(ep0);
- codec1_port = of_graph_get_remote_port(ep1);
+ struct device_node *codec0_ep __free(device_node) = of_graph_get_remote_endpoint(ep0);
+ struct device_node *codec1_ep __free(device_node) = of_graph_get_remote_endpoint(ep1);
/*
* call Codec first.
* see
* __graph_parse_node() :: DAI Naming
*/
- ret = graph_parse_node(priv, GRAPH_C2C, codec1_port, li, 0);
+ ret = graph_parse_node(priv, GRAPH_C2C, codec1_ep, li, 0);
if (ret < 0)
- goto err2;
+ goto end;
/*
* call CPU, and set DAI Name
*/
- ret = graph_parse_node(priv, GRAPH_C2C, codec0_port, li, 1);
+ ret = graph_parse_node(priv, GRAPH_C2C, codec0_ep, li, 1);
if (ret < 0)
- goto err2;
-
- graph_link_init(priv, lnk, codec0_port, codec1_port, li, 1);
-err2:
- of_node_put(ep0);
- of_node_put(ep1);
- of_node_put(codec0_port);
- of_node_put(codec1_port);
-err1:
- of_node_put(ports);
- of_node_put(port0);
- of_node_put(port1);
+ goto end;
- return ret;
+ graph_link_init(priv, lnk, codec0_ep, codec1_ep, li, 1);
+end:
+ return graph_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(audio_graph2_link_c2c);
@@ -1113,7 +1095,7 @@ static int graph_link(struct simple_util_priv *priv,
li->link++;
err:
- return ret;
+ return graph_ret(priv, ret);
}
static int graph_counter(struct device_node *lnk)
@@ -1153,8 +1135,8 @@ static int graph_count_normal(struct simple_util_priv *priv,
struct link_info *li)
{
struct device_node *cpu_port = lnk;
- struct device_node *cpu_ep = of_graph_get_next_port_endpoint(cpu_port, NULL);
- struct device_node *codec_port = of_graph_get_remote_port(cpu_ep);
+ struct device_node *cpu_ep __free(device_node) = of_graph_get_next_port_endpoint(cpu_port, NULL);
+ struct device_node *codec_port __free(device_node) = of_graph_get_remote_port(cpu_ep);
/*
* CPU {
@@ -1171,9 +1153,6 @@ static int graph_count_normal(struct simple_util_priv *priv,
li->num[li->link].codecs = graph_counter(codec_port);
- of_node_put(cpu_ep);
- of_node_put(codec_port);
-
return 0;
}
@@ -1181,8 +1160,8 @@ static int graph_count_dpcm(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ep = of_graph_get_next_port_endpoint(lnk, NULL);
- struct device_node *rport = of_graph_get_remote_port(ep);
+ struct device_node *ep __free(device_node) = of_graph_get_next_port_endpoint(lnk, NULL);
+ struct device_node *rport __free(device_node) = of_graph_get_remote_port(ep);
/*
* dpcm {
@@ -1211,9 +1190,6 @@ static int graph_count_dpcm(struct simple_util_priv *priv,
li->num[li->link].codecs = graph_counter(rport); /* BE */
}
- of_node_put(ep);
- of_node_put(rport);
-
return 0;
}
@@ -1221,13 +1197,13 @@ static int graph_count_c2c(struct simple_util_priv *priv,
struct device_node *lnk,
struct link_info *li)
{
- struct device_node *ports = port_to_ports(lnk);
- struct device_node *port0 = lnk;
- struct device_node *port1 = of_graph_get_next_port(ports, of_node_get(port0));
- struct device_node *ep0 = of_graph_get_next_port_endpoint(port0, NULL);
- struct device_node *ep1 = of_graph_get_next_port_endpoint(port1, NULL);
- struct device_node *codec0 = of_graph_get_remote_port(ep0);
- struct device_node *codec1 = of_graph_get_remote_port(ep1);
+ struct device_node *ports __free(device_node) = port_to_ports(lnk);
+ struct device_node *port0 = of_node_get(lnk);
+ struct device_node *port1 = of_node_get(of_graph_get_next_port(ports, of_node_get(port0)));
+ struct device_node *ep0 __free(device_node) = of_graph_get_next_port_endpoint(port0, NULL);
+ struct device_node *ep1 __free(device_node) = of_graph_get_next_port_endpoint(port1, NULL);
+ struct device_node *codec0 __free(device_node) = of_graph_get_remote_port(ep0);
+ struct device_node *codec1 __free(device_node) = of_graph_get_remote_port(ep1);
/*
* codec2codec {
@@ -1247,13 +1223,6 @@ static int graph_count_c2c(struct simple_util_priv *priv,
li->num[li->link].codecs = graph_counter(codec1);
- of_node_put(ports);
- of_node_put(port1);
- of_node_put(ep0);
- of_node_put(ep1);
- of_node_put(codec0);
- of_node_put(codec1);
-
return 0;
}
@@ -1297,7 +1266,7 @@ static int graph_count(struct simple_util_priv *priv,
li->link++;
err:
- return ret;
+ return graph_ret(priv, ret);
}
static int graph_for_each_link(struct simple_util_priv *priv,
@@ -1314,7 +1283,7 @@ static int graph_for_each_link(struct simple_util_priv *priv,
struct device_node *node = dev->of_node;
struct device_node *lnk;
enum graph_type gtype;
- int rc, ret;
+ int rc, ret = 0;
/* loop for all listed CPU port */
of_for_each_phandle(&it, rc, node, "links", NULL, 0) {
@@ -1324,10 +1293,10 @@ static int graph_for_each_link(struct simple_util_priv *priv,
ret = func(priv, hooks, gtype, lnk, li);
if (ret < 0)
- return ret;
+ break;
}
- return 0;
+ return graph_ret(priv, ret);
}
int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
@@ -1380,7 +1349,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
if (ret < 0)
goto err;
- ret = simple_util_parse_card_name(card, NULL);
+ ret = simple_util_parse_card_name(priv, NULL);
if (ret < 0)
goto err;
@@ -1403,7 +1372,7 @@ err:
if (ret < 0)
dev_err_probe(dev, ret, "parse error\n");
- return ret;
+ 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 24b371f32066..a1ccc300e68c 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -15,6 +15,13 @@
#include <sound/pcm_params.h>
#include <sound/simple_card_utils.h>
+#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret)
+static inline int _simple_ret(struct simple_util_priv *priv,
+ const char *func, int ret)
+{
+ return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
+}
+
int simple_util_get_sample_fmt(struct simple_util_data *data)
{
int i;
@@ -133,34 +140,42 @@ int simple_util_parse_daifmt(struct device *dev,
}
EXPORT_SYMBOL_GPL(simple_util_parse_daifmt);
-int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np,
+int simple_util_parse_tdm_width_map(struct simple_util_priv *priv, struct device_node *np,
struct simple_util_dai *dai)
{
+ struct device *dev = simple_priv_to_dev(priv);
int n, i, ret;
u32 *p;
- if (!of_property_read_bool(np, "dai-tdm-slot-width-map"))
- return 0;
+ /*
+ * NOTE
+ *
+ * Clang doesn't allow to use "goto end" before calling __free(),
+ * because it bypasses the initialization. Use simple_ret() directly.
+ */
n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32));
+ if (n <= 0)
+ return 0;
+
if (n % 3) {
dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n");
- return -EINVAL;
+ return simple_ret(priv, -EINVAL); /* see NOTE */
}
+ ret = -ENOMEM;
dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL);
if (!dai->tdm_width_map)
- return -ENOMEM;
+ return simple_ret(priv, ret); /* see NOTE */
- u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values),
- GFP_KERNEL);
+ u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), GFP_KERNEL);
if (!array_values)
- return -ENOMEM;
+ goto end;
ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n);
if (ret < 0) {
dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret);
- return ret;
+ goto end;
}
p = array_values;
@@ -171,15 +186,17 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np,
}
dai->n_tdm_widths = i;
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map);
-int simple_util_set_dailink_name(struct device *dev,
+int simple_util_set_dailink_name(struct simple_util_priv *priv,
struct snd_soc_dai_link *dai_link,
const char *fmt, ...)
{
+ struct device *dev = simple_priv_to_dev(priv);
va_list ap;
char *name = NULL;
int ret = -ENOMEM;
@@ -195,13 +212,14 @@ int simple_util_set_dailink_name(struct device *dev,
dai_link->stream_name = name;
}
- return ret;
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(simple_util_set_dailink_name);
-int simple_util_parse_card_name(struct snd_soc_card *card,
+int simple_util_parse_card_name(struct simple_util_priv *priv,
char *prefix)
{
+ struct snd_soc_card *card = simple_priv_to_card(priv);
int ret;
if (!prefix)
@@ -215,13 +233,13 @@ int simple_util_parse_card_name(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%sname", prefix);
ret = snd_soc_of_parse_card_name(card, prop);
if (ret < 0)
- return ret;
+ goto end;
}
if (!card->name && card->dai_link)
card->name = card->dai_link->name;
-
- return 0;
+end:
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(simple_util_parse_card_name);
@@ -296,7 +314,7 @@ int simple_util_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id);
+ struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
struct simple_util_dai *dai;
unsigned int fixed_sysclk = 0;
int i1, i2, i;
@@ -349,7 +367,8 @@ cpu_err:
break;
simple_clk_disable(dai);
}
- return ret;
+
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(simple_util_startup);
@@ -357,7 +376,7 @@ void simple_util_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id);
+ struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
struct simple_util_dai *dai;
int i;
@@ -365,8 +384,7 @@ void simple_util_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, i);
if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(cpu_dai))
- snd_soc_dai_set_sysclk(cpu_dai,
- 0, 0, SND_SOC_CLOCK_OUT);
+ snd_soc_dai_set_sysclk(cpu_dai, 0, 0, dai->clk_direction);
simple_clk_disable(dai);
}
@@ -374,24 +392,26 @@ void simple_util_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, i);
if (props->mclk_fs && !dai->clk_fixed && !snd_soc_dai_active(codec_dai))
- snd_soc_dai_set_sysclk(codec_dai,
- 0, 0, SND_SOC_CLOCK_IN);
+ snd_soc_dai_set_sysclk(codec_dai, 0, 0, dai->clk_direction);
simple_clk_disable(dai);
}
}
EXPORT_SYMBOL_GPL(simple_util_shutdown);
-static int simple_set_clk_rate(struct device *dev,
- struct simple_util_dai *simple_dai,
- unsigned long rate)
+static int simple_set_clk_rate(struct simple_util_priv *priv,
+ struct simple_util_dai *simple_dai,
+ unsigned long rate)
{
+ struct device *dev = simple_priv_to_dev(priv);
+ int ret = -EINVAL;
+
if (!simple_dai)
return 0;
if (simple_dai->clk_fixed && rate != simple_dai->sysclk) {
dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate);
- return -EINVAL;
+ goto end;
}
if (!simple_dai->clk)
@@ -400,12 +420,15 @@ static int simple_set_clk_rate(struct device *dev,
if (clk_get_rate(simple_dai->clk) == rate)
return 0;
- return clk_set_rate(simple_dai->clk, rate);
+ ret = clk_set_rate(simple_dai->clk, rate);
+end:
+ return simple_ret(priv, ret);
}
-static int simple_set_tdm(struct snd_soc_dai *dai,
- struct simple_util_dai *simple_dai,
- struct snd_pcm_hw_params *params)
+static int simple_set_tdm(struct simple_util_priv *priv,
+ struct snd_soc_dai *dai,
+ struct simple_util_dai *simple_dai,
+ struct snd_pcm_hw_params *params)
{
int sample_bits = params_width(params);
int slot_width, slot_count;
@@ -433,12 +456,8 @@ static int simple_set_tdm(struct snd_soc_dai *dai,
simple_dai->rx_slot_mask,
slot_count,
slot_width);
- if (ret && ret != -ENOTSUPP) {
- dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret);
- return ret;
- }
- return 0;
+ return simple_ret(priv, ret);
}
int simple_util_hw_params(struct snd_pcm_substream *substream,
@@ -448,7 +467,7 @@ int simple_util_hw_params(struct snd_pcm_substream *substream,
struct simple_util_dai *pdai;
struct snd_soc_dai *sdai;
struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id);
+ struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
unsigned int mclk, mclk_fs = 0;
int i, ret;
@@ -460,15 +479,15 @@ int simple_util_hw_params(struct snd_pcm_substream *substream,
mclk = params_rate(params) * mclk_fs;
for_each_prop_dai_codec(props, i, pdai) {
- ret = simple_set_clk_rate(rtd->dev, pdai, mclk);
+ ret = simple_set_clk_rate(priv, pdai, mclk);
if (ret < 0)
- return ret;
+ goto end;
}
for_each_prop_dai_cpu(props, i, pdai) {
- ret = simple_set_clk_rate(rtd->dev, pdai, mclk);
+ ret = simple_set_clk_rate(priv, pdai, mclk);
if (ret < 0)
- return ret;
+ goto end;
}
/* Ensure sysclk is set on all components in case any
@@ -479,37 +498,40 @@ int simple_util_hw_params(struct snd_pcm_substream *substream,
ret = snd_soc_component_set_sysclk(component, 0, 0,
mclk, SND_SOC_CLOCK_IN);
if (ret && ret != -ENOTSUPP)
- return ret;
+ goto end;
}
for_each_rtd_codec_dais(rtd, i, sdai) {
- ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_IN);
+ pdai = simple_props_to_dai_codec(props, i);
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
if (ret && ret != -ENOTSUPP)
- return ret;
+ goto end;
}
for_each_rtd_cpu_dais(rtd, i, sdai) {
- ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, SND_SOC_CLOCK_OUT);
+ pdai = simple_props_to_dai_cpu(props, i);
+ ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction);
if (ret && ret != -ENOTSUPP)
- return ret;
+ goto end;
}
}
for_each_prop_dai_codec(props, i, pdai) {
sdai = snd_soc_rtd_to_codec(rtd, i);
- ret = simple_set_tdm(sdai, pdai, params);
+ ret = simple_set_tdm(priv, sdai, pdai, params);
if (ret < 0)
- return ret;
+ goto end;
}
for_each_prop_dai_cpu(props, i, pdai) {
sdai = snd_soc_rtd_to_cpu(rtd, i);
- ret = simple_set_tdm(sdai, pdai, params);
+ ret = simple_set_tdm(priv, sdai, pdai, params);
if (ret < 0)
- return ret;
+ goto end;
}
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(simple_util_hw_params);
@@ -517,7 +539,7 @@ int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *dai_props = simple_priv_to_props(priv, rtd->id);
+ struct simple_dai_props *dai_props = runtime_simple_priv_to_props(priv, rtd);
struct simple_util_data *data = &dai_props->adata;
struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
@@ -537,7 +559,8 @@ int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
}
EXPORT_SYMBOL_GPL(simple_util_be_hw_params_fixup);
-static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simple_dai)
+static int simple_init_dai(struct simple_util_priv *priv,
+ struct snd_soc_dai *dai, struct simple_util_dai *simple_dai)
{
int ret;
@@ -549,7 +572,7 @@ static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simp
simple_dai->clk_direction);
if (ret && ret != -ENOTSUPP) {
dev_err(dai->dev, "simple-card: set_sysclk error\n");
- return ret;
+ goto end;
}
}
@@ -561,11 +584,12 @@ static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simp
simple_dai->slot_width);
if (ret && ret != -ENOTSUPP) {
dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
- return ret;
+ goto end;
}
}
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
static inline int simple_component_is_codec(struct snd_soc_component *component)
@@ -573,7 +597,8 @@ static inline int simple_component_is_codec(struct snd_soc_component *component)
return component->driver->endianness;
}
-static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
+static int simple_init_for_codec2codec(struct simple_util_priv *priv,
+ struct snd_soc_pcm_runtime *rtd,
struct simple_dai_props *dai_props)
{
struct snd_soc_dai_link *dai_link = rtd->dai_link;
@@ -605,12 +630,13 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
if (ret < 0) {
dev_err(rtd->dev, "simple-card: no valid dai_link params\n");
- return ret;
+ goto end;
}
+ ret = -ENOMEM;
c2c_params = devm_kzalloc(rtd->dev, sizeof(*c2c_params), GFP_KERNEL);
if (!c2c_params)
- return -ENOMEM;
+ goto end;
c2c_params->formats = hw.formats;
c2c_params->rates = hw.rates;
@@ -622,32 +648,32 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd,
dai_link->c2c_params = c2c_params;
dai_link->num_c2c_params = 1;
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd)
{
struct simple_util_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- struct simple_dai_props *props = simple_priv_to_props(priv, rtd->id);
+ struct simple_dai_props *props = runtime_simple_priv_to_props(priv, rtd);
struct simple_util_dai *dai;
int i, ret;
for_each_prop_dai_codec(props, i, dai) {
- ret = simple_init_dai(snd_soc_rtd_to_codec(rtd, i), dai);
+ ret = simple_init_dai(priv, snd_soc_rtd_to_codec(rtd, i), dai);
if (ret < 0)
- return ret;
+ goto end;
}
for_each_prop_dai_cpu(props, i, dai) {
- ret = simple_init_dai(snd_soc_rtd_to_cpu(rtd, i), dai);
+ ret = simple_init_dai(priv, snd_soc_rtd_to_cpu(rtd, i), dai);
if (ret < 0)
- return ret;
+ goto end;
}
- ret = simple_init_for_codec2codec(rtd, props);
- if (ret < 0)
- return ret;
-
- return 0;
+ ret = simple_init_for_codec2codec(priv, rtd, props);
+end:
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(simple_util_dai_init);
@@ -713,7 +739,7 @@ int simple_util_parse_routing(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
- if (!of_property_read_bool(node, prop))
+ if (!of_property_present(node, prop))
return 0;
return snd_soc_of_parse_audio_routing(card, prop);
@@ -731,7 +757,7 @@ int simple_util_parse_widgets(struct snd_soc_card *card,
snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
- if (of_property_read_bool(node, prop))
+ if (of_property_present(node, prop))
return snd_soc_of_parse_audio_simple_widgets(card, prop);
/* no widgets is not error */
@@ -832,7 +858,7 @@ int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix)
priv->aux_jacks = devm_kcalloc(card->dev, num,
sizeof(struct snd_soc_jack), GFP_KERNEL);
if (!priv->aux_jacks)
- return -ENOMEM;
+ return simple_ret(priv, -ENOMEM);
for_each_card_auxs(card, component) {
char id[128];
@@ -993,48 +1019,37 @@ int graph_util_card_probe(struct snd_soc_card *card)
ret = simple_util_init_hp(card, &priv->hp_jack, NULL);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_init_mic(card, &priv->mic_jack, NULL);
- if (ret < 0)
- return ret;
-
- return 0;
+end:
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(graph_util_card_probe);
int graph_util_is_ports0(struct device_node *np)
{
- struct device_node *port, *ports, *ports0, *top;
- int ret;
+ struct device_node *parent __free(device_node) = of_get_parent(np);
+ struct device_node *port;
/* np is "endpoint" or "port" */
- if (of_node_name_eq(np, "endpoint")) {
- port = of_get_parent(np);
- } else {
+ if (of_node_name_eq(np, "endpoint"))
+ port = parent;
+ else
port = np;
- of_node_get(port);
- }
-
- ports = of_get_parent(port);
- top = of_get_parent(ports);
- ports0 = of_get_child_by_name(top, "ports");
-
- ret = ports0 == ports;
- of_node_put(port);
- of_node_put(ports);
- of_node_put(ports0);
- of_node_put(top);
+ struct device_node *ports __free(device_node) = of_get_parent(port);
+ struct device_node *top __free(device_node) = of_get_parent(ports);
+ struct device_node *ports0 __free(device_node) = of_get_child_by_name(top, "ports");
- return ret;
+ return ports0 == ports;
}
EXPORT_SYMBOL_GPL(graph_util_is_ports0);
static int graph_get_dai_id(struct device_node *ep)
{
- struct device_node *node;
- struct device_node *endpoint;
+ struct device_node *node __free(device_node) = of_graph_get_port_parent(ep);
+ struct device_node *port __free(device_node) = of_get_parent(ep);
struct of_endpoint info;
int i, id;
int ret;
@@ -1053,16 +1068,16 @@ static int graph_get_dai_id(struct device_node *ep)
* only of_graph_parse_endpoint().
* We need to check "reg" property
*/
- if (of_property_present(ep, "reg"))
- return info.id;
- node = of_get_parent(ep);
- ret = of_property_present(node, "reg");
- of_node_put(node);
+ /* check port first */
+ ret = of_property_present(port, "reg");
if (ret)
return info.port;
+
+ /* check endpoint 2nd as backup */
+ if (of_property_present(ep, "reg"))
+ return info.id;
}
- node = of_graph_get_port_parent(ep);
/*
* Non HDMI sound case, counting port/endpoint on its DT
@@ -1070,23 +1085,24 @@ static int graph_get_dai_id(struct device_node *ep)
*/
i = 0;
id = -1;
- for_each_endpoint_of_node(node, endpoint) {
- if (endpoint == ep)
+ for_each_of_graph_port(node, p) {
+ if (port == p) {
id = i;
+ break;
+ }
i++;
}
- of_node_put(node);
-
if (id < 0)
return -ENODEV;
return id;
}
-int graph_util_parse_dai(struct device *dev, struct device_node *ep,
+int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep,
struct snd_soc_dai_link_component *dlc, int *is_single_link)
{
+ struct device *dev = simple_priv_to_dev(priv);
struct device_node *node;
struct of_phandle_args args = {};
struct snd_soc_dai *dai;
@@ -1103,10 +1119,12 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep,
args.np = ep;
dai = snd_soc_get_dai_via_args(&args);
if (dai) {
+ ret = -ENOMEM;
+ dlc->of_node = node;
dlc->dai_name = snd_soc_dai_name_get(dai);
dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
if (!dlc->dai_args)
- return -ENOMEM;
+ goto end;
goto parse_dai_end;
}
@@ -1138,14 +1156,15 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep,
ret = snd_soc_get_dlc(&args, dlc);
if (ret < 0) {
of_node_put(node);
- return ret;
+ goto end;
}
parse_dai_end:
if (is_single_link)
*is_single_link = of_graph_get_endpoint_count(node) == 1;
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
EXPORT_SYMBOL_GPL(graph_util_parse_dai);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 76a1d05e2ebe..5af6d1b308f2 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -29,7 +29,16 @@ static const struct snd_soc_ops simple_ops = {
.hw_params = simple_util_hw_params,
};
-static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_link_component *dlc)
+#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret)
+static inline int _simple_ret(struct simple_util_priv *priv,
+ const char *func, int ret)
+{
+ return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
+}
+
+static int simple_parse_platform(struct simple_util_priv *priv,
+ struct device_node *node,
+ struct snd_soc_dai_link_component *dlc)
{
struct of_phandle_args args;
int ret;
@@ -43,7 +52,7 @@ static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_li
*/
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
if (ret)
- return ret;
+ return simple_ret(priv, ret);
/* dai_name is not required and may not exist for plat component */
@@ -52,11 +61,12 @@ static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_li
return 0;
}
-static int simple_parse_dai(struct device *dev,
+static int simple_parse_dai(struct simple_util_priv *priv,
struct device_node *node,
struct snd_soc_dai_link_component *dlc,
int *is_single_link)
{
+ struct device *dev = simple_priv_to_dev(priv);
struct of_phandle_args args;
struct snd_soc_dai *dai;
int ret;
@@ -70,17 +80,18 @@ static int simple_parse_dai(struct device *dev,
*/
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
if (ret)
- return ret;
+ goto end;
/*
* Try to find from DAI args
*/
dai = snd_soc_get_dai_via_args(&args);
if (dai) {
+ ret = -ENOMEM;
dlc->dai_name = snd_soc_dai_name_get(dai);
dlc->dai_args = snd_soc_copy_dai_args(dev, &args);
if (!dlc->dai_args)
- return -ENOMEM;
+ goto end;
goto parse_dai_end;
}
@@ -106,13 +117,14 @@ static int simple_parse_dai(struct device *dev,
*/
ret = snd_soc_get_dlc(&args, dlc);
if (ret < 0)
- return ret;
+ goto end;
parse_dai_end:
if (is_single_link)
*is_single_link = !args.args_count;
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
static void simple_parse_convert(struct device *dev,
@@ -120,14 +132,12 @@ static void simple_parse_convert(struct device *dev,
struct simple_util_data *adata)
{
struct device_node *top = dev->of_node;
- struct device_node *node = of_get_parent(np);
+ struct device_node *node __free(device_node) = of_get_parent(np);
simple_util_parse_convert(top, PREFIX, adata);
simple_util_parse_convert(node, PREFIX, adata);
simple_util_parse_convert(node, NULL, adata);
simple_util_parse_convert(np, NULL, adata);
-
- of_node_put(node);
}
static int simple_parse_node(struct simple_util_priv *priv,
@@ -151,19 +161,17 @@ static int simple_parse_node(struct simple_util_priv *priv,
dai = simple_props_to_dai_codec(dai_props, 0);
}
- ret = simple_parse_dai(dev, np, dlc, cpu);
+ ret = simple_parse_dai(priv, np, dlc, cpu);
if (ret)
- return ret;
+ goto end;
ret = simple_util_parse_clk(dev, np, dai, dlc);
if (ret)
- return ret;
+ goto end;
ret = simple_util_parse_tdm(np, dai);
- if (ret)
- return ret;
-
- return 0;
+end:
+ return simple_ret(priv, ret);
}
static int simple_link_init(struct simple_util_priv *priv,
@@ -176,7 +184,7 @@ static int simple_link_init(struct simple_util_priv *priv,
struct device_node *top = dev->of_node;
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
- struct device_node *node = of_get_parent(cpu);
+ struct device_node *node __free(device_node) = of_get_parent(cpu);
enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT;
bool playback_only = 0, capture_only = 0;
@@ -185,7 +193,7 @@ static int simple_link_init(struct simple_util_priv *priv,
ret = simple_util_parse_daifmt(dev, node, codec,
prefix, &dai_link->dai_fmt);
if (ret < 0)
- goto init_end;
+ goto end;
graph_util_parse_link_direction(top, &playback_only, &capture_only);
graph_util_parse_link_direction(node, &playback_only, &capture_only);
@@ -215,11 +223,9 @@ static int simple_link_init(struct simple_util_priv *priv,
dai_link->init = simple_util_dai_init;
dai_link->ops = &simple_ops;
- ret = simple_util_set_dailink_name(dev, dai_link, name);
-init_end:
- of_node_put(node);
-
- return ret;
+ ret = simple_util_set_dailink_name(priv, dai_link, name);
+end:
+ return simple_ret(priv, ret);
}
static int simple_dai_link_of_dpcm(struct simple_util_priv *priv,
@@ -232,7 +238,7 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv,
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
struct device_node *top = dev->of_node;
- struct device_node *node = of_get_parent(np);
+ struct device_node *node __free(device_node) = of_get_parent(np);
char *prefix = "";
char dai_name[64];
int ret;
@@ -296,8 +302,7 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv,
out_put_node:
li->link++;
- of_node_put(node);
- return ret;
+ return simple_ret(priv, ret);
}
static int simple_dai_link_of(struct simple_util_priv *priv,
@@ -312,15 +317,13 @@ static int simple_dai_link_of(struct simple_util_priv *priv,
struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, 0);
struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, 0);
struct device_node *cpu = NULL;
- struct device_node *node = NULL;
- struct device_node *plat = NULL;
char dai_name[64];
char prop[128];
char *prefix = "";
int ret, single_cpu = 0;
cpu = np;
- node = of_get_parent(np);
+ struct device_node *node __free(device_node) = of_get_parent(np);
dev_dbg(dev, "link_of (%pOF)\n", node);
@@ -329,7 +332,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv,
prefix = PREFIX;
snprintf(prop, sizeof(prop), "%splat", prefix);
- plat = of_get_child_by_name(node, prop);
+ struct device_node *plat __free(device_node) = of_get_child_by_name(node, prop);
ret = simple_parse_node(priv, cpu, li, prefix, &single_cpu);
if (ret < 0)
@@ -339,7 +342,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv,
if (ret < 0)
goto dai_link_of_err;
- ret = simple_parse_platform(plat, platforms);
+ ret = simple_parse_platform(priv, plat, platforms);
if (ret < 0)
goto dai_link_of_err;
@@ -352,12 +355,9 @@ static int simple_dai_link_of(struct simple_util_priv *priv,
ret = simple_link_init(priv, cpu, codec, li, prefix, dai_name);
dai_link_of_err:
- of_node_put(plat);
- of_node_put(node);
-
li->link++;
- return ret;
+ return simple_ret(priv, ret);
}
static int __simple_for_each_link(struct simple_util_priv *priv,
@@ -374,7 +374,6 @@ static int __simple_for_each_link(struct simple_util_priv *priv,
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct device_node *node;
- struct device_node *add_devs;
uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
bool is_top = 0;
int ret = 0;
@@ -386,14 +385,11 @@ static int __simple_for_each_link(struct simple_util_priv *priv,
is_top = 1;
}
- add_devs = of_get_child_by_name(top, PREFIX "additional-devs");
+ struct device_node *add_devs __free(device_node) = of_get_child_by_name(top, PREFIX "additional-devs");
/* loop for all dai-link */
do {
struct simple_util_data adata;
- struct device_node *codec;
- struct device_node *plat;
- struct device_node *np;
int num = of_get_child_count(node);
/* Skip additional-devs node */
@@ -403,26 +399,26 @@ static int __simple_for_each_link(struct simple_util_priv *priv,
}
/* get codec */
- codec = of_get_child_by_name(node, is_top ?
- PREFIX "codec" : "codec");
+ struct device_node *codec __free(device_node) =
+ of_get_child_by_name(node, is_top ? PREFIX "codec" : "codec");
if (!codec) {
ret = -ENODEV;
goto error;
}
/* get platform */
- plat = of_get_child_by_name(node, is_top ?
- PREFIX "plat" : "plat");
+ struct device_node *plat __free(device_node) =
+ of_get_child_by_name(node, is_top ? PREFIX "plat" : "plat");
/* get convert-xxx property */
memset(&adata, 0, sizeof(adata));
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
if (np == add_devs)
continue;
simple_parse_convert(dev, np, &adata);
}
/* loop for all CPU/Codec node */
- for_each_child_of_node(node, np) {
+ for_each_child_of_node_scoped(node, np) {
if (plat == np || add_devs == np)
continue;
/*
@@ -452,23 +448,17 @@ static int __simple_for_each_link(struct simple_util_priv *priv,
ret = func_noml(priv, np, codec, li, is_top);
}
- if (ret < 0) {
- of_node_put(codec);
- of_node_put(plat);
- of_node_put(np);
+ if (ret < 0)
goto error;
- }
}
- of_node_put(codec);
- of_node_put(plat);
node = of_get_next_child(top, node);
} while (!is_top && node);
- error:
- of_node_put(add_devs);
+error:
of_node_put(node);
- return ret;
+
+ return simple_ret(priv, ret);
}
static int simple_for_each_link(struct simple_util_priv *priv,
@@ -501,7 +491,7 @@ static int simple_for_each_link(struct simple_util_priv *priv,
break;
}
- return ret;
+ return simple_ret(priv, ret);
}
static void simple_depopulate_aux(void *data)
@@ -514,19 +504,19 @@ static void simple_depopulate_aux(void *data)
static int simple_populate_aux(struct simple_util_priv *priv)
{
struct device *dev = simple_priv_to_dev(priv);
- struct device_node *node;
+ struct device_node *node __free(device_node) = of_get_child_by_name(dev->of_node, PREFIX "additional-devs");
int ret;
- node = of_get_child_by_name(dev->of_node, PREFIX "additional-devs");
if (!node)
return 0;
ret = of_platform_populate(node, NULL, NULL, dev);
- of_node_put(node);
if (ret)
- return ret;
+ goto end;
- return devm_add_action_or_reset(dev, simple_depopulate_aux, priv);
+ ret = devm_add_action_or_reset(dev, simple_depopulate_aux, priv);
+end:
+ return simple_ret(priv, ret);
}
static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li)
@@ -536,15 +526,15 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li)
ret = simple_util_parse_widgets(card, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_routing(card, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_parse_pin_switches(card, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
/* Single/Muti DAI link(s) & New style of DT node */
memset(li, 0, sizeof(*li));
@@ -552,19 +542,19 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li)
simple_dai_link_of,
simple_dai_link_of_dpcm);
if (ret < 0)
- return ret;
+ goto end;
- ret = simple_util_parse_card_name(card, PREFIX);
+ ret = simple_util_parse_card_name(priv, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_populate_aux(priv);
if (ret < 0)
- return ret;
+ goto end;
ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs");
-
- return ret;
+end:
+ return simple_ret(priv, ret);
}
static int simple_count_noml(struct simple_util_priv *priv,
@@ -572,12 +562,10 @@ static int simple_count_noml(struct simple_util_priv *priv,
struct device_node *codec,
struct link_info *li, bool is_top)
{
- if (li->link >= SNDRV_MAX_LINKS) {
- struct device *dev = simple_priv_to_dev(priv);
+ int ret = -EINVAL;
- dev_err(dev, "too many links\n");
- return -EINVAL;
- }
+ if (li->link >= SNDRV_MAX_LINKS)
+ goto end;
/*
* DON'T REMOVE platforms
@@ -599,8 +587,9 @@ static int simple_count_noml(struct simple_util_priv *priv,
li->num[li->link].codecs = 1;
li->link += 1;
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
static int simple_count_dpcm(struct simple_util_priv *priv,
@@ -608,12 +597,10 @@ static int simple_count_dpcm(struct simple_util_priv *priv,
struct device_node *codec,
struct link_info *li, bool is_top)
{
- if (li->link >= SNDRV_MAX_LINKS) {
- struct device *dev = simple_priv_to_dev(priv);
+ int ret = -EINVAL;
- dev_err(dev, "too many links\n");
- return -EINVAL;
- }
+ if (li->link >= SNDRV_MAX_LINKS)
+ goto end;
if (li->cpu) {
/*
@@ -630,8 +617,9 @@ static int simple_count_dpcm(struct simple_util_priv *priv,
li->link++; /* dummy-Codec */
}
-
- return 0;
+ ret = 0;
+end:
+ return simple_ret(priv, ret);
}
static int simple_get_dais_count(struct simple_util_priv *priv,
@@ -707,17 +695,15 @@ static int simple_soc_probe(struct snd_soc_card *card)
ret = simple_util_init_hp(card, &priv->hp_jack, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_init_mic(card, &priv->mic_jack, PREFIX);
if (ret < 0)
- return ret;
+ goto end;
ret = simple_util_init_aux_jacks(priv, PREFIX);
- if (ret < 0)
- return ret;
-
- return 0;
+end:
+ return simple_ret(priv, ret);
}
static int simple_probe(struct platform_device *pdev)
@@ -739,20 +725,22 @@ static int simple_probe(struct platform_device *pdev)
card->probe = simple_soc_probe;
card->driver_name = "simple-card";
+ ret = -ENOMEM;
struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
if (!li)
- return -ENOMEM;
+ goto end;
ret = simple_get_dais_count(priv, li);
if (ret < 0)
- return ret;
+ goto end;
+ ret = -EINVAL;
if (!li->link)
- return -EINVAL;
+ goto end;
ret = simple_util_init_priv(priv, li);
if (ret < 0)
- return ret;
+ goto end;
if (np && of_device_is_available(np)) {
@@ -819,8 +807,8 @@ static int simple_probe(struct platform_device *pdev)
return 0;
err:
simple_util_clean_reference(card);
-
- return ret;
+end:
+ return dev_err_probe(dev, ret, "parse error\n");
}
static const struct of_device_id simple_of_match[] = {
diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c
index 6a988976fb0d..98d2ab68883a 100644
--- a/sound/soc/img/img-i2s-in.c
+++ b/sound/soc/img/img-i2s-in.c
@@ -539,7 +539,6 @@ static void img_i2s_in_dev_remove(struct platform_device *pdev)
img_i2s_in_runtime_suspend(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int img_i2s_in_suspend(struct device *dev)
{
struct img_i2s_in *i2s = dev_get_drvdata(dev);
@@ -586,7 +585,6 @@ static int img_i2s_in_resume(struct device *dev)
return 0;
}
-#endif
static const struct of_device_id img_i2s_in_of_match[] = {
{ .compatible = "img,i2s-in" },
@@ -595,16 +593,15 @@ static const struct of_device_id img_i2s_in_of_match[] = {
MODULE_DEVICE_TABLE(of, img_i2s_in_of_match);
static const struct dev_pm_ops img_i2s_in_pm_ops = {
- SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend,
- img_i2s_in_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume)
+ RUNTIME_PM_OPS(img_i2s_in_runtime_suspend, img_i2s_in_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume)
};
static struct platform_driver img_i2s_in_driver = {
.driver = {
.name = "img-i2s-in",
.of_match_table = img_i2s_in_of_match,
- .pm = &img_i2s_in_pm_ops
+ .pm = pm_ptr(&img_i2s_in_pm_ops)
},
.probe = img_i2s_in_probe,
.remove = img_i2s_in_dev_remove
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 1211e6184d97..aedcf56a5359 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -539,7 +539,6 @@ static void img_i2s_out_dev_remove(struct platform_device *pdev)
img_i2s_out_runtime_suspend(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int img_i2s_out_suspend(struct device *dev)
{
struct img_i2s_out *i2s = dev_get_drvdata(dev);
@@ -586,7 +585,6 @@ static int img_i2s_out_resume(struct device *dev)
return 0;
}
-#endif
static const struct of_device_id img_i2s_out_of_match[] = {
{ .compatible = "img,i2s-out" },
@@ -595,16 +593,15 @@ static const struct of_device_id img_i2s_out_of_match[] = {
MODULE_DEVICE_TABLE(of, img_i2s_out_of_match);
static const struct dev_pm_ops img_i2s_out_pm_ops = {
- SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend,
- img_i2s_out_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume)
+ RUNTIME_PM_OPS(img_i2s_out_runtime_suspend, img_i2s_out_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume)
};
static struct platform_driver img_i2s_out_driver = {
.driver = {
.name = "img-i2s-out",
.of_match_table = img_i2s_out_of_match,
- .pm = &img_i2s_out_pm_ops
+ .pm = pm_ptr(&img_i2s_out_pm_ops)
},
.probe = img_i2s_out_probe,
.remove = img_i2s_out_dev_remove
diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c
index 4ec63119d67c..86b60e6dab38 100644
--- a/sound/soc/img/img-parallel-out.c
+++ b/sound/soc/img/img-parallel-out.c
@@ -300,15 +300,14 @@ static const struct of_device_id img_prl_out_of_match[] = {
MODULE_DEVICE_TABLE(of, img_prl_out_of_match);
static const struct dev_pm_ops img_prl_out_pm_ops = {
- SET_RUNTIME_PM_OPS(img_prl_out_suspend,
- img_prl_out_resume, NULL)
+ RUNTIME_PM_OPS(img_prl_out_suspend, img_prl_out_resume, NULL)
};
static struct platform_driver img_prl_out_driver = {
.driver = {
.name = "img-parallel-out",
.of_match_table = img_prl_out_of_match,
- .pm = &img_prl_out_pm_ops
+ .pm = pm_ptr(&img_prl_out_pm_ops)
},
.probe = img_prl_out_probe,
.remove = img_prl_out_dev_remove
diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c
index 3c513f5b8c54..82295e2508fa 100644
--- a/sound/soc/img/img-spdif-in.c
+++ b/sound/soc/img/img-spdif-in.c
@@ -817,7 +817,6 @@ static void img_spdif_in_dev_remove(struct platform_device *pdev)
img_spdif_in_runtime_suspend(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int img_spdif_in_suspend(struct device *dev)
{
struct img_spdif_in *spdif = dev_get_drvdata(dev);
@@ -857,7 +856,6 @@ static int img_spdif_in_resume(struct device *dev)
return 0;
}
-#endif
static const struct of_device_id img_spdif_in_of_match[] = {
{ .compatible = "img,spdif-in" },
@@ -866,16 +864,15 @@ static const struct of_device_id img_spdif_in_of_match[] = {
MODULE_DEVICE_TABLE(of, img_spdif_in_of_match);
static const struct dev_pm_ops img_spdif_in_pm_ops = {
- SET_RUNTIME_PM_OPS(img_spdif_in_runtime_suspend,
- img_spdif_in_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume)
+ RUNTIME_PM_OPS(img_spdif_in_runtime_suspend, img_spdif_in_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume)
};
static struct platform_driver img_spdif_in_driver = {
.driver = {
.name = "img-spdif-in",
.of_match_table = img_spdif_in_of_match,
- .pm = &img_spdif_in_pm_ops
+ .pm = pm_ptr(&img_spdif_in_pm_ops)
},
.probe = img_spdif_in_probe,
.remove = img_spdif_in_dev_remove
diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c
index 402695b5fc41..52f696219ef4 100644
--- a/sound/soc/img/img-spdif-out.c
+++ b/sound/soc/img/img-spdif-out.c
@@ -409,7 +409,6 @@ static void img_spdif_out_dev_remove(struct platform_device *pdev)
img_spdif_out_runtime_suspend(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int img_spdif_out_suspend(struct device *dev)
{
struct img_spdif_out *spdif = dev_get_drvdata(dev);
@@ -448,7 +447,7 @@ static int img_spdif_out_resume(struct device *dev)
return 0;
}
-#endif
+
static const struct of_device_id img_spdif_out_of_match[] = {
{ .compatible = "img,spdif-out" },
{}
@@ -456,16 +455,15 @@ static const struct of_device_id img_spdif_out_of_match[] = {
MODULE_DEVICE_TABLE(of, img_spdif_out_of_match);
static const struct dev_pm_ops img_spdif_out_pm_ops = {
- SET_RUNTIME_PM_OPS(img_spdif_out_runtime_suspend,
- img_spdif_out_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(img_spdif_out_suspend, img_spdif_out_resume)
+ RUNTIME_PM_OPS(img_spdif_out_runtime_suspend, img_spdif_out_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(img_spdif_out_suspend, img_spdif_out_resume)
};
static struct platform_driver img_spdif_out_driver = {
.driver = {
.name = "img-spdif-out",
.of_match_table = img_spdif_out_of_match,
- .pm = &img_spdif_out_pm_ops
+ .pm = pm_ptr(&img_spdif_out_pm_ops)
},
.probe = img_spdif_out_probe,
.remove = img_spdif_out_dev_remove
diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c
index fdeceb271e7f..ec4f891295c9 100644
--- a/sound/soc/img/pistachio-internal-dac.c
+++ b/sound/soc/img/pistachio-internal-dac.c
@@ -224,7 +224,6 @@ static void pistachio_internal_dac_remove(struct platform_device *pdev)
regulator_disable(dac->supply);
}
-#ifdef CONFIG_PM
static int pistachio_internal_dac_rt_resume(struct device *dev)
{
struct pistachio_internal_dac *dac = dev_get_drvdata(dev);
@@ -251,11 +250,10 @@ static int pistachio_internal_dac_rt_suspend(struct device *dev)
return 0;
}
-#endif
static const struct dev_pm_ops pistachio_internal_dac_pm_ops = {
- SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
- pistachio_internal_dac_rt_resume, NULL)
+ RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend,
+ pistachio_internal_dac_rt_resume, NULL)
};
static const struct of_device_id pistachio_internal_dac_of_match[] = {
@@ -268,7 +266,7 @@ static struct platform_driver pistachio_internal_dac_plat_driver = {
.driver = {
.name = "img-pistachio-internal-dac",
.of_match_table = pistachio_internal_dac_of_match,
- .pm = &pistachio_internal_dac_pm_ops
+ .pm = pm_ptr(&pistachio_internal_dac_pm_ops)
},
.probe = pistachio_internal_dac_probe,
.remove = pistachio_internal_dac_remove
diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c
index 27516ef57185..3dccf0a57a3a 100644
--- a/sound/soc/intel/avs/apl.c
+++ b/sound/soc/intel/avs/apl.c
@@ -12,6 +12,7 @@
#include "avs.h"
#include "messages.h"
#include "path.h"
+#include "registers.h"
#include "topology.h"
static irqreturn_t avs_apl_dsp_interrupt(struct avs_dev *adev)
@@ -125,7 +126,7 @@ int avs_apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg)
struct avs_apl_log_buffer_layout layout;
void __iomem *addr, *buf;
size_t dump_size;
- u16 offset = 0;
+ u32 offset = 0;
u8 *dump, *pos;
dump_size = AVS_FW_REGS_SIZE + msg->ext.coredump.stack_dump_size;
diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h
index eca6ec0428bb..585543f872fc 100644
--- a/sound/soc/intel/avs/avs.h
+++ b/sound/soc/intel/avs/avs.h
@@ -51,6 +51,7 @@ struct avs_dsp_ops {
int (* const load_basefw)(struct avs_dev *, struct firmware *);
int (* const load_lib)(struct avs_dev *, struct firmware *, u32);
int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32);
+ int (* const config_basefw)(struct avs_dev *);
int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long,
u32 *);
int (* const log_buffer_offset)(struct avs_dev *, u32);
diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c
index 0266edeafc19..2d706edcbf92 100644
--- a/sound/soc/intel/avs/board_selection.c
+++ b/sound/soc/intel/avs/board_selection.c
@@ -312,6 +312,18 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {
{},
};
+static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = {
+ {
+ .id = "PCM3168A",
+ .drv_name = "avs_pcm3168a",
+ .mach_params = {
+ .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2),
+ },
+ .tplg_filename = "pcm3168a-tplg.bin",
+ },
+ {}
+};
+
static struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
{
.drv_name = "avs_i2s_test",
@@ -378,10 +390,11 @@ static const struct avs_acpi_boards i2s_boards[] = {
AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines),
AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines),
AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines),
+ AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines),
AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines),
AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines),
- AVS_MACH_ENTRY(HDA_RPL_M, avs_tgl_i2s_machines),
- {},
+ AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines),
+ {}
};
static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig
index 00b0f6c176d6..ba4bee42124c 100644
--- a/sound/soc/intel/avs/boards/Kconfig
+++ b/sound/soc/intel/avs/boards/Kconfig
@@ -87,6 +87,16 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825
Say Y or m if you have such a device. This is a recommended option.
If unsure select "N".
+config SND_SOC_INTEL_AVS_MACH_PCM3168A
+ tristate "pcm3168a I2S board"
+ depends on I2C
+ depends on MFD_INTEL_LPSS || COMPILE_TEST
+ select SND_SOC_PCM3168A_I2C
+ help
+ This adds support for AVS with PCM3168A I2C codec configuration.
+ Say Y or m if you have such a device. This is a recommended option.
+ If unsure select "N".
+
config SND_SOC_INTEL_AVS_MACH_PROBE
tristate "Probing (data) board"
depends on DEBUG_FS
diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile
index 4fbd936ffb3e..a95256b94dc8 100644
--- a/sound/soc/intel/avs/boards/Makefile
+++ b/sound/soc/intel/avs/boards/Makefile
@@ -9,6 +9,7 @@ snd-soc-avs-max98927-y := max98927.o
snd-soc-avs-max98357a-y := max98357a.o
snd-soc-avs-max98373-y := max98373.o
snd-soc-avs-nau8825-y := nau8825.o
+snd-soc-avs-pcm3168a-y := pcm3168a.o
snd-soc-avs-probe-y := probe.o
snd-soc-avs-rt274-y := rt274.o
snd-soc-avs-rt286-y := rt286.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o
+obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PCM3168A) += snd-soc-avs-pcm3168a.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o
obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o
diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c
index 76078a7005b0..7217ae51e89c 100644
--- a/sound/soc/intel/avs/boards/da7219.c
+++ b/sound/soc/intel/avs/boards/da7219.c
@@ -113,7 +113,8 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime)
}
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -197,7 +198,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->be_hw_params_fixup = avs_da7219_be_fixup;
dl->init = avs_da7219_codec_init;
dl->exit = avs_da7219_codec_exit;
diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c
index 426ce37105ae..6f3c4f6c9302 100644
--- a/sound/soc/intel/avs/boards/es8336.c
+++ b/sound/soc/intel/avs/boards/es8336.c
@@ -109,7 +109,8 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime)
data = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c
index 6570209c1a63..c55c1d60b777 100644
--- a/sound/soc/intel/avs/boards/max98357a.c
+++ b/sound/soc/intel/avs/boards/max98357a.c
@@ -78,7 +78,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->be_hw_params_fixup = avs_max98357a_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c
index 6f25e66344b7..970f82bf4ce8 100644
--- a/sound/soc/intel/avs/boards/max98373.c
+++ b/sound/soc/intel/avs/boards/max98373.c
@@ -111,7 +111,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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);
- dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c
index ad18c4e9a670..e4ce553bf1d6 100644
--- a/sound/soc/intel/avs/boards/max98927.c
+++ b/sound/soc/intel/avs/boards/max98927.c
@@ -108,7 +108,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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);
- dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
@@ -127,7 +127,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->be_hw_params_fixup = avs_max98927_be_fixup;
dl->nonatomic = 1;
dl->no_pcm = 1;
diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c
index bf902540744c..e203ceb83b87 100644
--- a/sound/soc/intel/avs/boards/nau8825.c
+++ b/sound/soc/intel/avs/boards/nau8825.c
@@ -88,7 +88,8 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -203,7 +204,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_nau8825_codec_init;
dl->exit = avs_nau8825_codec_exit;
dl->be_hw_params_fixup = avs_nau8825_be_fixup;
diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c
new file mode 100644
index 000000000000..5d0e7a5bdc74
--- /dev/null
+++ b/sound/soc/intel/avs/boards/pcm3168a.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright(c) 2024-2025 Intel Corporation
+//
+// Author: Cezary Rojewski <cezary.rojewski@intel.com>
+//
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+static const struct snd_soc_dapm_widget card_widgets[] = {
+ SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL),
+ SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL),
+ SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL),
+ SND_SOC_DAPM_LINE("CPB Line Out", NULL),
+ SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL),
+ SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL),
+ SND_SOC_DAPM_LINE("CPB Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route card_routes[] = {
+ { "CPB Stereo HP 1", NULL, "AOUT1L" },
+ { "CPB Stereo HP 1", NULL, "AOUT1R" },
+ { "CPB Stereo HP 2", NULL, "AOUT2L" },
+ { "CPB Stereo HP 2", NULL, "AOUT2R" },
+ { "CPB Stereo HP 3", NULL, "AOUT3L" },
+ { "CPB Stereo HP 3", NULL, "AOUT3R" },
+ { "CPB Line Out", NULL, "AOUT4L" },
+ { "CPB Line Out", NULL, "AOUT4R" },
+
+ { "AIN1L", NULL, "CPB Stereo Mic 1" },
+ { "AIN1R", NULL, "CPB Stereo Mic 1" },
+ { "AIN2L", NULL, "CPB Stereo Mic 2" },
+ { "AIN2R", NULL, "CPB Stereo Mic 2" },
+ { "AIN3L", NULL, "CPB Line In" },
+ { "AIN3R", NULL, "CPB Line In" },
+};
+
+static int avs_pcm3168a_be_fixup(struct snd_soc_pcm_runtime *runtime,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+
+ /* Set SSP to 24 bit. */
+ snd_mask_none(fmt);
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE);
+
+ return 0;
+}
+
+SND_SOC_DAILINK_DEF(pcm3168a_dac,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-dac")));
+SND_SOC_DAILINK_DEF(pcm3168a_adc,
+ DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-adc")));
+SND_SOC_DAILINK_DEF(cpu_ssp0, DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin")));
+SND_SOC_DAILINK_DEF(cpu_ssp2, DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin")));
+
+static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links)
+{
+ struct snd_soc_dai_link_component *platform;
+ struct snd_soc_dai_link *dl;
+ const int num_dl = 2;
+
+ dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL);
+ platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
+ if (!dl || !platform)
+ return -ENOMEM;
+
+ platform->name = dev_name(dev);
+ dl[0].num_cpus = 1;
+ dl[0].num_codecs = 1;
+ dl[0].platforms = platform;
+ dl[0].num_platforms = 1;
+ dl[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ dl[0].be_hw_params_fixup = avs_pcm3168a_be_fixup;
+ dl[0].nonatomic = 1;
+ dl[0].no_pcm = 1;
+ memcpy(&dl[1], &dl[0], sizeof(*dl));
+
+ dl[0].name = "SSP0-Codec-dac";
+ dl[0].cpus = cpu_ssp0;
+ dl[0].codecs = pcm3168a_dac;
+ dl[1].name = "SSP2-Codec-adc";
+ dl[1].cpus = cpu_ssp2;
+ dl[1].codecs = pcm3168a_adc;
+
+ *links = dl;
+ *num_links = num_dl;
+ return 0;
+}
+
+static int avs_pcm3168a_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct snd_soc_card *card;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links);
+ if (ret)
+ return ret;
+
+ card->name = "avs_pcm3168a";
+ card->dev = dev;
+ card->owner = THIS_MODULE;
+ card->dapm_widgets = card_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(card_widgets);
+ card->dapm_routes = card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(card_routes);
+ card->fully_routed = true;
+
+ return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct platform_device_id avs_pcm3168a_driver_ids[] = {
+ {
+ .name = "avs_pcm3168a",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids);
+
+static struct platform_driver avs_pcm3168a_driver = {
+ .probe = avs_pcm3168a_probe,
+ .driver = {
+ .name = "avs_pcm3168a",
+ .pm = &snd_soc_pm_ops,
+ },
+ .id_table = avs_pcm3168a_driver_ids,
+};
+
+module_platform_driver(avs_pcm3168a_driver);
+
+MODULE_DESCRIPTION("Intel pcm3168a machine driver");
+MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c
index 4b6c02a40204..29977aee2153 100644
--- a/sound/soc/intel/avs/boards/rt274.c
+++ b/sound/soc/intel/avs/boards/rt274.c
@@ -98,7 +98,8 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -178,7 +179,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt274_codec_init;
dl->exit = avs_rt274_codec_exit;
dl->be_hw_params_fixup = avs_rt274_be_fixup;
diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c
index e40563ca99fd..6a27c6a9f394 100644
--- a/sound/soc/intel/avs/boards/rt286.c
+++ b/sound/soc/intel/avs/boards/rt286.c
@@ -59,7 +59,8 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -146,7 +147,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt286_codec_init;
dl->exit = avs_rt286_codec_exit;
dl->be_hw_params_fixup = avs_rt286_be_fixup;
diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c
index 94fce07c83f9..a7a463d6f852 100644
--- a/sound/soc/intel/avs/boards/rt298.c
+++ b/sound/soc/intel/avs/boards/rt298.c
@@ -70,7 +70,8 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
@@ -164,9 +165,9 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->num_platforms = 1;
dl->id = 0;
if (dmi_first_match(kblr_dmi_table))
- dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt298_codec_init;
dl->exit = avs_rt298_codec_exit;
dl->be_hw_params_fixup = avs_rt298_be_fixup;
diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c
index 30588d9e9ba3..d1c3e29a28ff 100644
--- a/sound/soc/intel/avs/boards/rt5514.c
+++ b/sound/soc/intel/avs/boards/rt5514.c
@@ -116,7 +116,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_rt5514_codec_init;
dl->be_hw_params_fixup = avs_rt5514_be_fixup;
dl->nonatomic = 1;
diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c
index b456b9d14665..e3310b3268ba 100644
--- a/sound/soc/intel/avs/boards/rt5663.c
+++ b/sound/soc/intel/avs/boards/rt5663.c
@@ -65,7 +65,8 @@ static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = &priv->jack;
num_pins = ARRAY_SIZE(card_headset_pins);
- pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins,
+ sizeof(card_headset_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c
index 335960cfd7ba..339df0b944c1 100644
--- a/sound/soc/intel/avs/boards/rt5682.c
+++ b/sound/soc/intel/avs/boards/rt5682.c
@@ -102,7 +102,8 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime)
jack = snd_soc_card_get_drvdata(card);
num_pins = ARRAY_SIZE(card_jack_pins);
- pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL);
+ pins = devm_kmemdup_array(card->dev, card_jack_pins, num_pins,
+ sizeof(card_jack_pins[0]), GFP_KERNEL);
if (!pins)
return -ENOMEM;
diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c
index cfef00462f66..7667790d5273 100644
--- a/sound/soc/intel/avs/boards/ssm4567.c
+++ b/sound/soc/intel/avs/boards/ssm4567.c
@@ -97,7 +97,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
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);
- dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL);
+ dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL);
if (!dl->name || !dl->cpus || !dl->codecs)
return -ENOMEM;
@@ -116,7 +116,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in
dl->platforms = platform;
dl->num_platforms = 1;
dl->id = 0;
- dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS;
+ dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC;
dl->init = avs_ssm4567_codec_init;
dl->be_hw_params_fixup = avs_ssm4567_be_fixup;
dl->nonatomic = 1;
diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c
index bd3c4bb8bf5a..03f8fb0dc187 100644
--- a/sound/soc/intel/avs/cnl.c
+++ b/sound/soc/intel/avs/cnl.c
@@ -9,6 +9,7 @@
#include <sound/hdaudio_ext.h>
#include "avs.h"
#include "messages.h"
+#include "registers.h"
static void avs_cnl_ipc_interrupt(struct avs_dev *adev)
{
diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c
index dc7dc45e0a0a..2e01dc75a15a 100644
--- a/sound/soc/intel/avs/control.c
+++ b/sound/soc/intel/avs/control.c
@@ -6,6 +6,7 @@
// Cezary Rojewski <cezary.rojewski@intel.com>
//
+#include <linux/cleanup.h>
#include <sound/soc.h>
#include "avs.h"
#include "control.h"
@@ -31,8 +32,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
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) {
- if (guid_equal(&mod->template->cfg_ext->type, &AVS_PEAKVOL_MOD_UUID)
- && mod->template->ctl_id == id) {
+ guid_t *type = &mod->template->cfg_ext->type;
+
+ 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);
return mod;
}
@@ -44,70 +48,168 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i
return NULL;
}
-int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
- struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
- struct avs_volume_cfg *dspvols = NULL;
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct avs_control_data *ctl_data = mc->dobj.private;
struct avs_path_module *active_module;
+ struct avs_volume_cfg *dspvols;
+ struct avs_dev *adev;
size_t num_dspvols;
- int ret = 0;
+ int ret, i;
+
+ adev = avs_get_kcontrol_adev(kctl);
- /* prevent access to modules while path is being constructed */
- mutex_lock(&adev->path_mutex);
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
active_module = avs_get_volume_module(adev, ctl_data->id);
if (active_module) {
ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id,
active_module->instance_id, &dspvols,
&num_dspvols);
- if (!ret)
- ucontrol->value.integer.value[0] = dspvols[0].target_volume;
+ if (ret)
+ return AVS_IPC_RET(ret);
- ret = AVS_IPC_RET(ret);
+ /* Do not copy more than the control can store. */
+ num_dspvols = min_t(u32, num_dspvols, SND_SOC_TPLG_MAX_CHAN);
+ for (i = 0; i < num_dspvols; i++)
+ ctl_data->values[i] = dspvols[i].target_volume;
kfree(dspvols);
- } else {
- ucontrol->value.integer.value[0] = ctl_data->volume;
}
- mutex_unlock(&adev->path_mutex);
- return ret;
+ memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
+ return 0;
}
-int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
{
- struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private;
- struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol);
- long *volume = &ctl_data->volume;
struct avs_path_module *active_module;
- struct avs_volume_cfg dspvol = {0};
- long ctlvol = ucontrol->value.integer.value[0];
- int ret = 0, changed = 0;
+ struct avs_control_data *ctl_data;
+ struct soc_mixer_control *mc;
+ struct avs_dev *adev;
+ long *input;
+ int ret, i;
+
+ mc = (struct soc_mixer_control *)kctl->private_value;
+ ctl_data = mc->dobj.private;
+ adev = avs_get_kcontrol_adev(kctl);
+ input = uctl->value.integer.value;
+ i = 0;
+
+ /* mc->num_channels can be 0. */
+ do {
+ if (input[i] < mc->min || input[i] > mc->max)
+ return -EINVAL;
+ } while (++i < mc->num_channels);
+
+ if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
+ return 0;
+
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
- if (ctlvol < 0 || ctlvol > mc->max)
- return -EINVAL;
+ active_module = avs_get_volume_module(adev, ctl_data->id);
+ if (active_module) {
+ ret = avs_peakvol_set_volume(adev, active_module, mc, input);
+ if (ret)
+ return ret;
+ }
- /* prevent access to modules while path is being constructed */
- mutex_lock(&adev->path_mutex);
+ memcpy(ctl_data->values, input, sizeof(ctl_data->values));
+ return 1;
+}
- if (*volume != ctlvol) {
- *volume = ctlvol;
- changed = 1;
- }
+int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = max_t(u32, 1, mc->num_channels);
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mc->max;
+ return 0;
+}
+
+int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct avs_control_data *ctl_data = mc->dobj.private;
+ struct avs_path_module *active_module;
+ struct avs_mute_cfg *dspmutes;
+ struct avs_dev *adev;
+ size_t num_dspmutes;
+ int ret, i;
+
+ adev = avs_get_kcontrol_adev(kctl);
+
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
active_module = avs_get_volume_module(adev, ctl_data->id);
if (active_module) {
- dspvol.channel_id = AVS_ALL_CHANNELS_MASK;
- dspvol.target_volume = *volume;
+ ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id,
+ active_module->instance_id, &dspmutes,
+ &num_dspmutes);
+ if (ret)
+ return AVS_IPC_RET(ret);
+
+ /* Do not copy more than the control can store. */
+ num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN);
+ for (i = 0; i < num_dspmutes; i++)
+ ctl_data->values[i] = !dspmutes[i].mute;
+ kfree(dspmutes);
+ }
- ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id,
- active_module->instance_id, &dspvol);
- ret = AVS_IPC_RET(ret);
+ memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values));
+ return 0;
+}
+
+int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl)
+{
+ struct avs_path_module *active_module;
+ struct avs_control_data *ctl_data;
+ struct soc_mixer_control *mc;
+ struct avs_dev *adev;
+ long *input;
+ int ret, i;
+
+ mc = (struct soc_mixer_control *)kctl->private_value;
+ ctl_data = mc->dobj.private;
+ adev = avs_get_kcontrol_adev(kctl);
+ input = uctl->value.integer.value;
+ i = 0;
+
+ /* mc->num_channels can be 0. */
+ do {
+ if (input[i] < mc->min || input[i] > mc->max)
+ return -EINVAL;
+ } while (++i < mc->num_channels);
+
+ if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values)))
+ return 0;
+
+ /* Prevent access to modules while path is being constructed. */
+ guard(mutex)(&adev->path_mutex);
+
+ active_module = avs_get_volume_module(adev, ctl_data->id);
+ if (active_module) {
+ ret = avs_peakvol_set_mute(adev, active_module, mc, input);
+ if (ret)
+ return ret;
}
- mutex_unlock(&adev->path_mutex);
+ memcpy(ctl_data->values, input, sizeof(ctl_data->values));
+ return 1;
+}
+
+int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
- return ret ? ret : changed;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = max_t(u32, 1, mc->num_channels);
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = mc->max;
+ return 0;
}
diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h
index d9fac3569e8d..08b2919e4629 100644
--- a/sound/soc/intel/avs/control.h
+++ b/sound/soc/intel/avs/control.h
@@ -10,14 +10,18 @@
#define __SOUND_SOC_INTEL_AVS_CTRL_H
#include <sound/control.h>
+#include <uapi/sound/asoc.h>
struct avs_control_data {
u32 id;
-
- long volume;
+ long values[SND_SOC_TPLG_MAX_CHAN];
};
-int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo);
+int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl);
+int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo);
#endif
diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c
index 73d4bde9b2f7..8fbf33e30dfc 100644
--- a/sound/soc/intel/avs/core.c
+++ b/sound/soc/intel/avs/core.c
@@ -612,7 +612,7 @@ static int avs_suspend_standby(struct avs_dev *adev)
return 0;
}
-static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power)
+static int avs_suspend_common(struct avs_dev *adev, bool low_power)
{
struct hdac_bus *bus = &adev->base.core;
int ret;
@@ -673,7 +673,7 @@ static int avs_resume_standby(struct avs_dev *adev)
return 0;
}
-static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
+static int avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
{
struct hdac_bus *bus = &adev->base.core;
int ret;
@@ -696,41 +696,41 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power
return 0;
}
-static int __maybe_unused avs_suspend(struct device *dev)
+static int avs_suspend(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), true);
}
-static int __maybe_unused avs_resume(struct device *dev)
+static int avs_resume(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), true, true);
}
-static int __maybe_unused avs_runtime_suspend(struct device *dev)
+static int avs_runtime_suspend(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), true);
}
-static int __maybe_unused avs_runtime_resume(struct device *dev)
+static int avs_runtime_resume(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), true, false);
}
-static int __maybe_unused avs_freeze(struct device *dev)
+static int avs_freeze(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), false);
}
-static int __maybe_unused avs_thaw(struct device *dev)
+static int avs_thaw(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), false, true);
}
-static int __maybe_unused avs_poweroff(struct device *dev)
+static int avs_poweroff(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), false);
}
-static int __maybe_unused avs_restore(struct device *dev)
+static int avs_restore(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), false, true);
}
@@ -742,7 +742,7 @@ static const struct dev_pm_ops avs_dev_pm = {
.thaw = avs_thaw,
.poweroff = avs_poweroff,
.restore = avs_restore,
- SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
+ RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
};
static const struct avs_sram_spec skl_sram_spec = {
@@ -829,10 +829,10 @@ static const struct avs_spec jsl_desc = {
.hipc = &cnl_hipc_spec,
};
-#define AVS_TGL_BASED_SPEC(sname) \
+#define AVS_TGL_BASED_SPEC(sname, min) \
static const struct avs_spec sname##_desc = { \
.name = #sname, \
- .min_fw_version = { 10, 29, 0, 5646 }, \
+ .min_fw_version = { 10, min, 0, 5646 }, \
.dsp_ops = &avs_tgl_dsp_ops, \
.core_init_mask = 1, \
.attributes = AVS_PLATATTR_IMR, \
@@ -840,11 +840,11 @@ static const struct avs_spec sname##_desc = { \
.hipc = &cnl_hipc_spec, \
}
-AVS_TGL_BASED_SPEC(lkf);
-AVS_TGL_BASED_SPEC(tgl);
-AVS_TGL_BASED_SPEC(ehl);
-AVS_TGL_BASED_SPEC(adl);
-AVS_TGL_BASED_SPEC(adl_n);
+AVS_TGL_BASED_SPEC(lkf, 28);
+AVS_TGL_BASED_SPEC(tgl, 29);
+AVS_TGL_BASED_SPEC(ehl, 30);
+AVS_TGL_BASED_SPEC(adl, 35);
+AVS_TGL_BASED_SPEC(adl_n, 35);
static const struct pci_device_id avs_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) },
@@ -893,7 +893,7 @@ static struct pci_driver avs_pci_driver = {
.shutdown = avs_pci_shutdown,
.dev_groups = avs_attr_groups,
.driver = {
- .pm = &avs_dev_pm,
+ .pm = pm_ptr(&avs_dev_pm),
},
};
module_pci_driver(avs_pci_driver);
@@ -902,3 +902,13 @@ MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>");
MODULE_DESCRIPTION("Intel cAVS sound driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("intel/skl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/apl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/cnl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/icl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/jsl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/lkf/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/tgl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/ehl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/adl/dsp_basefw.bin");
+MODULE_FIRMWARE("intel/adl_n/dsp_basefw.bin");
diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c
index 1767ded4d983..8c4edda97f75 100644
--- a/sound/soc/intel/avs/debugfs.c
+++ b/sound/soc/intel/avs/debugfs.c
@@ -10,6 +10,7 @@
#include <linux/kfifo.h>
#include <linux/wait.h>
#include <linux/sched/signal.h>
+#include <linux/string_helpers.h>
#include <sound/soc.h>
#include "avs.h"
#include "messages.h"
diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c
index 7b47e52c2b39..b9de691e9b9b 100644
--- a/sound/soc/intel/avs/dsp.c
+++ b/sound/soc/intel/avs/dsp.c
@@ -6,6 +6,7 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/string_choices.h>
#include <sound/hdaudio_ext.h>
#include "avs.h"
#include "registers.h"
@@ -39,7 +40,7 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
AVS_ADSPCS_TIMEOUT_US);
if (ret)
dev_err(adev->dev, "core_mask %d power %s failed: %d\n",
- core_mask, power ? "on" : "off", ret);
+ core_mask, str_on_off(power), ret);
return ret;
}
diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c
index 4fba46e77c47..08ed9d96738a 100644
--- a/sound/soc/intel/avs/ipc.c
+++ b/sound/soc/intel/avs/ipc.c
@@ -184,10 +184,11 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header)
{
struct avs_ipc *ipc = adev->ipc;
union avs_reply_msg msg = AVS_MSG(header);
- u64 reg;
+ u32 sts, lec;
- reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
- trace_avs_ipc_reply_msg(header, reg);
+ sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev));
+ lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev));
+ trace_avs_ipc_reply_msg(header, sts, lec);
ipc->rx.header = header;
/* Abort copying payload if request processing was unsuccessful. */
@@ -209,10 +210,11 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header)
union avs_notify_msg msg = AVS_MSG(header);
size_t data_size = 0;
void *data = NULL;
- u64 reg;
+ u32 sts, lec;
- reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
- trace_avs_ipc_notify_msg(header, reg);
+ sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev));
+ lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev));
+ trace_avs_ipc_notify_msg(header, sts, lec);
/* Ignore spurious notifications until handshake is established. */
if (!adev->ipc->ready && msg.notify_msg_type != AVS_NOTIFY_FW_READY) {
@@ -367,13 +369,16 @@ static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg *reply)
static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx, bool read_fwregs)
{
const struct avs_spec *const spec = adev->spec;
- u64 reg = ULONG_MAX;
+ u32 sts = UINT_MAX;
+ u32 lec = UINT_MAX;
tx->header |= spec->hipc->req_busy_mask;
- if (read_fwregs)
- reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
+ if (read_fwregs) {
+ sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev));
+ lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev));
+ }
- trace_avs_request(tx, reg);
+ trace_avs_request(tx, sts, lec);
if (tx->size)
memcpy_toio(avs_downlink_addr(adev), tx->data, tx->size);
diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c
index 890efd2f1fea..0b29941feb0e 100644
--- a/sound/soc/intel/avs/loader.c
+++ b/sound/soc/intel/avs/loader.c
@@ -167,7 +167,8 @@ int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw)
(reg & AVS_ROM_INIT_DONE) == AVS_ROM_INIT_DONE,
AVS_ROM_INIT_POLLING_US, SKL_ROM_INIT_TIMEOUT_US);
if (ret < 0) {
- dev_err(adev->dev, "rom init timeout: %d\n", ret);
+ dev_err(adev->dev, "rom init failed: %d, status: 0x%08x, lec: 0x%08x\n",
+ ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)));
avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
return ret;
}
@@ -180,7 +181,8 @@ int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw)
AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US);
hda_cldma_stop(cl);
if (ret < 0) {
- dev_err(adev->dev, "transfer fw failed: %d\n", ret);
+ dev_err(adev->dev, "transfer fw failed: %d, status: 0x%08x, lec: 0x%08x\n",
+ ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)));
avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
return ret;
}
@@ -308,12 +310,13 @@ avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge)
}
/* await ROM init */
- ret = snd_hdac_adsp_readq_poll(adev, spec->sram->rom_status_offset, reg,
+ ret = snd_hdac_adsp_readl_poll(adev, spec->sram->rom_status_offset, reg,
(reg & 0xF) == AVS_ROM_INIT_DONE ||
(reg & 0xF) == APL_ROM_FW_ENTERED,
AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US);
if (ret < 0) {
- dev_err(adev->dev, "rom init timeout: %d\n", ret);
+ dev_err(adev->dev, "rom init failed: %d, status: 0x%08x, lec: 0x%08x\n",
+ ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)));
goto err;
}
@@ -337,15 +340,15 @@ static int avs_imr_load_basefw(struct avs_dev *adev)
/* DMA id ignored when flashing from IMR as no transfer occurs. */
ret = avs_hda_init_rom(adev, 0, false);
- if (ret < 0) {
- dev_err(adev->dev, "rom init failed: %d\n", ret);
+ if (ret < 0)
return ret;
- }
ret = wait_for_completion_timeout(&adev->fw_ready,
msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));
if (!ret) {
- dev_err(adev->dev, "firmware ready timeout\n");
+ dev_err(adev->dev, "firmware ready timeout, status: 0x%08x, lec: 0x%08x\n",
+ snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)),
+ snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)));
avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
return -ETIMEDOUT;
}
@@ -392,7 +395,7 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
ret = avs_hda_init_rom(adev, dma_id, true);
if (!ret)
break;
- dev_info(adev->dev, "#%d rom init fail: %d\n", i + 1, ret);
+ dev_info(adev->dev, "#%d rom init failed: %d\n", i + 1, ret);
}
if (ret < 0)
goto cleanup_resources;
@@ -404,7 +407,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw)
AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US);
snd_hdac_dsp_trigger(hstream, false);
if (ret < 0) {
- dev_err(adev->dev, "transfer fw failed: %d\n", ret);
+ dev_err(adev->dev, "transfer fw failed: %d, status: 0x%08x, lec: 0x%08x\n",
+ ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)));
avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
}
@@ -584,7 +588,9 @@ static int avs_dsp_load_basefw(struct avs_dev *adev)
ret = wait_for_completion_timeout(&adev->fw_ready,
msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS));
if (!ret) {
- dev_err(adev->dev, "firmware ready timeout\n");
+ dev_err(adev->dev, "firmware ready timeout, status: 0x%08x, lec: 0x%08x\n",
+ snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)),
+ snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)));
avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
ret = -ETIMEDOUT;
goto release_fw;
@@ -597,7 +603,7 @@ release_fw:
return ret;
}
-int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
+static int avs_load_firmware(struct avs_dev *adev, bool purge)
{
struct avs_soc_component *acomp;
int ret, i;
@@ -651,40 +657,41 @@ reenable_gating:
return 0;
}
-int avs_dsp_first_boot_firmware(struct avs_dev *adev)
+static int avs_config_basefw(struct avs_dev *adev)
{
- int ret, i;
+ int ret;
- if (avs_platattr_test(adev, CLDMA)) {
- ret = hda_cldma_init(&code_loader, &adev->base.core,
- adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE);
- if (ret < 0) {
- dev_err(adev->dev, "cldma init failed: %d\n", ret);
+ if (adev->spec->dsp_ops->config_basefw) {
+ ret = avs_dsp_op(adev, config_basefw);
+ if (ret)
return ret;
- }
}
- ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
- if (ret < 0)
- return ret;
+ return 0;
+}
- ret = avs_dsp_boot_firmware(adev, true);
- if (ret < 0) {
- dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge)
+{
+ int ret;
+
+ ret = avs_load_firmware(adev, purge);
+ if (ret)
return ret;
- }
+
+ return avs_config_basefw(adev);
+}
+
+static int avs_dsp_alloc_resources(struct avs_dev *adev)
+{
+ int ret, i;
ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg);
- if (ret) {
- dev_err(adev->dev, "get hw cfg failed: %d\n", ret);
+ if (ret)
return AVS_IPC_RET(ret);
- }
ret = avs_ipc_get_fw_config(adev, &adev->fw_cfg);
- if (ret) {
- dev_err(adev->dev, "get fw cfg failed: %d\n", ret);
+ if (ret)
return AVS_IPC_RET(ret);
- }
adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores,
sizeof(*adev->core_refs), GFP_KERNEL);
@@ -703,6 +710,31 @@ int avs_dsp_first_boot_firmware(struct avs_dev *adev)
strscpy(adev->lib_names[0], "BASEFW", AVS_LIB_NAME_SIZE);
ida_init(&adev->ppl_ida);
-
return 0;
}
+
+int avs_dsp_first_boot_firmware(struct avs_dev *adev)
+{
+ int ret;
+
+ if (avs_platattr_test(adev, CLDMA)) {
+ ret = hda_cldma_init(&code_loader, &adev->base.core,
+ adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE);
+ if (ret < 0) {
+ dev_err(adev->dev, "cldma init failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK);
+ if (ret < 0)
+ return ret;
+
+ ret = avs_dsp_boot_firmware(adev, true);
+ if (ret < 0) {
+ dev_err(adev->dev, "firmware boot failed: %d\n", ret);
+ return ret;
+ }
+
+ return avs_dsp_alloc_resources(adev);
+}
diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c
index ec458bd51b10..a5ba27983091 100644
--- a/sound/soc/intel/avs/messages.c
+++ b/sound/soc/intel/avs/messages.c
@@ -400,10 +400,12 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
AVS_BASEFW_FIRMWARE_CONFIG, NULL, 0,
&payload, &payload_size);
if (ret)
- return ret;
+ goto err;
/* Non-zero payload expected for FIRMWARE_CONFIG. */
- if (!payload_size)
- return -EREMOTEIO;
+ if (!payload_size) {
+ ret = -EREMOTEIO;
+ goto err;
+ }
while (offset < payload_size) {
tlv = (struct avs_tlv *)(payload + offset);
@@ -502,6 +504,47 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg)
/* No longer needed, free it as it's owned by the get_large_config() caller. */
kfree(payload);
+err:
+ if (ret)
+ dev_err(adev->dev, "get fw cfg failed: %d\n", ret);
+ return ret;
+}
+
+int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...)
+{
+ struct avs_tlv *tlv;
+ void *payload;
+ size_t offset;
+ va_list args;
+ int ret, i;
+
+ payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ va_start(args, num_tlvs);
+ for (offset = i = 0; i < num_tlvs && offset < AVS_MAILBOX_SIZE - sizeof(*tlv); i++) {
+ tlv = (struct avs_tlv *)(payload + offset);
+ tlv->type = va_arg(args, u32);
+ tlv->length = va_arg(args, u32);
+
+ offset += sizeof(*tlv) + tlv->length;
+ if (offset > AVS_MAILBOX_SIZE)
+ break;
+
+ memcpy(tlv->value, va_arg(args, u8*), tlv->length);
+ }
+
+ if (i == num_tlvs)
+ ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID,
+ AVS_BASEFW_FIRMWARE_CONFIG, payload, offset);
+ else
+ ret = -ERANGE;
+
+ va_end(args);
+ kfree(payload);
+ if (ret)
+ dev_err(adev->dev, "set fw cfg failed: %d\n", ret);
return ret;
}
@@ -517,10 +560,12 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg)
AVS_BASEFW_HARDWARE_CONFIG, NULL, 0,
&payload, &payload_size);
if (ret)
- return ret;
+ goto err;
/* Non-zero payload expected for HARDWARE_CONFIG. */
- if (!payload_size)
- return -EREMOTEIO;
+ if (!payload_size) {
+ ret = -EREMOTEIO;
+ goto err;
+ }
while (offset < payload_size) {
tlv = (struct avs_tlv *)(payload + offset);
@@ -590,6 +635,9 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg)
exit:
/* No longer needed, free it as it's owned by the get_large_config() caller. */
kfree(payload);
+err:
+ if (ret)
+ dev_err(adev->dev, "get hw cfg failed: %d\n", ret);
return ret;
}
@@ -629,13 +677,6 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
(u8 *)&cpr_fmt, sizeof(cpr_fmt));
}
-int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
- struct avs_volume_cfg *vol)
-{
- return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol,
- sizeof(*vol));
-}
-
int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
struct avs_volume_cfg **vols, size_t *num_vols)
{
@@ -658,6 +699,110 @@ int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_
return 0;
}
+int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vol)
+{
+ return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME,
+ (u8 *)vol, sizeof(*vol));
+}
+
+int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vols, size_t num_vols)
+{
+ struct avs_tlv *tlv;
+ size_t offset;
+ size_t size;
+ u8 *payload;
+ int ret, i;
+
+ size = num_vols * sizeof(*vols);
+ size += num_vols * sizeof(*tlv);
+ if (size > AVS_MAILBOX_SIZE)
+ return -EINVAL;
+
+ payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ for (offset = i = 0; i < num_vols; i++) {
+ tlv = (struct avs_tlv *)(payload + offset);
+
+ tlv->type = AVS_PEAKVOL_VOLUME;
+ tlv->length = sizeof(*vols);
+ memcpy(tlv->value, &vols[i], tlv->length);
+
+ offset += sizeof(*tlv) + tlv->length;
+ }
+
+ ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload,
+ size);
+ kfree(payload);
+ return ret;
+}
+
+int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg **mutes, size_t *num_mutes)
+{
+ size_t payload_size;
+ u8 *payload;
+ int ret;
+
+ ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE, NULL, 0,
+ &payload, &payload_size);
+ if (ret)
+ return ret;
+
+ /* Non-zero payload expected for PEAKVOL_MUTE. */
+ if (!payload_size)
+ return -EREMOTEIO;
+
+ *mutes = (struct avs_mute_cfg *)payload;
+ *num_mutes = payload_size / sizeof(**mutes);
+
+ return 0;
+}
+
+int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mute)
+{
+ return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE,
+ (u8 *)mute, sizeof(*mute));
+}
+
+int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mutes, size_t num_mutes)
+{
+ struct avs_tlv *tlv;
+ size_t offset;
+ size_t size;
+ u8 *payload;
+ int ret, i;
+
+ size = num_mutes * sizeof(*mutes);
+ size += num_mutes * sizeof(*tlv);
+ if (size > AVS_MAILBOX_SIZE)
+ return -EINVAL;
+
+ payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL);
+ if (!payload)
+ return -ENOMEM;
+
+ for (offset = i = 0; i < num_mutes; i++) {
+ tlv = (struct avs_tlv *)(payload + offset);
+
+ tlv->type = AVS_PEAKVOL_MUTE;
+ tlv->length = sizeof(*mutes);
+ memcpy(tlv->value, &mutes[i], tlv->length);
+
+ offset += sizeof(*tlv) + tlv->length;
+ }
+
+ ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload,
+ size);
+ kfree(payload);
+ return ret;
+}
+
#ifdef CONFIG_DEBUG_FS
int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size)
{
diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h
index d0bdb7d9266c..2f243802ccc2 100644
--- a/sound/soc/intel/avs/messages.h
+++ b/sound/soc/intel/avs/messages.h
@@ -451,6 +451,8 @@ enum avs_fw_cfg_params {
AVS_FW_CFG_RESERVED,
AVS_FW_CFG_POWER_GATING_POLICY,
AVS_FW_CFG_ASSERT_MODE,
+ AVS_FW_CFG_RESERVED2,
+ AVS_FW_CFG_BUS_HARDWARE_ID,
};
struct avs_fw_cfg {
@@ -475,7 +477,14 @@ struct avs_fw_cfg {
u32 power_gating_policy;
};
+struct avs_bus_hwid {
+ u32 device;
+ u32 subsystem;
+ u8 revision;
+};
+
int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg);
+int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...);
enum avs_hw_cfg_params {
AVS_HW_CFG_AVS_VER,
@@ -643,6 +652,9 @@ int avs_ipc_set_system_time(struct avs_dev *adev);
#define AVS_INTELWOV_MOD_UUID \
GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9, 0x84, 0xF1, 0xEE, 0xB7)
+#define AVS_WOVHOSTM_MOD_UUID \
+ GUID_INIT(0xF9ED62B7, 0x092E, 0x4A90, 0x8F, 0x4D, 0x82, 0xDA, 0xA8, 0xB3, 0x8F, 0x3B)
+
/* channel map */
enum avs_channel_index {
AVS_CHANNEL_LEFT = 0,
@@ -802,6 +814,15 @@ struct avs_volume_cfg {
} __packed;
static_assert(sizeof(struct avs_volume_cfg) == 24);
+struct avs_mute_cfg {
+ u32 channel_id;
+ u32 mute;
+ u32 curve_type;
+ u32 reserved; /* alignment */
+ u64 curve_duration;
+} __packed;
+static_assert(sizeof(struct avs_mute_cfg) == 24);
+
struct avs_peakvol_cfg {
struct avs_modcfg_base base;
struct avs_volume_cfg vols[];
@@ -859,8 +880,7 @@ static_assert(sizeof(struct avs_aec_cfg) == 92);
struct avs_asrc_cfg {
struct avs_modcfg_base base;
u32 out_freq;
- u32 rsvd0:1;
- u32 mode:1;
+ u32 mode:2;
u32 rsvd2:2;
u32 disable_jitter_buffer:1;
u32 rsvd3:27;
@@ -873,8 +893,20 @@ struct avs_wov_cfg {
} __packed;
static_assert(sizeof(struct avs_wov_cfg) == 44);
+struct avs_whm_cfg {
+ struct avs_modcfg_base base;
+ /* Audio format for output pin 0 */
+ struct avs_audio_format ref_fmt;
+ struct avs_audio_format out_fmt;
+ u32 wake_tick_period;
+ struct avs_copier_gtw_cfg gtw_cfg;
+} __packed;
+static_assert(sizeof(struct avs_whm_cfg) == 108);
+
/* Module runtime parameters */
+#define AVS_VENDOR_CONFIG 0xFF
+
enum avs_copier_runtime_param {
AVS_COPIER_SET_SINK_FORMAT = 2,
};
@@ -893,6 +925,7 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id,
enum avs_peakvol_runtime_param {
AVS_PEAKVOL_VOLUME = 0,
+ AVS_PEAKVOL_MUTE = 3,
};
enum avs_audio_curve_type {
@@ -900,10 +933,18 @@ enum avs_audio_curve_type {
AVS_AUDIO_CURVE_WINDOWS_FADE = 1,
};
-int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
- struct avs_volume_cfg *vol);
int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
struct avs_volume_cfg **vols, size_t *num_vols);
+int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vol);
+int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_volume_cfg *vols, size_t num_vols);
+int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg **mutes, size_t *num_mutes);
+int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mute);
+int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id,
+ struct avs_mute_cfg *mutes, size_t num_mutes);
#define AVS_PROBE_INST_ID 0
diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c
index f31d5e2caa7b..ef0c1d125d66 100644
--- a/sound/soc/intel/avs/path.c
+++ b/sound/soc/intel/avs/path.c
@@ -115,154 +115,193 @@ avs_path_find_variant(struct avs_dev *adev,
return NULL;
}
-__maybe_unused
-static bool avs_dma_type_is_host(u32 dma_type)
+static void avs_init_node_id(union avs_connector_node_id *node_id,
+ struct avs_tplg_modcfg_ext *te, u32 dma_id)
{
- return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||
- dma_type == AVS_DMA_HDA_HOST_INPUT;
-}
+ node_id->val = 0;
+ node_id->dma_type = te->copier.dma_type;
-__maybe_unused
-static bool avs_dma_type_is_link(u32 dma_type)
-{
- return !avs_dma_type_is_host(dma_type);
-}
+ switch (node_id->dma_type) {
+ case AVS_DMA_DMIC_LINK_INPUT:
+ case AVS_DMA_I2S_LINK_OUTPUT:
+ case AVS_DMA_I2S_LINK_INPUT:
+ /* Gateway's virtual index is statically assigned in the topology. */
+ node_id->vindex = te->copier.vindex.val;
+ break;
-__maybe_unused
-static bool avs_dma_type_is_output(u32 dma_type)
-{
- return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||
- dma_type == AVS_DMA_HDA_LINK_OUTPUT ||
- dma_type == AVS_DMA_I2S_LINK_OUTPUT;
-}
+ case AVS_DMA_HDA_HOST_OUTPUT:
+ case AVS_DMA_HDA_HOST_INPUT:
+ /* Gateway's virtual index is dynamically assigned with DMA ID */
+ node_id->vindex = dma_id;
+ break;
-__maybe_unused
-static bool avs_dma_type_is_input(u32 dma_type)
-{
- return !avs_dma_type_is_output(dma_type);
+ case AVS_DMA_HDA_LINK_OUTPUT:
+ case AVS_DMA_HDA_LINK_INPUT:
+ node_id->vindex = te->copier.vindex.val | dma_id;
+ break;
+
+ default:
+ *node_id = INVALID_NODE_ID;
+ break;
+ }
}
-static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)
-{
- struct avs_tplg_module *t = mod->template;
- struct avs_copier_cfg *cfg;
- struct acpi_nhlt_format_config *ep_blob;
- struct acpi_nhlt_endpoint *ep;
- union avs_connector_node_id node_id = {0};
- size_t cfg_size, data_size;
- void *data = NULL;
- u32 dma_type;
- int ret;
+/* Every BLOB contains at least gateway attributes. */
+static struct acpi_nhlt_config *default_blob = (struct acpi_nhlt_config *)&(u32[2]) {4};
- data_size = sizeof(cfg->gtw_cfg.config);
- dma_type = t->cfg_ext->copier.dma_type;
- node_id.dma_type = dma_type;
+static struct acpi_nhlt_config *
+avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t)
+{
+ struct acpi_nhlt_format_config *fmtcfg;
+ struct avs_tplg_modcfg_ext *te;
+ struct avs_audio_format *fmt;
+ int link_type, dev_type;
+ int bus_id, dir;
- switch (dma_type) {
- struct avs_audio_format *fmt;
- int direction;
+ te = t->cfg_ext;
+ switch (te->copier.dma_type) {
case AVS_DMA_I2S_LINK_OUTPUT:
- case AVS_DMA_I2S_LINK_INPUT:
- if (avs_dma_type_is_input(dma_type))
- direction = SNDRV_PCM_STREAM_CAPTURE;
- else
- direction = SNDRV_PCM_STREAM_PLAYBACK;
-
- if (t->cfg_ext->copier.blob_fmt)
- fmt = t->cfg_ext->copier.blob_fmt;
- else if (direction == SNDRV_PCM_STREAM_CAPTURE)
- fmt = t->in_fmt;
- else
- fmt = t->cfg_ext->copier.out_fmt;
-
- ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP,
- ACPI_NHLT_DEVICETYPE_CODEC, direction,
- t->cfg_ext->copier.vindex.i2s.instance);
- ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq,
- fmt->valid_bit_depth, fmt->bit_depth);
- if (!ep_blob) {
- dev_err(adev->dev, "no I2S ep_blob found\n");
- return -ENOENT;
- }
-
- data = ep_blob->config.capabilities;
- data_size = ep_blob->config.capabilities_size;
- /* I2S gateway's vindex is statically assigned in topology */
- node_id.vindex = t->cfg_ext->copier.vindex.val;
+ link_type = ACPI_NHLT_LINKTYPE_SSP;
+ dev_type = ACPI_NHLT_DEVICETYPE_CODEC;
+ bus_id = te->copier.vindex.i2s.instance;
+ dir = SNDRV_PCM_STREAM_PLAYBACK;
+ fmt = te->copier.out_fmt;
+ break;
+ case AVS_DMA_I2S_LINK_INPUT:
+ link_type = ACPI_NHLT_LINKTYPE_SSP;
+ dev_type = ACPI_NHLT_DEVICETYPE_CODEC;
+ bus_id = te->copier.vindex.i2s.instance;
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ fmt = t->in_fmt;
break;
case AVS_DMA_DMIC_LINK_INPUT:
- direction = SNDRV_PCM_STREAM_CAPTURE;
-
- if (t->cfg_ext->copier.blob_fmt)
- fmt = t->cfg_ext->copier.blob_fmt;
- else
- fmt = t->in_fmt;
-
- ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, direction, 0);
- ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq,
- fmt->valid_bit_depth, fmt->bit_depth);
- if (!ep_blob) {
- dev_err(adev->dev, "no DMIC ep_blob found\n");
- return -ENOENT;
- }
-
- data = ep_blob->config.capabilities;
- data_size = ep_blob->config.capabilities_size;
- /* DMIC gateway's vindex is statically assigned in topology */
- node_id.vindex = t->cfg_ext->copier.vindex.val;
-
+ link_type = ACPI_NHLT_LINKTYPE_PDM;
+ dev_type = -1; /* ignored */
+ bus_id = 0;
+ dir = SNDRV_PCM_STREAM_CAPTURE;
+ fmt = t->in_fmt;
break;
- case AVS_DMA_HDA_HOST_OUTPUT:
- case AVS_DMA_HDA_HOST_INPUT:
- /* HOST gateway's vindex is dynamically assigned with DMA id */
- node_id.vindex = mod->owner->owner->dma_id;
- break;
+ default:
+ return default_blob;
+ }
- case AVS_DMA_HDA_LINK_OUTPUT:
- case AVS_DMA_HDA_LINK_INPUT:
- node_id.vindex = t->cfg_ext->copier.vindex.val |
- mod->owner->owner->dma_id;
- break;
+ /* Override format selection if necessary. */
+ if (te->copier.blob_fmt)
+ fmt = te->copier.blob_fmt;
- case INVALID_OBJECT_ID:
- default:
- node_id = INVALID_NODE_ID;
- break;
+ fmtcfg = acpi_nhlt_find_fmtcfg(link_type, dev_type, dir, bus_id,
+ fmt->num_channels, fmt->sampling_freq, fmt->valid_bit_depth,
+ fmt->bit_depth);
+ if (!fmtcfg) {
+ dev_warn(adev->dev, "Endpoint format configuration not found.\n");
+ return ERR_PTR(-ENOENT);
}
- cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config) + data_size;
- if (cfg_size > AVS_MAILBOX_SIZE)
- return -EINVAL;
+ if (fmtcfg->config.capabilities_size < default_blob->capabilities_size)
+ return ERR_PTR(-ETOOSMALL);
+ /* The firmware expects the payload to be DWORD-aligned. */
+ if (fmtcfg->config.capabilities_size % sizeof(u32))
+ return ERR_PTR(-EINVAL);
+ return &fmtcfg->config;
+}
+
+static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw,
+ struct avs_tplg_module *t, size_t *cfg_size)
+{
+ struct acpi_nhlt_config *blob;
+ size_t gtw_size;
+
+ blob = avs_nhlt_config_or_default(adev, t);
+ if (IS_ERR(blob))
+ return PTR_ERR(blob);
+
+ gtw_size = blob->capabilities_size;
+ if (*cfg_size + gtw_size > AVS_MAILBOX_SIZE)
+ return -E2BIG;
+
+ gtw->config_length = gtw_size / sizeof(u32);
+ memcpy(gtw->config.blob, blob->capabilities, blob->capabilities_size);
+ *cfg_size += gtw_size;
+
+ return 0;
+}
+
+static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)
+{
+ struct avs_tplg_module *t = mod->template;
+ struct avs_tplg_modcfg_ext *te;
+ struct avs_copier_cfg *cfg;
+ size_t cfg_size;
+ u32 dma_id;
+ int ret;
+
+ te = t->cfg_ext;
cfg = adev->modcfg_buf;
- memset(cfg, 0, cfg_size);
+ dma_id = mod->owner->owner->dma_id;
+ cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config);
+
+ ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size);
+ if (ret)
+ return ret;
+
cfg->base.cpc = t->cfg_base->cpc;
cfg->base.ibs = t->cfg_base->ibs;
cfg->base.obs = t->cfg_base->obs;
cfg->base.is_pages = t->cfg_base->is_pages;
cfg->base.audio_fmt = *t->in_fmt;
- cfg->out_fmt = *t->cfg_ext->copier.out_fmt;
- cfg->feature_mask = t->cfg_ext->copier.feature_mask;
- cfg->gtw_cfg.node_id = node_id;
- cfg->gtw_cfg.dma_buffer_size = t->cfg_ext->copier.dma_buffer_size;
- /* config_length in DWORDs */
- cfg->gtw_cfg.config_length = DIV_ROUND_UP(data_size, 4);
- if (data)
- memcpy(&cfg->gtw_cfg.config.blob, data, data_size);
+ cfg->out_fmt = *te->copier.out_fmt;
+ cfg->feature_mask = te->copier.feature_mask;
+ avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id);
+ cfg->gtw_cfg.dma_buffer_size = te->copier.dma_buffer_size;
+ mod->gtw_attrs = cfg->gtw_cfg.config.attrs;
+
+ ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,
+ t->domain, cfg, cfg_size, &mod->instance_id);
+ return ret;
+}
+
+static int avs_whm_create(struct avs_dev *adev, struct avs_path_module *mod)
+{
+ struct avs_tplg_module *t = mod->template;
+ struct avs_tplg_modcfg_ext *te;
+ struct avs_whm_cfg *cfg;
+ size_t cfg_size;
+ u32 dma_id;
+ int ret;
+ te = t->cfg_ext;
+ cfg = adev->modcfg_buf;
+ dma_id = mod->owner->owner->dma_id;
+ cfg_size = offsetof(struct avs_whm_cfg, gtw_cfg.config);
+
+ ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size);
+ if (ret)
+ return ret;
+
+ cfg->base.cpc = t->cfg_base->cpc;
+ cfg->base.ibs = t->cfg_base->ibs;
+ cfg->base.obs = t->cfg_base->obs;
+ cfg->base.is_pages = t->cfg_base->is_pages;
+ cfg->base.audio_fmt = *t->in_fmt;
+ cfg->ref_fmt = *te->whm.ref_fmt;
+ cfg->out_fmt = *te->whm.out_fmt;
+ cfg->wake_tick_period = te->whm.wake_tick_period;
+ avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id);
+ cfg->gtw_cfg.dma_buffer_size = te->whm.dma_buffer_size;
mod->gtw_attrs = cfg->gtw_cfg.config.attrs;
- ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,
- t->core_id, t->domain, cfg, cfg_size,
- &mod->instance_id);
+ ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,
+ t->domain, cfg, cfg_size, &mod->instance_id);
return ret;
}
-static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod)
+static struct soc_mixer_control *avs_get_module_control(struct avs_path_module *mod,
+ const char *name)
{
struct avs_tplg_module *t = mod->template;
struct avs_tplg_path_template *path_tmpl;
@@ -278,27 +317,93 @@ static struct avs_control_data *avs_get_module_control(struct avs_path_module *m
mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value;
ctl_data = (struct avs_control_data *)mc->dobj.private;
- if (ctl_data->id == t->ctl_id)
- return ctl_data;
+ if (ctl_data->id == t->ctl_id && strstr(w->kcontrols[i]->id.name, name))
+ return mc;
}
return NULL;
}
+int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input)
+{
+ struct avs_volume_cfg vols[SND_SOC_TPLG_MAX_CHAN] = {{0}};
+ struct avs_control_data *ctl_data;
+ struct avs_tplg_module *t;
+ int ret, i;
+
+ ctl_data = mc->dobj.private;
+ t = mod->template;
+ if (!input)
+ input = ctl_data->values;
+
+ if (mc->num_channels) {
+ for (i = 0; i < mc->num_channels; i++) {
+ vols[i].channel_id = i;
+ vols[i].target_volume = input[i];
+ vols[i].curve_type = t->cfg_ext->peakvol.curve_type;
+ vols[i].curve_duration = t->cfg_ext->peakvol.curve_duration;
+ }
+
+ ret = avs_ipc_peakvol_set_volumes(adev, mod->module_id, mod->instance_id, vols,
+ mc->num_channels);
+ return AVS_IPC_RET(ret);
+ }
+
+ /* Target all channels if no individual selected. */
+ vols[0].channel_id = AVS_ALL_CHANNELS_MASK;
+ vols[0].target_volume = input[0];
+ vols[0].curve_type = t->cfg_ext->peakvol.curve_type;
+ vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration;
+
+ ret = avs_ipc_peakvol_set_volume(adev, mod->module_id, mod->instance_id, &vols[0]);
+ return AVS_IPC_RET(ret);
+}
+
+int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input)
+{
+ struct avs_mute_cfg mutes[SND_SOC_TPLG_MAX_CHAN] = {{0}};
+ struct avs_control_data *ctl_data;
+ struct avs_tplg_module *t;
+ int ret, i;
+
+ ctl_data = mc->dobj.private;
+ t = mod->template;
+ if (!input)
+ input = ctl_data->values;
+
+ if (mc->num_channels) {
+ for (i = 0; i < mc->num_channels; i++) {
+ mutes[i].channel_id = i;
+ mutes[i].mute = !input[i];
+ mutes[i].curve_type = t->cfg_ext->peakvol.curve_type;
+ mutes[i].curve_duration = t->cfg_ext->peakvol.curve_duration;
+ }
+
+ ret = avs_ipc_peakvol_set_mutes(adev, mod->module_id, mod->instance_id, mutes,
+ mc->num_channels);
+ return AVS_IPC_RET(ret);
+ }
+
+ /* Target all channels if no individual selected. */
+ mutes[0].channel_id = AVS_ALL_CHANNELS_MASK;
+ mutes[0].mute = !input[0];
+ mutes[0].curve_type = t->cfg_ext->peakvol.curve_type;
+ mutes[0].curve_duration = t->cfg_ext->peakvol.curve_duration;
+
+ ret = avs_ipc_peakvol_set_mute(adev, mod->module_id, mod->instance_id, &mutes[0]);
+ return AVS_IPC_RET(ret);
+}
+
static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod)
{
struct avs_tplg_module *t = mod->template;
- struct avs_control_data *ctl_data;
+ struct soc_mixer_control *mc;
struct avs_peakvol_cfg *cfg;
- int volume = S32_MAX;
size_t cfg_size;
int ret;
- ctl_data = avs_get_module_control(mod);
- if (ctl_data)
- volume = ctl_data->volume;
-
- /* As 2+ channels controls are unsupported, have a single block for all channels. */
cfg_size = struct_size(cfg, vols, 1);
if (cfg_size > AVS_MAILBOX_SIZE)
return -EINVAL;
@@ -310,15 +415,28 @@ static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod)
cfg->base.obs = t->cfg_base->obs;
cfg->base.is_pages = t->cfg_base->is_pages;
cfg->base.audio_fmt = *t->in_fmt;
- cfg->vols[0].target_volume = volume;
cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK;
- cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE;
- cfg->vols[0].curve_duration = 0;
+ cfg->vols[0].target_volume = S32_MAX;
+ cfg->vols[0].curve_type = t->cfg_ext->peakvol.curve_type;
+ cfg->vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration;
ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,
t->domain, cfg, cfg_size, &mod->instance_id);
+ if (ret)
+ return ret;
- return ret;
+ /* Now configure both VOLUME and MUTE parameters. */
+ mc = avs_get_module_control(mod, "Volume");
+ if (mc) {
+ ret = avs_peakvol_set_volume(adev, mod, mc, NULL);
+ if (ret)
+ return ret;
+ }
+
+ mc = avs_get_module_control(mod, "Switch");
+ if (mc)
+ return avs_peakvol_set_mute(adev, mod, mc, NULL);
+ return 0;
}
static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod)
@@ -533,6 +651,7 @@ static struct avs_module_create avs_module_create[] = {
{ &AVS_ASRC_MOD_UUID, avs_asrc_create },
{ &AVS_INTELWOV_MOD_UUID, avs_wov_create },
{ &AVS_PROBE_MOD_UUID, avs_probe_create },
+ { &AVS_WOVHOSTM_MOD_UUID, avs_whm_create },
};
static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod)
diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h
index bfd253c9fa95..7ed7e94e0a56 100644
--- a/sound/soc/intel/avs/path.h
+++ b/sound/soc/intel/avs/path.h
@@ -69,4 +69,9 @@ int avs_path_reset(struct avs_path *path);
int avs_path_pause(struct avs_path *path);
int avs_path_run(struct avs_path *path, int trigger);
+int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input);
+int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod,
+ struct soc_mixer_control *mc, long *input);
+
#endif
diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c
index 945f9c0a6a54..dac463390da1 100644
--- a/sound/soc/intel/avs/pcm.c
+++ b/sound/soc/intel/avs/pcm.c
@@ -161,6 +161,7 @@ static int avs_dai_be_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dpcm *dpcm;
be = snd_soc_substream_to_rtd(substream);
+ /* dpcm_fe_dai_open() guarantees the list is not empty at this point. */
for_each_dpcm_fe(be, substream->stream, dpcm) {
fe = dpcm->fe;
fe_hw_params = &fe->dpcm[substream->stream].hw_params;
@@ -576,6 +577,7 @@ static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream,
hdac_stream(host_stream)->format_val = 0;
fe = snd_soc_substream_to_rtd(substream);
+ /* dpcm_fe_dai_open() guarantees the list is not empty at this point. */
for_each_dpcm_be(fe, substream->stream, dpcm) {
be = dpcm->be;
be_hw_params = &be->dpcm[substream->stream].hw_params;
@@ -1378,7 +1380,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l
for_each_set_bit(i, &port_mask, ssp_count)
cpu_count += hweight_long(tdms[i]);
- cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL);
+ cpus = devm_kcalloc(adev->dev, cpu_count, sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return -ENOMEM;
@@ -1564,6 +1566,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component)
if (ret < 0) {
dev_err(component->dev, "create widgets failed: %d\n",
ret);
+ snd_soc_unregister_dai(dai);
goto exit;
}
}
@@ -1578,8 +1581,8 @@ exit:
static void avs_component_hda_remove(struct snd_soc_component *component)
{
- avs_component_hda_unregister_dais(component);
avs_component_remove(component);
+ avs_component_hda_unregister_dais(component);
}
static int avs_component_hda_open(struct snd_soc_component *component,
diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h
index f76e91cff2a9..368ede05f2cd 100644
--- a/sound/soc/intel/avs/registers.h
+++ b/sound/soc/intel/avs/registers.h
@@ -9,6 +9,8 @@
#ifndef __SOUND_SOC_INTEL_AVS_REGS_H
#define __SOUND_SOC_INTEL_AVS_REGS_H
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iopoll.h>
#include <linux/sizes.h>
#define AZX_PCIREG_PGCTL 0x44
@@ -74,7 +76,7 @@
/* Constants used when accessing SRAM, space shared with firmware */
#define AVS_FW_REG_BASE(adev) ((adev)->spec->sram->base_offset)
#define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0)
-#define AVS_FW_REG_ERROR_CODE(adev) (AVS_FW_REG_BASE(adev) + 0x4)
+#define AVS_FW_REG_ERROR(adev) (AVS_FW_REG_BASE(adev) + 0x4)
#define AVS_WINDOW_CHUNK_SIZE SZ_4K
#define AVS_FW_REGS_SIZE AVS_WINDOW_CHUNK_SIZE
@@ -98,4 +100,47 @@
#define avs_downlink_addr(adev) \
avs_sram_addr(adev, AVS_DOWNLINK_WINDOW)
+#define snd_hdac_adsp_writeb(adev, reg, value) \
+ snd_hdac_reg_writeb(&(adev)->base.core, (adev)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readb(adev, reg) \
+ snd_hdac_reg_readb(&(adev)->base.core, (adev)->dsp_ba + (reg))
+#define snd_hdac_adsp_writew(adev, reg, value) \
+ snd_hdac_reg_writew(&(adev)->base.core, (adev)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readw(adev, reg) \
+ snd_hdac_reg_readw(&(adev)->base.core, (adev)->dsp_ba + (reg))
+#define snd_hdac_adsp_writel(adev, reg, value) \
+ snd_hdac_reg_writel(&(adev)->base.core, (adev)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readl(adev, reg) \
+ snd_hdac_reg_readl(&(adev)->base.core, (adev)->dsp_ba + (reg))
+#define snd_hdac_adsp_writeq(adev, reg, value) \
+ snd_hdac_reg_writeq(&(adev)->base.core, (adev)->dsp_ba + (reg), value)
+#define snd_hdac_adsp_readq(adev, reg) \
+ snd_hdac_reg_readq(&(adev)->base.core, (adev)->dsp_ba + (reg))
+
+#define snd_hdac_adsp_updateb(adev, reg, mask, val) \
+ snd_hdac_adsp_writeb(adev, reg, \
+ (snd_hdac_adsp_readb(adev, reg) & ~(mask)) | (val))
+#define snd_hdac_adsp_updatew(adev, reg, mask, val) \
+ snd_hdac_adsp_writew(adev, reg, \
+ (snd_hdac_adsp_readw(adev, reg) & ~(mask)) | (val))
+#define snd_hdac_adsp_updatel(adev, reg, mask, val) \
+ snd_hdac_adsp_writel(adev, reg, \
+ (snd_hdac_adsp_readl(adev, reg) & ~(mask)) | (val))
+#define snd_hdac_adsp_updateq(adev, reg, mask, val) \
+ snd_hdac_adsp_writeq(adev, reg, \
+ (snd_hdac_adsp_readq(adev, reg) & ~(mask)) | (val))
+
+#define snd_hdac_adsp_readb_poll(adev, reg, val, cond, delay_us, timeout_us) \
+ readb_poll_timeout((adev)->dsp_ba + (reg), val, cond, \
+ delay_us, timeout_us)
+#define snd_hdac_adsp_readw_poll(adev, reg, val, cond, delay_us, timeout_us) \
+ readw_poll_timeout((adev)->dsp_ba + (reg), val, cond, \
+ delay_us, timeout_us)
+#define snd_hdac_adsp_readl_poll(adev, reg, val, cond, delay_us, timeout_us) \
+ readl_poll_timeout((adev)->dsp_ba + (reg), val, cond, \
+ delay_us, timeout_us)
+#define snd_hdac_adsp_readq_poll(adev, reg, val, cond, delay_us, timeout_us) \
+ readq_poll_timeout((adev)->dsp_ba + (reg), val, cond, \
+ delay_us, timeout_us)
+
#endif /* __SOUND_SOC_INTEL_AVS_REGS_H */
diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c
index 34f859d6e5a4..d66ef000de9e 100644
--- a/sound/soc/intel/avs/skl.c
+++ b/sound/soc/intel/avs/skl.c
@@ -12,6 +12,7 @@
#include "avs.h"
#include "cldma.h"
#include "messages.h"
+#include "registers.h"
void avs_skl_ipc_interrupt(struct avs_dev *adev)
{
diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c
index a9019ff5e3af..56905f2b9eb2 100644
--- a/sound/soc/intel/avs/tgl.c
+++ b/sound/soc/intel/avs/tgl.c
@@ -6,7 +6,11 @@
// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
//
+#include <linux/pci.h>
#include "avs.h"
+#include "messages.h"
+
+#define CPUID_TSC_LEAF 0x15
static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power)
{
@@ -35,6 +39,34 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal
return avs_dsp_core_stall(adev, core_mask, stall);
}
+static int avs_tgl_config_basefw(struct avs_dev *adev)
+{
+ struct pci_dev *pci = adev->base.pci;
+ struct avs_bus_hwid hwid;
+ int ret;
+#ifdef CONFIG_X86
+ unsigned int ecx;
+
+#include <asm/cpuid.h>
+ ecx = cpuid_ecx(CPUID_TSC_LEAF);
+ if (ecx) {
+ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx);
+ if (ret)
+ return AVS_IPC_RET(ret);
+ }
+#endif
+
+ hwid.device = pci->device;
+ hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16);
+ hwid.revision = pci->revision;
+
+ ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_BUS_HARDWARE_ID, sizeof(hwid), &hwid);
+ if (ret)
+ return AVS_IPC_RET(ret);
+
+ return 0;
+}
+
const struct avs_dsp_ops avs_tgl_dsp_ops = {
.power = avs_tgl_dsp_core_power,
.reset = avs_tgl_dsp_core_reset,
@@ -44,6 +76,7 @@ const struct avs_dsp_ops avs_tgl_dsp_ops = {
.load_basefw = avs_icl_load_basefw,
.load_lib = avs_hda_load_library,
.transfer_mods = avs_hda_transfer_modules,
+ .config_basefw = avs_tgl_config_basefw,
.log_buffer_offset = avs_icl_log_buffer_offset,
.log_buffer_status = avs_apl_log_buffer_status,
.coredump = avs_apl_coredump,
diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c
index 5cda527020c7..3c222c352701 100644
--- a/sound/soc/intel/avs/topology.c
+++ b/sound/soc/intel/avs/topology.c
@@ -815,6 +815,66 @@ static const struct avs_tplg_token_parser modcfg_ext_parsers[] = {
.offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_output_pins),
.parse = avs_parse_short_token,
},
+ {
+ .token = AVS_TKN_MODCFG_WHM_REF_AFMT_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.ref_fmt),
+ .parse = avs_parse_audio_format_ptr,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_OUT_AFMT_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.out_fmt),
+ .parse = avs_parse_audio_format_ptr,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_WAKE_TICK_PERIOD_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.wake_tick_period),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_VINDEX_U8,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.vindex),
+ .parse = avs_parse_byte_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_DMA_TYPE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_type),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_DMABUFF_SIZE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_buffer_size),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_WHM_BLOB_AFMT_ID_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, whm.blob_fmt),
+ .parse = avs_parse_audio_format_ptr,
+ },
+ {
+ .token = AVS_TKN_MODCFG_PEAKVOL_VOLUME_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.target_volume),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_TYPE_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_type),
+ .parse = avs_parse_word_token,
+ },
+ {
+ .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_DURATION_U32,
+ .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
+ .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_duration),
+ .parse = avs_parse_word_token,
+ },
};
static const struct avs_tplg_token_parser pin_format_parsers[] = {
@@ -1466,7 +1526,7 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o
static const struct avs_tplg_token_parser mod_init_config_parsers[] = {
{
- .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32,
+ .token = AVS_TKN_INIT_CONFIG_ID_U32,
.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
.offset = offsetof(struct avs_tplg_init_config, id),
.parse = avs_parse_word_token,
@@ -1519,7 +1579,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp,
esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size);
ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config),
- AVS_TKN_MOD_INIT_CONFIG_ID_U32,
+ AVS_TKN_INIT_CONFIG_ID_U32,
mod_init_config_parsers,
ARRAY_SIZE(mod_init_config_parsers));
@@ -1845,13 +1905,23 @@ static int avs_manifest(struct snd_soc_component *comp, int index,
return 0;
}
-#define AVS_CONTROL_OPS_VOLUME 257
+enum {
+ AVS_CONTROL_OPS_VOLUME = 257,
+ AVS_CONTROL_OPS_MUTE,
+};
static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = {
{
.id = AVS_CONTROL_OPS_VOLUME,
.get = avs_control_volume_get,
.put = avs_control_volume_put,
+ .info = avs_control_volume_info,
+ },
+ {
+ .id = AVS_CONTROL_OPS_MUTE,
+ .get = avs_control_mute_get,
+ .put = avs_control_mute_put,
+ .info = avs_control_mute_info,
},
};
@@ -1873,18 +1943,20 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
struct avs_control_data *ctl_data;
struct soc_mixer_control *mc;
size_t block_size;
- int ret;
+ int ret, i;
switch (le32_to_cpu(hdr->type)) {
case SND_SOC_TPLG_TYPE_MIXER:
- tmc = container_of(hdr, typeof(*tmc), hdr);
- tuples = tmc->priv.array;
- block_size = le32_to_cpu(tmc->priv.size);
break;
default:
return -EINVAL;
}
+ mc = (struct soc_mixer_control *)ctmpl->private_value;
+ tmc = container_of(hdr, typeof(*tmc), hdr);
+ tuples = tmc->priv.array;
+ block_size = le32_to_cpu(tmc->priv.size);
+
ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL);
if (!ctl_data)
return -ENOMEM;
@@ -1895,8 +1967,13 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_
if (ret)
return ret;
- mc = (struct soc_mixer_control *)ctmpl->private_value;
mc->dobj.private = ctl_data;
+ if (tmc->invert) {
+ ctl_data->values[0] = mc->max;
+ for (i = 1; i < mc->num_channels; i++)
+ ctl_data->values[i] = mc->max;
+ }
+
return 0;
}
diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h
index 7892e3797f63..304880997717 100644
--- a/sound/soc/intel/avs/topology.h
+++ b/sound/soc/intel/avs/topology.h
@@ -74,10 +74,17 @@ struct avs_tplg_modcfg_ext {
union avs_virtual_index vindex;
u32 dma_type;
u32 dma_buffer_size;
- u32 config_length;
- /* config_data part of priv data */
} copier;
struct {
+ struct avs_audio_format *ref_fmt;
+ struct avs_audio_format *out_fmt;
+ u32 wake_tick_period;
+ union avs_virtual_index vindex;
+ u32 dma_type;
+ u32 dma_buffer_size;
+ struct avs_audio_format *blob_fmt; /* optional override */
+ } whm;
+ struct {
u32 out_channel_config;
u32 coefficients_select;
s32 coefficients[AVS_CHANNELS_MAX];
@@ -106,6 +113,11 @@ struct avs_tplg_modcfg_ext {
struct {
struct avs_audio_format *out_fmt;
} micsel;
+ struct {
+ u32 target_volume;
+ u32 curve_type;
+ u32 curve_duration;
+ } peakvol;
};
};
diff --git a/sound/soc/intel/avs/trace.h b/sound/soc/intel/avs/trace.h
index c9eaa5a60ed3..f4288d0ad5ef 100644
--- a/sound/soc/intel/avs/trace.h
+++ b/sound/soc/intel/avs/trace.h
@@ -37,60 +37,62 @@ TRACE_EVENT(avs_dsp_core_op,
void trace_avs_msg_payload(const void *data, size_t size);
-#define trace_avs_request(msg, fwregs) \
+#define trace_avs_request(msg, sts, lec) \
({ \
- trace_avs_ipc_request_msg((msg)->header, fwregs); \
+ trace_avs_ipc_request_msg((msg)->header, sts, lec); \
trace_avs_msg_payload((msg)->data, (msg)->size); \
})
-#define trace_avs_reply(msg, fwregs) \
+#define trace_avs_reply(msg, sts, lec) \
({ \
- trace_avs_ipc_reply_msg((msg)->header, fwregs); \
+ trace_avs_ipc_reply_msg((msg)->header, sts, lec); \
trace_avs_msg_payload((msg)->data, (msg)->size); \
})
-#define trace_avs_notify(msg, fwregs) \
+#define trace_avs_notify(msg, sts, lec) \
({ \
- trace_avs_ipc_notify_msg((msg)->header, fwregs); \
+ trace_avs_ipc_notify_msg((msg)->header, sts, lec); \
trace_avs_msg_payload((msg)->data, (msg)->size); \
})
#endif
DECLARE_EVENT_CLASS(avs_ipc_msg_hdr,
- TP_PROTO(u64 header, u64 fwregs),
+ TP_PROTO(u64 header, u32 sts, u32 lec),
- TP_ARGS(header, fwregs),
+ TP_ARGS(header, sts, lec),
TP_STRUCT__entry(
__field(u64, header)
- __field(u64, fwregs)
+ __field(u32, sts)
+ __field(u32, lec)
),
TP_fast_assign(
__entry->header = header;
- __entry->fwregs = fwregs;
+ __entry->sts = sts;
+ __entry->lec = lec;
),
TP_printk("primary: 0x%08X, extension: 0x%08X,\n"
- "fwstatus: 0x%08X, fwerror: 0x%08X",
+ "status: 0x%08X, error: 0x%08X",
lower_32_bits(__entry->header), upper_32_bits(__entry->header),
- lower_32_bits(__entry->fwregs), upper_32_bits(__entry->fwregs))
+ __entry->sts, __entry->lec)
);
DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_request_msg,
- TP_PROTO(u64 header, u64 fwregs),
- TP_ARGS(header, fwregs)
+ TP_PROTO(u64 header, u32 sts, u32 lec),
+ TP_ARGS(header, sts, lec)
);
DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_reply_msg,
- TP_PROTO(u64 header, u64 fwregs),
- TP_ARGS(header, fwregs)
+ TP_PROTO(u64 header, u32 sts, u32 lec),
+ TP_ARGS(header, sts, lec)
);
DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_notify_msg,
- TP_PROTO(u64 header, u64 fwregs),
- TP_ARGS(header, fwregs)
+ TP_PROTO(u64 header, u32 sts, u32 lec),
+ TP_ARGS(header, sts, lec)
);
TRACE_EVENT_CONDITION(avs_ipc_msg_payload,
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c
index 9caa4407c1ca..6446cda0f857 100644
--- a/sound/soc/intel/boards/bytcr_rt5640.c
+++ b/sound/soc/intel/boards/bytcr_rt5640.c
@@ -1132,7 +1132,22 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF2 |
BYT_RT5640_MCLK_EN),
},
- { /* Vexia Edu Atla 10 tablet */
+ {
+ /* Vexia Edu Atla 10 tablet 5V version */
+ .matches = {
+ /* Having all 3 of these not set is somewhat unique */
+ DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
+ DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),
+ /* Above strings are too generic, also match on BIOS date */
+ DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"),
+ },
+ .driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
+ BYT_RT5640_JD_NOT_INV |
+ BYT_RT5640_SSP0_AIF1 |
+ BYT_RT5640_MCLK_EN),
+ },
+ { /* Vexia Edu Atla 10 tablet 9V version */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
index 22668bac74a1..0554c7e2cb34 100644
--- a/sound/soc/intel/boards/skl_hda_dsp_generic.c
+++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c
@@ -124,8 +124,6 @@ static int skl_hda_audio_probe(struct platform_device *pdev)
return ret;
card->dev = &pdev->dev;
- if (!snd_soc_acpi_sof_parent(&pdev->dev))
- card->disable_route_checks = true;
if (mach->mach_params.dmic_num > 0) {
card->components = devm_kasprintf(card->dev, GFP_KERNEL,
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index c9f9c9b0de9b..90dafa810b2e 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -13,6 +13,7 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_intel.h>
+#include <sound/core.h>
#include <sound/soc-acpi.h>
#include "sof_sdw_common.h"
#include "../../codecs/rt711.h"
@@ -22,6 +23,8 @@ static int quirk_override = -1;
module_param_named(quirk, quirk_override, int, 0444);
MODULE_PARM_DESC(quirk, "Board-specific quirk override");
+#define DMIC_DEFAULT_CHANNELS 2
+
static void log_quirks(struct device *dev)
{
if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk))
@@ -42,6 +45,8 @@ static void log_quirks(struct device *dev)
dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n");
if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS)
dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n");
+ if (sof_sdw_quirk & SOC_SDW_CODEC_MIC)
+ dev_dbg(dev, "quirk SOC_SDW_CODEC_MIC enabled\n");
}
static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
@@ -608,25 +613,41 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "3838")
+ DMI_MATCH(DMI_PRODUCT_NAME, "83JX")
},
- .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
},
{
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "3832")
+ DMI_MATCH(DMI_PRODUCT_NAME, "83LC")
},
- .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
},
{
.callback = sof_sdw_quirk_cb,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "380E")
+ DMI_MATCH(DMI_PRODUCT_NAME, "83MC")
},
- .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
+ }, {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83NM")
+ },
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
+ },
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "83HM")
+ },
+ .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS |
+ SOC_SDW_CODEC_MIC),
},
{
.callback = sof_sdw_quirk_cb,
@@ -728,9 +749,36 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
},
.driver_data = (void *)(SOC_SDW_PCH_DMIC),
},
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"),
+ },
+ .driver_data = (void *)(SOC_SDW_PCH_DMIC |
+ SOF_BT_OFFLOAD_SSP(2) |
+ SOF_SSP_BT_OFFLOAD_PRESENT),
+ },
{}
};
+static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = {
+ SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC),
+ {}
+};
+
+static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach)
+{
+ const struct snd_pci_quirk *quirk_entry;
+
+ quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor,
+ mach->mach_params.subsystem_device,
+ sof_sdw_ssid_quirk_table);
+
+ if (quirk_entry)
+ sof_sdw_quirk = quirk_entry->value;
+}
+
static struct snd_soc_dai_link_component platform_component[] = {
{
/* name might be overridden during probe */
@@ -755,7 +803,9 @@ static int create_sdw_dailink(struct snd_soc_card *card,
int *be_id, struct snd_soc_codec_conf **codec_conf)
{
struct device *dev = card->dev;
+ struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
+ struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
struct asoc_sdw_endpoint *sof_end;
int stream;
@@ -852,6 +902,11 @@ static int create_sdw_dailink(struct snd_soc_card *card,
codecs[j].name = sof_end->codec_name;
codecs[j].dai_name = sof_end->dai_info->dai_name;
+ if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC &&
+ mach_params->dmic_num > 0) {
+ dev_warn(dev,
+ "Both SDW DMIC and PCH DMIC are present, if incorrect, please set kernel params snd_sof_intel_hda_generic dmic_num=0 to disable PCH DMIC\n");
+ }
j++;
}
@@ -899,7 +954,7 @@ static int create_sdw_dailinks(struct snd_soc_card *card,
/* generate DAI links by each sdw link */
while (sof_dais->initialised) {
- int current_be_id;
+ int current_be_id = 0;
ret = create_sdw_dailink(card, sof_dais, dai_links,
&current_be_id, codec_conf);
@@ -1127,22 +1182,24 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
/* enable dmic01 & dmic16k */
- if (sof_sdw_quirk & SOC_SDW_PCH_DMIC || mach_params->dmic_num) {
- if (ctx->ignore_internal_dmic)
- dev_warn(dev, "Ignoring PCH DMIC\n");
- else
- dmic_num = 2;
+ if (ctx->ignore_internal_dmic) {
+ dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n");
+ mach_params->dmic_num = 0;
+ } else if (mach_params->dmic_num) {
+ dmic_num = 2;
+ } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) {
+ dmic_num = 2;
+ /*
+ * mach_params->dmic_num will be used to set the cfg-mics value of
+ * card->components string. Set it to the default value.
+ */
+ mach_params->dmic_num = DMIC_DEFAULT_CHANNELS;
}
- /*
- * mach_params->dmic_num will be used to set the cfg-mics value of card->components
- * string. Overwrite it to the actual number of PCH DMICs used in the device.
- */
- mach_params->dmic_num = dmic_num;
if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
bt_num = 1;
- dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
+ dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
sdw_be_num, ssp_num, dmic_num,
intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
@@ -1256,6 +1313,13 @@ static int mc_probe(struct platform_device *pdev)
snd_soc_card_set_drvdata(card, ctx);
+ if (mach->mach_params.subsystem_id_set) {
+ snd_soc_card_set_pci_ssid(card,
+ mach->mach_params.subsystem_vendor,
+ mach->mach_params.subsystem_device);
+ sof_sdw_check_ssid_quirk(mach);
+ }
+
dmi_check_system(sof_sdw_quirk_table);
if (quirk_override != -1) {
@@ -1271,12 +1335,6 @@ static int mc_probe(struct platform_device *pdev)
for (i = 0; i < ctx->codec_info_list_count; i++)
codec_info_list[i].amp_num = 0;
- if (mach->mach_params.subsystem_id_set) {
- snd_soc_card_set_pci_ssid(card,
- mach->mach_params.subsystem_vendor,
- mach->mach_params.subsystem_device);
- }
-
ret = sof_card_dai_links_create(card);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c
index 2aa637124bec..faa916f40069 100644
--- a/sound/soc/intel/catpt/device.c
+++ b/sound/soc/intel/catpt/device.c
@@ -28,7 +28,7 @@
#define CREATE_TRACE_POINTS
#include "trace.h"
-static int __maybe_unused catpt_suspend(struct device *dev)
+static int catpt_suspend(struct device *dev)
{
struct catpt_dev *cdev = dev_get_drvdata(dev);
struct dma_chan *chan;
@@ -72,7 +72,7 @@ release_dma_chan:
return catpt_dsp_power_down(cdev);
}
-static int __maybe_unused catpt_resume(struct device *dev)
+static int catpt_resume(struct device *dev)
{
struct catpt_dev *cdev = dev_get_drvdata(dev);
int ret, i;
@@ -106,7 +106,7 @@ static int __maybe_unused catpt_resume(struct device *dev)
return 0;
}
-static int __maybe_unused catpt_runtime_suspend(struct device *dev)
+static int catpt_runtime_suspend(struct device *dev)
{
if (!try_module_get(dev->driver->owner)) {
dev_info(dev, "module unloading, skipping suspend\n");
@@ -117,14 +117,14 @@ static int __maybe_unused catpt_runtime_suspend(struct device *dev)
return catpt_suspend(dev);
}
-static int __maybe_unused catpt_runtime_resume(struct device *dev)
+static int catpt_runtime_resume(struct device *dev)
{
return catpt_resume(dev);
}
static const struct dev_pm_ops catpt_dev_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume)
- SET_RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume)
+ RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL)
};
/* machine board owned by CATPT is removed with this hook */
@@ -378,7 +378,7 @@ static struct platform_driver catpt_acpi_driver = {
.driver = {
.name = "intel_catpt",
.acpi_match_table = catpt_ids,
- .pm = &catpt_dev_pm,
+ .pm = pm_ptr(&catpt_dev_pm),
.dev_groups = catpt_attr_groups,
},
};
diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
index bb1324fb588e..a68efbe98948 100644
--- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c
@@ -214,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = {
+ {
+ .adr = 0x000232025D131601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1316-2"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt1316_1_single_adr[] = {
{
.adr = 0x000130025D131601ull,
@@ -547,6 +556,20 @@ static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = {
{}
};
+static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link02[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+ .adr_d = rt1316_0_group2_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1316_2_group2_adr),
+ .adr_d = rt1316_2_group2_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_codecs adl_max98357a_amp = {
.num_codecs = 1,
.codecs = {"MX98357A"}
@@ -749,6 +772,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-adl-sdw-max98373-rt5682.tplg",
},
+ {
+ .link_mask = BIT(0) | BIT(2),
+ .links = adl_sdw_rt1316_link02,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-adl-rt1316-l02.tplg",
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines);
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 24d850df77ca..32147dc9d2d6 100644
--- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c
@@ -138,7 +138,7 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_r1_adr[] = {
},
};
-static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = {
+static const struct snd_soc_acpi_adr_device cs35l56_3_l3_adr[] = {
{
.adr = 0x00033301fa355601ull,
.num_endpoints = 1,
@@ -147,6 +147,24 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = {
},
};
+static const struct snd_soc_acpi_adr_device cs35l56_2_r3_adr[] = {
+ {
+ .adr = 0x00023301fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = {
+ {
+ .adr = 0x00033101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+};
+
static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
{ /* Jack Playback Endpoint */
.num = 0,
@@ -306,6 +324,25 @@ static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_2_l23[] = {
},
{
.mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_l3_adr),
+ .adr_d = cs35l56_3_l3_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_3_l23[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_0_adr),
+ .adr_d = cs42l43_0_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs35l56_2_r3_adr),
+ .adr_d = cs35l56_2_r3_adr,
+ },
+ {
+ .mask = BIT(3),
.num_adr = ARRAY_SIZE(cs35l56_3_l1_adr),
.adr_d = cs35l56_3_l1_adr,
},
@@ -407,6 +444,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
.sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
},
{
+ .link_mask = BIT(0) | BIT(2) | BIT(3),
+ .links = arl_cs42l43_l0_cs35l56_3_l23,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg",
+ },
+ {
.link_mask = BIT(0) | BIT(2),
.links = arl_cs42l43_l0_cs35l56_l2,
.drv_name = "sof_sdw",
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 98a9c36d7a4c..e04f6de746eb 100644
--- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c
@@ -37,6 +37,13 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
.group_id = 1,
};
+static const struct snd_soc_acpi_endpoint spk_1_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+};
+
static const struct snd_soc_acpi_endpoint spk_2_endpoint = {
.num = 0,
.aggregated = 1,
@@ -51,6 +58,27 @@ static const struct snd_soc_acpi_endpoint spk_3_endpoint = {
.group_id = 1,
};
+static const struct snd_soc_acpi_endpoint spk_4_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_5_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 5,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_6_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 6,
+ .group_id = 1,
+};
+
static const struct snd_soc_acpi_endpoint rt712_endpoints[] = {
{
.num = 0,
@@ -91,6 +119,23 @@ static const struct snd_soc_acpi_endpoint rt722_endpoints[] = {
},
};
+static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = {
+ /* Jack Endpoint */
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ /* DMIC Endpoint */
+ {
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] = {
/* Jack Endpoint */
{
@@ -142,6 +187,33 @@ static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
},
};
+static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+ },
+};
+
static const struct snd_soc_acpi_adr_device cs35l56_2_l_adr[] = {
{
.adr = 0x00023001FA355601ull,
@@ -187,6 +259,48 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = {
+ {
+ .adr = 0x00013001fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_1_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00013201fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP3"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = {
+ {
+ .adr = 0x00033301fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_4_endpoint,
+ .name_prefix = "AMP4"
+ },
+ {
+ .adr = 0x00033401fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_5_endpoint,
+ .name_prefix = "AMP5"
+ },
+ {
+ .adr = 0x00033501fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_6_endpoint,
+ .name_prefix = "AMP6"
+ }
+};
+
static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
{
.adr = 0x00003001FA424301ull,
@@ -196,6 +310,15 @@ static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = {
+ {
+ .adr = 0x00023001fa424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints),
+ .endpoints = cs42l43_amp_spkagg_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -295,6 +418,24 @@ static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = {
+ {
+ .adr = 0x000130025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = {
+ {
+ .adr = 0x000330025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-2"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt713_0_adr[] = {
{
.adr = 0x000031025D071301ull,
@@ -304,6 +445,15 @@ static const struct snd_soc_acpi_adr_device rt713_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt713_vb_2_adr[] = {
+ {
+ .adr = 0x000230025d071301ull,
+ .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
+ .endpoints = jack_dmic_endpoints,
+ .name_prefix = "rt713"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt714_0_adr[] = {
{
.adr = 0x000030025D071401ull,
@@ -364,6 +514,25 @@ static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l23[] = {
{}
};
+static const struct snd_soc_acpi_link_adr lnl_cs42l43_l2_cs35l56x6_l13[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs42l43_2_adr),
+ .adr_d = cs42l43_2_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr),
+ .adr_d = cs35l56_1_3amp_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr),
+ .adr_d = cs35l56_3_3amp_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr lnl_rvp[] = {
{
.mask = BIT(0),
@@ -453,6 +622,25 @@ static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = {
{}
};
+static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_vb_l2_rt1320_l13[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt713_vb_2_adr),
+ .adr_d = rt713_vb_2_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1320_1_group2_adr),
+ .adr_d = rt1320_1_group2_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1320_3_group2_adr),
+ .adr_d = rt1320_3_group2_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr lnl_sdw_rt712_vb_l2_rt1320_l1[] = {
{
.mask = BIT(2),
@@ -490,6 +678,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.sof_tplg_filename = "sof-lnl-rt715-rt711-rt1308-mono.tplg",
},
{
+ .link_mask = BIT(0),
+ .links = sdw_mockup_multi_func,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-lnl-rt722-l0.tplg", /* Reuse the existing tplg file */
+ },
+ {
.link_mask = GENMASK(3, 0),
.links = lnl_3_in_1_sdca,
.drv_name = "sof_sdw",
@@ -502,6 +696,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg",
},
{
+ .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",
+ },
+ {
.link_mask = BIT(0) | BIT(3),
.links = lnl_cs42l43_l0_cs35l56_l3,
.drv_name = "sof_sdw",
@@ -550,6 +750,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = {
.machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
.sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg"
},
+ {
+ .link_mask = BIT(1) | BIT(2) | BIT(3),
+ .links = lnl_sdw_rt713_vb_l2_rt1320_l13,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-lnl-rt713-l2-rt1320-l13.tplg"
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_lnl_sdw_machines);
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 03fc5a187012..9e611e3667ad 100644
--- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c
@@ -330,7 +330,7 @@ static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = {
static const struct snd_soc_acpi_adr_device rt1318_1_single_adr[] = {
{
- .adr = 0x000130025D131801,
+ .adr = 0x000130025D131801ull,
.num_endpoints = 1,
.endpoints = &single_endpoint,
.name_prefix = "rt1318-1"
@@ -441,6 +441,179 @@ static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = {
}
};
+/* CS42L43 - speaker DAI aggregated with 4 amps */
+static const struct snd_soc_acpi_endpoint cs42l43_4amp_spkagg_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 1,
+ },
+};
+
+/* CS42L43 on link3 aggregated with 4 amps */
+static const struct snd_soc_acpi_adr_device cs42l43_l3_4amp_spkagg_adr[] = {
+ {
+ .adr = 0x00033001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_4amp_spkagg_endpoints),
+ .endpoints = cs42l43_4amp_spkagg_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_l_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_r_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_2_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 2,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 2,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_3_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 3,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 3,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_4_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_5_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 5,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 5,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_6_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 6,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 6,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_7_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 7,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 7,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_0_adr[] = {
+ {
+ .adr = 0x00003301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00003201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ }
+};
+
static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = {
{
.adr = 0x00013701FA355601ull,
@@ -471,17 +644,71 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device cs35l56_0_fb_adr[] = {
+ {
+ .adr = 0x00003301FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints),
+ .endpoints = cs35l56_l_fb_endpoints,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00003201FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints),
+ .endpoints = cs35l56_2_fb_endpoints,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00003101FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_4_fb_endpoints),
+ .endpoints = cs35l56_4_fb_endpoints,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00003001FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_6_fb_endpoints),
+ .endpoints = cs35l56_6_fb_endpoints,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_1_fb_adr[] = {
+ {
+ .adr = 0x00013701FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints),
+ .endpoints = cs35l56_r_fb_endpoints,
+ .name_prefix = "AMP8"
+ },
+ {
+ .adr = 0x00013601FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints),
+ .endpoints = cs35l56_3_fb_endpoints,
+ .name_prefix = "AMP7"
+ },
+ {
+ .adr = 0x00013501FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints),
+ .endpoints = cs35l56_5_fb_endpoints,
+ .name_prefix = "AMP6"
+ },
+ {
+ .adr = 0x00013401FA355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_7_fb_endpoints),
+ .endpoints = cs35l56_7_fb_endpoints,
+ .name_prefix = "AMP5"
+ },
+};
+
static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = {
{
.adr = 0x00023201FA355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_r_endpoint,
+ .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints),
+ .endpoints = cs35l56_r_fb_endpoints,
.name_prefix = "AMP3"
},
{
.adr = 0x00023301FA355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_3_endpoint,
+ .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints),
+ .endpoints = cs35l56_3_fb_endpoints,
.name_prefix = "AMP4"
}
@@ -490,14 +717,14 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = {
static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = {
{
.adr = 0x00033001fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_l_endpoint,
+ .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints),
+ .endpoints = cs35l56_l_fb_endpoints,
.name_prefix = "AMP1"
},
{
.adr = 0x00033101fa355601ull,
- .num_endpoints = 1,
- .endpoints = &spk_2_endpoint,
+ .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints),
+ .endpoints = cs35l56_2_fb_endpoints,
.name_prefix = "AMP2"
}
};
@@ -765,6 +992,40 @@ static const struct snd_soc_acpi_link_adr cs42l43_link0_cs35l56_link2_link3[] =
{}
};
+static const struct snd_soc_acpi_link_adr cs42l43_link3_cs35l56_x4_link0_link1_spkagg[] = {
+ /* Expected order: jack -> amp */
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs42l43_l3_4amp_spkagg_adr),
+ .adr_d = cs42l43_l3_4amp_spkagg_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = 2,
+ .adr_d = cs35l56_1_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = 2,
+ .adr_d = cs35l56_0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr mtl_cs35l56_x8_link0_link1_fb[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56_1_fb_adr),
+ .adr_d = cs35l56_1_fb_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs35l56_0_fb_adr),
+ .adr_d = cs35l56_0_fb_adr,
+ },
+ {}
+};
+
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -842,12 +1103,24 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = {
.sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l23.tplg",
},
{
+ .link_mask = BIT(0) | BIT(1) | BIT(3),
+ .links = cs42l43_link3_cs35l56_x4_link0_link1_spkagg,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-cs42l43-l3-cs35l56-l01-spkagg.tplg",
+ },
+ {
.link_mask = GENMASK(2, 0),
.links = mtl_cs42l43_cs35l56,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l12.tplg",
},
{
+ .link_mask = BIT(0) | BIT(1),
+ .links = mtl_cs35l56_x8_link0_link1_fb,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg"
+ },
+ {
.link_mask = BIT(0),
.links = mtl_cs42l43_l0,
.drv_name = "sof_sdw",
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 f1c0d7a02cda..6603d8de501c 100644
--- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c
@@ -8,6 +8,7 @@
#include <sound/soc-acpi.h>
#include <sound/soc-acpi-intel-match.h>
+#include "soc-acpi-intel-sdca-quirks.h"
#include "soc-acpi-intel-sdw-mockup-match.h"
#include <sound/soc-acpi-intel-ssp-common.h>
@@ -35,6 +36,62 @@ static const struct snd_soc_acpi_endpoint single_endpoint = {
.group_id = 0,
};
+static const struct snd_soc_acpi_endpoint spk_l_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_1_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_2_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 2,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_3_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 3,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_4_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_5_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 5,
+ .group_id = 1,
+};
+
+static const struct snd_soc_acpi_endpoint spk_6_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 6,
+ .group_id = 1,
+};
+
/*
* Multi-function codecs with three endpoints created for
* headset, amp and dmic functions.
@@ -60,6 +117,161 @@ static const struct snd_soc_acpi_endpoint rt_mf_endpoints[] = {
},
};
+static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = {
+ /* Jack Endpoint */
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ /* DMIC Endpoint */
+ {
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] = {
+ /* Jack Endpoint */
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ /* Amp Endpoint, work as spk_l_endpoint */
+ {
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+ },
+ /* DMIC Endpoint */
+ {
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = {
+ {
+ .adr = 0x00023001fa424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints),
+ .endpoints = cs42l43_amp_spkagg_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = {
+ {
+ .adr = 0x00013001fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_1_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013101fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00013201fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP3"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = {
+ {
+ .adr = 0x00033301fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_4_endpoint,
+ .name_prefix = "AMP4"
+ },
+ {
+ .adr = 0x00033401fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_5_endpoint,
+ .name_prefix = "AMP5"
+ },
+ {
+ .adr = 0x00033501fa355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_6_endpoint,
+ .name_prefix = "AMP6"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = {
+ {
+ .adr = 0x00033001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -69,6 +281,42 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D071201ull,
+ .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints),
+ .endpoints = jack_amp_g1_dmic_endpoints_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt712_vb_3_group1_adr[] = {
+ {
+ .adr = 0x000330025D071201ull,
+ .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints),
+ .endpoints = jack_amp_g1_dmic_endpoints_endpoints,
+ .name_prefix = "rt712"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt713_vb_2_adr[] = {
+ {
+ .adr = 0x000230025d071301ull,
+ .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
+ .endpoints = jack_dmic_endpoints,
+ .name_prefix = "rt713"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt713_vb_3_adr[] = {
+ {
+ .adr = 0x000330025D071301ull,
+ .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
+ .endpoints = jack_dmic_endpoints,
+ .name_prefix = "rt713"
+ }
+};
+
static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = {
{
.adr = 0x000330025d072101ull,
@@ -114,6 +362,78 @@ static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = {
+ {
+ .adr = 0x000130025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = {
+ {
+ .adr = 0x000130025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_2_group1_adr[] = {
+ {
+ .adr = 0x000230025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_2_group2_adr[] = {
+ {
+ .adr = 0x000230025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-1"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = {
+ {
+ .adr = 0x000330025D132001ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "rt1320-2"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(cs42l43_2_adr),
+ .adr_d = cs42l43_2_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr),
+ .adr_d = cs35l56_1_3amp_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr),
+ .adr_d = cs35l56_3_3amp_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_cs42l43_l3[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(cs42l43_3_adr),
+ .adr_d = cs42l43_3_adr,
+ }
+};
+
static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = {
{
.mask = BIT(0),
@@ -150,6 +470,72 @@ static const struct snd_soc_acpi_link_adr ptl_rvp[] = {
{}
};
+static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l2_rt1320_l13[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt713_vb_2_adr),
+ .adr_d = rt713_vb_2_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1320_1_group2_adr),
+ .adr_d = rt1320_1_group2_adr,
+ },
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt1320_3_group2_adr),
+ .adr_d = rt1320_3_group2_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l3_rt1320_l12[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt713_vb_3_adr),
+ .adr_d = rt713_vb_3_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1320_1_group2_adr),
+ .adr_d = rt1320_1_group2_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1320_2_group2_adr),
+ .adr_d = rt1320_2_group2_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l2_rt1320_l1[] = {
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt712_vb_2_group1_adr),
+ .adr_d = rt712_vb_2_group1_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(rt1320_1_group1_adr),
+ .adr_d = rt1320_1_group1_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l2[] = {
+ {
+ .mask = BIT(3),
+ .num_adr = ARRAY_SIZE(rt712_vb_3_group1_adr),
+ .adr_d = rt712_vb_3_group1_adr,
+ },
+ {
+ .mask = BIT(2),
+ .num_adr = ARRAY_SIZE(rt1320_2_group1_adr),
+ .adr_d = rt1320_2_group1_adr,
+ },
+ {}
+};
+
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -172,6 +558,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.sof_tplg_filename = "sof-ptl-rt715-rt711-rt1308-mono.tplg",
},
{
+ .link_mask = BIT(1) | BIT(2) | BIT(3),
+ .links = ptl_cs42l43_l2_cs35l56x6_l13,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-cs42l43-l2-cs35l56x6-l13.tplg",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = sdw_mockup_multi_func,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-rt722.tplg", /* Reuse the existing tplg file */
+ },
+ {
.link_mask = BIT(0),
.links = ptl_rvp,
.drv_name = "sof_sdw",
@@ -179,6 +577,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
},
{
.link_mask = BIT(3),
+ .links = ptl_cs42l43_l3,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-ptl-cs42l43-l3.tplg",
+ },
+ {
+ .link_mask = BIT(3),
.links = ptl_rt721_l3,
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-ptl-rt721.tplg",
@@ -201,6 +605,34 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-ptl-rt722.tplg",
},
+ {
+ .link_mask = BIT(1) | BIT(2),
+ .links = ptl_sdw_rt712_vb_l2_rt1320_l1,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-ptl-rt712-l2-rt1320-l1.tplg"
+ },
+ {
+ .link_mask = BIT(2) | BIT(3),
+ .links = ptl_sdw_rt712_vb_l3_rt1320_l2,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l2.tplg"
+ },
+ {
+ .link_mask = BIT(1) | BIT(2) | BIT(3),
+ .links = ptl_sdw_rt713_vb_l2_rt1320_l13,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-ptl-rt713-l2-rt1320-l13.tplg"
+ },
+ {
+ .link_mask = BIT(1) | BIT(2) | BIT(3),
+ .links = ptl_sdw_rt713_vb_l3_rt1320_l12,
+ .drv_name = "sof_sdw",
+ .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
+ .sof_tplg_filename = "sof-ptl-rt713-l3-rt1320-l12.tplg"
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines);
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c
index a3d33997736a..d122ce69fa4f 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c
@@ -31,6 +31,30 @@ static const struct snd_soc_acpi_endpoint sdw_mockup_r_endpoint = {
.group_id = 1,
};
+static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = {
+ /* Jack Endpoint */
+ {
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ /* Amp Endpoint, work as spk_l_endpoint */
+ {
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+ },
+ /* DMIC Endpoint */
+ {
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
static const struct snd_soc_acpi_adr_device sdw_mockup_headset_0_adr[] = {
{
.adr = 0x0000000105AA5500ull,
@@ -103,6 +127,15 @@ static const struct snd_soc_acpi_adr_device sdw_mockup_amp_2_group1_adr[] = {
}
};
+static const struct snd_soc_acpi_adr_device sdw_mockup_multi_function_adr[] = {
+ {
+ .adr = 0x0000000105AAAA01ull,
+ .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints),
+ .endpoints = jack_amp_g1_dmic_endpoints,
+ .name_prefix = "sdw_mockup_mmulti-function"
+ }
+};
+
const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[] = {
{
.mask = BIT(0),
@@ -164,3 +197,12 @@ const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[] = {
},
{}
};
+
+const struct snd_soc_acpi_link_adr sdw_mockup_multi_func[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(sdw_mockup_multi_function_adr),
+ .adr_d = sdw_mockup_multi_function_adr,
+ },
+ {}
+};
diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h
index c99eecd19e03..f7ed5beaca96 100644
--- a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h
+++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h
@@ -13,5 +13,6 @@
extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[];
extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_2amps_mic[];
extern const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[];
+extern const struct snd_soc_acpi_link_adr sdw_mockup_multi_func[];
#endif
diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
index 161ba532d270..b77aafb0bfb6 100644
--- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
+++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c
@@ -536,6 +536,194 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = {
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines);
+static const struct snd_soc_acpi_endpoint cs35l56_l_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 0,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_r_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 1,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_2_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 2,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 2,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_3_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 3,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 3,
+ .group_id = 2,
+ },
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_4_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 4,
+ .group_id = 2,
+ }
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_5_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 5,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 5,
+ .group_id = 2,
+ }
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_6_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 6,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 6,
+ .group_id = 2,
+ }
+};
+
+static const struct snd_soc_acpi_endpoint cs35l56_7_fb_endpoints[] = {
+ { /* Speaker Playback Endpoint */
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 7,
+ .group_id = 1,
+ },
+ { /* Feedback Capture Endpoint */
+ .num = 1,
+ .aggregated = 1,
+ .group_position = 7,
+ .group_id = 2,
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_sdw_eight_1_4_fb_adr[] = {
+ {
+ .adr = 0x00003301fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints),
+ .endpoints = cs35l56_l_fb_endpoints,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00003201fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints),
+ .endpoints = cs35l56_2_fb_endpoints,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00003101fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_4_fb_endpoints),
+ .endpoints = cs35l56_4_fb_endpoints,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00003001fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_6_fb_endpoints),
+ .endpoints = cs35l56_6_fb_endpoints,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56_sdw_eight_5_8_fb_adr[] = {
+ {
+ .adr = 0x00013701fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints),
+ .endpoints = cs35l56_r_fb_endpoints,
+ .name_prefix = "AMP8"
+ },
+ {
+ .adr = 0x00013601fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints),
+ .endpoints = cs35l56_3_fb_endpoints,
+ .name_prefix = "AMP7"
+ },
+ {
+ .adr = 0x00013501fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints),
+ .endpoints = cs35l56_5_fb_endpoints,
+ .name_prefix = "AMP6"
+ },
+ {
+ .adr = 0x00013401fa355601ull,
+ .num_endpoints = ARRAY_SIZE(cs35l56_7_fb_endpoints),
+ .endpoints = cs35l56_7_fb_endpoints,
+ .name_prefix = "AMP5"
+ },
+};
+
+static const struct snd_soc_acpi_link_adr up_extreme_cs35l56_sdw_eight[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56_sdw_eight_5_8_fb_adr),
+ .adr_d = cs35l56_sdw_eight_5_8_fb_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs35l56_sdw_eight_1_4_fb_adr),
+ .adr_d = cs35l56_sdw_eight_1_4_fb_adr,
+ },
+ {}
+};
+
/* this table is used when there is no I2S codec present */
struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
/* mockup tests need to be first */
@@ -635,6 +823,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = {
.drv_name = "sof_sdw",
.sof_tplg_filename = "sof-tgl-rt711.tplg",
},
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = up_extreme_cs35l56_sdw_eight,
+ .drv_name = "sof_sdw",
+ .sof_tplg_filename = "sof-tgl-cs35l56-l01-fb8.tplg"
+ },
{},
};
EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines);
diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c
index aa5de167e790..4ed71d11ad77 100644
--- a/sound/soc/intel/keembay/kmb_platform.c
+++ b/sound/soc/intel/keembay/kmb_platform.c
@@ -869,7 +869,7 @@ static int kmb_plat_dai_probe(struct platform_device *pdev)
kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2;
- kmb_i2s->use_pio = !(of_property_read_bool(np, "dmas"));
+ kmb_i2s->use_pio = !of_property_present(np, "dmas");
if (kmb_i2s->use_pio) {
irq = platform_get_irq_optional(pdev, 0);
diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c
index 79ee7599f06a..77a5f440364e 100644
--- a/sound/soc/kirkwood/armada-370-db.c
+++ b/sound/soc/kirkwood/armada-370-db.c
@@ -73,20 +73,20 @@ static struct snd_soc_dai_link a370db_dai[] = {
{
.name = "CS42L51",
.stream_name = "analog",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC,
.ops = &a370db_ops,
SND_SOC_DAILINK_REG(analog),
},
{
.name = "S/PDIF out",
.stream_name = "spdif-out",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(spdif_out),
},
{
.name = "S/PDIF in",
.stream_name = "spdif-in",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(spdif_in),
},
};
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
index 3044d9ab3d4d..3809068f5620 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -500,26 +500,6 @@ static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe,
return 0;
}
-int mtk_memif_set_rate(struct mtk_base_afe *afe,
- int id, unsigned int rate)
-{
- int fs = 0;
-
- if (!afe->get_dai_fs) {
- dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n",
- __func__);
- return -EINVAL;
- }
-
- fs = afe->get_dai_fs(afe, id, rate);
-
- if (fs < 0)
- return -EINVAL;
-
- return mtk_memif_set_rate_fs(afe, id, fs);
-}
-EXPORT_SYMBOL_GPL(mtk_memif_set_rate);
-
int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
int id, unsigned int rate)
{
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
index 8cec90671827..b6d0f2b27e86 100644
--- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
@@ -42,8 +42,6 @@ int mtk_memif_set_addr(struct mtk_base_afe *afe, int id,
size_t dma_bytes);
int mtk_memif_set_channel(struct mtk_base_afe *afe,
int id, unsigned int channel);
-int mtk_memif_set_rate(struct mtk_base_afe *afe,
- int id, unsigned int rate);
int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream,
int id, unsigned int rate);
int mtk_memif_set_format(struct mtk_base_afe *afe,
diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h
index 3f6e24dd22df..a1d2794ac1f7 100644
--- a/sound/soc/mediatek/common/mtk-soc-card.h
+++ b/sound/soc/mediatek/common/mtk-soc-card.h
@@ -16,6 +16,7 @@ struct mtk_soc_card_data {
const struct mtk_sof_priv *sof_priv;
struct list_head sof_dai_link_list;
struct mtk_platform_card_data *card_data;
+ struct snd_soc_component *accdet;
void *mach_priv;
};
diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c
index 3bbf42c42805..713a368f79cf 100644
--- a/sound/soc/mediatek/common/mtk-soundcard-driver.c
+++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <sound/soc.h>
#include "mtk-dsp-sof-common.h"
@@ -192,7 +193,9 @@ EXPORT_SYMBOL_GPL(mtk_soundcard_common_capture_ops);
int mtk_soundcard_common_probe(struct platform_device *pdev)
{
- struct device_node *platform_node, *adsp_node;
+ struct device_node *platform_node, *adsp_node, *accdet_node;
+ struct snd_soc_component *accdet_comp;
+ struct platform_device *accdet_pdev;
const struct mtk_soundcard_pdata *pdata;
struct mtk_soc_card_data *soc_card_data;
struct snd_soc_dai_link *orig_dai_link, *dai_link;
@@ -221,7 +224,7 @@ int mtk_soundcard_common_probe(struct platform_device *pdev)
card->name = pdata->card_name;
}
- needs_legacy_probe = !of_property_read_bool(pdev->dev.of_node, "audio-routing");
+ needs_legacy_probe = !of_property_present(pdev->dev.of_node, "audio-routing");
if (needs_legacy_probe) {
/*
* If we have no .soc_probe() callback there's no way of using
@@ -250,6 +253,20 @@ int mtk_soundcard_common_probe(struct platform_device *pdev)
soc_card_data->card_data->jacks = jacks;
+ accdet_node = of_parse_phandle(pdev->dev.of_node, "mediatek,accdet", 0);
+ if (accdet_node) {
+ accdet_pdev = of_find_device_by_node(accdet_node);
+ if (accdet_pdev) {
+ accdet_comp = snd_soc_lookup_component(&accdet_pdev->dev, NULL);
+ if (accdet_comp)
+ soc_card_data->accdet = accdet_comp;
+ else
+ dev_err(&pdev->dev, "No sound component found from mediatek,accdet property\n");
+ } else {
+ dev_err(&pdev->dev, "No device found from mediatek,accdet property\n");
+ }
+ }
+
platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0);
if (!platform_node)
return dev_err_probe(&pdev->dev, -EINVAL,
@@ -262,7 +279,7 @@ int mtk_soundcard_common_probe(struct platform_device *pdev)
adsp_node = NULL;
if (adsp_node) {
- if (of_property_read_bool(pdev->dev.of_node, "mediatek,dai-link")) {
+ if (of_property_present(pdev->dev.of_node, "mediatek,dai-link")) {
ret = mtk_sof_dailink_parse_of(card, pdev->dev.of_node,
"mediatek,dai-link",
card->dai_link, card->num_links);
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index 5f11bc5438bd..fcae38135d93 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -1462,15 +1462,15 @@ static const struct of_device_id mt2701_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match);
static const struct dev_pm_ops mt2701_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend,
- mt2701_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt2701_afe_runtime_suspend,
+ mt2701_afe_runtime_resume, NULL)
};
static struct platform_driver mt2701_afe_pcm_driver = {
.driver = {
.name = "mt2701-audio",
.of_match_table = mt2701_afe_pcm_dt_match,
- .pm = &mt2701_afe_pm_ops,
+ .pm = pm_ptr(&mt2701_afe_pm_ops),
},
.probe = mt2701_afe_pcm_dev_probe,
.remove = mt2701_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
index 00a79867235d..778a9dccfcaa 100644
--- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -266,7 +266,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
[DAI_LINK_BE_I2S0] = {
.name = "mt2701-cs42448-I2S0",
.no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
| SND_SOC_DAIFMT_GATED,
.ops = &mt2701_cs42448_be_ops,
SND_SOC_DAILINK_REG(be_i2s0),
@@ -274,7 +274,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
[DAI_LINK_BE_I2S1] = {
.name = "mt2701-cs42448-I2S1",
.no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
| SND_SOC_DAIFMT_GATED,
.ops = &mt2701_cs42448_be_ops,
SND_SOC_DAILINK_REG(be_i2s1),
@@ -282,7 +282,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
[DAI_LINK_BE_I2S2] = {
.name = "mt2701-cs42448-I2S2",
.no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
| SND_SOC_DAIFMT_GATED,
.ops = &mt2701_cs42448_be_ops,
SND_SOC_DAILINK_REG(be_i2s2),
@@ -290,7 +290,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
[DAI_LINK_BE_I2S3] = {
.name = "mt2701-cs42448-I2S3",
.no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
| SND_SOC_DAIFMT_GATED,
.ops = &mt2701_cs42448_be_ops,
SND_SOC_DAILINK_REG(be_i2s3),
diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
index 2814f0570928..84b3d6cd77a5 100644
--- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c
+++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c
@@ -83,7 +83,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = {
{
.name = "wm8960-codec",
.no_pcm = 1,
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC
| SND_SOC_DAIFMT_GATED,
.ops = &mt2701_wm8960_be_ops,
SND_SOC_DAILINK_REG(codec),
diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
index 9159b42adf6a..f62a32f2f2b6 100644
--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
@@ -879,15 +879,15 @@ static const struct of_device_id mt6797_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt6797_afe_pcm_dt_match);
static const struct dev_pm_ops mt6797_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt6797_afe_runtime_suspend,
- mt6797_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt6797_afe_runtime_suspend,
+ mt6797_afe_runtime_resume, NULL)
};
static struct platform_driver mt6797_afe_pcm_driver = {
.driver = {
.name = "mt6797-audio",
.of_match_table = mt6797_afe_pcm_dt_match,
- .pm = &mt6797_afe_pm_ops,
+ .pm = pm_ptr(&mt6797_afe_pm_ops),
},
.probe = mt6797_afe_pcm_dev_probe,
.remove = mt6797_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
index 7db090414d59..7a6ad9116e55 100644
--- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
@@ -589,15 +589,15 @@ static const struct of_device_id mt7986_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match);
static const struct dev_pm_ops mt7986_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend,
- mt7986_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt7986_afe_runtime_suspend,
+ mt7986_afe_runtime_resume, NULL)
};
static struct platform_driver mt7986_afe_pcm_driver = {
.driver = {
.name = "mt7986-audio",
.of_match_table = mt7986_afe_pcm_dt_match,
- .pm = &mt7986_afe_pm_ops,
+ .pm = pm_ptr(&mt7986_afe_pm_ops),
},
.probe = mt7986_afe_pcm_dev_probe,
.remove = mt7986_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
index d57971413a04..fc55ff47b7bc 100644
--- a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
+++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c
@@ -348,10 +348,10 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
etdm_data->slave_mode = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
etdm_data->slave_mode = false;
break;
default:
diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
index c3d1e2eeb0e5..f1dc18222be7 100644
--- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c
+++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c
@@ -63,7 +63,7 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS |
+ SND_SOC_DAIFMT_CBC_CFC |
SND_SOC_DAIFMT_GATED,
SND_SOC_DAILINK_REG(codec),
},
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 03250273ea9c..04ed0cfec174 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -1212,15 +1212,15 @@ static const struct of_device_id mt8173_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8173_afe_pcm_dt_match);
static const struct dev_pm_ops mt8173_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8173_afe_runtime_suspend,
- mt8173_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt8173_afe_runtime_suspend,
+ mt8173_afe_runtime_resume, NULL)
};
static struct platform_driver mt8173_afe_pcm_driver = {
.driver = {
.name = "mt8173-afe-pcm",
.of_match_table = mt8173_afe_pcm_dt_match,
- .pm = &mt8173_afe_pm_ops,
+ .pm = pm_ptr(&mt8173_afe_pm_ops),
},
.probe = mt8173_afe_pcm_dev_probe,
.remove = mt8173_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c
index 0724564cee6a..49ebb67c818a 100644
--- a/sound/soc/mediatek/mt8173/mt8173-max98090.c
+++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c
@@ -122,7 +122,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = {
.init = mt8173_max98090_init,
.ops = &mt8173_max98090_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(hifi),
},
};
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
index d8e4e70d834c..dc063d85e62f 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c
@@ -156,7 +156,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = {
.no_pcm = 1,
.init = mt8173_rt5650_rt5514_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &mt8173_rt5650_rt5514_ops,
.ignore_pmdown_time = 1,
SND_SOC_DAILINK_REG(codec),
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
index 488f2314dbf7..a1ba5df87e1e 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c
@@ -197,7 +197,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.no_pcm = 1,
.init = mt8173_rt5650_rt5676_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &mt8173_rt5650_rt5676_ops,
.ignore_pmdown_time = 1,
SND_SOC_DAILINK_REG(codec),
@@ -214,7 +214,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = {
.stream_name = "rt5650_rt5676 intercodec",
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(intercodec),
},
};
diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
index 59c19fdd8675..7d6a3586cdd5 100644
--- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c
+++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c
@@ -235,7 +235,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = {
.no_pcm = 1,
.init = mt8173_rt5650_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &mt8173_rt5650_ops,
.ignore_pmdown_time = 1,
SND_SOC_DAILINK_REG(codec),
diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
index 3f377ba4ad53..d083b4bf0f95 100644
--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
@@ -1257,15 +1257,15 @@ static const struct of_device_id mt8183_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8183_afe_pcm_dt_match);
static const struct dev_pm_ops mt8183_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8183_afe_runtime_suspend,
- mt8183_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt8183_afe_runtime_suspend,
+ mt8183_afe_runtime_resume, NULL)
};
static struct platform_driver mt8183_afe_pcm_driver = {
.driver = {
.name = "mt8183-audio",
.of_match_table = mt8183_afe_pcm_dt_match,
- .pm = &mt8183_afe_pm_ops,
+ .pm = pm_ptr(&mt8183_afe_pm_ops),
},
.probe = mt8183_afe_pcm_dev_probe,
.remove = mt8183_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
index 1d8881e0a361..3388e076ccc9 100644
--- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
@@ -563,7 +563,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_IB_IF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
index 6267c8554c15..497a9043be7b 100644
--- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
+++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c
@@ -575,7 +575,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_IB_IF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
@@ -783,7 +783,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev)
strcmp(dai_link->name, "I2S3") == 0)
dai_link->dai_fmt = SND_SOC_DAIFMT_LEFT_J |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM;
+ SND_SOC_DAIFMT_CBP_CFP;
}
if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) {
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
index 70ec101890d3..daaca36a2d08 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c
@@ -329,61 +329,6 @@ void mt8186_afe_disable_clock(struct mtk_base_afe *afe)
clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]);
}
-int mt8186_afe_suspend_clock(struct mtk_base_afe *afe)
-{
- struct mt8186_afe_private *afe_priv = afe->platform_priv;
- int ret;
-
- /* set audio int bus to 26M */
- ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
- if (ret) {
- dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
- goto clk_mux_audio_intbus_err;
- }
- ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
- if (ret)
- goto clk_mux_audio_intbus_parent_err;
-
- clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
-
- return 0;
-
-clk_mux_audio_intbus_parent_err:
- mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4);
-clk_mux_audio_intbus_err:
- clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
- return ret;
-}
-
-int mt8186_afe_resume_clock(struct mtk_base_afe *afe)
-{
- struct mt8186_afe_private *afe_priv = afe->platform_priv;
- int ret;
-
- /* set audio int bus to normal working clock */
- ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
- if (ret) {
- dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n",
- __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret);
- goto clk_mux_audio_intbus_err;
- }
- ret = mt8186_set_audio_int_bus_parent(afe,
- CLK_TOP_MAINPLL_D2_D4);
- if (ret)
- goto clk_mux_audio_intbus_parent_err;
-
- clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
-
- return 0;
-
-clk_mux_audio_intbus_parent_err:
- mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M);
-clk_mux_audio_intbus_err:
- clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]);
- return ret;
-}
-
int mt8186_apll1_enable(struct mtk_base_afe *afe)
{
struct mt8186_afe_private *afe_priv = afe->platform_priv;
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h
index a9d59e506d9a..e524833ce780 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h
@@ -85,8 +85,6 @@ int mt8186_afe_enable_cgs(struct mtk_base_afe *afe);
void mt8186_afe_disable_cgs(struct mtk_base_afe *afe);
int mt8186_afe_enable_clock(struct mtk_base_afe *afe);
void mt8186_afe_disable_clock(struct mtk_base_afe *afe);
-int mt8186_afe_suspend_clock(struct mtk_base_afe *afe);
-int mt8186_afe_resume_clock(struct mtk_base_afe *afe);
int mt8186_apll1_enable(struct mtk_base_afe *afe);
void mt8186_apll1_disable(struct mtk_base_afe *afe);
diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
index bafbef96a42d..db7c93401bee 100644
--- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
+++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c
@@ -2978,15 +2978,15 @@ static const struct of_device_id mt8186_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8186_afe_pcm_dt_match);
static const struct dev_pm_ops mt8186_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8186_afe_runtime_suspend,
- mt8186_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt8186_afe_runtime_suspend,
+ mt8186_afe_runtime_resume, NULL)
};
static struct platform_driver mt8186_afe_pcm_driver = {
.driver = {
.name = "mt8186-audio",
.of_match_table = mt8186_afe_pcm_dt_match,
- .pm = &mt8186_afe_pm_ops,
+ .pm = pm_ptr(&mt8186_afe_pm_ops),
},
.probe = mt8186_afe_pcm_dev_probe,
};
diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
index a5ef913743d4..43546012cf61 100644
--- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c
+++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c
@@ -875,7 +875,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_IB_IF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.playback_only = 1,
.ignore_suspend = 1,
.init = mt8186_mt6366_rt1019_rt5682s_hdmi_init,
diff --git a/sound/soc/mediatek/mt8188/Makefile b/sound/soc/mediatek/mt8188/Makefile
index 1178bce45c50..b9f3e4ad7b07 100644
--- a/sound/soc/mediatek/mt8188/Makefile
+++ b/sound/soc/mediatek/mt8188/Makefile
@@ -6,6 +6,7 @@ snd-soc-mt8188-afe-y := \
mt8188-afe-pcm.o \
mt8188-audsys-clk.o \
mt8188-dai-adda.o \
+ mt8188-dai-dmic.o \
mt8188-dai-etdm.o \
mt8188-dai-pcm.o
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
index e69c1bb2cb23..7f411b857782 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c
@@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = {
[MT8188_CLK_AUD_ADC] = "aud_adc",
[MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires",
[MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp",
+ [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1",
+ [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2",
+ [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3",
+ [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4",
[MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires",
+ [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1",
+ [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2",
+ [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3",
+ [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4",
[MT8188_CLK_AUD_I2SIN] = "aud_i2sin",
[MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in",
[MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out",
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
index ec53c171c170..c6c78d684f3e 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h
@@ -54,7 +54,15 @@ enum {
MT8188_CLK_AUD_ADC,
MT8188_CLK_AUD_DAC_HIRES,
MT8188_CLK_AUD_A1SYS_HP,
+ MT8188_CLK_AUD_AFE_DMIC1,
+ MT8188_CLK_AUD_AFE_DMIC2,
+ MT8188_CLK_AUD_AFE_DMIC3,
+ MT8188_CLK_AUD_AFE_DMIC4,
MT8188_CLK_AUD_ADC_HIRES,
+ MT8188_CLK_AUD_DMIC_HIRES1,
+ MT8188_CLK_AUD_DMIC_HIRES2,
+ MT8188_CLK_AUD_DMIC_HIRES3,
+ MT8188_CLK_AUD_DMIC_HIRES4,
MT8188_CLK_AUD_I2SIN,
MT8188_CLK_AUD_TDM_IN,
MT8188_CLK_AUD_I2S_OUT,
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-common.h b/sound/soc/mediatek/mt8188/mt8188-afe-common.h
index 1304d685a306..01aa11242e29 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-common.h
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-common.h
@@ -137,6 +137,7 @@ struct mt8188_afe_private {
int mt8188_afe_fs_timing(unsigned int rate);
/* dai register */
int mt8188_dai_adda_register(struct mtk_base_afe *afe);
+int mt8188_dai_dmic_register(struct mtk_base_afe *afe);
int mt8188_dai_etdm_register(struct mtk_base_afe *afe);
int mt8188_dai_pcm_register(struct mtk_base_afe *afe);
diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
index 73e5c63aeec8..ac4fdf8ba78f 100644
--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
@@ -652,6 +652,7 @@ static struct snd_soc_dai_driver mt8188_memif_dai_driver[] = {
static const struct snd_kcontrol_new o002_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN2, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I004 Switch", AFE_CONN2, 4, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I012 Switch", AFE_CONN2, 12, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN2, 20, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN2, 22, 1, 0),
@@ -662,6 +663,8 @@ static const struct snd_kcontrol_new o002_mix[] = {
static const struct snd_kcontrol_new o003_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN3, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I005 Switch", AFE_CONN3, 5, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I006 Switch", AFE_CONN3, 6, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I013 Switch", AFE_CONN3, 13, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN3, 21, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN3, 23, 1, 0),
@@ -672,6 +675,8 @@ static const struct snd_kcontrol_new o003_mix[] = {
static const struct snd_kcontrol_new o004_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN4, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I006 Switch", AFE_CONN4, 6, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I008 Switch", AFE_CONN4, 8, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I014 Switch", AFE_CONN4, 14, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN4, 24, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I074 Switch", AFE_CONN4_2, 10, 1, 0),
@@ -679,6 +684,8 @@ static const struct snd_kcontrol_new o004_mix[] = {
static const struct snd_kcontrol_new o005_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN5, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I007 Switch", AFE_CONN5, 7, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I010 Switch", AFE_CONN5, 10, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I015 Switch", AFE_CONN5, 15, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN5, 25, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I075 Switch", AFE_CONN5_2, 11, 1, 0),
@@ -686,6 +693,7 @@ static const struct snd_kcontrol_new o005_mix[] = {
static const struct snd_kcontrol_new o006_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN6, 0, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I008 Switch", AFE_CONN6, 8, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I016 Switch", AFE_CONN6, 16, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN6, 26, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I076 Switch", AFE_CONN6_2, 12, 1, 0),
@@ -693,18 +701,21 @@ static const struct snd_kcontrol_new o006_mix[] = {
static const struct snd_kcontrol_new o007_mix[] = {
SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN7, 1, 1, 0),
+ SOC_DAPM_SINGLE_AUTODISABLE("I009 Switch", AFE_CONN7, 9, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I017 Switch", AFE_CONN7, 17, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN7, 27, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I077 Switch", AFE_CONN7_2, 13, 1, 0),
};
static const struct snd_kcontrol_new o008_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I010 Switch", AFE_CONN8, 10, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I018 Switch", AFE_CONN8, 18, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN8, 28, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I078 Switch", AFE_CONN8_2, 14, 1, 0),
};
static const struct snd_kcontrol_new o009_mix[] = {
+ SOC_DAPM_SINGLE_AUTODISABLE("I011 Switch", AFE_CONN9, 11, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I019 Switch", AFE_CONN9, 19, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN9, 29, 1, 0),
SOC_DAPM_SINGLE_AUTODISABLE("I079 Switch", AFE_CONN9_2, 15, 1, 0),
@@ -1275,6 +1286,18 @@ static const struct snd_soc_dapm_route mt8188_memif_routes[] = {
{"O002", "I070 Switch", "I070"},
{"O003", "I071 Switch", "I071"},
+ {"O002", "I004 Switch", "I004"},
+ {"O003", "I005 Switch", "I005"},
+ {"O003", "I006 Switch", "I006"},
+ {"O004", "I006 Switch", "I006"},
+ {"O004", "I008 Switch", "I008"},
+ {"O005", "I007 Switch", "I007"},
+ {"O005", "I010 Switch", "I010"},
+ {"O006", "I008 Switch", "I008"},
+ {"O007", "I009 Switch", "I009"},
+ {"O008", "I010 Switch", "I010"},
+ {"O009", "I011 Switch", "I011"},
+
{"O034", "I000 Switch", "I000"},
{"O035", "I001 Switch", "I001"},
{"O034", "I002 Switch", "I002"},
@@ -2855,10 +2878,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg)
case AFE_DMIC3_SRC_DEBUG_MON0:
case AFE_DMIC3_UL_SRC_MON0:
case AFE_DMIC3_UL_SRC_MON1:
- case DMIC_GAIN1_CUR:
- case DMIC_GAIN2_CUR:
- case DMIC_GAIN3_CUR:
- case DMIC_GAIN4_CUR:
case ETDM_IN1_MONITOR:
case ETDM_IN2_MONITOR:
case ETDM_OUT1_MONITOR:
@@ -3076,6 +3095,7 @@ static int mt8188_dai_memif_register(struct mtk_base_afe *afe)
typedef int (*dai_register_cb)(struct mtk_base_afe *);
static const dai_register_cb dai_register_cbs[] = {
mt8188_dai_adda_register,
+ mt8188_dai_dmic_register,
mt8188_dai_etdm_register,
mt8188_dai_pcm_register,
mt8188_dai_memif_register,
@@ -3361,15 +3381,15 @@ static const struct of_device_id mt8188_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8188_afe_pcm_dt_match);
static const struct dev_pm_ops mt8188_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8188_afe_runtime_suspend,
- mt8188_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt8188_afe_runtime_suspend,
+ mt8188_afe_runtime_resume, NULL)
};
static struct platform_driver mt8188_afe_pcm_driver = {
.driver = {
.name = "mt8188-audio",
.of_match_table = mt8188_afe_pcm_dt_match,
- .pm = &mt8188_afe_pm_ops,
+ .pm = pm_ptr(&mt8188_afe_pm_ops),
},
.probe = mt8188_afe_pcm_dev_probe,
};
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
index c796ad8b62ee..40d2ab0a7677 100644
--- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
@@ -84,6 +84,10 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
GATE_AUD1(CLK_AUD_AFE_26M_DMIC_TM, "aud_afe_26m_dmic_tm", "top_a1sys_hp", 14),
GATE_AUD1(CLK_AUD_UL_TML_HIRES, "aud_ul_tml_hires", "top_audio_h", 16),
GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires", "top_audio_h", 17),
+ GATE_AUD1(CLK_AUD_DMIC_HIRES1, "aud_dmic_hires1", "top_audio_h", 20),
+ GATE_AUD1(CLK_AUD_DMIC_HIRES2, "aud_dmic_hires2", "top_audio_h", 21),
+ GATE_AUD1(CLK_AUD_DMIC_HIRES3, "aud_dmic_hires3", "top_audio_h", 22),
+ GATE_AUD1(CLK_AUD_DMIC_HIRES4, "aud_dmic_hires4", "top_audio_h", 23),
/* AUD3 */
GATE_AUD3(CLK_AUD_LINEIN_TUNER, "aud_linein_tuner", "top_apll5", 5),
diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
index 6f34ffc760e0..9cb732863c10 100644
--- a/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
+++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h
@@ -33,6 +33,10 @@ enum{
CLK_AUD_AFE_26M_DMIC_TM,
CLK_AUD_UL_TML_HIRES,
CLK_AUD_ADC_HIRES,
+ CLK_AUD_DMIC_HIRES1,
+ CLK_AUD_DMIC_HIRES2,
+ CLK_AUD_DMIC_HIRES3,
+ CLK_AUD_DMIC_HIRES4,
CLK_AUD_LINEIN_TUNER,
CLK_AUD_EARC_TUNER,
CLK_AUD_I2SIN,
diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c b/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c
new file mode 100644
index 000000000000..adcea7818be2
--- /dev/null
+++ b/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c
@@ -0,0 +1,683 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MediaTek ALSA SoC Audio DAI DMIC I/F Control
+ *
+ * Copyright (c) 2020 MediaTek Inc.
+ * Author: Bicycle Tsai <bicycle.tsai@mediatek.com>
+ * Trevor Wu <trevor.wu@mediatek.com>
+ * Parker Yang <parker.yang@mediatek.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/pcm_params.h>
+#include "mt8188-afe-clk.h"
+#include "mt8188-afe-common.h"
+#include "mt8188-reg.h"
+
+/* DMIC HW Gain configuration maximum value. */
+#define DMIC_GAIN_MAX_STEP GENMASK(19, 0)
+#define DMIC_GAIN_MAX_PER_STEP GENMASK(7, 0)
+#define DMIC_GAIN_MAX_TARGET GENMASK(27, 0)
+#define DMIC_GAIN_MAX_CURRENT GENMASK(27, 0)
+
+#define CLK_PHASE_SEL_CH1 0
+#define CLK_PHASE_SEL_CH2 ((CLK_PHASE_SEL_CH1) + 4)
+
+#define DMIC1_SRC_SEL 0
+#define DMIC2_SRC_SEL 0
+#define DMIC3_SRC_SEL 2
+#define DMIC4_SRC_SEL 0
+#define DMIC5_SRC_SEL 4
+#define DMIC6_SRC_SEL 0
+#define DMIC7_SRC_SEL 6
+#define DMIC8_SRC_SEL 0
+
+enum {
+ SUPPLY_SEQ_DMIC_GAIN,
+ SUPPLY_SEQ_DMIC_CK,
+};
+
+enum {
+ DMIC0,
+ DMIC1,
+ DMIC2,
+ DMIC3,
+ DMIC_NUM,
+};
+
+struct mtk_dai_dmic_ctrl_reg {
+ unsigned int con0;
+};
+
+struct mtk_dai_dmic_hw_gain_ctrl_reg {
+ unsigned int bypass;
+ unsigned int con0;
+};
+
+struct mtk_dai_dmic_priv {
+ unsigned int gain_on[DMIC_NUM];
+ unsigned int channels;
+ bool hires_required;
+};
+
+static const struct mtk_dai_dmic_ctrl_reg dmic_ctrl_regs[DMIC_NUM] = {
+ [DMIC0] = {
+ .con0 = AFE_DMIC0_UL_SRC_CON0,
+ },
+ [DMIC1] = {
+ .con0 = AFE_DMIC1_UL_SRC_CON0,
+ },
+ [DMIC2] = {
+ .con0 = AFE_DMIC2_UL_SRC_CON0,
+ },
+ [DMIC3] = {
+ .con0 = AFE_DMIC3_UL_SRC_CON0,
+ },
+};
+
+static const struct mtk_dai_dmic_ctrl_reg *get_dmic_ctrl_reg(int id)
+{
+ if (id < 0 || id >= DMIC_NUM)
+ return NULL;
+
+ return &dmic_ctrl_regs[id];
+}
+
+static const struct mtk_dai_dmic_hw_gain_ctrl_reg
+ dmic_hw_gain_ctrl_regs[DMIC_NUM] = {
+ [DMIC0] = {
+ .bypass = DMIC_BYPASS_HW_GAIN,
+ .con0 = DMIC_GAIN1_CON0,
+ },
+ [DMIC1] = {
+ .bypass = DMIC_BYPASS_HW_GAIN,
+ .con0 = DMIC_GAIN2_CON0,
+ },
+ [DMIC2] = {
+ .bypass = DMIC_BYPASS_HW_GAIN,
+ .con0 = DMIC_GAIN3_CON0,
+ },
+ [DMIC3] = {
+ .bypass = DMIC_BYPASS_HW_GAIN,
+ .con0 = DMIC_GAIN4_CON0,
+ },
+};
+
+static const struct mtk_dai_dmic_hw_gain_ctrl_reg
+ *get_dmic_hw_gain_ctrl_reg(struct mtk_base_afe *afe, int id)
+{
+ if ((id < 0) || (id >= DMIC_NUM)) {
+ dev_dbg(afe->dev, "%s invalid id\n", __func__);
+ return NULL;
+ }
+
+ return &dmic_hw_gain_ctrl_regs[id];
+}
+
+static void mtk_dai_dmic_hw_gain_bypass(struct mtk_base_afe *afe,
+ unsigned int id, bool bypass)
+{
+ const struct mtk_dai_dmic_hw_gain_ctrl_reg *reg;
+ unsigned int msk;
+
+ reg = get_dmic_hw_gain_ctrl_reg(afe, id);
+ if (!reg)
+ return;
+
+ switch (id) {
+ case DMIC0:
+ msk = DMIC_BYPASS_HW_GAIN_DMIC1_BYPASS;
+ break;
+ case DMIC1:
+ msk = DMIC_BYPASS_HW_GAIN_DMIC2_BYPASS;
+ break;
+ case DMIC2:
+ msk = DMIC_BYPASS_HW_GAIN_DMIC3_BYPASS;
+ break;
+ case DMIC3:
+ msk = DMIC_BYPASS_HW_GAIN_DMIC4_BYPASS;
+ break;
+ default:
+ return;
+ }
+
+ if (bypass)
+ regmap_set_bits(afe->regmap, reg->bypass, msk);
+ else
+ regmap_clear_bits(afe->regmap, reg->bypass, msk);
+}
+
+static void mtk_dai_dmic_hw_gain_on(struct mtk_base_afe *afe, unsigned int id,
+ bool on)
+{
+ const struct mtk_dai_dmic_hw_gain_ctrl_reg *reg = get_dmic_hw_gain_ctrl_reg(afe, id);
+
+ if (!reg)
+ return;
+
+ if (on)
+ regmap_set_bits(afe->regmap, reg->con0, DMIC_GAIN_CON0_GAIN_ON);
+ else
+ regmap_clear_bits(afe->regmap, reg->con0, DMIC_GAIN_CON0_GAIN_ON);
+}
+
+static const struct reg_sequence mtk_dai_dmic_iir_coeff_reg_defaults[] = {
+ { AFE_DMIC0_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC0_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC0_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC0_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC0_IIR_COEF_10_09, 0x0000C048 },
+ { AFE_DMIC1_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC1_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC1_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC1_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC1_IIR_COEF_10_09, 0x0000C048 },
+ { AFE_DMIC2_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC2_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC2_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC2_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC2_IIR_COEF_10_09, 0x0000C048 },
+ { AFE_DMIC3_IIR_COEF_02_01, 0x00000000 },
+ { AFE_DMIC3_IIR_COEF_04_03, 0x00003FB8 },
+ { AFE_DMIC3_IIR_COEF_06_05, 0x3FB80000 },
+ { AFE_DMIC3_IIR_COEF_08_07, 0x3FB80000 },
+ { AFE_DMIC3_IIR_COEF_10_09, 0x0000C048 },
+};
+
+static int mtk_dai_dmic_load_iir_coeff_table(struct mtk_base_afe *afe)
+{
+ return regmap_multi_reg_write(afe->regmap,
+ mtk_dai_dmic_iir_coeff_reg_defaults,
+ ARRAY_SIZE(mtk_dai_dmic_iir_coeff_reg_defaults));
+}
+
+static int mtk_dai_dmic_configure_array(struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ const u32 mask = PWR2_TOP_CON_DMIC8_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC7_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC6_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC5_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC4_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC3_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC2_SRC_SEL_MASK |
+ PWR2_TOP_CON_DMIC1_SRC_SEL_MASK;
+ const u32 val = PWR2_TOP_CON_DMIC8_SRC_SEL_VAL(DMIC8_SRC_SEL) |
+ PWR2_TOP_CON_DMIC7_SRC_SEL_VAL(DMIC7_SRC_SEL) |
+ PWR2_TOP_CON_DMIC6_SRC_SEL_VAL(DMIC6_SRC_SEL) |
+ PWR2_TOP_CON_DMIC5_SRC_SEL_VAL(DMIC5_SRC_SEL) |
+ PWR2_TOP_CON_DMIC4_SRC_SEL_VAL(DMIC4_SRC_SEL) |
+ PWR2_TOP_CON_DMIC3_SRC_SEL_VAL(DMIC3_SRC_SEL) |
+ PWR2_TOP_CON_DMIC2_SRC_SEL_VAL(DMIC2_SRC_SEL) |
+ PWR2_TOP_CON_DMIC1_SRC_SEL_VAL(DMIC1_SRC_SEL);
+
+ return regmap_update_bits(afe->regmap, PWR2_TOP_CON0, mask, val);
+}
+
+/* This function assumes that the caller checked that channels is valid */
+static u8 mtk_dmic_channels_to_dmic_number(unsigned int channels)
+{
+ switch (channels) {
+ case 1:
+ return DMIC0;
+ case 2:
+ return DMIC1;
+ case 3:
+ return DMIC2;
+ case 4:
+ default:
+ return DMIC3;
+ }
+}
+
+static void mtk_dai_dmic_hw_gain_enable(struct mtk_base_afe *afe,
+ unsigned int channels, bool enable)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];
+ u8 dmic_num;
+ int i;
+
+ dmic_num = mtk_dmic_channels_to_dmic_number(channels);
+ for (i = dmic_num; i >= DMIC0; i--) {
+ if (enable && dmic_priv->gain_on[i]) {
+ mtk_dai_dmic_hw_gain_bypass(afe, i, false);
+ mtk_dai_dmic_hw_gain_on(afe, i, true);
+ } else {
+ mtk_dai_dmic_hw_gain_on(afe, i, false);
+ mtk_dai_dmic_hw_gain_bypass(afe, i, true);
+ }
+ }
+}
+
+static int mtk_dmic_gain_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];
+ unsigned int channels = dmic_priv->channels;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ if (!channels)
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mtk_dai_dmic_hw_gain_enable(afe, channels, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mtk_dai_dmic_hw_gain_enable(afe, channels, false);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_dmic_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];
+ const struct mtk_dai_dmic_ctrl_reg *reg = NULL;
+ unsigned int channels = dmic_priv->channels;
+ unsigned int msk;
+ u8 dmic_num;
+ int i;
+
+ dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n",
+ __func__, w->name, event);
+
+ if (!channels)
+ return -EINVAL;
+
+ dmic_num = mtk_dmic_channels_to_dmic_number(channels);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* request fifo soft rst */
+ msk = 0;
+ for (i = dmic_num; i >= DMIC0; i--)
+ msk |= PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(i);
+
+ regmap_set_bits(afe->regmap, PWR2_TOP_CON1, msk);
+
+ msk = AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL;
+
+ for (i = dmic_num; i >= DMIC0; i--) {
+ reg = get_dmic_ctrl_reg(i);
+ if (reg)
+ regmap_set_bits(afe->regmap, reg->con0, msk);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ msk = AFE_DMIC_UL_SRC_CON0_UL_SRC_ON_TMP_CTL;
+
+ for (i = dmic_num; i >= DMIC0; i--) {
+ reg = get_dmic_ctrl_reg(i);
+ if (reg)
+ regmap_set_bits(afe->regmap, reg->con0, msk);
+ }
+
+ if (dmic_priv->hires_required) {
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES1]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES2]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES3]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES4]);
+ }
+
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC1]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC2]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC3]);
+ mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC4]);
+
+ /* release fifo soft rst */
+ msk = 0;
+ for (i = dmic_num; i >= DMIC0; i--)
+ msk |= PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(i);
+
+ regmap_clear_bits(afe->regmap, PWR2_TOP_CON1, msk);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ msk = AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_SRC_ON_TMP_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL;
+
+ for (i = dmic_num; i >= DMIC0; i--) {
+ reg = get_dmic_ctrl_reg(i);
+ if (reg)
+ regmap_set_bits(afe->regmap, reg->con0, msk);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* should delayed 1/fs(smallest is 8k) = 125us before afe off */
+ usleep_range(125, 126);
+
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC1]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC2]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC3]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC4]);
+
+ if (dmic_priv->hires_required) {
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES1]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES2]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES3]);
+ mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES4]);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int mtk_dai_dmic_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];
+ unsigned int rate = params_rate(params);
+ unsigned int channels = params_channels(params);
+ const struct mtk_dai_dmic_ctrl_reg *reg = NULL;
+ u32 val = AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_CH1(CLK_PHASE_SEL_CH1) |
+ AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_CH2(CLK_PHASE_SEL_CH2) |
+ AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL(0);
+ const u32 msk = AFE_DMIC_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL |
+ AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_MASK |
+ AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL_MASK |
+ AFE_DMIC_UL_VOICE_MODE_MASK;
+ u8 dmic_num;
+ int ret;
+ int i;
+
+ if (!channels || channels > 8)
+ return -EINVAL;
+
+ ret = mtk_dai_dmic_configure_array(dai);
+ if (ret < 0)
+ return ret;
+
+ ret = mtk_dai_dmic_load_iir_coeff_table(afe);
+ if (ret < 0)
+ return ret;
+
+ switch (rate) {
+ case 96000:
+ val |= AFE_DMIC_UL_CON0_VOCIE_MODE_96K;
+ dmic_priv->hires_required = 1;
+ break;
+ case 48000:
+ val |= AFE_DMIC_UL_CON0_VOCIE_MODE_48K;
+ dmic_priv->hires_required = 0;
+ break;
+ case 32000:
+ val |= AFE_DMIC_UL_CON0_VOCIE_MODE_32K;
+ dmic_priv->hires_required = 0;
+ break;
+ case 16000:
+ val |= AFE_DMIC_UL_CON0_VOCIE_MODE_16K;
+ dmic_priv->hires_required = 0;
+ break;
+ case 8000:
+ val |= AFE_DMIC_UL_CON0_VOCIE_MODE_8K;
+ dmic_priv->hires_required = 0;
+ break;
+ default:
+ dev_dbg(afe->dev, "%s invalid rate %u, use 48000Hz\n", __func__, rate);
+ val |= AFE_DMIC_UL_CON0_VOCIE_MODE_48K;
+ dmic_priv->hires_required = 0;
+ break;
+ }
+
+ dmic_num = mtk_dmic_channels_to_dmic_number(channels);
+ for (i = dmic_num; i >= DMIC0; i--) {
+ reg = get_dmic_ctrl_reg(i);
+ if (reg) {
+ ret = regmap_update_bits(afe->regmap, reg->con0, msk, val);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ dmic_priv->channels = channels;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops mtk_dai_dmic_ops = {
+ .hw_params = mtk_dai_dmic_hw_params,
+};
+
+#define MTK_DMIC_RATES (SNDRV_PCM_RATE_8000 |\
+ SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000)
+
+#define MTK_DMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = {
+ {
+ .name = "DMIC",
+ .id = MT8188_AFE_IO_DMIC_IN,
+ .capture = {
+ .stream_name = "DMIC Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = MTK_DMIC_RATES,
+ .formats = MTK_DMIC_FORMATS,
+ },
+ .ops = &mtk_dai_dmic_ops,
+ },
+};
+
+static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = {
+ SND_SOC_DAPM_MIXER("I004", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I005", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I006", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I007", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I008", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I009", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I010", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("I011", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY_S("DMIC_GAIN_ON", SUPPLY_SEQ_DMIC_GAIN,
+ SND_SOC_NOPM, 0, 0,
+ mtk_dmic_gain_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY_S("DMIC_CK_ON", SUPPLY_SEQ_DMIC_CK,
+ PWR2_TOP_CON1,
+ PWR2_TOP_CON1_DMIC_CKDIV_ON_SHIFT, 0,
+ mtk_dmic_event,
+ SND_SOC_DAPM_PRE_POST_PMU |
+ SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_INPUT("DMIC_INPUT"),
+};
+
+static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = {
+ {"I004", NULL, "DMIC Capture"},
+ {"I005", NULL, "DMIC Capture"},
+ {"I006", NULL, "DMIC Capture"},
+ {"I007", NULL, "DMIC Capture"},
+ {"I008", NULL, "DMIC Capture"},
+ {"I009", NULL, "DMIC Capture"},
+ {"I010", NULL, "DMIC Capture"},
+ {"I011", NULL, "DMIC Capture"},
+ {"DMIC Capture", NULL, "DMIC_CK_ON"},
+ {"DMIC Capture", NULL, "DMIC_GAIN_ON"},
+ {"DMIC Capture", NULL, "DMIC_INPUT"},
+};
+
+static const char * const mt8188_dmic_gain_enable_text[] = {
+ "Bypass", "Connect",
+};
+
+static SOC_ENUM_SINGLE_EXT_DECL(dmic_gain_on_enum,
+ mt8188_dmic_gain_enable_text);
+
+static int mtk_dai_dmic_hw_gain_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];
+ unsigned int source = ucontrol->value.enumerated.item[0];
+ unsigned int *cached;
+
+ if (source >= e->items)
+ return -EINVAL;
+
+ if (!strcmp(kcontrol->id.name, "DMIC1_HW_GAIN_EN"))
+ cached = &dmic_priv->gain_on[0];
+ else if (!strcmp(kcontrol->id.name, "DMIC2_HW_GAIN_EN"))
+ cached = &dmic_priv->gain_on[1];
+ else if (!strcmp(kcontrol->id.name, "DMIC3_HW_GAIN_EN"))
+ cached = &dmic_priv->gain_on[2];
+ else if (!strcmp(kcontrol->id.name, "DMIC4_HW_GAIN_EN"))
+ cached = &dmic_priv->gain_on[3];
+ else
+ return -EINVAL;
+
+ if (source == *cached)
+ return 0;
+
+ *cached = source;
+ return 1;
+}
+
+static int mtk_dai_dmic_hw_gain_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN];
+ unsigned int val;
+
+ if (!strcmp(kcontrol->id.name, "DMIC1_HW_GAIN_EN"))
+ val = dmic_priv->gain_on[0];
+ else if (!strcmp(kcontrol->id.name, "DMIC2_HW_GAIN_EN"))
+ val = dmic_priv->gain_on[1];
+ else if (!strcmp(kcontrol->id.name, "DMIC3_HW_GAIN_EN"))
+ val = dmic_priv->gain_on[2];
+ else if (!strcmp(kcontrol->id.name, "DMIC4_HW_GAIN_EN"))
+ val = dmic_priv->gain_on[3];
+ else
+ return -EINVAL;
+
+ ucontrol->value.enumerated.item[0] = val;
+ return 0;
+}
+
+static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = {
+ SOC_ENUM_EXT("DMIC1_HW_GAIN_EN", dmic_gain_on_enum,
+ mtk_dai_dmic_hw_gain_ctrl_get,
+ mtk_dai_dmic_hw_gain_ctrl_put),
+ SOC_ENUM_EXT("DMIC2_HW_GAIN_EN", dmic_gain_on_enum,
+ mtk_dai_dmic_hw_gain_ctrl_get,
+ mtk_dai_dmic_hw_gain_ctrl_put),
+ SOC_ENUM_EXT("DMIC3_HW_GAIN_EN", dmic_gain_on_enum,
+ mtk_dai_dmic_hw_gain_ctrl_get,
+ mtk_dai_dmic_hw_gain_ctrl_put),
+ SOC_ENUM_EXT("DMIC4_HW_GAIN_EN", dmic_gain_on_enum,
+ mtk_dai_dmic_hw_gain_ctrl_get,
+ mtk_dai_dmic_hw_gain_ctrl_put),
+ SOC_SINGLE("DMIC1_HW_GAIN_TARGET", DMIC_GAIN1_CON1,
+ 0, DMIC_GAIN_MAX_TARGET, 0),
+ SOC_SINGLE("DMIC2_HW_GAIN_TARGET", DMIC_GAIN2_CON1,
+ 0, DMIC_GAIN_MAX_TARGET, 0),
+ SOC_SINGLE("DMIC3_HW_GAIN_TARGET", DMIC_GAIN3_CON1,
+ 0, DMIC_GAIN_MAX_TARGET, 0),
+ SOC_SINGLE("DMIC4_HW_GAIN_TARGET", DMIC_GAIN4_CON1,
+ 0, DMIC_GAIN_MAX_TARGET, 0),
+ SOC_SINGLE("DMIC1_HW_GAIN_CURRENT", DMIC_GAIN1_CUR,
+ 0, DMIC_GAIN_MAX_CURRENT, 0),
+ SOC_SINGLE("DMIC2_HW_GAIN_CURRENT", DMIC_GAIN2_CUR,
+ 0, DMIC_GAIN_MAX_CURRENT, 0),
+ SOC_SINGLE("DMIC3_HW_GAIN_CURRENT", DMIC_GAIN3_CUR,
+ 0, DMIC_GAIN_MAX_CURRENT, 0),
+ SOC_SINGLE("DMIC4_HW_GAIN_CURRENT", DMIC_GAIN4_CUR,
+ 0, DMIC_GAIN_MAX_CURRENT, 0),
+ SOC_SINGLE("DMIC1_HW_GAIN_UP_STEP", DMIC_GAIN1_CON3,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC2_HW_GAIN_UP_STEP", DMIC_GAIN2_CON3,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC3_HW_GAIN_UP_STEP", DMIC_GAIN3_CON3,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC4_HW_GAIN_UP_STEP", DMIC_GAIN4_CON3,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC1_HW_GAIN_DOWN_STEP", DMIC_GAIN1_CON2,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC2_HW_GAIN_DOWN_STEP", DMIC_GAIN2_CON2,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC3_HW_GAIN_DOWN_STEP", DMIC_GAIN3_CON2,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC4_HW_GAIN_DOWN_STEP", DMIC_GAIN4_CON2,
+ 0, DMIC_GAIN_MAX_STEP, 0),
+ SOC_SINGLE("DMIC1_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN1_CON0,
+ DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),
+ SOC_SINGLE("DMIC2_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN2_CON0,
+ DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),
+ SOC_SINGLE("DMIC3_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN3_CON0,
+ DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),
+ SOC_SINGLE("DMIC4_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN4_CON0,
+ DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0),
+};
+
+static int init_dmic_priv_data(struct mtk_base_afe *afe)
+{
+ struct mt8188_afe_private *afe_priv = afe->platform_priv;
+ struct mtk_dai_dmic_priv *dmic_priv;
+
+ dmic_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_dmic_priv),
+ GFP_KERNEL);
+ if (!dmic_priv)
+ return -ENOMEM;
+
+ afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN] = dmic_priv;
+ return 0;
+}
+
+int mt8188_dai_dmic_register(struct mtk_base_afe *afe)
+{
+ struct mtk_base_afe_dai *dai;
+
+ dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
+ if (!dai)
+ return -ENOMEM;
+
+ list_add(&dai->list, &afe->sub_dais);
+
+ dai->dai_drivers = mtk_dai_dmic_driver;
+ dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver);
+ dai->dapm_widgets = mtk_dai_dmic_widgets;
+ dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets);
+ dai->dapm_routes = mtk_dai_dmic_routes;
+ dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes);
+ dai->controls = mtk_dai_dmic_controls;
+ dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls);
+
+ return init_dmic_priv_data(afe);
+}
diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
index 2d0d04e0232d..20dc9470ba76 100644
--- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c
+++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c
@@ -17,6 +17,7 @@
#include "mt8188-afe-common.h"
#include "../../codecs/nau8825.h"
#include "../../codecs/mt6359.h"
+#include "../../codecs/mt6359-accdet.h"
#include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h"
#include "../common/mtk-soundcard-driver.h"
@@ -150,6 +151,11 @@ SND_SOC_DAILINK_DEFS(dl_src,
"mt6359-snd-codec-aif1")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
+SND_SOC_DAILINK_DEFS(DMIC_BE,
+ DAILINK_COMP_ARRAY(COMP_CPU("DMIC")),
+ DAILINK_COMP_ARRAY(COMP_DUMMY()),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
SND_SOC_DAILINK_DEFS(dptx,
DAILINK_COMP_ARRAY(COMP_CPU("DPTX")),
DAILINK_COMP_ARRAY(COMP_DUMMY()),
@@ -266,6 +272,17 @@ static struct snd_soc_jack_pin nau8825_jack_pins[] = {
},
};
+static struct snd_soc_jack_pin mt8188_headset_jack_pins[] = {
+ {
+ .pin = "Headphone",
+ .mask = SND_JACK_HEADPHONE,
+ },
+ {
+ .pin = "Headset Mic",
+ .mask = SND_JACK_MICROPHONE,
+ },
+};
+
static const struct snd_kcontrol_new mt8188_dumb_spk_controls[] = {
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
@@ -297,6 +314,7 @@ static const struct snd_soc_dapm_widget mt8188_rear_spk_widgets[] = {
static const struct snd_soc_dapm_widget mt8188_mt6359_widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("AP DMIC", NULL),
SND_SOC_DAPM_SINK("HDMI"),
SND_SOC_DAPM_SINK("DP"),
SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -500,6 +518,35 @@ static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int mt8188_mt6359_accdet_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card);
+ struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8188_JACK_HEADSET];
+ int ret;
+
+ if (!soc_card_data->accdet)
+ return 0;
+
+ ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
+ SND_JACK_HEADSET | SND_JACK_BTN_0 |
+ SND_JACK_BTN_1 | SND_JACK_BTN_2 |
+ SND_JACK_BTN_3,
+ jack, mt8188_headset_jack_pins,
+ ARRAY_SIZE(mt8188_headset_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack create failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = mt6359_accdet_enable_jack_detect(soc_card_data->accdet, jack);
+ if (ret) {
+ dev_err(rtd->dev, "Headset Jack enable failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int mt8188_mt6359_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_component *cmpnt_codec =
@@ -512,6 +559,8 @@ static int mt8188_mt6359_init(struct snd_soc_pcm_runtime *rtd)
/* mtkaif calibration */
mt8188_mt6359_mtkaif_calibration(rtd);
+ mt8188_mt6359_accdet_init(rtd);
+
return 0;
}
@@ -533,6 +582,7 @@ enum {
DAI_LINK_UL9_FE,
DAI_LINK_UL10_FE,
DAI_LINK_DL_SRC_BE,
+ DAI_LINK_DMIC_BE,
DAI_LINK_DPTX_BE,
DAI_LINK_ETDM1_IN_BE,
DAI_LINK_ETDM2_IN_BE,
@@ -1120,6 +1170,13 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = {
.playback_only = 1,
SND_SOC_DAILINK_REG(dl_src),
},
+ [DAI_LINK_DMIC_BE] = {
+ .name = "DMIC_BE",
+ .no_pcm = 1,
+ .capture_only = 1,
+ .ignore_suspend = 1,
+ SND_SOC_DAILINK_REG(DMIC_BE),
+ },
[DAI_LINK_DPTX_BE] = {
.name = "DPTX_BE",
.ops = &mt8188_dptx_ops,
diff --git a/sound/soc/mediatek/mt8188/mt8188-reg.h b/sound/soc/mediatek/mt8188/mt8188-reg.h
index bdd885419ff3..2e9c65de249d 100644
--- a/sound/soc/mediatek/mt8188/mt8188-reg.h
+++ b/sound/soc/mediatek/mt8188/mt8188-reg.h
@@ -2837,9 +2837,20 @@
#define PWR2_TOP_CON_DMIC3_SRC_SEL_MASK GENMASK(16, 14)
#define PWR2_TOP_CON_DMIC2_SRC_SEL_MASK GENMASK(13, 11)
#define PWR2_TOP_CON_DMIC1_SRC_SEL_MASK GENMASK(10, 8)
+#define PWR2_TOP_CON_DMIC8_SRC_SEL_VAL(x) ((x) << 29)
+#define PWR2_TOP_CON_DMIC7_SRC_SEL_VAL(x) ((x) << 26)
+#define PWR2_TOP_CON_DMIC6_SRC_SEL_VAL(x) ((x) << 23)
+#define PWR2_TOP_CON_DMIC5_SRC_SEL_VAL(x) ((x) << 20)
+#define PWR2_TOP_CON_DMIC4_SRC_SEL_VAL(x) ((x) << 17)
+#define PWR2_TOP_CON_DMIC3_SRC_SEL_VAL(x) ((x) << 14)
+#define PWR2_TOP_CON_DMIC2_SRC_SEL_VAL(x) ((x) << 11)
+#define PWR2_TOP_CON_DMIC1_SRC_SEL_VAL(x) ((x) << 8)
/* PWR2_TOP_CON1 */
-#define PWR2_TOP_CON1_DMIC_CKDIV_ON BIT(1)
+#define PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(x) BIT(5 + 6 * (x))
+#define PWR2_TOP_CON1_DMIC_CKDIV_ON BIT(1)
+#define PWR2_TOP_CON1_DMIC_CKDIV_ON_SHIFT 1
+
/* PCM_INTF_CON1 */
#define PCM_INTF_CON1_SYNC_OUT_INV BIT(23)
@@ -2921,13 +2932,14 @@
#define AFE_DMIC_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL BIT(23)
#define AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL BIT(22)
#define AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL BIT(21)
-
+#define AFE_DMIC_UL_VOICE_MODE(x) (((x) & GENMASK(2, 0)) << 17)
#define AFE_DMIC_UL_VOICE_MODE_MASK GENMASK(19, 17)
#define AFE_DMIC_UL_CON0_VOCIE_MODE_8K AFE_DMIC_UL_VOICE_MODE(0)
#define AFE_DMIC_UL_CON0_VOCIE_MODE_16K AFE_DMIC_UL_VOICE_MODE(1)
#define AFE_DMIC_UL_CON0_VOCIE_MODE_32K AFE_DMIC_UL_VOICE_MODE(2)
#define AFE_DMIC_UL_CON0_VOCIE_MODE_48K AFE_DMIC_UL_VOICE_MODE(3)
#define AFE_DMIC_UL_CON0_VOCIE_MODE_96K AFE_DMIC_UL_VOICE_MODE(4)
+#define AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL(x) (((x) & GENMASK(2, 0)) << 7)
#define AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL_MASK GENMASK(9, 7)
#define AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL BIT(10)
#define AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL BIT(1)
@@ -2944,6 +2956,7 @@
/* DMIC_GAINx_CON0 */
#define DMIC_GAIN_CON0_GAIN_ON BIT(0)
+#define DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT 8
#define DMIC_GAIN_CON0_SAMPLE_PER_STEP_MASK GENMASK(15, 8)
/* DMIC_GAINx_CON1 */
diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
index 9b502f4cd6ea..fd6af74d7995 100644
--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
@@ -2158,27 +2158,26 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
{
struct mtk_base_afe *afe;
struct mt8192_afe_private *afe_priv;
- struct device *dev;
+ struct device *dev = &pdev->dev;
struct reset_control *rstc;
int i, ret, irq_id;
- ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
if (ret)
return ret;
- afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
+ afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
if (!afe)
return -ENOMEM;
platform_set_drvdata(pdev, afe);
- afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+ afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv),
GFP_KERNEL);
if (!afe->platform_priv)
return -ENOMEM;
afe_priv = afe->platform_priv;
- afe->dev = &pdev->dev;
- dev = afe->dev;
+ afe->dev = dev;
/* init audio related clock */
ret = mt8192_init_clock(afe);
@@ -2196,7 +2195,7 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "failed to trigger audio reset\n");
- ret = devm_pm_runtime_enable(&pdev->dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret)
return ret;
@@ -2212,13 +2211,13 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
/* enable clock for regcache get default value from hw */
afe_priv->pm_runtime_bypass_reg_ctl = true;
- pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_get_sync(dev);
ret = regmap_reinit_cache(afe->regmap, &mt8192_afe_regmap_config);
if (ret)
return dev_err_probe(dev, ret, "regmap_reinit_cache fail\n");
- pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_put_sync(dev);
afe_priv->pm_runtime_bypass_reg_ctl = false;
regcache_cache_only(afe->regmap, true);
@@ -2285,7 +2284,7 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
afe->runtime_suspend = mt8192_afe_runtime_suspend;
/* register platform */
- ret = devm_snd_soc_register_component(&pdev->dev,
+ ret = devm_snd_soc_register_component(dev,
&mtk_afe_pcm_platform,
afe->dai_drivers,
afe->num_dai_drivers);
@@ -2314,15 +2313,15 @@ static const struct of_device_id mt8192_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8192_afe_pcm_dt_match);
static const struct dev_pm_ops mt8192_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8192_afe_runtime_suspend,
- mt8192_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt8192_afe_runtime_suspend,
+ mt8192_afe_runtime_resume, NULL)
};
static struct platform_driver mt8192_afe_pcm_driver = {
.driver = {
.name = "mt8192-audio",
.of_match_table = mt8192_afe_pcm_dt_match,
- .pm = &mt8192_afe_pm_ops,
+ .pm = pm_ptr(&mt8192_afe_pm_ops),
},
.probe = mt8192_afe_pcm_dev_probe,
.remove = mt8192_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
index b1598cc5587e..bf483a8fb34a 100644
--- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
+++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c
@@ -920,7 +920,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.playback_only = 1,
.ignore_suspend = 1,
.be_hw_params_fixup = mt8192_i2s_hw_params_fixup,
diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
index 8016bfb35015..5d025ad72263 100644
--- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
+++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
@@ -3188,15 +3188,15 @@ static const struct of_device_id mt8195_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8195_afe_pcm_dt_match);
static const struct dev_pm_ops mt8195_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8195_afe_runtime_suspend,
- mt8195_afe_runtime_resume, NULL)
+ RUNTIME_PM_OPS(mt8195_afe_runtime_suspend,
+ mt8195_afe_runtime_resume, NULL)
};
static struct platform_driver mt8195_afe_pcm_driver = {
.driver = {
.name = "mt8195-audio",
.of_match_table = mt8195_afe_pcm_dt_match,
- .pm = &mt8195_afe_pm_ops,
+ .pm = pm_ptr(&mt8195_afe_pm_ops),
},
.probe = mt8195_afe_pcm_dev_probe,
.remove = mt8195_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
index 2b9cb3248795..df29a9fa5aee 100644
--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
@@ -1114,7 +1114,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.capture_only = 1,
SND_SOC_DAILINK_REG(ETDM1_IN_BE),
},
@@ -1123,7 +1123,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.capture_only = 1,
.be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
SND_SOC_DAILINK_REG(ETDM2_IN_BE),
@@ -1133,7 +1133,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.playback_only = 1,
.be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
SND_SOC_DAILINK_REG(ETDM1_OUT_BE),
@@ -1143,7 +1143,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.playback_only = 1,
SND_SOC_DAILINK_REG(ETDM2_OUT_BE),
},
@@ -1152,7 +1152,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.playback_only = 1,
SND_SOC_DAILINK_REG(ETDM3_OUT_BE),
},
@@ -1161,7 +1161,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
.no_pcm = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(PCM1_BE),
},
[DAI_LINK_UL_SRC1_BE] = {
diff --git a/sound/soc/mediatek/mt8365/Makefile b/sound/soc/mediatek/mt8365/Makefile
index 52ba45a8498a..b197025e34bb 100644
--- a/sound/soc/mediatek/mt8365/Makefile
+++ b/sound/soc/mediatek/mt8365/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# MTK Platform driver
-snd-soc-mt8365-pcm-objs := \
+snd-soc-mt8365-pcm-y := \
mt8365-afe-clk.o \
mt8365-afe-pcm.o \
mt8365-dai-adda.o \
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
index 8a0af2ea8546..7078c01ba19b 100644
--- a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c
@@ -49,8 +49,7 @@ int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe)
void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk)
{
- if (clk)
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(clk);
}
int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
index 743b46572144..10793bbe9275 100644
--- a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
+++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c
@@ -1957,7 +1957,7 @@ err_irq:
return IRQ_HANDLED;
}
-static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev)
+static int mt8365_afe_runtime_suspend(struct device *dev)
{
return 0;
}
@@ -1967,7 +1967,7 @@ static int mt8365_afe_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused mt8365_afe_suspend(struct device *dev)
+static int mt8365_afe_suspend(struct device *dev)
{
struct mtk_base_afe *afe = dev_get_drvdata(dev);
struct regmap *regmap = afe->regmap;
@@ -1989,7 +1989,7 @@ static int __maybe_unused mt8365_afe_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mt8365_afe_resume(struct device *dev)
+static int mt8365_afe_resume(struct device *dev)
{
struct mtk_base_afe *afe = dev_get_drvdata(dev);
struct regmap *regmap = afe->regmap;
@@ -2009,7 +2009,7 @@ static int __maybe_unused mt8365_afe_resume(struct device *dev)
return 0;
}
-static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev)
+static int mt8365_afe_dev_runtime_suspend(struct device *dev)
{
struct mtk_base_afe *afe = dev_get_drvdata(dev);
@@ -2021,7 +2021,7 @@ static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev)
+static int mt8365_afe_dev_runtime_resume(struct device *dev)
{
struct mtk_base_afe *afe = dev_get_drvdata(dev);
@@ -2250,17 +2250,16 @@ static const struct of_device_id mt8365_afe_pcm_dt_match[] = {
MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match);
static const struct dev_pm_ops mt8365_afe_pm_ops = {
- SET_RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend,
- mt8365_afe_dev_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend,
- mt8365_afe_resume)
+ RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend,
+ mt8365_afe_dev_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend, mt8365_afe_resume)
};
static struct platform_driver mt8365_afe_pcm_driver = {
.driver = {
.name = "mt8365-afe-pcm",
.of_match_table = mt8365_afe_pcm_dt_match,
- .pm = &mt8365_afe_pm_ops,
+ .pm = pm_ptr(&mt8365_afe_pm_ops),
},
.probe = mt8365_afe_pcm_dev_probe,
.remove = mt8365_afe_pcm_dev_remove,
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
index 11b9a5bc7163..cae51756cead 100644
--- a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c
@@ -313,7 +313,7 @@ static int mt8365_dai_set_config(struct mtk_base_afe *afe,
}
if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
- SND_SOC_DAIFMT_CBM_CFM) {
+ SND_SOC_DAIFMT_CBP_CFP) {
val |= AFE_I2S_CON_SRC_SLAVE;
val &= ~(u32)AFE_I2S_CON_FROM_IO_MUX;//from consys
}
@@ -523,7 +523,7 @@ static int mt8365_dai_i2s_startup(struct snd_pcm_substream *substream,
bool i2s_in_slave =
(substream->stream == SNDRV_PCM_STREAM_CAPTURE) &&
((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
- SND_SOC_DAIFMT_CBM_CFM);
+ SND_SOC_DAIFMT_CBP_CFP);
mt8365_afe_enable_main_clk(afe);
@@ -551,7 +551,7 @@ static void mt8365_dai_i2s_shutdown(struct snd_pcm_substream *substream,
bool i2s_in_slave =
(substream->stream == SNDRV_PCM_STREAM_CAPTURE) &&
((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) ==
- SND_SOC_DAIFMT_CBM_CFM);
+ SND_SOC_DAIFMT_CBP_CFP);
if (be->prepared[substream->stream]) {
if (reset_i2s_out_change)
@@ -613,7 +613,7 @@ static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream,
if (apply_i2s_in_change) {
if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
- == SND_SOC_DAIFMT_CBM_CFM) {
+ == SND_SOC_DAIFMT_CBP_CFP) {
ret = mt8365_afe_set_2nd_i2s_asrc(afe, 32000, rate,
(unsigned int)bit_width,
0, 0, 1);
@@ -659,7 +659,7 @@ static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream,
mt8365_dai_set_enable(afe, i2s_data, true, true);
if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK)
- == SND_SOC_DAIFMT_CBM_CFM)
+ == SND_SOC_DAIFMT_CBP_CFP)
mt8365_afe_set_2nd_i2s_asrc_enable(afe, true);
be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true;
@@ -712,7 +712,7 @@ static int mt8365_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK);
- if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM))
+ if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP))
be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK);
return 0;
diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
index 3373b88da28e..0ec114a566ad 100644
--- a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
+++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
@@ -189,10 +189,10 @@ static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
pcm_priv->slave_mode = true;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
pcm_priv->slave_mode = false;
break;
default:
diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
index d398e83ea052..a998fba82bfe 100644
--- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c
+++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c
@@ -6,12 +6,19 @@
* Authors: Nicolas Belin <nbelin@baylibre.com>
*/
+#include <linux/array_size.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
#include <sound/soc.h>
#include <sound/pcm_params.h>
+
#include "mt8365-afe-common.h"
-#include <linux/pinctrl/consumer.h>
#include "../common/mtk-soc-card.h"
#include "../common/mtk-soundcard-driver.h"
@@ -218,7 +225,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = {
.id = DAI_LINK_2ND_I2S_INTF,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(i2s3),
},
[DAI_LINK_DMIC] = {
diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c
index 09103eef2a97..421b5d719fb3 100644
--- a/sound/soc/meson/axg-tdm-interface.c
+++ b/sound/soc/meson/axg-tdm-interface.c
@@ -529,7 +529,6 @@ static int axg_tdm_iface_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct snd_soc_dai_driver *dai_drv;
struct axg_tdm_iface *iface;
- int i;
iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL);
if (!iface)
@@ -541,15 +540,11 @@ static int axg_tdm_iface_probe(struct platform_device *pdev)
* We'll change the number of channel provided by DAI stream, so dpcm
* channel merge can be done properly
*/
- dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv),
- sizeof(*dai_drv), GFP_KERNEL);
+ dai_drv = devm_kmemdup_array(dev, axg_tdm_iface_dai_drv, ARRAY_SIZE(axg_tdm_iface_dai_drv),
+ sizeof(axg_tdm_iface_dai_drv[0]), GFP_KERNEL);
if (!dai_drv)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++)
- memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i],
- sizeof(*dai_drv));
-
/* Bit clock provided on the pad */
iface->sclk = devm_clk_get(dev, "sclk");
if (IS_ERR(iface->sclk))
diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c
index 1a4ef124e4e2..cfc7f6e41ab5 100644
--- a/sound/soc/meson/meson-card-utils.c
+++ b/sound/soc/meson/meson-card-utils.c
@@ -119,10 +119,10 @@ unsigned int meson_card_parse_daifmt(struct device_node *node,
/* If no master is provided, default to cpu master */
if (!bitclkmaster || bitclkmaster == cpu_node) {
daifmt |= (!framemaster || framemaster == cpu_node) ?
- SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM;
+ SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBC_CFP;
} else {
daifmt |= (!framemaster || framemaster == cpu_node) ?
- SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM;
+ SND_SOC_DAIFMT_CBP_CFC : SND_SOC_DAIFMT_CBP_CFP;
}
of_node_put(bitclkmaster);
diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c
index 571f65788c59..a80e9c9d6288 100644
--- a/sound/soc/meson/t9015.c
+++ b/sound/soc/meson/t9015.c
@@ -57,11 +57,11 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
unsigned int val;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_CBP_CFP:
val = I2S_MODE;
break;
- case SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_CBC_CFC:
val = 0;
break;
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index a41a13ae38a5..245f17411638 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -59,7 +59,7 @@ static const struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
};
#define MXS_SGTL5000_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBS_CFS)
+ SND_SOC_DAIFMT_CBC_CFC)
SND_SOC_DAILINK_DEFS(hifi_tx,
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 8caa1aa99bdc..6ca0a6bcd34c 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -260,7 +260,7 @@ static struct snd_soc_dai_link spitz_dai = {
.name = "wm8750",
.stream_name = "WM8750",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &spitz_ops,
SND_SOC_DAILINK_REG(wm8750),
};
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 928cf5cb5999..7ee60a58a336 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -44,20 +44,20 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
return ret;
}
- if (of_property_read_bool(dev->of_node, "widgets")) {
+ if (of_property_present(dev->of_node, "widgets")) {
ret = snd_soc_of_parse_audio_simple_widgets(card, "widgets");
if (ret)
return ret;
}
/* DAPM routes */
- if (of_property_read_bool(dev->of_node, "audio-routing")) {
+ if (of_property_present(dev->of_node, "audio-routing")) {
ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
if (ret)
return ret;
}
/* Deprecated, only for compatibility with old device trees */
- if (of_property_read_bool(dev->of_node, "qcom,audio-routing")) {
+ if (of_property_present(dev->of_node, "qcom,audio-routing")) {
ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing");
if (ret)
return ret;
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index addd2c4bdd3e..9946f12254b3 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -1232,14 +1232,16 @@ static int lpass_platform_copy(struct snd_soc_component *component,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (is_cdc_dma_port(dai_id)) {
- ret = copy_from_iter_toio(dma_buf, buf, bytes);
+ if (copy_from_iter_toio(dma_buf, bytes, buf) != bytes)
+ ret = -EFAULT;
} else {
if (copy_from_iter((void __force *)dma_buf, bytes, buf) != bytes)
ret = -EFAULT;
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
if (is_cdc_dma_port(dai_id)) {
- ret = copy_to_iter_fromio(buf, dma_buf, bytes);
+ if (copy_to_iter_fromio(dma_buf, bytes, buf) != bytes)
+ ret = -EFAULT;
} else {
if (copy_to_iter((void __force *)dma_buf, bytes, buf) != bytes)
ret = -EFAULT;
diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c
index fbead6af3d95..7c6a9b0fda89 100644
--- a/sound/soc/qcom/lpass-sc7180.c
+++ b/sound/soc/qcom/lpass-sc7180.c
@@ -160,14 +160,14 @@ static int sc7180_lpass_exit(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused sc7180_lpass_dev_resume(struct device *dev)
+static int sc7180_lpass_dev_resume(struct device *dev)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks);
}
-static int __maybe_unused sc7180_lpass_dev_suspend(struct device *dev)
+static int sc7180_lpass_dev_suspend(struct device *dev)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
@@ -176,7 +176,7 @@ static int __maybe_unused sc7180_lpass_dev_suspend(struct device *dev)
}
static const struct dev_pm_ops sc7180_lpass_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(sc7180_lpass_dev_suspend, sc7180_lpass_dev_resume)
+ SYSTEM_SLEEP_PM_OPS(sc7180_lpass_dev_suspend, sc7180_lpass_dev_resume)
};
static const struct lpass_variant sc7180_data = {
@@ -312,7 +312,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = {
.driver = {
.name = "sc7180-lpass-cpu",
.of_match_table = of_match_ptr(sc7180_lpass_cpu_device_id),
- .pm = &sc7180_lpass_pm_ops,
+ .pm = pm_ptr(&sc7180_lpass_pm_ops),
},
.probe = asoc_qcom_lpass_cpu_platform_probe,
.remove = asoc_qcom_lpass_cpu_platform_remove,
diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
index 7cd3e291382a..817c824f9179 100644
--- a/sound/soc/qcom/lpass-sc7280.c
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -233,14 +233,14 @@ static int sc7280_lpass_exit(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused sc7280_lpass_dev_resume(struct device *dev)
+static int sc7280_lpass_dev_resume(struct device *dev)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks);
}
-static int __maybe_unused sc7280_lpass_dev_suspend(struct device *dev)
+static int sc7280_lpass_dev_suspend(struct device *dev)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
@@ -249,7 +249,7 @@ static int __maybe_unused sc7280_lpass_dev_suspend(struct device *dev)
}
static const struct dev_pm_ops sc7280_lpass_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(sc7280_lpass_dev_suspend, sc7280_lpass_dev_resume)
+ SYSTEM_SLEEP_PM_OPS(sc7280_lpass_dev_suspend, sc7280_lpass_dev_resume)
};
static const struct lpass_variant sc7280_data = {
@@ -442,7 +442,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = {
.driver = {
.name = "sc7280-lpass-cpu",
.of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id),
- .pm = &sc7280_lpass_pm_ops,
+ .pm = pm_ptr(&sc7280_lpass_pm_ops),
},
.probe = asoc_qcom_lpass_cpu_platform_probe,
.remove = asoc_qcom_lpass_cpu_platform_remove,
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 2a2a5bd98110..11e252a70f69 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -230,7 +230,7 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a
return 0;
}
- buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_KERNEL);
+ buf = kcalloc(periods, sizeof(struct audio_buffer), GFP_KERNEL);
if (!buf) {
mutex_unlock(&graph->lock);
return -ENOMEM;
diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c
index bc030ce29680..84b6ac5d2a20 100644
--- a/sound/soc/qcom/sc7180.c
+++ b/sound/soc/qcom/sc7180.c
@@ -397,7 +397,7 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream)
switch (cpu_dai->id) {
case MI2S_PRIMARY:
snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_CBS_CFS |
+ SND_SOC_DAIFMT_CBC_CFC |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_I2S);
runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
@@ -513,7 +513,7 @@ static int sc7180_snd_platform_probe(struct platform_device *pdev)
card->controls = sc7180_snd_controls;
card->num_controls = ARRAY_SIZE(sc7180_snd_controls);
- if (of_property_read_bool(dev->of_node, "dmic-gpios")) {
+ if (of_property_present(dev->of_node, "dmic-gpios")) {
card->dapm_widgets = sc7180_snd_dual_mic_widgets,
card->num_dapm_widgets = ARRAY_SIZE(sc7180_snd_dual_mic_widgets),
card->controls = sc7180_snd_dual_mic_controls,
diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c
index 230af8d7b205..af412bd0c89f 100644
--- a/sound/soc/qcom/sc7280.c
+++ b/sound/soc/qcom/sc7280.c
@@ -342,8 +342,8 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
static int sc7280_snd_startup(struct snd_pcm_substream *substream)
{
- unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
- unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
+ unsigned int fmt = SND_SOC_DAIFMT_CBC_CFC;
+ unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBC_CFC;
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 snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index a479d7e5b7fb..fcc7df75346f 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -215,6 +215,7 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
ret = sdm845_slim_snd_hw_params(substream, params);
break;
case QUATERNARY_MI2S_RX:
+ case SECONDARY_MI2S_RX:
break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
@@ -356,6 +357,7 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
break;
+ case SECONDARY_MI2S_RX:
case SECONDARY_MI2S_TX:
codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
if (++(data->sec_mi2s_clk_count) == 1) {
@@ -371,8 +373,6 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
snd_soc_dai_set_fmt(cpu_dai, fmt);
-
-
break;
case QUATERNARY_TDM_RX_0:
@@ -441,6 +441,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
}
break;
+ case SECONDARY_MI2S_RX:
case SECONDARY_MI2S_TX:
if (--(data->sec_mi2s_clk_count) == 0) {
snd_soc_dai_set_sysclk(cpu_dai,
diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c
index f2eda2ff46c0..1d01b9329e08 100644
--- a/sound/soc/qcom/sdw.c
+++ b/sound/soc/qcom/sdw.c
@@ -23,9 +23,11 @@ int qcom_snd_sdw_startup(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);
+ u32 rx_ch[SDW_MAX_PORTS], tx_ch[SDW_MAX_PORTS];
struct sdw_stream_runtime *sruntime;
struct snd_soc_dai *codec_dai;
- int ret, i;
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret, i, j;
sruntime = sdw_alloc_stream(cpu_dai->name);
if (!sruntime)
@@ -35,9 +37,35 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream)
ret = snd_soc_dai_set_stream(codec_dai, sruntime,
substream->stream);
if (ret < 0 && ret != -ENOTSUPP) {
- dev_err(rtd->dev, "Failed to set sdw stream on %s\n",
- codec_dai->name);
+ dev_err(rtd->dev, "Failed to set sdw stream on %s\n", codec_dai->name);
goto err_set_stream;
+ } else if (ret == -ENOTSUPP) {
+ /* Ignore unsupported */
+ continue;
+ }
+
+ ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch,
+ &rx_ch_cnt, rx_ch);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to get codec chan map %s\n", codec_dai->name);
+ goto err_set_stream;
+ } else if (ret == -ENOTSUPP) {
+ /* Ignore unsupported */
+ continue;
+ }
+ }
+
+ switch (cpu_dai->id) {
+ case RX_CODEC_DMA_RX_0:
+ case TX_CODEC_DMA_TX_3:
+ if (tx_ch_cnt || rx_ch_cnt) {
+ for_each_rtd_codec_dais(rtd, j, codec_dai) {
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ tx_ch_cnt, tx_ch,
+ rx_ch_cnt, rx_ch);
+ if (ret != 0 && ret != -ENOTSUPP)
+ goto err_set_stream;
+ }
}
}
diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index 45e0c33fc3f3..9039107972e2 100644
--- a/sound/soc/qcom/sm8250.c
+++ b/sound/soc/qcom/sm8250.c
@@ -7,6 +7,7 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <linux/soundwire/sdw.h>
#include <sound/jack.h>
#include <linux/input-event-codes.h>
@@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_RATE);
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
rate->min = rate->max = 48000;
channels->min = channels->max = 2;
+ snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
return 0;
}
diff --git a/sound/soc/renesas/Kconfig b/sound/soc/renesas/Kconfig
index 426632996a0a..cb01fb36355f 100644
--- a/sound/soc/renesas/Kconfig
+++ b/sound/soc/renesas/Kconfig
@@ -67,7 +67,7 @@ config SND_SH7760_AC97
config SND_SIU_MIGOR
tristate "SIU sound support on Migo-R"
- depends on SH_MIGOR && I2C
+ depends on SH_MIGOR && I2C && DMADEVICES
select SND_SOC_SH4_SIU
select SND_SOC_WM8978
help
diff --git a/sound/soc/renesas/migor.c b/sound/soc/renesas/migor.c
index 5a0bc6edac0a..45fc594d331b 100644
--- a/sound/soc/renesas/migor.c
+++ b/sound/soc/renesas/migor.c
@@ -132,7 +132,7 @@ static struct snd_soc_dai_link migor_dai = {
.name = "wm8978",
.stream_name = "WM8978",
.dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &migor_dai_ops,
SND_SOC_DAILINK_REG(wm8978),
};
diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c
index d3709fd0409e..30afc942d381 100644
--- a/sound/soc/renesas/rcar/core.c
+++ b/sound/soc/renesas/rcar/core.c
@@ -1770,20 +1770,6 @@ int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
return 1;
}
-int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
-{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_priv *priv = rsnd_io_to_priv(io);
- struct device *dev = rsnd_priv_to_dev(priv);
-
- if (!runtime) {
- dev_warn(dev, "Can't update kctrl when idle\n");
- return 0;
- }
-
- return 1;
-}
-
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
{
cfg->cfg.val = cfg->val;
@@ -2073,7 +2059,7 @@ static void rsnd_remove(struct platform_device *pdev)
remove_func[i](priv);
}
-static int __maybe_unused rsnd_suspend(struct device *dev)
+static int rsnd_suspend(struct device *dev)
{
struct rsnd_priv *priv = dev_get_drvdata(dev);
@@ -2082,7 +2068,7 @@ static int __maybe_unused rsnd_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rsnd_resume(struct device *dev)
+static int rsnd_resume(struct device *dev)
{
struct rsnd_priv *priv = dev_get_drvdata(dev);
@@ -2090,13 +2076,13 @@ static int __maybe_unused rsnd_resume(struct device *dev)
}
static const struct dev_pm_ops rsnd_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume)
+ SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume)
};
static struct platform_driver rsnd_driver = {
.driver = {
.name = "rcar_sound",
- .pm = &rsnd_pm_ops,
+ .pm = pm_ptr(&rsnd_pm_ops),
.of_match_table = rsnd_of_match,
},
.probe = rsnd_probe,
diff --git a/sound/soc/renesas/rcar/rsnd.h b/sound/soc/renesas/rcar/rsnd.h
index a5f54b65313c..04c70690f7a2 100644
--- a/sound/soc/renesas/rcar/rsnd.h
+++ b/sound/soc/renesas/rcar/rsnd.h
@@ -742,7 +742,6 @@ struct rsnd_kctrl_cfg_s {
#define rsnd_kctrl_vals(x) ((x).val) /* = (x).cfg.val[0] */
int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io);
-int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io);
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg);
struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg);
int rsnd_kctrl_new(struct rsnd_mod *mod,
diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c
index e7f86db0d94c..7d73b183bda6 100644
--- a/sound/soc/renesas/rcar/src.c
+++ b/sound/soc/renesas/rcar/src.c
@@ -35,6 +35,7 @@ struct rsnd_src {
struct rsnd_mod *dma;
struct rsnd_kctrl_cfg_s sen; /* sync convert enable */
struct rsnd_kctrl_cfg_s sync; /* sync convert */
+ u32 current_sync_rate;
int irq;
};
@@ -100,7 +101,7 @@ static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io,
if (!rsnd_src_sync_is_enabled(mod))
return rsnd_io_converted_rate(io);
- convert_rate = src->sync.val;
+ convert_rate = src->current_sync_rate;
if (!convert_rate)
convert_rate = rsnd_io_converted_rate(io);
@@ -201,13 +202,73 @@ static const u32 chan222222[] = {
static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
struct rsnd_mod *mod)
{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
- struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 fin, fout, new_rate;
+ int inc, cnt, rate;
+ u64 base, val;
+
+ if (!runtime)
+ return;
+
+ if (!rsnd_src_sync_is_enabled(mod))
+ return;
+
+ fin = rsnd_src_get_in_rate(priv, io);
+ fout = rsnd_src_get_out_rate(priv, io);
+
+ new_rate = src->sync.val;
+
+ if (!new_rate)
+ new_rate = fout;
+
+ /* Do nothing if no diff */
+ if (new_rate == src->current_sync_rate)
+ return;
+
+ /*
+ * SRCm_IFSVR::INTIFS can change within 1%
+ * see
+ * SRCm_IFSVR::INTIFS Note
+ */
+ inc = fout / 100;
+ cnt = abs(new_rate - fout) / inc;
+ if (fout > new_rate)
+ inc *= -1;
+
+ /*
+ * After start running SRC, we can update only SRC_IFSVR
+ * for Synchronous Mode
+ */
+ base = (u64)0x0400000 * fin;
+ rate = fout;
+ for (int i = 0; i < cnt; i++) {
+ val = base;
+ rate += inc;
+ do_div(val, rate);
+
+ rsnd_mod_write(mod, SRC_IFSVR, val);
+ }
+ val = base;
+ do_div(val, new_rate);
+
+ rsnd_mod_write(mod, SRC_IFSVR, val);
+
+ /* update current_sync_rate */
+ src->current_sync_rate = new_rate;
+}
+
+static void rsnd_src_init_convert_rate(struct rsnd_dai_stream *io,
+ struct rsnd_mod *mod)
+{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
int is_play = rsnd_io_is_play(io);
int use_src = 0;
u32 fin, fout;
- u32 ifscr, fsrate, adinr;
+ u32 ifscr, adinr;
u32 cr, route;
u32 i_busif, o_busif, tmp;
const u32 *bsdsr_table;
@@ -245,26 +306,15 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
adinr = rsnd_get_adinr_bit(mod, io) | chan;
/*
- * SRC_IFSCR / SRC_IFSVR
- */
- ifscr = 0;
- fsrate = 0;
- if (use_src) {
- u64 n;
-
- ifscr = 1;
- n = (u64)0x0400000 * fin;
- do_div(n, fout);
- fsrate = n;
- }
-
- /*
+ * SRC_IFSCR
* SRC_SRCCR / SRC_ROUTE_MODE0
*/
+ ifscr = 0;
cr = 0x00011110;
route = 0x0;
if (use_src) {
route = 0x1;
+ ifscr = 0x1;
if (rsnd_src_sync_is_enabled(mod)) {
cr |= 0x1;
@@ -335,7 +385,6 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */
rsnd_mod_write(mod, SRC_ADINR, adinr);
rsnd_mod_write(mod, SRC_IFSCR, ifscr);
- rsnd_mod_write(mod, SRC_IFSVR, fsrate);
rsnd_mod_write(mod, SRC_SRCCR, cr);
rsnd_mod_write(mod, SRC_BSDSR, bsdsr_table[idx]);
rsnd_mod_write(mod, SRC_BSISR, bsisr_table[idx]);
@@ -348,6 +397,9 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io,
rsnd_adg_set_src_timesel_gen2(mod, io, fin, fout);
+ /* update SRC_IFSVR */
+ rsnd_src_set_convert_rate(io, mod);
+
return;
convert_rate_err:
@@ -467,7 +519,8 @@ static int rsnd_src_init(struct rsnd_mod *mod,
int ret;
/* reset sync convert_rate */
- src->sync.val = 0;
+ src->sync.val =
+ src->current_sync_rate = 0;
ret = rsnd_mod_power_on(mod);
if (ret < 0)
@@ -475,7 +528,7 @@ static int rsnd_src_init(struct rsnd_mod *mod,
rsnd_src_activation(mod);
- rsnd_src_set_convert_rate(io, mod);
+ rsnd_src_init_convert_rate(io, mod);
rsnd_src_status_clear(mod);
@@ -493,7 +546,8 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
rsnd_mod_power_off(mod);
/* reset sync convert_rate */
- src->sync.val = 0;
+ src->sync.val =
+ src->current_sync_rate = 0;
return 0;
}
@@ -531,6 +585,22 @@ static irqreturn_t rsnd_src_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
+static int rsnd_src_kctrl_accept_runtime(struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+ if (!runtime) {
+ struct rsnd_priv *priv = rsnd_io_to_priv(io);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ dev_warn(dev, "\"SRC Out Rate\" can use during running\n");
+
+ return 0;
+ }
+
+ return 1;
+}
+
static int rsnd_src_probe_(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
@@ -585,7 +655,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
"SRC Out Rate Switch" :
"SRC In Rate Switch",
rsnd_kctrl_accept_anytime,
- rsnd_src_set_convert_rate,
+ rsnd_src_init_convert_rate,
&src->sen, 1);
if (ret < 0)
return ret;
@@ -594,7 +664,7 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
rsnd_io_is_play(io) ?
"SRC Out Rate" :
"SRC In Rate",
- rsnd_kctrl_accept_runtime,
+ rsnd_src_kctrl_accept_runtime,
rsnd_src_set_convert_rate,
&src->sync, 192000);
diff --git a/sound/soc/renesas/rcar/ssi.c b/sound/soc/renesas/rcar/ssi.c
index b3d4e8ae07ef..0c6424a1fcac 100644
--- a/sound/soc/renesas/rcar/ssi.c
+++ b/sound/soc/renesas/rcar/ssi.c
@@ -336,7 +336,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0;
rate_err:
- dev_err(dev, "unsupported clock rate\n");
+ dev_err(dev, "unsupported clock rate (%d)\n", rate);
+
return ret;
}
diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
index 6efd017aaa7f..3a0af4ca7ab6 100644
--- a/sound/soc/renesas/rz-ssi.c
+++ b/sound/soc/renesas/rz-ssi.c
@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -71,7 +72,7 @@
#define PREALLOC_BUFFER (SZ_32K)
#define PREALLOC_BUFFER_MAX (SZ_32K)
-#define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */
+#define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-48kHz */
#define SSI_FMTS SNDRV_PCM_FMTBIT_S16_LE
#define SSI_CHAN_MIN 2
#define SSI_CHAN_MAX 2
@@ -99,7 +100,6 @@ struct rz_ssi_stream {
struct rz_ssi_priv {
void __iomem *base;
- struct platform_device *pdev;
struct reset_control *rstc;
struct device *dev;
struct clk *sfr_clk;
@@ -163,16 +163,7 @@ static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg,
writel(val, (priv->base + reg));
}
-static inline struct snd_soc_dai *
-rz_ssi_get_dai(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-
- return snd_soc_rtd_to_cpu(rtd, 0);
-}
-
-static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi,
- struct snd_pcm_substream *substream)
+static inline bool rz_ssi_stream_is_play(struct snd_pcm_substream *substream)
{
return substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
}
@@ -244,22 +235,21 @@ static void rz_ssi_stream_init(struct rz_ssi_stream *strm,
static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi,
struct rz_ssi_stream *strm)
{
- struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream);
+ struct device *dev = ssi->dev;
rz_ssi_set_substream(strm, NULL);
if (strm->oerr_num > 0)
- dev_info(dai->dev, "overrun = %d\n", strm->oerr_num);
+ dev_info(dev, "overrun = %d\n", strm->oerr_num);
if (strm->uerr_num > 0)
- dev_info(dai->dev, "underrun = %d\n", strm->uerr_num);
+ dev_info(dev, "underrun = %d\n", strm->uerr_num);
}
static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
unsigned int channels)
{
- static s8 ckdv[16] = { 1, 2, 4, 8, 16, 32, 64, 128,
- 6, 12, 24, 48, 96, -1, -1, -1 };
+ static u8 ckdv[] = { 1, 2, 4, 8, 16, 32, 64, 128, 6, 12, 24, 48, 96 };
unsigned int channel_bits = 32; /* System Word Length */
unsigned long bclk_rate = rate * channels * channel_bits;
unsigned int div;
@@ -318,7 +308,8 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
{
- int timeout;
+ u32 tmp;
+ int ret;
/* Disable irqs */
rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
@@ -331,15 +322,9 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
SSISR_RUIRQ), 0);
/* Wait for idle */
- timeout = 100;
- while (--timeout) {
- if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ)
- break;
- udelay(1);
- }
-
- if (!timeout)
- dev_info(ssi->dev, "timeout waiting for SSI idle\n");
+ ret = readl_poll_timeout_atomic(ssi->base + SSISR, tmp, (tmp & SSISR_IIRQ), 1, 100);
+ if (ret)
+ dev_warn_ratelimited(ssi->dev, "timeout waiting for SSI idle\n");
/* Hold FIFOs in reset */
rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST);
@@ -347,7 +332,7 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
{
- bool is_play = rz_ssi_stream_is_play(ssi, strm->substream);
+ bool is_play = rz_ssi_stream_is_play(strm->substream);
bool is_full_duplex;
u32 ssicr, ssifcr;
@@ -403,6 +388,15 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
return 0;
}
+static int rz_ssi_swreset(struct rz_ssi_priv *ssi)
+{
+ u32 tmp;
+
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST);
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);
+ return readl_poll_timeout_atomic(ssi->base + SSIFCR, tmp, !(tmp & SSIFCR_SSIRST), 1, 5);
+}
+
static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
{
strm->running = 0;
@@ -415,8 +409,12 @@ static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
/* Cancel all remaining DMA transactions */
- if (rz_ssi_is_dma_enabled(ssi))
- dmaengine_terminate_async(strm->dma_ch);
+ if (rz_ssi_is_dma_enabled(ssi)) {
+ if (ssi->playback.dma_ch)
+ dmaengine_terminate_async(ssi->playback.dma_ch);
+ if (ssi->capture.dma_ch)
+ dmaengine_terminate_async(ssi->capture.dma_ch);
+ }
rz_ssi_set_idle(ssi);
@@ -523,6 +521,8 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
sample_space = strm->fifo_sample_size;
ssifsr = rz_ssi_reg_readl(ssi, SSIFSR);
sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK;
+ if (sample_space < 0)
+ return -EINVAL;
/* Only add full frames at a time */
while (frames_left && (sample_space >= runtime->channels)) {
@@ -680,7 +680,7 @@ static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi,
*/
return 0;
- dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ dir = rz_ssi_stream_is_play(substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
/* Always transfer 1 period */
amount = runtime->period_size;
@@ -784,6 +784,32 @@ no_dma:
return -ENODEV;
}
+static int rz_ssi_trigger_resume(struct rz_ssi_priv *ssi)
+{
+ int ret;
+
+ if (rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture))
+ return 0;
+
+ ret = rz_ssi_swreset(ssi);
+ if (ret)
+ return ret;
+
+ return rz_ssi_clk_setup(ssi, ssi->hw_params_cache.rate,
+ ssi->hw_params_cache.channels);
+}
+
+static void rz_ssi_streams_suspend(struct rz_ssi_priv *ssi)
+{
+ if (rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture))
+ return;
+
+ ssi->playback.dma_buffer_pos = 0;
+ ssi->capture.dma_buffer_pos = 0;
+}
+
static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
@@ -792,21 +818,21 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
int ret = 0, i, num_transfer = 1;
switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- /* Soft Reset */
- if (!rz_ssi_is_stream_running(&ssi->playback) &&
- !rz_ssi_is_stream_running(&ssi->capture)) {
- rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST);
- rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);
- udelay(5);
- }
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ret = rz_ssi_trigger_resume(ssi);
+ if (ret)
+ return ret;
- rz_ssi_stream_init(strm, substream);
+ fallthrough;
+
+ case SNDRV_PCM_TRIGGER_START:
+ if (cmd == SNDRV_PCM_TRIGGER_START)
+ rz_ssi_stream_init(strm, substream);
if (ssi->dma_rt) {
bool is_playback;
- is_playback = rz_ssi_stream_is_play(ssi, substream);
+ is_playback = rz_ssi_stream_is_play(substream);
ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch,
is_playback);
/* Fallback to pio */
@@ -829,6 +855,12 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
ret = rz_ssi_start(ssi, strm);
break;
+
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ rz_ssi_stop(ssi, strm);
+ rz_ssi_streams_suspend(ssi);
+ break;
+
case SNDRV_PCM_TRIGGER_STOP:
rz_ssi_stop(ssi, strm);
rz_ssi_stream_quit(ssi, strm);
@@ -925,6 +957,7 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
unsigned int channels = params_channels(params);
unsigned int rate = params_rate(params);
+ int ret;
if (sample_bits != 16) {
dev_err(ssi->dev, "Unsupported sample width: %d\n",
@@ -951,6 +984,10 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width,
sample_bits);
+ ret = rz_ssi_swreset(ssi);
+ if (ret)
+ return ret;
+
return rz_ssi_clk_setup(ssi, rate, channels);
}
@@ -963,7 +1000,8 @@ static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
static const struct snd_pcm_hardware rz_ssi_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID,
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_RESUME,
.buffer_bytes_max = PREALLOC_BUFFER,
.period_bytes_min = 32,
.period_bytes_max = 8192,
@@ -986,7 +1024,8 @@ static int rz_ssi_pcm_open(struct snd_soc_component *component,
static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_dai *dai = rz_ssi_get_dai(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0);
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
@@ -1031,37 +1070,37 @@ static const struct snd_soc_component_driver rz_ssi_soc_component = {
static int rz_ssi_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct rz_ssi_priv *ssi;
struct clk *audio_clk;
struct resource *res;
int ret;
- ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
+ ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL);
if (!ssi)
return -ENOMEM;
- ssi->pdev = pdev;
- ssi->dev = &pdev->dev;
+ ssi->dev = dev;
ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(ssi->base))
return PTR_ERR(ssi->base);
ssi->phys = res->start;
- ssi->clk = devm_clk_get(&pdev->dev, "ssi");
+ ssi->clk = devm_clk_get(dev, "ssi");
if (IS_ERR(ssi->clk))
return PTR_ERR(ssi->clk);
- ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr");
+ ssi->sfr_clk = devm_clk_get(dev, "ssi_sfr");
if (IS_ERR(ssi->sfr_clk))
return PTR_ERR(ssi->sfr_clk);
- audio_clk = devm_clk_get(&pdev->dev, "audio_clk1");
+ audio_clk = devm_clk_get(dev, "audio_clk1");
if (IS_ERR(audio_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
"no audio clk1");
ssi->audio_clk_1 = clk_get_rate(audio_clk);
- audio_clk = devm_clk_get(&pdev->dev, "audio_clk2");
+ audio_clk = devm_clk_get(dev, "audio_clk2");
if (IS_ERR(audio_clk))
return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk),
"no audio clk2");
@@ -1074,13 +1113,13 @@ static int rz_ssi_probe(struct platform_device *pdev)
ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2;
/* Detect DMA support */
- ret = rz_ssi_dma_request(ssi, &pdev->dev);
+ ret = rz_ssi_dma_request(ssi, dev);
if (ret < 0) {
- dev_warn(&pdev->dev, "DMA not available, using PIO\n");
+ dev_warn(dev, "DMA not available, using PIO\n");
ssi->playback.transfer = rz_ssi_pio_send;
ssi->capture.transfer = rz_ssi_pio_recv;
} else {
- dev_info(&pdev->dev, "DMA enabled");
+ dev_info(dev, "DMA enabled");
ssi->playback.transfer = rz_ssi_dma_transfer;
ssi->capture.transfer = rz_ssi_dma_transfer;
}
@@ -1089,21 +1128,20 @@ static int rz_ssi_probe(struct platform_device *pdev)
ssi->capture.priv = ssi;
spin_lock_init(&ssi->lock);
- dev_set_drvdata(&pdev->dev, ssi);
+ dev_set_drvdata(dev, ssi);
/* Error Interrupt */
ssi->irq_int = platform_get_irq_byname(pdev, "int_req");
if (ssi->irq_int < 0) {
- rz_ssi_release_dma_channels(ssi);
- return ssi->irq_int;
+ ret = ssi->irq_int;
+ goto err_release_dma_chs;
}
- ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt,
- 0, dev_name(&pdev->dev), ssi);
+ ret = devm_request_irq(dev, ssi->irq_int, &rz_ssi_interrupt,
+ 0, dev_name(dev), ssi);
if (ret < 0) {
- rz_ssi_release_dma_channels(ssi);
- return dev_err_probe(&pdev->dev, ret,
- "irq request error (int_req)\n");
+ dev_err_probe(dev, ret, "irq request error (int_req)\n");
+ goto err_release_dma_chs;
}
if (!rz_ssi_is_dma_enabled(ssi)) {
@@ -1115,11 +1153,11 @@ static int rz_ssi_probe(struct platform_device *pdev)
if (ssi->irq_rt < 0)
return ssi->irq_rt;
- ret = devm_request_irq(&pdev->dev, ssi->irq_rt,
+ ret = devm_request_irq(dev, ssi->irq_rt,
&rz_ssi_interrupt, 0,
- dev_name(&pdev->dev), ssi);
+ dev_name(dev), ssi);
if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
+ return dev_err_probe(dev, ret,
"irq request error (dma_rt)\n");
} else {
if (ssi->irq_tx < 0)
@@ -1128,52 +1166,48 @@ static int rz_ssi_probe(struct platform_device *pdev)
if (ssi->irq_rx < 0)
return ssi->irq_rx;
- ret = devm_request_irq(&pdev->dev, ssi->irq_tx,
+ ret = devm_request_irq(dev, ssi->irq_tx,
&rz_ssi_interrupt, 0,
- dev_name(&pdev->dev), ssi);
+ dev_name(dev), ssi);
if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
+ return dev_err_probe(dev, ret,
"irq request error (dma_tx)\n");
- ret = devm_request_irq(&pdev->dev, ssi->irq_rx,
+ ret = devm_request_irq(dev, ssi->irq_rx,
&rz_ssi_interrupt, 0,
- dev_name(&pdev->dev), ssi);
+ dev_name(dev), ssi);
if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
+ return dev_err_probe(dev, ret,
"irq request error (dma_rx)\n");
}
}
- ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ ssi->rstc = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(ssi->rstc)) {
ret = PTR_ERR(ssi->rstc);
- goto err_reset;
+ goto err_release_dma_chs;
}
- reset_control_deassert(ssi->rstc);
- pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_resume_and_get(&pdev->dev);
+ /* Default 0 for power saving. Can be overridden via sysfs. */
+ pm_runtime_set_autosuspend_delay(dev, 0);
+ pm_runtime_use_autosuspend(dev);
+ ret = devm_pm_runtime_enable(dev);
if (ret < 0) {
- dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n");
- goto err_pm;
+ dev_err(dev, "Failed to enable runtime PM!\n");
+ goto err_release_dma_chs;
}
- ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component,
+ ret = devm_snd_soc_register_component(dev, &rz_ssi_soc_component,
rz_ssi_soc_dai,
ARRAY_SIZE(rz_ssi_soc_dai));
if (ret < 0) {
- dev_err(&pdev->dev, "failed to register snd component\n");
- goto err_snd_soc;
+ dev_err(dev, "failed to register snd component\n");
+ goto err_release_dma_chs;
}
return 0;
-err_snd_soc:
- pm_runtime_put(ssi->dev);
-err_pm:
- pm_runtime_disable(ssi->dev);
- reset_control_assert(ssi->rstc);
-err_reset:
+err_release_dma_chs:
rz_ssi_release_dma_channels(ssi);
return ret;
@@ -1185,8 +1219,6 @@ static void rz_ssi_remove(struct platform_device *pdev)
rz_ssi_release_dma_channels(ssi);
- pm_runtime_put(ssi->dev);
- pm_runtime_disable(ssi->dev);
reset_control_assert(ssi->rstc);
}
@@ -1196,10 +1228,30 @@ static const struct of_device_id rz_ssi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, rz_ssi_of_match);
+static int rz_ssi_runtime_suspend(struct device *dev)
+{
+ struct rz_ssi_priv *ssi = dev_get_drvdata(dev);
+
+ return reset_control_assert(ssi->rstc);
+}
+
+static int rz_ssi_runtime_resume(struct device *dev)
+{
+ struct rz_ssi_priv *ssi = dev_get_drvdata(dev);
+
+ return reset_control_deassert(ssi->rstc);
+}
+
+static const struct dev_pm_ops rz_ssi_pm_ops = {
+ RUNTIME_PM_OPS(rz_ssi_runtime_suspend, rz_ssi_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
+};
+
static struct platform_driver rz_ssi_driver = {
.driver = {
.name = "rz-ssi-pcm-audio",
.of_match_table = rz_ssi_of_match,
+ .pm = pm_ptr(&rz_ssi_pm_ops),
},
.probe = rz_ssi_probe,
.remove = rz_ssi_remove,
diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c
index a65d923d94dc..ffbc5a39b493 100644
--- a/sound/soc/rockchip/rk3288_hdmi_analog.c
+++ b/sound/soc/rockchip/rk3288_hdmi_analog.c
@@ -148,7 +148,7 @@ static struct snd_soc_dai_link rk_dailink = {
.ops = &rk_ops,
/* Set codecs as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(audio),
};
diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c
index 6c89c7331229..c8137e8883c4 100644
--- a/sound/soc/rockchip/rk3399_gru_sound.c
+++ b/sound/soc/rockchip/rk3399_gru_sound.c
@@ -338,7 +338,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
.stream_name = "DP PCM",
.init = rockchip_sound_cdndp_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(cdndp),
},
[DAILINK_DA7219] = {
@@ -348,7 +348,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
.ops = &rockchip_sound_da7219_ops,
/* set da7219 as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(da7219),
},
[DAILINK_DMIC] = {
@@ -356,7 +356,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
.stream_name = "DMIC PCM",
.ops = &rockchip_sound_dmic_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(dmic),
},
[DAILINK_MAX98357A] = {
@@ -365,7 +365,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
.ops = &rockchip_sound_max98357a_ops,
/* set max98357a as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(max98357a),
},
[DAILINK_RT5514] = {
@@ -374,7 +374,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = {
.ops = &rockchip_sound_rt5514_ops,
/* set rt5514 as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(rt5514),
},
/* RT5514 DSP for voice wakeup via spi bus */
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 4315da4a47c1..0a0a95b4f520 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -860,8 +860,7 @@ static void rockchip_i2s_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops rockchip_i2s_pm_ops = {
- SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, NULL)
};
static struct platform_driver rockchip_i2s_driver = {
@@ -870,7 +869,7 @@ static struct platform_driver rockchip_i2s_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(rockchip_i2s_match),
- .pm = &rockchip_i2s_pm_ops,
+ .pm = pm_ptr(&rockchip_i2s_pm_ops),
},
};
module_platform_driver(rockchip_i2s_driver);
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
index d1f28699652f..d9a1fab7f403 100644
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
@@ -22,7 +22,6 @@
#define DRV_NAME "rockchip-i2s-tdm"
-#define DEFAULT_MCLK_FS 256
#define CH_GRP_MAX 4 /* The max channel 8 / 2 */
#define MULTIPLEX_CH_MAX 10
@@ -70,6 +69,8 @@ struct rk_i2s_tdm_dev {
bool has_playback;
bool has_capture;
struct snd_soc_dai_driver *dai;
+ unsigned int mclk_rx_freq;
+ unsigned int mclk_tx_freq;
};
static int to_ch_num(unsigned int val)
@@ -121,7 +122,7 @@ err_mclk_tx:
return ret;
}
-static int __maybe_unused i2s_tdm_runtime_suspend(struct device *dev)
+static int i2s_tdm_runtime_suspend(struct device *dev)
{
struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
@@ -133,7 +134,7 @@ static int __maybe_unused i2s_tdm_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused i2s_tdm_runtime_resume(struct device *dev)
+static int i2s_tdm_runtime_resume(struct device *dev)
{
struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
int ret;
@@ -450,11 +451,11 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,
break;
case SND_SOC_DAIFMT_DSP_A:
val = I2S_TXCR_TFS_TDM_PCM;
- tdm_val = TDM_SHIFT_CTRL(0);
+ tdm_val = TDM_SHIFT_CTRL(2);
break;
case SND_SOC_DAIFMT_DSP_B:
val = I2S_TXCR_TFS_TDM_PCM;
- tdm_val = TDM_SHIFT_CTRL(2);
+ tdm_val = TDM_SHIFT_CTRL(4);
break;
default:
ret = -EINVAL;
@@ -514,33 +515,6 @@ static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream,
I2S_XFER_RXS_START);
}
-static int rockchip_i2s_ch_to_io(unsigned int ch, bool substream_capture)
-{
- if (substream_capture) {
- switch (ch) {
- case I2S_CHN_4:
- return I2S_IO_6CH_OUT_4CH_IN;
- case I2S_CHN_6:
- return I2S_IO_4CH_OUT_6CH_IN;
- case I2S_CHN_8:
- return I2S_IO_2CH_OUT_8CH_IN;
- default:
- return I2S_IO_8CH_OUT_2CH_IN;
- }
- } else {
- switch (ch) {
- case I2S_CHN_4:
- return I2S_IO_4CH_OUT_6CH_IN;
- case I2S_CHN_6:
- return I2S_IO_6CH_OUT_4CH_IN;
- case I2S_CHN_8:
- return I2S_IO_8CH_OUT_2CH_IN;
- default:
- return I2S_IO_2CH_OUT_8CH_IN;
- }
- }
-}
-
static int rockchip_i2s_io_multiplex(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -577,7 +551,6 @@ static int rockchip_i2s_io_multiplex(struct snd_pcm_substream *substream,
return -EINVAL;
}
- rockchip_i2s_ch_to_io(val, true);
} else {
struct snd_pcm_str *capture_str =
&substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE];
@@ -645,6 +618,27 @@ static int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream,
return 0;
}
+static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,
+ unsigned int freq, int dir)
+{
+ struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai);
+
+ if (i2s_tdm->clk_trcm) {
+ i2s_tdm->mclk_tx_freq = freq;
+ i2s_tdm->mclk_rx_freq = freq;
+ } else {
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ i2s_tdm->mclk_tx_freq = freq;
+ else
+ i2s_tdm->mclk_rx_freq = freq;
+ }
+
+ dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n",
+ stream ? "rx" : "tx", freq);
+
+ return 0;
+}
+
static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -659,15 +653,19 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
if (i2s_tdm->clk_trcm == TRCM_TX) {
mclk = i2s_tdm->mclk_tx;
+ mclk_rate = i2s_tdm->mclk_tx_freq;
} else if (i2s_tdm->clk_trcm == TRCM_RX) {
mclk = i2s_tdm->mclk_rx;
+ mclk_rate = i2s_tdm->mclk_rx_freq;
} else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mclk = i2s_tdm->mclk_tx;
+ mclk_rate = i2s_tdm->mclk_tx_freq;
} else {
mclk = i2s_tdm->mclk_rx;
+ mclk_rate = i2s_tdm->mclk_rx_freq;
}
- err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params));
+ err = clk_set_rate(mclk, mclk_rate);
if (err)
return err;
@@ -827,6 +825,7 @@ static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {
.hw_params = rockchip_i2s_tdm_hw_params,
.set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio,
.set_fmt = rockchip_i2s_tdm_set_fmt,
+ .set_sysclk = rockchip_i2s_tdm_set_sysclk,
.set_tdm_slot = rockchip_dai_tdm_slot,
.trigger = rockchip_i2s_tdm_trigger,
};
@@ -1391,7 +1390,7 @@ static void rockchip_i2s_tdm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused rockchip_i2s_tdm_suspend(struct device *dev)
+static int rockchip_i2s_tdm_suspend(struct device *dev)
{
struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
@@ -1400,7 +1399,7 @@ static int __maybe_unused rockchip_i2s_tdm_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rockchip_i2s_tdm_resume(struct device *dev)
+static int rockchip_i2s_tdm_resume(struct device *dev)
{
struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
int ret;
@@ -1415,10 +1414,8 @@ static int __maybe_unused rockchip_i2s_tdm_resume(struct device *dev)
}
static const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = {
- SET_RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume,
- NULL)
- SET_SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend,
- rockchip_i2s_tdm_resume)
+ RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend, rockchip_i2s_tdm_resume)
};
static struct platform_driver rockchip_i2s_tdm_driver = {
@@ -1427,7 +1424,7 @@ static struct platform_driver rockchip_i2s_tdm_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = rockchip_i2s_tdm_match,
- .pm = &rockchip_i2s_tdm_pm_ops,
+ .pm = pm_ptr(&rockchip_i2s_tdm_pm_ops),
},
};
module_platform_driver(rockchip_i2s_tdm_driver);
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 783956dc83b5..b8326e9143b6 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -247,7 +247,7 @@ static struct snd_soc_dai_link rk_max98090_dailinks[] = {
.ops = &rk_aif1_ops,
/* set max98090 as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(analog),
},
};
@@ -260,7 +260,7 @@ static struct snd_soc_dai_link rk_hdmi_dailinks[] = {
.init = rk_hdmi_init,
.ops = &rk_aif1_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(hdmi),
}
};
@@ -274,7 +274,7 @@ static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = {
.ops = &rk_aif1_ops,
/* set max98090 as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(analog),
},
[DAILINK_HDMI] = {
@@ -283,7 +283,7 @@ static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = {
.init = rk_hdmi_init,
.ops = &rk_aif1_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(hdmi),
}
};
diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c
index cae91108f7a8..c1ee470ec607 100644
--- a/sound/soc/rockchip/rockchip_pdm.c
+++ b/sound/soc/rockchip/rockchip_pdm.c
@@ -668,7 +668,6 @@ static void rockchip_pdm_remove(struct platform_device *pdev)
clk_disable_unprepare(pdm->hclk);
}
-#ifdef CONFIG_PM_SLEEP
static int rockchip_pdm_suspend(struct device *dev)
{
struct rk_pdm_dev *pdm = dev_get_drvdata(dev);
@@ -693,12 +692,11 @@ static int rockchip_pdm_resume(struct device *dev)
return ret;
}
-#endif
static const struct dev_pm_ops rockchip_pdm_pm_ops = {
- SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend,
- rockchip_pdm_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume)
+ RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend,
+ rockchip_pdm_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume)
};
static struct platform_driver rockchip_pdm_driver = {
@@ -707,7 +705,7 @@ static struct platform_driver rockchip_pdm_driver = {
.driver = {
.name = "rockchip-pdm",
.of_match_table = of_match_ptr(rockchip_pdm_match),
- .pm = &rockchip_pdm_pm_ops,
+ .pm = pm_ptr(&rockchip_pdm_pm_ops),
},
};
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c
index b085d80ea2e4..590b64b362f6 100644
--- a/sound/soc/rockchip/rockchip_rt5645.c
+++ b/sound/soc/rockchip/rockchip_rt5645.c
@@ -145,7 +145,7 @@ static struct snd_soc_dai_link rk_dailink = {
.ops = &rk_aif1_ops,
/* set rt5645 as slave */
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(pcm),
};
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index d87c0e4f6f91..d365168934dc 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -63,7 +63,7 @@ static const struct of_device_id rk_spdif_match[] __maybe_unused = {
};
MODULE_DEVICE_TABLE(of, rk_spdif_match);
-static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev)
+static int rk_spdif_runtime_suspend(struct device *dev)
{
struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
@@ -74,7 +74,7 @@ static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rk_spdif_runtime_resume(struct device *dev)
+static int rk_spdif_runtime_resume(struct device *dev)
{
struct rk_spdif_dev *spdif = dev_get_drvdata(dev);
int ret;
@@ -374,8 +374,7 @@ static void rk_spdif_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops rk_spdif_pm_ops = {
- SET_RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume,
- NULL)
+ RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume, NULL)
};
static struct platform_driver rk_spdif_driver = {
@@ -384,7 +383,7 @@ static struct platform_driver rk_spdif_driver = {
.driver = {
.name = "rockchip-spdif",
.of_match_table = of_match_ptr(rk_spdif_match),
- .pm = &rk_spdif_pm_ops,
+ .pm = pm_ptr(&rk_spdif_pm_ops),
},
};
module_platform_driver(rk_spdif_driver);
diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c
index 01716df0c842..3723329b266d 100644
--- a/sound/soc/samsung/aries_wm8994.c
+++ b/sound/soc/samsung/aries_wm8994.c
@@ -474,7 +474,7 @@ static struct snd_soc_dai_link aries_dai[] = {
.name = "WM8994 AIF1",
.stream_name = "HiFi",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ops = &aries_ops,
SND_SOC_DAILINK_REG(aif1),
},
@@ -510,13 +510,13 @@ static struct snd_soc_card aries_card = {
};
static const struct aries_wm8994_variant fascinate4g_variant = {
- .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS
+ .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBC_CFC
| SND_SOC_DAIFMT_IB_NF,
.has_fm_radio = false,
};
static const struct aries_wm8994_variant aries_variant = {
- .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM
+ .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBP_CFP
| SND_SOC_DAIFMT_IB_NF,
.has_fm_radio = true,
};
diff --git a/sound/soc/samsung/arndale.c b/sound/soc/samsung/arndale.c
index 9619f550608c..172943bb3b24 100644
--- a/sound/soc/samsung/arndale.c
+++ b/sound/soc/samsung/arndale.c
@@ -95,7 +95,7 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = {
.stream_name = "Primary",
.dai_fmt = SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBS_CFS,
+ | SND_SOC_DAIFMT_CBC_CFC,
.ops = &arndale_rt5631_ops,
SND_SOC_DAILINK_REG(rt5631_hifi),
},
@@ -112,7 +112,7 @@ static struct snd_soc_dai_link arndale_wm1811_dai[] = {
.stream_name = "Primary",
.dai_fmt = SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ops = &arndale_wm1811_ops,
SND_SOC_DAILINK_REG(wm1811_hifi),
},
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index 365b1aca4855..8dc3b2da4c8f 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -7,7 +7,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include "../codecs/wm5102.h"
@@ -256,14 +255,14 @@ static struct snd_soc_dai_link bells_dai_wm2200[] = {
.name = "CPU-DSP",
.stream_name = "CPU-DSP",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(wm2200_cpu_dsp),
},
{
.name = "DSP-CODEC",
.stream_name = "DSP-CODEC",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.c2c_params = &sub_params,
.num_c2c_params = 1,
.ignore_suspend = 1,
@@ -293,14 +292,14 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = {
.name = "CPU-DSP",
.stream_name = "CPU-DSP",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(wm5102_cpu_dsp),
},
{
.name = "DSP-CODEC",
.stream_name = "DSP-CODEC",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.c2c_params = &sub_params,
.num_c2c_params = 1,
.ignore_suspend = 1,
@@ -310,7 +309,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = {
.name = "Baseband",
.stream_name = "Baseband",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
.c2c_params = &baseband_params,
.num_c2c_params = 1,
@@ -320,7 +319,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = {
.name = "Sub",
.stream_name = "Sub",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBS_CFS,
+ | SND_SOC_DAIFMT_CBC_CFC,
.ignore_suspend = 1,
.c2c_params = &sub_params,
.num_c2c_params = 1,
@@ -351,14 +350,14 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = {
.name = "CPU-DSP",
.stream_name = "CPU-DSP",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(wm5110_cpu_dsp),
},
{
.name = "DSP-CODEC",
.stream_name = "DSP-CODEC",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.c2c_params = &sub_params,
.num_c2c_params = 1,
.ignore_suspend = 1,
@@ -368,7 +367,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = {
.name = "Baseband",
.stream_name = "Baseband",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
.c2c_params = &baseband_params,
.num_c2c_params = 1,
@@ -378,7 +377,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = {
.name = "Sub",
.stream_name = "Sub",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBS_CFS,
+ | SND_SOC_DAIFMT_CBC_CFC,
.ignore_suspend = 1,
.c2c_params = &sub_params,
.num_c2c_params = 1,
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 8f6deb06e234..e9964f0e010a 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -1216,7 +1216,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
return 0;
}
-#ifdef CONFIG_PM
static int i2s_runtime_suspend(struct device *dev)
{
struct samsung_i2s_priv *priv = dev_get_drvdata(dev);
@@ -1254,7 +1253,6 @@ static int i2s_runtime_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM */
static void i2s_unregister_clocks(struct samsung_i2s_priv *priv)
{
@@ -1733,10 +1731,8 @@ MODULE_DEVICE_TABLE(of, exynos_i2s_match);
#endif
static const struct dev_pm_ops samsung_i2s_pm = {
- SET_RUNTIME_PM_OPS(i2s_runtime_suspend,
- i2s_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver samsung_i2s_driver = {
@@ -1746,7 +1742,7 @@ static struct platform_driver samsung_i2s_driver = {
.driver = {
.name = "samsung-i2s",
.of_match_table = of_match_ptr(exynos_i2s_match),
- .pm = &samsung_i2s_pm,
+ .pm = pm_ptr(&samsung_i2s_pm),
},
};
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index c5260e101c2a..5a02aac9b423 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -7,7 +7,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include "../codecs/wm8994.h"
@@ -157,7 +156,7 @@ static struct snd_soc_dai_link littlemill_dai[] = {
.name = "CPU",
.stream_name = "CPU",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ops = &littlemill_ops,
SND_SOC_DAILINK_REG(cpu),
},
@@ -165,7 +164,7 @@ static struct snd_soc_dai_link littlemill_dai[] = {
.name = "Baseband",
.stream_name = "Baseband",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
.c2c_params = &baseband_params,
.num_c2c_params = 1,
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 702cb4cc1ce9..1e95a2a435d4 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -7,7 +7,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include "../codecs/wm5100.h"
@@ -105,7 +104,7 @@ static struct snd_soc_dai_link lowland_dai[] = {
.name = "CPU",
.stream_name = "CPU",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.init = lowland_wm5100_init,
SND_SOC_DAILINK_REG(cpu),
},
@@ -113,7 +112,7 @@ static struct snd_soc_dai_link lowland_dai[] = {
.name = "Baseband",
.stream_name = "Baseband",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(baseband),
},
@@ -121,7 +120,7 @@ static struct snd_soc_dai_link lowland_dai[] = {
.name = "Sub Speaker",
.stream_name = "Sub Speaker",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
.c2c_params = &sub_params,
.num_c2c_params = 1,
diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index bbfe5fef59af..239e958b88d3 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -537,7 +537,7 @@ static struct snd_soc_dai_link midas_dai[] = {
.stream_name = "HiFi Primary",
.ops = &midas_aif1_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(wm1811_hifi),
}, {
.name = "WM1811 Voice",
diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c
index 40ac12c07145..ab3398f39f4a 100644
--- a/sound/soc/samsung/odroid.c
+++ b/sound/soc/samsung/odroid.c
@@ -180,7 +180,7 @@ static struct snd_soc_dai_link odroid_card_dais[] = {
.no_pcm = 1,
.playback_only = 1,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(mixer),
}, {
/* Secondary FE <-> BE link */
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c
index def92cc09f9c..acb29cd785a9 100644
--- a/sound/soc/samsung/smdk_wm8994.c
+++ b/sound/soc/samsung/smdk_wm8994.c
@@ -106,14 +106,14 @@ static struct snd_soc_dai_link smdk_dai[] = {
.stream_name = "Pri_Dai",
.init = smdk_wm8994_init_paiftx,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ops = &smdk_ops,
SND_SOC_DAILINK_REG(aif1),
}, { /* Sec_Fifo Playback i/f */
.name = "Sec_FIFO TX",
.stream_name = "Sec_Dai",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ops = &smdk_ops,
SND_SOC_DAILINK_REG(fifo_tx),
},
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c
index 5802f92ab8ba..a3f539fbde5f 100644
--- a/sound/soc/samsung/smdk_wm8994pcm.c
+++ b/sound/soc/samsung/smdk_wm8994pcm.c
@@ -99,7 +99,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
.name = "WM8994 PAIF PCM",
.stream_name = "Primary PCM",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &smdk_wm8994_pcm_ops,
SND_SOC_DAILINK_REG(paif_pcm),
},
diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c
index 4bbe7bcdb845..66ef49dff1ba 100644
--- a/sound/soc/samsung/snow.c
+++ b/sound/soc/samsung/snow.c
@@ -137,7 +137,7 @@ static int snow_probe(struct platform_device *pdev)
link = &priv->dai_link;
link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
+ SND_SOC_DAIFMT_CBC_CFC;
link->name = "Primary";
link->stream_name = link->name;
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index 79476e8eb680..9262e5626584 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -7,13 +7,13 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include "../codecs/wm8996.h"
#include "../codecs/wm9081.h"
-#define WM8996_HPSEL_GPIO 214
#define MCLK_AUDIO_RATE (512 * 48000)
static int speyside_set_bias_level(struct snd_soc_card *card,
@@ -105,6 +105,7 @@ static struct snd_soc_jack_pin speyside_headset_pins[] = {
},
};
+static struct gpio_desc *speyside_hpsel_gpio;
/* Default the headphone selection to active high */
static int speyside_jack_polarity;
@@ -123,7 +124,7 @@ static void speyside_set_polarity(struct snd_soc_component *component,
int polarity)
{
speyside_jack_polarity = !polarity;
- gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
+ gpiod_direction_output(speyside_hpsel_gpio, speyside_jack_polarity);
/* Re-run DAPM to make sure we're using the correct mic bias */
snd_soc_dapm_sync(snd_soc_component_get_dapm(component));
@@ -145,16 +146,22 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = dai->component;
+ enum gpiod_flags flags;
int ret;
ret = snd_soc_dai_set_sysclk(dai, WM8996_SYSCLK_MCLK2, 32768, 0);
if (ret < 0)
return ret;
- ret = gpio_request(WM8996_HPSEL_GPIO, "HP_SEL");
- if (ret != 0)
- pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
- gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity);
+ if (speyside_jack_polarity)
+ flags = GPIOD_OUT_HIGH;
+ else
+ flags = GPIOD_OUT_LOW;
+ speyside_hpsel_gpio = devm_gpiod_get(rtd->card->dev,
+ "hp-sel",
+ flags);
+ if (IS_ERR(speyside_hpsel_gpio))
+ return PTR_ERR(speyside_hpsel_gpio);
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset",
SND_JACK_LINEOUT | SND_JACK_HEADSET |
@@ -210,7 +217,7 @@ static struct snd_soc_dai_link speyside_dai[] = {
.stream_name = "CPU-DSP",
.init = speyside_wm0010_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(cpu_dsp),
},
{
@@ -218,7 +225,7 @@ static struct snd_soc_dai_link speyside_dai[] = {
.stream_name = "DSP-CODEC",
.init = speyside_wm8996_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.c2c_params = &dsp_codec_params,
.num_c2c_params = 1,
.ignore_suspend = 1,
@@ -228,7 +235,7 @@ static struct snd_soc_dai_link speyside_dai[] = {
.name = "Baseband",
.stream_name = "Baseband",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(baseband),
},
@@ -325,6 +332,26 @@ static struct snd_soc_card speyside = {
.late_probe = speyside_late_probe,
};
+static struct gpiod_lookup_table wm8996_gpiod_table = {
+ /* Hardcoded device name in board file mach-crag6410.c */
+ .dev_id = "speyside",
+ .table = {
+ /*
+ * This line was hardcoded to 214 in the global GPIO
+ * number space, S3C GPIO macros seems top set the
+ * wm8996 codec GPIO start offset to 212, so this will
+ * be GPIO 214 - 212 = 2 on the wm8996.
+ */
+ GPIO_LOOKUP("wm8996", 2, "hp-sel", GPIO_ACTIVE_HIGH),
+ { },
+ },
+};
+
+static void speyside_gpiod_table_action(void *data)
+{
+ gpiod_remove_lookup_table(&wm8996_gpiod_table);
+}
+
static int speyside_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &speyside;
@@ -332,6 +359,12 @@ static int speyside_probe(struct platform_device *pdev)
card->dev = &pdev->dev;
+ gpiod_add_lookup_table(&wm8996_gpiod_table);
+ ret = devm_add_action_or_reset(&pdev->dev, speyside_gpiod_table_action,
+ NULL);
+ if (ret)
+ return ret;
+
ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret)
dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n");
diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c
index 2417b91a328f..b68ce7bd44ef 100644
--- a/sound/soc/samsung/tm2_wm5110.c
+++ b/sound/soc/samsung/tm2_wm5110.c
@@ -6,7 +6,6 @@
// Sylwester Nawrocki <s.nawrocki@samsung.com>
#include <linux/clk.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -451,21 +450,21 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
.stream_name = "HiFi Primary",
.ops = &tm2_aif1_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(aif1),
}, {
.name = "WM5110 Voice",
.stream_name = "Voice call",
.ops = &tm2_aif2_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(voice),
}, {
.name = "WM5110 BT",
.stream_name = "Bluetooth",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ignore_suspend = 1,
SND_SOC_DAILINK_REG(bt),
}, {
@@ -473,7 +472,7 @@ static struct snd_soc_dai_link tm2_dai_links[] = {
.stream_name = "i2s1",
.ops = &tm2_hdmi_ops,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(hdmi),
}
};
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c
index 2bdd81bf821a..d0f0c01365aa 100644
--- a/sound/soc/samsung/tobermory.c
+++ b/sound/soc/samsung/tobermory.c
@@ -7,7 +7,6 @@
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
-#include <linux/gpio.h>
#include <linux/module.h>
#include "../codecs/wm8962.h"
@@ -119,7 +118,7 @@ static struct snd_soc_dai_link tobermory_dai[] = {
.name = "CPU",
.stream_name = "CPU",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM,
+ | SND_SOC_DAIFMT_CBP_CFP,
.ops = &tobermory_ops,
SND_SOC_DAILINK_REG(cpu),
},
diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile
index c296bd5a0a7c..dddc3e694256 100644
--- a/sound/soc/sdca/Makefile
+++ b/sound/soc/sdca/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-snd-soc-sdca-objs := sdca_functions.o sdca_device.o
+snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o
obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o
diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c
index 80d663777eb5..0244cdcdd109 100644
--- a/sound/soc/sdca/sdca_device.c
+++ b/sound/soc/sdca/sdca_device.c
@@ -7,6 +7,8 @@
*/
#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/property.h>
#include <linux/soundwire/sdw.h>
#include <sound/sdca.h>
#include <sound/sdca_function.h>
@@ -46,8 +48,7 @@ static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave)
return false;
for (i = 0; i < slave->sdca_data.num_functions; i++) {
- if (slave->sdca_data.sdca_func[i].type ==
- SDCA_FUNCTION_TYPE_SMART_MIC)
+ if (slave->sdca_data.function[i].type == SDCA_FUNCTION_TYPE_SMART_MIC)
return true;
}
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 652865329968..493f390f087a 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -6,86 +6,83 @@
* https://www.mipi.org/mipi-sdca-v1-0-download
*/
+#define dev_fmt(fmt) "%s: " fmt, __func__
+
#include <linux/acpi.h>
+#include <linux/byteorder/generic.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/module.h>
+#include <linux/property.h>
#include <linux/soundwire/sdw.h>
+#include <linux/types.h>
#include <sound/sdca.h>
#include <sound/sdca_function.h>
-static int patch_sdca_function_type(struct device *dev,
- u32 interface_revision,
- u32 *function_type,
- const char **function_name)
-{
- unsigned long function_type_patch = 0;
+/*
+ * Should be long enough to encompass all the MIPI DisCo properties.
+ */
+#define SDCA_PROPERTY_LENGTH 64
+static int patch_sdca_function_type(u32 interface_revision, u32 *function_type)
+{
/*
* Unfortunately early SDCA specifications used different indices for Functions,
- * for backwards compatibility we have to reorder the values found
+ * for backwards compatibility we have to reorder the values found.
*/
- if (interface_revision >= 0x0801)
- goto skip_early_draft_order;
-
- switch (*function_type) {
- case 1:
- function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP;
- break;
- case 2:
- function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC;
- break;
- case 3:
- function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC;
- break;
- case 4:
- function_type_patch = SDCA_FUNCTION_TYPE_UAJ;
- break;
- case 5:
- function_type_patch = SDCA_FUNCTION_TYPE_RJ;
- break;
- case 6:
- function_type_patch = SDCA_FUNCTION_TYPE_HID;
- break;
- default:
- dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n",
- __func__, interface_revision, *function_type);
- return -EINVAL;
+ if (interface_revision < 0x0801) {
+ switch (*function_type) {
+ case 1:
+ *function_type = SDCA_FUNCTION_TYPE_SMART_AMP;
+ break;
+ case 2:
+ *function_type = SDCA_FUNCTION_TYPE_SMART_MIC;
+ break;
+ case 3:
+ *function_type = SDCA_FUNCTION_TYPE_SPEAKER_MIC;
+ break;
+ case 4:
+ *function_type = SDCA_FUNCTION_TYPE_UAJ;
+ break;
+ case 5:
+ *function_type = SDCA_FUNCTION_TYPE_RJ;
+ break;
+ case 6:
+ *function_type = SDCA_FUNCTION_TYPE_HID;
+ break;
+ default:
+ return -EINVAL;
+ }
}
-skip_early_draft_order:
- if (function_type_patch)
- *function_type = function_type_patch;
+ return 0;
+}
- /* now double-check the values */
- switch (*function_type) {
+static const char *get_sdca_function_name(u32 function_type)
+{
+ switch (function_type) {
case SDCA_FUNCTION_TYPE_SMART_AMP:
- *function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME;
- break;
+ return SDCA_FUNCTION_TYPE_SMART_AMP_NAME;
case SDCA_FUNCTION_TYPE_SMART_MIC:
- *function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME;
- break;
+ return SDCA_FUNCTION_TYPE_SMART_MIC_NAME;
case SDCA_FUNCTION_TYPE_UAJ:
- *function_name = SDCA_FUNCTION_TYPE_UAJ_NAME;
- break;
+ return SDCA_FUNCTION_TYPE_UAJ_NAME;
case SDCA_FUNCTION_TYPE_HID:
- *function_name = SDCA_FUNCTION_TYPE_HID_NAME;
- break;
+ return SDCA_FUNCTION_TYPE_HID_NAME;
case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
+ return SDCA_FUNCTION_TYPE_SIMPLE_AMP_NAME;
case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
+ return SDCA_FUNCTION_TYPE_SIMPLE_MIC_NAME;
case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
+ return SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME;
case SDCA_FUNCTION_TYPE_RJ:
+ return SDCA_FUNCTION_TYPE_RJ_NAME;
case SDCA_FUNCTION_TYPE_IMP_DEF:
- dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n",
- __func__, *function_type);
- return -EINVAL;
+ return SDCA_FUNCTION_TYPE_IMP_DEF_NAME;
default:
- dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n",
- __func__, *function_type);
- return -EINVAL;
+ return NULL;
}
-
- dev_info(dev, "%s: found SDCA function %s (type %d)\n",
- __func__, *function_name, *function_type);
-
- return 0;
}
static int find_sdca_function(struct acpi_device *adev, void *data)
@@ -96,26 +93,21 @@ static int find_sdca_function(struct acpi_device *adev, void *data)
struct fwnode_handle *control5; /* used to identify function type */
const char *function_name;
u32 function_type;
- int func_index;
+ int function_index;
u64 addr;
int ret;
if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) {
- dev_err(dev, "%s: maximum number of functions exceeded\n", __func__);
+ dev_err(dev, "maximum number of functions exceeded\n");
return -EINVAL;
}
- /*
- * The number of functions cannot exceed 8, we could use
- * acpi_get_local_address() but the value is stored as u64 so
- * we might as well avoid casts and intermediate levels
- */
ret = acpi_get_local_u64_address(adev->handle, &addr);
if (ret < 0)
return ret;
- if (!addr) {
- dev_err(dev, "%s: no addr\n", __func__);
+ if (!addr || addr > 0x7) {
+ dev_err(dev, "invalid addr: 0x%llx\n", addr);
return -ENODEV;
}
@@ -140,38 +132,1723 @@ static int find_sdca_function(struct acpi_device *adev, void *data)
fwnode_handle_put(control5);
if (ret < 0) {
- dev_err(dev, "%s: the function type can only be determined from ACPI information\n",
- __func__);
+ dev_err(dev, "function type only supported as DisCo constant\n");
return ret;
}
- ret = patch_sdca_function_type(dev, sdca_data->interface_revision,
- &function_type, &function_name);
- if (ret < 0)
+ ret = patch_sdca_function_type(sdca_data->interface_revision, &function_type);
+ if (ret < 0) {
+ dev_err(dev, "SDCA version %#x invalid function type %d\n",
+ sdca_data->interface_revision, function_type);
return ret;
+ }
+
+ function_name = get_sdca_function_name(function_type);
+ if (!function_name) {
+ dev_err(dev, "invalid SDCA function type %d\n", function_type);
+ return -EINVAL;
+ }
+
+ dev_info(dev, "SDCA function %s (type %d) at 0x%llx\n",
+ function_name, function_type, addr);
/* store results */
- func_index = sdca_data->num_functions;
- sdca_data->sdca_func[func_index].adr = addr;
- sdca_data->sdca_func[func_index].type = function_type;
- sdca_data->sdca_func[func_index].name = function_name;
+ function_index = sdca_data->num_functions;
+ sdca_data->function[function_index].adr = addr;
+ sdca_data->function[function_index].type = function_type;
+ sdca_data->function[function_index].name = function_name;
+ sdca_data->function[function_index].node = function_node;
sdca_data->num_functions++;
return 0;
}
+/**
+ * sdca_lookup_functions - Parse sdca_device_desc for each Function
+ * @slave: SoundWire slave device to be processed.
+ *
+ * Iterate through the available SDCA Functions and fill in a short
+ * descriptor (struct sdca_function_desc) for each function, this
+ * information is stored along with the SoundWire slave device and
+ * used for adding drivers and quirks before the devices have fully
+ * probed.
+ */
void sdca_lookup_functions(struct sdw_slave *slave)
{
struct device *dev = &slave->dev;
struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
if (!adev) {
- dev_info(dev, "No matching ACPI device found, ignoring peripheral\n");
+ dev_info(dev, "no matching ACPI device found, ignoring peripheral\n");
return;
}
+
acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data);
}
EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA");
+struct raw_init_write {
+ __le32 addr;
+ u8 val;
+} __packed;
+
+static int find_sdca_init_table(struct device *dev,
+ struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ struct raw_init_write *raw __free(kfree) = NULL;
+ struct sdca_init_write *init_write;
+ int i, num_init_writes;
+
+ num_init_writes = fwnode_property_count_u8(function_node,
+ "mipi-sdca-function-initialization-table");
+ if (!num_init_writes || num_init_writes == -EINVAL) {
+ return 0;
+ } else if (num_init_writes < 0) {
+ dev_err(dev, "%pfwP: failed to read initialization table: %d\n",
+ function_node, num_init_writes);
+ return num_init_writes;
+ } else if (num_init_writes % sizeof(*raw) != 0) {
+ dev_err(dev, "%pfwP: init table size invalid\n", function_node);
+ return -EINVAL;
+ } else if (num_init_writes > SDCA_MAX_INIT_COUNT) {
+ dev_err(dev, "%pfwP: maximum init table size exceeded\n", function_node);
+ return -EINVAL;
+ }
+
+ raw = kzalloc(num_init_writes, GFP_KERNEL);
+ if (!raw)
+ return -ENOMEM;
+
+ fwnode_property_read_u8_array(function_node,
+ "mipi-sdca-function-initialization-table",
+ (u8 *)raw, num_init_writes);
+
+ num_init_writes /= sizeof(*raw);
+
+ init_write = devm_kcalloc(dev, num_init_writes, sizeof(*init_write), GFP_KERNEL);
+ if (!init_write)
+ return -ENOMEM;
+
+ for (i = 0; i < num_init_writes; i++) {
+ init_write[i].addr = le32_to_cpu(raw[i].addr);
+ init_write[i].val = raw[i].val;
+ }
+
+ function->num_init_table = num_init_writes;
+ function->init_table = init_write;
+
+ return 0;
+}
+
+static const char *find_sdca_control_label(struct device *dev,
+ const struct sdca_entity *entity,
+ const struct sdca_control *control)
+{
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(IT, MIC_BIAS):
+ return SDCA_CTL_MIC_BIAS_NAME;
+ case SDCA_CTL_TYPE_S(IT, USAGE):
+ case SDCA_CTL_TYPE_S(OT, USAGE):
+ return SDCA_CTL_USAGE_NAME;
+ case SDCA_CTL_TYPE_S(IT, LATENCY):
+ case SDCA_CTL_TYPE_S(OT, LATENCY):
+ case SDCA_CTL_TYPE_S(MU, LATENCY):
+ case SDCA_CTL_TYPE_S(SU, LATENCY):
+ case SDCA_CTL_TYPE_S(FU, LATENCY):
+ case SDCA_CTL_TYPE_S(XU, LATENCY):
+ case SDCA_CTL_TYPE_S(CRU, LATENCY):
+ case SDCA_CTL_TYPE_S(UDMPU, LATENCY):
+ case SDCA_CTL_TYPE_S(MFPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SMPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SAPU, LATENCY):
+ case SDCA_CTL_TYPE_S(PPU, LATENCY):
+ return SDCA_CTL_LATENCY_NAME;
+ case SDCA_CTL_TYPE_S(IT, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(CRU, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(UDMPU, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(MFPU, CLUSTERINDEX):
+ return SDCA_CTL_CLUSTERINDEX_NAME;
+ case SDCA_CTL_TYPE_S(IT, DATAPORT_SELECTOR):
+ case SDCA_CTL_TYPE_S(OT, DATAPORT_SELECTOR):
+ return SDCA_CTL_DATAPORT_SELECTOR_NAME;
+ case SDCA_CTL_TYPE_S(IT, MATCHING_GUID):
+ case SDCA_CTL_TYPE_S(OT, MATCHING_GUID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, MATCHING_GUID):
+ return SDCA_CTL_MATCHING_GUID_NAME;
+ case SDCA_CTL_TYPE_S(IT, KEEP_ALIVE):
+ case SDCA_CTL_TYPE_S(OT, KEEP_ALIVE):
+ return SDCA_CTL_KEEP_ALIVE_NAME;
+ case SDCA_CTL_TYPE_S(IT, NDAI_STREAM):
+ case SDCA_CTL_TYPE_S(OT, NDAI_STREAM):
+ return SDCA_CTL_NDAI_STREAM_NAME;
+ case SDCA_CTL_TYPE_S(IT, NDAI_CATEGORY):
+ case SDCA_CTL_TYPE_S(OT, NDAI_CATEGORY):
+ return SDCA_CTL_NDAI_CATEGORY_NAME;
+ case SDCA_CTL_TYPE_S(IT, NDAI_CODINGTYPE):
+ case SDCA_CTL_TYPE_S(OT, NDAI_CODINGTYPE):
+ return SDCA_CTL_NDAI_CODINGTYPE_NAME;
+ case SDCA_CTL_TYPE_S(IT, NDAI_PACKETTYPE):
+ case SDCA_CTL_TYPE_S(OT, NDAI_PACKETTYPE):
+ return SDCA_CTL_NDAI_PACKETTYPE_NAME;
+ case SDCA_CTL_TYPE_S(MU, MIXER):
+ return SDCA_CTL_MIXER_NAME;
+ case SDCA_CTL_TYPE_S(SU, SELECTOR):
+ return SDCA_CTL_SELECTOR_NAME;
+ case SDCA_CTL_TYPE_S(FU, MUTE):
+ return SDCA_CTL_MUTE_NAME;
+ case SDCA_CTL_TYPE_S(FU, CHANNEL_VOLUME):
+ return SDCA_CTL_CHANNEL_VOLUME_NAME;
+ case SDCA_CTL_TYPE_S(FU, AGC):
+ return SDCA_CTL_AGC_NAME;
+ case SDCA_CTL_TYPE_S(FU, BASS_BOOST):
+ return SDCA_CTL_BASS_BOOST_NAME;
+ case SDCA_CTL_TYPE_S(FU, LOUDNESS):
+ return SDCA_CTL_LOUDNESS_NAME;
+ case SDCA_CTL_TYPE_S(FU, GAIN):
+ return SDCA_CTL_GAIN_NAME;
+ case SDCA_CTL_TYPE_S(XU, BYPASS):
+ case SDCA_CTL_TYPE_S(MFPU, BYPASS):
+ return SDCA_CTL_BYPASS_NAME;
+ case SDCA_CTL_TYPE_S(XU, XU_ID):
+ return SDCA_CTL_XU_ID_NAME;
+ case SDCA_CTL_TYPE_S(XU, XU_VERSION):
+ return SDCA_CTL_XU_VERSION_NAME;
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
+ return SDCA_CTL_FDL_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET):
+ return SDCA_CTL_FDL_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH):
+ return SDCA_CTL_FDL_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(XU, FDL_STATUS):
+ return SDCA_CTL_FDL_STATUS_NAME;
+ case SDCA_CTL_TYPE_S(XU, FDL_SET_INDEX):
+ return SDCA_CTL_FDL_SET_INDEX_NAME;
+ case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST):
+ return SDCA_CTL_FDL_HOST_REQUEST_NAME;
+ case SDCA_CTL_TYPE_S(CS, CLOCK_VALID):
+ return SDCA_CTL_CLOCK_VALID_NAME;
+ case SDCA_CTL_TYPE_S(CS, SAMPLERATEINDEX):
+ return SDCA_CTL_SAMPLERATEINDEX_NAME;
+ case SDCA_CTL_TYPE_S(CX, CLOCK_SELECT):
+ return SDCA_CTL_CLOCK_SELECT_NAME;
+ case SDCA_CTL_TYPE_S(PDE, REQUESTED_PS):
+ return SDCA_CTL_REQUESTED_PS_NAME;
+ case SDCA_CTL_TYPE_S(PDE, ACTUAL_PS):
+ return SDCA_CTL_ACTUAL_PS_NAME;
+ case SDCA_CTL_TYPE_S(GE, SELECTED_MODE):
+ return SDCA_CTL_SELECTED_MODE_NAME;
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ return SDCA_CTL_DETECTED_MODE_NAME;
+ case SDCA_CTL_TYPE_S(SPE, PRIVATE):
+ return SDCA_CTL_PRIVATE_NAME;
+ case SDCA_CTL_TYPE_S(SPE, PRIVACY_POLICY):
+ return SDCA_CTL_PRIVACY_POLICY_NAME;
+ case SDCA_CTL_TYPE_S(SPE, PRIVACY_LOCKSTATE):
+ return SDCA_CTL_PRIVACY_LOCKSTATE_NAME;
+ case SDCA_CTL_TYPE_S(SPE, PRIVACY_OWNER):
+ return SDCA_CTL_PRIVACY_OWNER_NAME;
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER):
+ return SDCA_CTL_AUTHTX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET):
+ return SDCA_CTL_AUTHTX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH):
+ return SDCA_CTL_AUTHTX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER):
+ return SDCA_CTL_AUTHRX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET):
+ return SDCA_CTL_AUTHRX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH):
+ return SDCA_CTL_AUTHRX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, ACOUSTIC_ENERGY_LEVEL_MONITOR):
+ return SDCA_CTL_ACOUSTIC_ENERGY_LEVEL_MONITOR_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, ULTRASOUND_LOOP_GAIN):
+ return SDCA_CTL_ULTRASOUND_LOOP_GAIN_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_0):
+ return SDCA_CTL_OPAQUESET_0_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_1):
+ return SDCA_CTL_OPAQUESET_1_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_2):
+ return SDCA_CTL_OPAQUESET_2_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_3):
+ return SDCA_CTL_OPAQUESET_3_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_4):
+ return SDCA_CTL_OPAQUESET_4_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_5):
+ return SDCA_CTL_OPAQUESET_5_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_6):
+ return SDCA_CTL_OPAQUESET_6_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_7):
+ return SDCA_CTL_OPAQUESET_7_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_8):
+ return SDCA_CTL_OPAQUESET_8_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_9):
+ return SDCA_CTL_OPAQUESET_9_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_10):
+ return SDCA_CTL_OPAQUESET_10_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_11):
+ return SDCA_CTL_OPAQUESET_11_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_12):
+ return SDCA_CTL_OPAQUESET_12_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_13):
+ return SDCA_CTL_OPAQUESET_13_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_14):
+ return SDCA_CTL_OPAQUESET_14_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_15):
+ return SDCA_CTL_OPAQUESET_15_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_16):
+ return SDCA_CTL_OPAQUESET_16_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_17):
+ return SDCA_CTL_OPAQUESET_17_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_18):
+ return SDCA_CTL_OPAQUESET_18_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_19):
+ return SDCA_CTL_OPAQUESET_19_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_20):
+ return SDCA_CTL_OPAQUESET_20_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_21):
+ return SDCA_CTL_OPAQUESET_21_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_22):
+ return SDCA_CTL_OPAQUESET_22_NAME;
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_23):
+ return SDCA_CTL_OPAQUESET_23_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_READY):
+ return SDCA_CTL_ALGORITHM_READY_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_ENABLE):
+ return SDCA_CTL_ALGORITHM_ENABLE_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_PREPARE):
+ return SDCA_CTL_ALGORITHM_PREPARE_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, CENTER_FREQUENCY_INDEX):
+ return SDCA_CTL_CENTER_FREQUENCY_INDEX_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, ULTRASOUND_LEVEL):
+ return SDCA_CTL_ULTRASOUND_LEVEL_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, AE_NUMBER):
+ return SDCA_CTL_AE_NUMBER_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER):
+ return SDCA_CTL_AE_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET):
+ return SDCA_CTL_AE_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH):
+ return SDCA_CTL_AE_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_ENABLE):
+ return SDCA_CTL_TRIGGER_ENABLE_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_STATUS):
+ return SDCA_CTL_TRIGGER_STATUS_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_MODE):
+ return SDCA_CTL_HIST_BUFFER_MODE_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_PREAMBLE):
+ return SDCA_CTL_HIST_BUFFER_PREAMBLE_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, HIST_ERROR):
+ return SDCA_CTL_HIST_ERROR_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_EXTENSION):
+ return SDCA_CTL_TRIGGER_EXTENSION_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_READY):
+ return SDCA_CTL_TRIGGER_READY_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER):
+ return SDCA_CTL_HIST_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET):
+ return SDCA_CTL_HIST_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH):
+ return SDCA_CTL_HIST_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER):
+ return SDCA_CTL_DTODTX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET):
+ return SDCA_CTL_DTODTX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH):
+ return SDCA_CTL_DTODTX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER):
+ return SDCA_CTL_DTODRX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET):
+ return SDCA_CTL_DTODRX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH):
+ return SDCA_CTL_DTODRX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, PROTECTION_MODE):
+ return SDCA_CTL_PROTECTION_MODE_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, PROTECTION_STATUS):
+ return SDCA_CTL_PROTECTION_STATUS_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, OPAQUESETREQ_INDEX):
+ return SDCA_CTL_OPAQUESETREQ_INDEX_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER):
+ return SDCA_CTL_DTODTX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET):
+ return SDCA_CTL_DTODTX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH):
+ return SDCA_CTL_DTODTX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER):
+ return SDCA_CTL_DTODRX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET):
+ return SDCA_CTL_DTODRX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH):
+ return SDCA_CTL_DTODRX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(PPU, POSTURENUMBER):
+ return SDCA_CTL_POSTURENUMBER_NAME;
+ case SDCA_CTL_TYPE_S(PPU, POSTUREEXTENSION):
+ return SDCA_CTL_POSTUREEXTENSION_NAME;
+ case SDCA_CTL_TYPE_S(PPU, HORIZONTALBALANCE):
+ return SDCA_CTL_HORIZONTALBALANCE_NAME;
+ case SDCA_CTL_TYPE_S(PPU, VERTICALBALANCE):
+ return SDCA_CTL_VERTICALBALANCE_NAME;
+ case SDCA_CTL_TYPE_S(TG, TONE_DIVIDER):
+ return SDCA_CTL_TONE_DIVIDER_NAME;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ return SDCA_CTL_HIDTX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET):
+ return SDCA_CTL_HIDTX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH):
+ return SDCA_CTL_HIDTX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER):
+ return SDCA_CTL_HIDRX_CURRENTOWNER_NAME;
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET):
+ return SDCA_CTL_HIDRX_MESSAGEOFFSET_NAME;
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH):
+ return SDCA_CTL_HIDRX_MESSAGELENGTH_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, COMMIT_GROUP_MASK):
+ return SDCA_CTL_COMMIT_GROUP_MASK_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_SDCA_VERSION):
+ return SDCA_CTL_FUNCTION_SDCA_VERSION_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_TYPE):
+ return SDCA_CTL_FUNCTION_TYPE_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_MANUFACTURER_ID):
+ return SDCA_CTL_FUNCTION_MANUFACTURER_ID_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ID):
+ return SDCA_CTL_FUNCTION_ID_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_VERSION):
+ return SDCA_CTL_FUNCTION_VERSION_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_ID):
+ return SDCA_CTL_FUNCTION_EXTENSION_ID_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_VERSION):
+ return SDCA_CTL_FUNCTION_EXTENSION_VERSION_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS):
+ return SDCA_CTL_FUNCTION_STATUS_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ACTION):
+ return SDCA_CTL_FUNCTION_ACTION_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_MANUFACTURER_ID):
+ return SDCA_CTL_DEVICE_MANUFACTURER_ID_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_PART_ID):
+ return SDCA_CTL_DEVICE_PART_ID_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_VERSION):
+ return SDCA_CTL_DEVICE_VERSION_NAME;
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_SDCA_VERSION):
+ return SDCA_CTL_DEVICE_SDCA_VERSION_NAME;
+ default:
+ return devm_kasprintf(dev, GFP_KERNEL, "Imp-Def %#x", control->sel);
+ }
+}
+
+static unsigned int find_sdca_control_bits(const struct sdca_entity *entity,
+ const struct sdca_control *control)
+{
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(IT, LATENCY):
+ case SDCA_CTL_TYPE_S(OT, LATENCY):
+ case SDCA_CTL_TYPE_S(MU, LATENCY):
+ case SDCA_CTL_TYPE_S(SU, LATENCY):
+ case SDCA_CTL_TYPE_S(FU, LATENCY):
+ case SDCA_CTL_TYPE_S(XU, LATENCY):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(CRU, LATENCY):
+ case SDCA_CTL_TYPE_S(UDMPU, LATENCY):
+ case SDCA_CTL_TYPE_S(MFPU, LATENCY):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(PPU, LATENCY):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH):
+ return 32;
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_MANUFACTURER_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_MANUFACTURER_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_PART_ID):
+ case SDCA_CTL_TYPE_S(IT, DATAPORT_SELECTOR):
+ case SDCA_CTL_TYPE_S(OT, DATAPORT_SELECTOR):
+ case SDCA_CTL_TYPE_S(MU, MIXER):
+ case SDCA_CTL_TYPE_S(FU, CHANNEL_VOLUME):
+ case SDCA_CTL_TYPE_S(FU, GAIN):
+ case SDCA_CTL_TYPE_S(XU, XU_ID):
+ case SDCA_CTL_TYPE_S(UDMPU, ACOUSTIC_ENERGY_LEVEL_MONITOR):
+ case SDCA_CTL_TYPE_S(UDMPU, ULTRASOUND_LOOP_GAIN):
+ case SDCA_CTL_TYPE_S(MFPU, ULTRASOUND_LEVEL):
+ case SDCA_CTL_TYPE_S(PPU, HORIZONTALBALANCE):
+ case SDCA_CTL_TYPE_S(PPU, VERTICALBALANCE):
+ return 16;
+ case SDCA_CTL_TYPE_S(FU, MUTE):
+ case SDCA_CTL_TYPE_S(FU, AGC):
+ case SDCA_CTL_TYPE_S(FU, BASS_BOOST):
+ case SDCA_CTL_TYPE_S(FU, LOUDNESS):
+ case SDCA_CTL_TYPE_S(XU, BYPASS):
+ case SDCA_CTL_TYPE_S(MFPU, BYPASS):
+ return 1;
+ default:
+ return 8;
+ }
+}
+
+static enum sdca_control_datatype
+find_sdca_control_datatype(const struct sdca_entity *entity,
+ const struct sdca_control *control)
+{
+ switch (SDCA_CTL_TYPE(entity->type, control->sel)) {
+ case SDCA_CTL_TYPE_S(XU, BYPASS):
+ case SDCA_CTL_TYPE_S(MFPU, BYPASS):
+ case SDCA_CTL_TYPE_S(FU, MUTE):
+ case SDCA_CTL_TYPE_S(FU, AGC):
+ case SDCA_CTL_TYPE_S(FU, BASS_BOOST):
+ case SDCA_CTL_TYPE_S(FU, LOUDNESS):
+ return SDCA_CTL_DATATYPE_ONEBIT;
+ case SDCA_CTL_TYPE_S(IT, LATENCY):
+ case SDCA_CTL_TYPE_S(OT, LATENCY):
+ case SDCA_CTL_TYPE_S(MU, LATENCY):
+ case SDCA_CTL_TYPE_S(SU, LATENCY):
+ case SDCA_CTL_TYPE_S(FU, LATENCY):
+ case SDCA_CTL_TYPE_S(XU, LATENCY):
+ case SDCA_CTL_TYPE_S(CRU, LATENCY):
+ case SDCA_CTL_TYPE_S(UDMPU, LATENCY):
+ case SDCA_CTL_TYPE_S(MFPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SMPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SAPU, LATENCY):
+ case SDCA_CTL_TYPE_S(PPU, LATENCY):
+ case SDCA_CTL_TYPE_S(SU, SELECTOR):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_0):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_1):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_2):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_3):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_4):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_5):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_6):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_7):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_8):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_9):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_10):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_11):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_12):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_13):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_14):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_15):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_16):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_17):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_18):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_19):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_20):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_21):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_22):
+ case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_23):
+ case SDCA_CTL_TYPE_S(SAPU, PROTECTION_MODE):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_PREAMBLE):
+ case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST):
+ case SDCA_CTL_TYPE_S(XU, XU_ID):
+ case SDCA_CTL_TYPE_S(CX, CLOCK_SELECT):
+ case SDCA_CTL_TYPE_S(TG, TONE_DIVIDER):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_MANUFACTURER_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_MANUFACTURER_ID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_PART_ID):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH):
+ return SDCA_CTL_DATATYPE_INTEGER;
+ case SDCA_CTL_TYPE_S(IT, MIC_BIAS):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_MODE):
+ case SDCA_CTL_TYPE_S(PDE, REQUESTED_PS):
+ case SDCA_CTL_TYPE_S(PDE, ACTUAL_PS):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_TYPE):
+ return SDCA_CTL_DATATYPE_SPEC_ENCODED_VALUE;
+ case SDCA_CTL_TYPE_S(XU, XU_VERSION):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_SDCA_VERSION):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_VERSION):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_VERSION):
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_VERSION):
+ case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_SDCA_VERSION):
+ return SDCA_CTL_DATATYPE_BCD;
+ case SDCA_CTL_TYPE_S(FU, CHANNEL_VOLUME):
+ case SDCA_CTL_TYPE_S(FU, GAIN):
+ case SDCA_CTL_TYPE_S(MU, MIXER):
+ case SDCA_CTL_TYPE_S(PPU, HORIZONTALBALANCE):
+ case SDCA_CTL_TYPE_S(PPU, VERTICALBALANCE):
+ case SDCA_CTL_TYPE_S(MFPU, ULTRASOUND_LEVEL):
+ case SDCA_CTL_TYPE_S(UDMPU, ACOUSTIC_ENERGY_LEVEL_MONITOR):
+ case SDCA_CTL_TYPE_S(UDMPU, ULTRASOUND_LOOP_GAIN):
+ return SDCA_CTL_DATATYPE_Q7P8DB;
+ case SDCA_CTL_TYPE_S(IT, USAGE):
+ case SDCA_CTL_TYPE_S(OT, USAGE):
+ case SDCA_CTL_TYPE_S(IT, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(CRU, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(UDMPU, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(MFPU, CLUSTERINDEX):
+ case SDCA_CTL_TYPE_S(MFPU, CENTER_FREQUENCY_INDEX):
+ case SDCA_CTL_TYPE_S(MFPU, AE_NUMBER):
+ case SDCA_CTL_TYPE_S(SAPU, OPAQUESETREQ_INDEX):
+ case SDCA_CTL_TYPE_S(XU, FDL_SET_INDEX):
+ case SDCA_CTL_TYPE_S(CS, SAMPLERATEINDEX):
+ case SDCA_CTL_TYPE_S(GE, SELECTED_MODE):
+ case SDCA_CTL_TYPE_S(GE, DETECTED_MODE):
+ return SDCA_CTL_DATATYPE_BYTEINDEX;
+ case SDCA_CTL_TYPE_S(PPU, POSTURENUMBER):
+ return SDCA_CTL_DATATYPE_POSTURENUMBER;
+ case SDCA_CTL_TYPE_S(IT, DATAPORT_SELECTOR):
+ case SDCA_CTL_TYPE_S(OT, DATAPORT_SELECTOR):
+ return SDCA_CTL_DATATYPE_DP_INDEX;
+ case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_READY):
+ case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_ENABLE):
+ case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_PREPARE):
+ case SDCA_CTL_TYPE_S(SAPU, PROTECTION_STATUS):
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_ENABLE):
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_STATUS):
+ case SDCA_CTL_TYPE_S(SMPU, TRIGGER_READY):
+ case SDCA_CTL_TYPE_S(SPE, PRIVACY_POLICY):
+ case SDCA_CTL_TYPE_S(SPE, PRIVACY_OWNER):
+ return SDCA_CTL_DATATYPE_BITINDEX;
+ case SDCA_CTL_TYPE_S(IT, KEEP_ALIVE):
+ case SDCA_CTL_TYPE_S(OT, KEEP_ALIVE):
+ case SDCA_CTL_TYPE_S(IT, NDAI_STREAM):
+ case SDCA_CTL_TYPE_S(OT, NDAI_STREAM):
+ case SDCA_CTL_TYPE_S(IT, NDAI_CATEGORY):
+ case SDCA_CTL_TYPE_S(OT, NDAI_CATEGORY):
+ case SDCA_CTL_TYPE_S(IT, NDAI_CODINGTYPE):
+ case SDCA_CTL_TYPE_S(OT, NDAI_CODINGTYPE):
+ case SDCA_CTL_TYPE_S(IT, NDAI_PACKETTYPE):
+ case SDCA_CTL_TYPE_S(OT, NDAI_PACKETTYPE):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_ERROR):
+ case SDCA_CTL_TYPE_S(XU, FDL_STATUS):
+ case SDCA_CTL_TYPE_S(CS, CLOCK_VALID):
+ case SDCA_CTL_TYPE_S(SPE, PRIVACY_LOCKSTATE):
+ case SDCA_CTL_TYPE_S(ENTITY_0, COMMIT_GROUP_MASK):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS):
+ case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ACTION):
+ case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER):
+ case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER):
+ return SDCA_CTL_DATATYPE_BITMAP;
+ case SDCA_CTL_TYPE_S(IT, MATCHING_GUID):
+ case SDCA_CTL_TYPE_S(OT, MATCHING_GUID):
+ case SDCA_CTL_TYPE_S(ENTITY_0, MATCHING_GUID):
+ return SDCA_CTL_DATATYPE_GUID;
+ default:
+ return SDCA_CTL_DATATYPE_IMPDEF;
+ }
+}
+
+static int find_sdca_control_range(struct device *dev,
+ struct fwnode_handle *control_node,
+ struct sdca_control_range *range)
+{
+ u8 *range_list;
+ int num_range;
+ u16 *limits;
+ int i;
+
+ num_range = fwnode_property_count_u8(control_node, "mipi-sdca-control-range");
+ if (!num_range || num_range == -EINVAL)
+ return 0;
+ else if (num_range < 0)
+ return num_range;
+
+ range_list = devm_kcalloc(dev, num_range, sizeof(*range_list), GFP_KERNEL);
+ if (!range_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u8_array(control_node, "mipi-sdca-control-range",
+ range_list, num_range);
+
+ limits = (u16 *)range_list;
+
+ range->cols = le16_to_cpu(limits[0]);
+ range->rows = le16_to_cpu(limits[1]);
+ range->data = (u32 *)&limits[2];
+
+ num_range = (num_range - (2 * sizeof(*limits))) / sizeof(*range->data);
+ if (num_range != range->cols * range->rows)
+ return -EINVAL;
+
+ for (i = 0; i < num_range; i++)
+ range->data[i] = le32_to_cpu(range->data[i]);
+
+ return 0;
+}
+
+/*
+ * TODO: Add support for -cn- properties, allowing different channels to have
+ * different defaults etc.
+ */
+static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity,
+ struct fwnode_handle *control_node,
+ struct sdca_control *control)
+{
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_u32(control_node, "mipi-sdca-control-access-mode", &tmp);
+ if (ret) {
+ dev_err(dev, "%s: control %#x: access mode missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ control->mode = tmp;
+
+ ret = fwnode_property_read_u32(control_node, "mipi-sdca-control-access-layer", &tmp);
+ if (ret) {
+ dev_err(dev, "%s: control %#x: access layer missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ control->layers = tmp;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_DC:
+ ret = fwnode_property_read_u32(control_node,
+ "mipi-sdca-control-dc-value",
+ &tmp);
+ if (ret) {
+ dev_err(dev, "%s: control %#x: dc value missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ control->value = tmp;
+ control->has_fixed = true;
+ break;
+ case SDCA_ACCESS_MODE_RW:
+ case SDCA_ACCESS_MODE_DUAL:
+ ret = fwnode_property_read_u32(control_node,
+ "mipi-sdca-control-default-value",
+ &tmp);
+ if (!ret) {
+ control->value = tmp;
+ control->has_default = true;
+ }
+
+ ret = fwnode_property_read_u32(control_node,
+ "mipi-sdca-control-fixed-value",
+ &tmp);
+ if (!ret) {
+ if (control->has_default && control->value != tmp) {
+ dev_err(dev,
+ "%s: control %#x: default and fixed value don't match\n",
+ entity->label, control->sel);
+ return -EINVAL;
+ }
+
+ control->value = tmp;
+ control->has_fixed = true;
+ }
+
+ control->deferrable = fwnode_property_read_bool(control_node,
+ "mipi-sdca-control-deferrable");
+ break;
+ default:
+ break;
+ }
+
+ ret = find_sdca_control_range(dev, control_node, &control->range);
+ if (ret) {
+ dev_err(dev, "%s: control %#x: range missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list",
+ &control->cn_list);
+ if (ret == -EINVAL) {
+ /* Spec allows not specifying cn-list if only the first number is used */
+ control->cn_list = 0x1;
+ } else if (ret || !control->cn_list) {
+ dev_err(dev, "%s: control %#x: cn list missing: %d\n",
+ entity->label, control->sel, ret);
+ return ret;
+ }
+
+ ret = fwnode_property_read_u32(control_node,
+ "mipi-sdca-control-interrupt-position",
+ &tmp);
+ if (!ret)
+ control->interrupt_position = tmp;
+
+ control->label = find_sdca_control_label(dev, entity, control);
+ if (!control->label)
+ return -ENOMEM;
+
+ control->type = find_sdca_control_datatype(entity, control);
+ control->nbits = find_sdca_control_bits(entity, control);
+
+ dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d value %#x %s\n",
+ entity->label, control->label, control->sel,
+ control->mode, control->layers, control->cn_list,
+ control->interrupt_position, control->value,
+ control->deferrable ? "deferrable" : "");
+
+ return 0;
+}
+
+static int find_sdca_entity_controls(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_control *controls;
+ int num_controls;
+ u64 control_list;
+ int control_sel;
+ int i, ret;
+
+ ret = fwnode_property_read_u64(entity_node, "mipi-sdca-control-list", &control_list);
+ if (ret == -EINVAL) {
+ /* Allow missing control lists, assume no controls. */
+ dev_warn(dev, "%s: missing control list\n", entity->label);
+ return 0;
+ } else if (ret) {
+ dev_err(dev, "%s: failed to read control list: %d\n", entity->label, ret);
+ return ret;
+ } else if (!control_list) {
+ return 0;
+ }
+
+ num_controls = hweight64(control_list);
+ controls = devm_kcalloc(dev, num_controls, sizeof(*controls), GFP_KERNEL);
+ if (!controls)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_set_bit(control_sel, (unsigned long *)&control_list,
+ BITS_PER_TYPE(control_list)) {
+ struct fwnode_handle *control_node;
+ char control_property[SDCA_PROPERTY_LENGTH];
+
+ /* DisCo uses upper-case for hex numbers */
+ snprintf(control_property, sizeof(control_property),
+ "mipi-sdca-control-0x%X-subproperties", control_sel);
+
+ control_node = fwnode_get_named_child_node(entity_node, control_property);
+ if (!control_node) {
+ dev_err(dev, "%s: control node %s not found\n",
+ entity->label, control_property);
+ return -EINVAL;
+ }
+
+ controls[i].sel = control_sel;
+
+ ret = find_sdca_entity_control(dev, entity, control_node, &controls[i]);
+ fwnode_handle_put(control_node);
+ if (ret)
+ return ret;
+
+ i++;
+ }
+
+ entity->num_controls = num_controls;
+ entity->controls = controls;
+
+ return 0;
+}
+
+static bool find_sdca_iot_dataport(struct sdca_entity_iot *terminal)
+{
+ switch (terminal->type) {
+ case SDCA_TERM_TYPE_GENERIC:
+ case SDCA_TERM_TYPE_ULTRASOUND:
+ case SDCA_TERM_TYPE_CAPTURE_DIRECT_PCM_MIC:
+ case SDCA_TERM_TYPE_RAW_PDM_MIC:
+ case SDCA_TERM_TYPE_SPEECH:
+ case SDCA_TERM_TYPE_VOICE:
+ case SDCA_TERM_TYPE_SECONDARY_PCM_MIC:
+ case SDCA_TERM_TYPE_ACOUSTIC_CONTEXT_AWARENESS:
+ case SDCA_TERM_TYPE_DTOD_STREAM:
+ case SDCA_TERM_TYPE_REFERENCE_STREAM:
+ case SDCA_TERM_TYPE_SENSE_CAPTURE:
+ case SDCA_TERM_TYPE_STREAMING_MIC:
+ case SDCA_TERM_TYPE_OPTIMIZATION_STREAM:
+ case SDCA_TERM_TYPE_PDM_RENDER_STREAM:
+ case SDCA_TERM_TYPE_COMPANION_DATA:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int find_sdca_entity_iot(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_iot *terminal = &entity->iot;
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_u32(entity_node, "mipi-sdca-terminal-type", &tmp);
+ if (ret) {
+ dev_err(dev, "%s: terminal type missing: %d\n", entity->label, ret);
+ return ret;
+ }
+
+ terminal->type = tmp;
+ terminal->is_dataport = find_sdca_iot_dataport(terminal);
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-terminal-reference-number", &tmp);
+ if (!ret)
+ terminal->reference = tmp;
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-terminal-connector-type", &tmp);
+ if (!ret)
+ terminal->connector = tmp;
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-terminal-transducer-count", &tmp);
+ if (!ret)
+ terminal->num_transducer = tmp;
+
+ dev_info(dev, "%s: terminal type %#x ref %#x conn %#x count %d\n",
+ entity->label, terminal->type, terminal->reference,
+ terminal->connector, terminal->num_transducer);
+
+ return 0;
+}
+
+static int find_sdca_entity_cs(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_cs *clock = &entity->cs;
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_u32(entity_node, "mipi-sdca-cs-type", &tmp);
+ if (ret) {
+ dev_err(dev, "%s: clock type missing: %d\n", entity->label, ret);
+ return ret;
+ }
+
+ clock->type = tmp;
+
+ ret = fwnode_property_read_u32(entity_node,
+ "mipi-sdca-clock-valid-max-delay", &tmp);
+ if (!ret)
+ clock->max_delay = tmp;
+
+ dev_info(dev, "%s: clock type %#x delay %d\n", entity->label,
+ clock->type, clock->max_delay);
+
+ return 0;
+}
+
+static int find_sdca_entity_pde(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ static const int mult_delay = 3;
+ struct sdca_entity_pde *power = &entity->pde;
+ u32 *delay_list __free(kfree) = NULL;
+ struct sdca_pde_delay *delays;
+ int num_delays;
+ int i, j;
+
+ num_delays = fwnode_property_count_u32(entity_node,
+ "mipi-sdca-powerdomain-transition-max-delay");
+ if (num_delays <= 0) {
+ dev_err(dev, "%s: max delay list missing: %d\n",
+ entity->label, num_delays);
+ return -EINVAL;
+ } else if (num_delays % mult_delay != 0) {
+ dev_err(dev, "%s: delays not multiple of %d\n",
+ entity->label, mult_delay);
+ return -EINVAL;
+ } else if (num_delays > SDCA_MAX_DELAY_COUNT) {
+ dev_err(dev, "%s: maximum number of transition delays exceeded\n",
+ entity->label);
+ return -EINVAL;
+ }
+
+ /* There are 3 values per delay */
+ delays = devm_kcalloc(dev, num_delays / mult_delay,
+ sizeof(*delays), GFP_KERNEL);
+ if (!delays)
+ return -ENOMEM;
+
+ delay_list = kcalloc(num_delays, sizeof(*delay_list), GFP_KERNEL);
+ if (!delay_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-powerdomain-transition-max-delay",
+ delay_list, num_delays);
+
+ num_delays /= mult_delay;
+
+ for (i = 0, j = 0; i < num_delays; i++) {
+ delays[i].from_ps = delay_list[j++];
+ delays[i].to_ps = delay_list[j++];
+ delays[i].us = delay_list[j++];
+
+ dev_info(dev, "%s: from %#x to %#x delay %dus\n", entity->label,
+ delays[i].from_ps, delays[i].to_ps, delays[i].us);
+ }
+
+ power->num_max_delay = num_delays;
+ power->max_delay = delays;
+
+ return 0;
+}
+
+struct raw_ge_mode {
+ u8 val;
+ u8 num_controls;
+ struct {
+ u8 id;
+ u8 sel;
+ u8 cn;
+ __le32 val;
+ } __packed controls[] __counted_by(num_controls);
+} __packed;
+
+static int find_sdca_entity_ge(struct device *dev,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_ge *group = &entity->ge;
+ u8 *affected_list __free(kfree) = NULL;
+ u8 *affected_iter;
+ int num_affected;
+ int i, j;
+
+ num_affected = fwnode_property_count_u8(entity_node,
+ "mipi-sdca-ge-selectedmode-controls-affected");
+ if (!num_affected) {
+ return 0;
+ } else if (num_affected < 0) {
+ dev_err(dev, "%s: failed to read affected controls: %d\n",
+ entity->label, num_affected);
+ return num_affected;
+ } else if (num_affected > SDCA_MAX_AFFECTED_COUNT) {
+ dev_err(dev, "%s: maximum affected controls size exceeded\n",
+ entity->label);
+ return -EINVAL;
+ }
+
+ affected_list = kcalloc(num_affected, sizeof(*affected_list), GFP_KERNEL);
+ if (!affected_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u8_array(entity_node,
+ "mipi-sdca-ge-selectedmode-controls-affected",
+ affected_list, num_affected);
+
+ group->num_modes = *affected_list;
+ affected_iter = affected_list + 1;
+
+ group->modes = devm_kcalloc(dev, group->num_modes, sizeof(*group->modes),
+ GFP_KERNEL);
+ if (!group->modes)
+ return -ENOMEM;
+
+ for (i = 0; i < group->num_modes; i++) {
+ struct raw_ge_mode *raw = (struct raw_ge_mode *)affected_iter;
+ struct sdca_ge_mode *mode = &group->modes[i];
+
+ affected_iter += sizeof(*raw);
+ if (affected_iter > affected_list + num_affected)
+ goto bad_list;
+
+ mode->val = raw->val;
+ mode->num_controls = raw->num_controls;
+
+ affected_iter += mode->num_controls * sizeof(raw->controls[0]);
+ if (affected_iter > affected_list + num_affected)
+ goto bad_list;
+
+ mode->controls = devm_kcalloc(dev, mode->num_controls,
+ sizeof(*mode->controls), GFP_KERNEL);
+ if (!mode->controls)
+ return -ENOMEM;
+
+ for (j = 0; j < mode->num_controls; j++) {
+ mode->controls[j].id = raw->controls[j].id;
+ mode->controls[j].sel = raw->controls[j].sel;
+ mode->controls[j].cn = raw->controls[j].cn;
+ mode->controls[j].val = le32_to_cpu(raw->controls[j].val);
+ }
+ }
+
+ return 0;
+
+bad_list:
+ dev_err(dev, "%s: malformed affected controls list\n", entity->label);
+ return -EINVAL;
+}
+
+static int find_sdca_entity(struct device *dev,
+ struct fwnode_handle *function_node,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_string(entity_node, "mipi-sdca-entity-label",
+ &entity->label);
+ if (ret) {
+ dev_err(dev, "%pfwP: entity %#x: label missing: %d\n",
+ function_node, entity->id, ret);
+ return ret;
+ }
+
+ ret = fwnode_property_read_u32(entity_node, "mipi-sdca-entity-type", &tmp);
+ if (ret) {
+ dev_err(dev, "%s: type missing: %d\n", entity->label, ret);
+ return ret;
+ }
+
+ entity->type = tmp;
+
+ dev_info(dev, "%s: entity %#x type %#x\n",
+ entity->label, entity->id, entity->type);
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ case SDCA_ENTITY_TYPE_OT:
+ ret = find_sdca_entity_iot(dev, entity_node, entity);
+ break;
+ case SDCA_ENTITY_TYPE_CS:
+ ret = find_sdca_entity_cs(dev, entity_node, entity);
+ break;
+ case SDCA_ENTITY_TYPE_PDE:
+ ret = find_sdca_entity_pde(dev, entity_node, entity);
+ break;
+ case SDCA_ENTITY_TYPE_GE:
+ ret = find_sdca_entity_ge(dev, entity_node, entity);
+ break;
+ default:
+ break;
+ }
+ if (ret)
+ return ret;
+
+ ret = find_sdca_entity_controls(dev, entity_node, entity);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int find_sdca_entities(struct device *dev,
+ struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ u32 *entity_list __free(kfree) = NULL;
+ struct sdca_entity *entities;
+ int num_entities;
+ int i, ret;
+
+ num_entities = fwnode_property_count_u32(function_node,
+ "mipi-sdca-entity-id-list");
+ if (num_entities <= 0) {
+ dev_err(dev, "%pfwP: entity id list missing: %d\n",
+ function_node, num_entities);
+ return -EINVAL;
+ } else if (num_entities > SDCA_MAX_ENTITY_COUNT) {
+ dev_err(dev, "%pfwP: maximum number of entities exceeded\n",
+ function_node);
+ return -EINVAL;
+ }
+
+ /* Add 1 to make space for Entity 0 */
+ entities = devm_kcalloc(dev, num_entities + 1, sizeof(*entities), GFP_KERNEL);
+ if (!entities)
+ return -ENOMEM;
+
+ entity_list = kcalloc(num_entities, sizeof(*entity_list), GFP_KERNEL);
+ if (!entity_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(function_node, "mipi-sdca-entity-id-list",
+ entity_list, num_entities);
+
+ for (i = 0; i < num_entities; i++)
+ entities[i].id = entity_list[i];
+
+ /* now read subproperties */
+ for (i = 0; i < num_entities; i++) {
+ char entity_property[SDCA_PROPERTY_LENGTH];
+ struct fwnode_handle *entity_node;
+
+ /* DisCo uses upper-case for hex numbers */
+ snprintf(entity_property, sizeof(entity_property),
+ "mipi-sdca-entity-id-0x%X-subproperties", entities[i].id);
+
+ entity_node = fwnode_get_named_child_node(function_node, entity_property);
+ if (!entity_node) {
+ dev_err(dev, "%pfwP: entity node %s not found\n",
+ function_node, entity_property);
+ return -EINVAL;
+ }
+
+ ret = find_sdca_entity(dev, function_node, entity_node, &entities[i]);
+ fwnode_handle_put(entity_node);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Add Entity 0 at end of the array, makes it easy to skip during
+ * all the Entity searches involved in creating connections.
+ */
+ entities[num_entities].label = "entity0";
+
+ ret = find_sdca_entity_controls(dev, function_node, &entities[num_entities]);
+ if (ret)
+ return ret;
+
+ function->num_entities = num_entities + 1;
+ function->entities = entities;
+
+ return 0;
+}
+
+static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function,
+ const char *entity_label)
+{
+ int i;
+
+ for (i = 0; i < function->num_entities; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ if (!strcmp(entity->label, entity_label))
+ return entity;
+ }
+
+ return NULL;
+}
+
+static struct sdca_entity *find_sdca_entity_by_id(struct sdca_function_data *function,
+ const int id)
+{
+ int i;
+
+ for (i = 0; i < function->num_entities; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ if (entity->id == id)
+ return entity;
+ }
+
+ return NULL;
+}
+
+static int find_sdca_entity_connection_iot(struct device *dev,
+ struct sdca_function_data *function,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_iot *terminal = &entity->iot;
+ struct fwnode_handle *clock_node;
+ struct sdca_entity *clock_entity;
+ const char *clock_label;
+ int ret;
+
+ clock_node = fwnode_get_named_child_node(entity_node,
+ "mipi-sdca-terminal-clock-connection");
+ if (!clock_node)
+ return 0;
+
+ ret = fwnode_property_read_string(clock_node, "mipi-sdca-entity-label",
+ &clock_label);
+ if (ret) {
+ dev_err(dev, "%s: clock label missing: %d\n", entity->label, ret);
+ fwnode_handle_put(clock_node);
+ return ret;
+ }
+
+ clock_entity = find_sdca_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);
+ fwnode_handle_put(clock_node);
+ return -EINVAL;
+ }
+
+ terminal->clock = clock_entity;
+
+ dev_info(dev, "%s -> %s\n", clock_entity->label, entity->label);
+
+ fwnode_handle_put(clock_node);
+ return 0;
+}
+
+static int find_sdca_entity_connection_pde(struct device *dev,
+ struct sdca_function_data *function,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity_pde *power = &entity->pde;
+ u32 *managed_list __free(kfree) = NULL;
+ struct sdca_entity **managed;
+ int num_managed;
+ int i;
+
+ num_managed = fwnode_property_count_u32(entity_node,
+ "mipi-sdca-powerdomain-managed-list");
+ if (!num_managed) {
+ return 0;
+ } else if (num_managed < 0) {
+ dev_err(dev, "%s: managed list missing: %d\n", entity->label, num_managed);
+ return num_managed;
+ } else if (num_managed > SDCA_MAX_ENTITY_COUNT) {
+ dev_err(dev, "%s: maximum number of managed entities exceeded\n",
+ entity->label);
+ return -EINVAL;
+ }
+
+ managed = devm_kcalloc(dev, num_managed, sizeof(*managed), GFP_KERNEL);
+ if (!managed)
+ return -ENOMEM;
+
+ managed_list = kcalloc(num_managed, sizeof(*managed_list), GFP_KERNEL);
+ if (!managed_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(entity_node,
+ "mipi-sdca-powerdomain-managed-list",
+ managed_list, num_managed);
+
+ for (i = 0; i < num_managed; i++) {
+ managed[i] = find_sdca_entity_by_id(function, managed_list[i]);
+ if (!managed[i]) {
+ dev_err(dev, "%s: failed to find entity with id %#x\n",
+ entity->label, managed_list[i]);
+ return -EINVAL;
+ }
+
+ dev_info(dev, "%s -> %s\n", managed[i]->label, entity->label);
+ }
+
+ power->num_managed = num_managed;
+ power->managed = managed;
+
+ return 0;
+}
+
+static int find_sdca_entity_connection_ge(struct device *dev,
+ struct sdca_function_data *function,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ int i, j;
+
+ for (i = 0; i < entity->ge.num_modes; i++) {
+ struct sdca_ge_mode *mode = &entity->ge.modes[i];
+
+ for (j = 0; j < mode->num_controls; j++) {
+ struct sdca_ge_control *affected = &mode->controls[j];
+ struct sdca_entity *managed;
+
+ managed = find_sdca_entity_by_id(function, affected->id);
+ if (!managed) {
+ dev_err(dev, "%s: failed to find entity with id %#x\n",
+ entity->label, affected->id);
+ return -EINVAL;
+ }
+
+ if (managed->group && managed->group != entity) {
+ dev_err(dev,
+ "%s: entity controlled by two groups %s, %s\n",
+ managed->label, managed->group->label,
+ entity->label);
+ return -EINVAL;
+ }
+
+ managed->group = entity;
+ }
+ }
+
+ return 0;
+}
+
+static int find_sdca_entity_connection(struct device *dev,
+ struct sdca_function_data *function,
+ struct fwnode_handle *entity_node,
+ struct sdca_entity *entity)
+{
+ struct sdca_entity **pins;
+ int num_pins, pin;
+ u64 pin_list;
+ int i, ret;
+
+ switch (entity->type) {
+ case SDCA_ENTITY_TYPE_IT:
+ case SDCA_ENTITY_TYPE_OT:
+ ret = find_sdca_entity_connection_iot(dev, function,
+ entity_node, entity);
+ break;
+ case SDCA_ENTITY_TYPE_PDE:
+ ret = find_sdca_entity_connection_pde(dev, function,
+ entity_node, entity);
+ break;
+ case SDCA_ENTITY_TYPE_GE:
+ ret = find_sdca_entity_connection_ge(dev, function,
+ entity_node, entity);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+ if (ret)
+ return ret;
+
+ ret = fwnode_property_read_u64(entity_node, "mipi-sdca-input-pin-list", &pin_list);
+ if (ret == -EINVAL) {
+ /* Allow missing pin lists, assume no pins. */
+ dev_warn(dev, "%s: missing pin list\n", entity->label);
+ return 0;
+ } else if (ret) {
+ dev_err(dev, "%s: failed to read pin list: %d\n", entity->label, ret);
+ return ret;
+ } else if (pin_list & BIT(0)) {
+ /*
+ * Each bit set in the pin-list refers to an entity_id in this
+ * Function. Entity 0 is an illegal connection since it is used
+ * for Function-level configurations.
+ */
+ dev_err(dev, "%s: pin 0 used as input\n", entity->label);
+ return -EINVAL;
+ } else if (!pin_list) {
+ return 0;
+ }
+
+ num_pins = hweight64(pin_list);
+ pins = devm_kcalloc(dev, num_pins, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_set_bit(pin, (unsigned long *)&pin_list, BITS_PER_TYPE(pin_list)) {
+ char pin_property[SDCA_PROPERTY_LENGTH];
+ struct fwnode_handle *connected_node;
+ struct sdca_entity *connected_entity;
+ const char *connected_label;
+
+ snprintf(pin_property, sizeof(pin_property), "mipi-sdca-input-pin-%d", pin);
+
+ connected_node = fwnode_get_named_child_node(entity_node, pin_property);
+ if (!connected_node) {
+ dev_err(dev, "%s: pin node %s not found\n",
+ entity->label, pin_property);
+ return -EINVAL;
+ }
+
+ ret = fwnode_property_read_string(connected_node, "mipi-sdca-entity-label",
+ &connected_label);
+ if (ret) {
+ dev_err(dev, "%s: pin %d label missing: %d\n",
+ entity->label, pin, ret);
+ fwnode_handle_put(connected_node);
+ return ret;
+ }
+
+ connected_entity = find_sdca_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);
+ fwnode_handle_put(connected_node);
+ return -EINVAL;
+ }
+
+ pins[i] = connected_entity;
+
+ dev_info(dev, "%s -> %s\n", connected_entity->label, entity->label);
+
+ i++;
+ fwnode_handle_put(connected_node);
+ }
+
+ entity->num_sources = num_pins;
+ entity->sources = pins;
+
+ return 0;
+}
+
+static int find_sdca_connections(struct device *dev,
+ struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ int i;
+
+ /* Entity 0 cannot have connections */
+ for (i = 0; i < function->num_entities - 1; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+ char entity_property[SDCA_PROPERTY_LENGTH];
+ struct fwnode_handle *entity_node;
+ int ret;
+
+ /* DisCo uses upper-case for hex numbers */
+ snprintf(entity_property, sizeof(entity_property),
+ "mipi-sdca-entity-id-0x%X-subproperties",
+ entity->id);
+
+ entity_node = fwnode_get_named_child_node(function_node, entity_property);
+ if (!entity_node) {
+ dev_err(dev, "%pfwP: entity node %s not found\n",
+ function_node, entity_property);
+ return -EINVAL;
+ }
+
+ ret = find_sdca_entity_connection(dev, function, entity_node, entity);
+ fwnode_handle_put(entity_node);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int find_sdca_cluster_channel(struct device *dev,
+ struct sdca_cluster *cluster,
+ struct fwnode_handle *channel_node,
+ struct sdca_channel *channel)
+{
+ u32 tmp;
+ int ret;
+
+ ret = fwnode_property_read_u32(channel_node, "mipi-sdca-cluster-channel-id", &tmp);
+ if (ret) {
+ dev_err(dev, "cluster %#x: missing channel id: %d\n",
+ cluster->id, ret);
+ return ret;
+ }
+
+ channel->id = tmp;
+
+ ret = fwnode_property_read_u32(channel_node,
+ "mipi-sdca-cluster-channel-purpose",
+ &tmp);
+ if (ret) {
+ dev_err(dev, "cluster %#x: channel %#x: missing purpose: %d\n",
+ cluster->id, channel->id, ret);
+ return ret;
+ }
+
+ channel->purpose = tmp;
+
+ ret = fwnode_property_read_u32(channel_node,
+ "mipi-sdca-cluster-channel-relationship",
+ &tmp);
+ if (ret) {
+ dev_err(dev, "cluster %#x: channel %#x: missing relationship: %d\n",
+ cluster->id, channel->id, ret);
+ return ret;
+ }
+
+ channel->relationship = tmp;
+
+ dev_info(dev, "cluster %#x: channel id %#x purpose %#x relationship %#x\n",
+ cluster->id, channel->id, channel->purpose, channel->relationship);
+
+ return 0;
+}
+
+static int find_sdca_cluster_channels(struct device *dev,
+ struct fwnode_handle *cluster_node,
+ struct sdca_cluster *cluster)
+{
+ struct sdca_channel *channels;
+ u32 num_channels;
+ int i, ret;
+
+ ret = fwnode_property_read_u32(cluster_node, "mipi-sdca-channel-count",
+ &num_channels);
+ if (ret < 0) {
+ dev_err(dev, "cluster %#x: failed to read channel list: %d\n",
+ cluster->id, ret);
+ return ret;
+ } else if (num_channels > SDCA_MAX_CHANNEL_COUNT) {
+ dev_err(dev, "cluster %#x: maximum number of channels exceeded\n",
+ cluster->id);
+ return -EINVAL;
+ }
+
+ channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ for (i = 0; i < num_channels; i++) {
+ char channel_property[SDCA_PROPERTY_LENGTH];
+ struct fwnode_handle *channel_node;
+
+ /* DisCo uses upper-case for hex numbers */
+ snprintf(channel_property, sizeof(channel_property),
+ "mipi-sdca-channel-%d-subproperties", i + 1);
+
+ channel_node = fwnode_get_named_child_node(cluster_node, channel_property);
+ if (!channel_node) {
+ dev_err(dev, "cluster %#x: channel node %s not found\n",
+ cluster->id, channel_property);
+ return -EINVAL;
+ }
+
+ ret = find_sdca_cluster_channel(dev, cluster, channel_node, &channels[i]);
+ fwnode_handle_put(channel_node);
+ if (ret)
+ return ret;
+ }
+
+ cluster->num_channels = num_channels;
+ cluster->channels = channels;
+
+ return 0;
+}
+
+static int find_sdca_clusters(struct device *dev,
+ struct fwnode_handle *function_node,
+ struct sdca_function_data *function)
+{
+ u32 *cluster_list __free(kfree) = NULL;
+ struct sdca_cluster *clusters;
+ int num_clusters;
+ int i, ret;
+
+ num_clusters = fwnode_property_count_u32(function_node, "mipi-sdca-cluster-id-list");
+ if (!num_clusters || num_clusters == -EINVAL) {
+ return 0;
+ } else if (num_clusters < 0) {
+ dev_err(dev, "%pfwP: failed to read cluster id list: %d\n",
+ function_node, num_clusters);
+ return num_clusters;
+ } else if (num_clusters > SDCA_MAX_CLUSTER_COUNT) {
+ dev_err(dev, "%pfwP: maximum number of clusters exceeded\n", function_node);
+ return -EINVAL;
+ }
+
+ clusters = devm_kcalloc(dev, num_clusters, sizeof(*clusters), GFP_KERNEL);
+ if (!clusters)
+ return -ENOMEM;
+
+ cluster_list = kcalloc(num_clusters, sizeof(*cluster_list), GFP_KERNEL);
+ if (!cluster_list)
+ return -ENOMEM;
+
+ fwnode_property_read_u32_array(function_node, "mipi-sdca-cluster-id-list",
+ cluster_list, num_clusters);
+
+ for (i = 0; i < num_clusters; i++)
+ clusters[i].id = cluster_list[i];
+
+ /* now read subproperties */
+ for (i = 0; i < num_clusters; i++) {
+ char cluster_property[SDCA_PROPERTY_LENGTH];
+ struct fwnode_handle *cluster_node;
+
+ /* DisCo uses upper-case for hex numbers */
+ snprintf(cluster_property, sizeof(cluster_property),
+ "mipi-sdca-cluster-id-0x%X-subproperties", clusters[i].id);
+
+ cluster_node = fwnode_get_named_child_node(function_node, cluster_property);
+ if (!cluster_node) {
+ dev_err(dev, "%pfwP: cluster node %s not found\n",
+ function_node, cluster_property);
+ return -EINVAL;
+ }
+
+ ret = find_sdca_cluster_channels(dev, cluster_node, &clusters[i]);
+ fwnode_handle_put(cluster_node);
+ if (ret)
+ return ret;
+ }
+
+ function->num_clusters = num_clusters;
+ function->clusters = clusters;
+
+ return 0;
+}
+
+/**
+ * sdca_parse_function - parse ACPI DisCo for a Function
+ * @dev: Pointer to device against which function data will be allocated.
+ * @function_desc: Pointer to the Function short descriptor.
+ * @function: Pointer to the Function information, to be populated.
+ *
+ * Return: Returns 0 for success.
+ */
+int sdca_parse_function(struct device *dev,
+ struct sdca_function_desc *function_desc,
+ struct sdca_function_data *function)
+{
+ u32 tmp;
+ int ret;
+
+ function->desc = function_desc;
+
+ ret = fwnode_property_read_u32(function_desc->node,
+ "mipi-sdca-function-busy-max-delay", &tmp);
+ if (!ret)
+ function->busy_max_delay = tmp;
+
+ dev_info(dev, "%pfwP: name %s delay %dus\n", function->desc->node,
+ function->desc->name, function->busy_max_delay);
+
+ ret = find_sdca_init_table(dev, function_desc->node, function);
+ if (ret)
+ return ret;
+
+ ret = find_sdca_entities(dev, function_desc->node, function);
+ if (ret)
+ return ret;
+
+ ret = find_sdca_connections(dev, function_desc->node, function);
+ if (ret)
+ return ret;
+
+ ret = find_sdca_clusters(dev, function_desc->node, function);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA");
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SDCA library");
diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c
new file mode 100644
index 000000000000..4b78188cfceb
--- /dev/null
+++ b/sound/soc/sdca/sdca_regmap.c
@@ -0,0 +1,321 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/bitops.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/types.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_regmap.h>
+
+static struct sdca_entity *
+function_find_entity(struct sdca_function_data *function, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < function->num_entities; i++)
+ if (SDW_SDCA_CTL_ENT(reg) == function->entities[i].id)
+ return &function->entities[i];
+
+ return NULL;
+}
+
+static struct sdca_control *
+entity_find_control(struct sdca_entity *entity, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < entity->num_controls; i++) {
+ if (SDW_SDCA_CTL_CSEL(reg) == entity->controls[i].sel)
+ return &entity->controls[i];
+ }
+
+ return NULL;
+}
+
+static struct sdca_control *
+function_find_control(struct sdca_function_data *function, unsigned int reg)
+{
+ struct sdca_entity *entity;
+
+ entity = function_find_entity(function, reg);
+ if (!entity)
+ return NULL;
+
+ return entity_find_control(entity, reg);
+}
+
+/**
+ * sdca_regmap_readable - return if a given SDCA Control is readable
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is readable.
+ */
+bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg)
+{
+ struct sdca_control *control;
+
+ if (!SDW_SDCA_VALID_CTL(reg))
+ return false;
+
+ control = function_find_control(function, reg);
+ if (!control)
+ return false;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_RW:
+ case SDCA_ACCESS_MODE_RO:
+ case SDCA_ACCESS_MODE_DUAL:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ /* No access to registers marked solely for device use */
+ return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS(sdca_regmap_readable, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_writeable - return if a given SDCA Control is writeable
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is writeable.
+ */
+bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg)
+{
+ struct sdca_control *control;
+
+ if (!SDW_SDCA_VALID_CTL(reg))
+ return false;
+
+ control = function_find_control(function, reg);
+ if (!control)
+ return false;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_RW:
+ case SDCA_ACCESS_MODE_DUAL:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ /* No access to registers marked solely for device use */
+ return control->layers & ~SDCA_ACCESS_LAYER_DEVICE;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS(sdca_regmap_writeable, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_volatile - return if a given SDCA Control is volatile
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is volatile.
+ */
+bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg)
+{
+ struct sdca_control *control;
+
+ if (!SDW_SDCA_VALID_CTL(reg))
+ return false;
+
+ control = function_find_control(function, reg);
+ if (!control)
+ return false;
+
+ switch (control->mode) {
+ case SDCA_ACCESS_MODE_RO:
+ case SDCA_ACCESS_MODE_RW1S:
+ case SDCA_ACCESS_MODE_RW1C:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_deferrable - return if a given SDCA Control is deferrable
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns true if the register is deferrable.
+ */
+bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg)
+{
+ struct sdca_control *control;
+
+ if (!SDW_SDCA_VALID_CTL(reg))
+ return false;
+
+ control = function_find_control(function, reg);
+ if (!control)
+ return false;
+
+ return control->deferrable;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_deferrable, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_mbq_size - return size in bytes of a given SDCA Control
+ * @function: Pointer to the Function information.
+ * @reg: Register address/Control to be processed.
+ *
+ * Return: Returns the size in bytes of the Control.
+ */
+int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg)
+{
+ struct sdca_control *control;
+
+ if (!SDW_SDCA_VALID_CTL(reg))
+ return -EINVAL;
+
+ control = function_find_control(function, reg);
+ if (!control)
+ return false;
+
+ return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32));
+}
+EXPORT_SYMBOL_NS(sdca_regmap_mbq_size, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_count_constants - count the number of DisCo constant Controls
+ * @dev: Pointer to the device.
+ * @function: Pointer to the Function information, to be parsed.
+ *
+ * This function returns the number of DisCo constant Controls present
+ * in a function. Typically this information will be used to populate
+ * the regmap defaults array, allowing drivers to access the values of
+ * DisCo constants as any other physical register.
+ *
+ * Return: Returns number of DisCo constant controls, or a negative error
+ * code on failure.
+ */
+int sdca_regmap_count_constants(struct device *dev,
+ struct sdca_function_data *function)
+{
+ int nconsts = 0;
+ int i, j;
+
+ for (i = 0; i < function->num_entities; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ for (j = 0; j < entity->num_controls; j++) {
+ if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC)
+ nconsts += hweight64(entity->controls[j].cn_list);
+ }
+ }
+
+ return nconsts;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_count_constants, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_populate_constants - fill an array with DisCo constant values
+ * @dev: Pointer to the device.
+ * @function: Pointer to the Function information, to be parsed.
+ * @consts: Pointer to the array which should be filled with the DisCo
+ * constant values.
+ *
+ * This function will populate a regmap struct reg_default array with
+ * the values of the DisCo constants for a given Function. This
+ * allows to access the values of DisCo constants the same as any
+ * other physical register.
+ *
+ * Return: Returns the number of constants populated on success, a negative
+ * error code on failure.
+ */
+int sdca_regmap_populate_constants(struct device *dev,
+ struct sdca_function_data *function,
+ struct reg_default *consts)
+{
+ int i, j, k;
+
+ for (i = 0, k = 0; i < function->num_entities; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ for (j = 0; j < entity->num_controls; j++) {
+ struct sdca_control *control = &entity->controls[j];
+ int cn;
+
+ if (control->mode != SDCA_ACCESS_MODE_DC)
+ continue;
+
+ for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+ BITS_PER_TYPE(control->cn_list)) {
+ consts[k].reg = SDW_SDCA_CTL(function->desc->adr,
+ entity->id,
+ control->sel, cn);
+ consts[k].def = control->value;
+ k++;
+ }
+ }
+ }
+
+ return k;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA");
+
+/**
+ * sdca_regmap_write_defaults - write out DisCo defaults to device
+ * @dev: Pointer to the device.
+ * @regmap: Pointer to the Function register map.
+ * @function: Pointer to the Function information, to be parsed.
+ *
+ * This function will write out to the hardware all the DisCo default and
+ * fixed value controls. This will cause them to be populated into the cache,
+ * and subsequent handling can be done through a cache sync.
+ *
+ * Return: Returns zero on success, and a negative error code on failure.
+ */
+int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap,
+ struct sdca_function_data *function)
+{
+ int i, j;
+ int ret;
+
+ for (i = 0; i < function->num_entities; i++) {
+ struct sdca_entity *entity = &function->entities[i];
+
+ for (j = 0; j < entity->num_controls; j++) {
+ struct sdca_control *control = &entity->controls[j];
+ int cn;
+
+ if (control->mode == SDCA_ACCESS_MODE_DC)
+ continue;
+
+ if (!control->has_default && !control->has_fixed)
+ continue;
+
+ for_each_set_bit(cn, (unsigned long *)&control->cn_list,
+ BITS_PER_TYPE(control->cn_list)) {
+ unsigned int reg;
+
+ reg = SDW_SDCA_CTL(function->desc->adr, entity->id,
+ control->sel, cn);
+
+ ret = regmap_write(regmap, reg, control->value);
+ if (ret)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(sdca_regmap_write_defaults, "SND_SOC_SDCA");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SDCA library");
diff --git a/sound/soc/sdw_utils/soc_sdw_cs_amp.c b/sound/soc/sdw_utils/soc_sdw_cs_amp.c
index a0bb626c5cb8..4b6181cf2971 100644
--- a/sound/soc/sdw_utils/soc_sdw_cs_amp.c
+++ b/sound/soc/sdw_utils/soc_sdw_cs_amp.c
@@ -15,6 +15,7 @@
#include <sound/soc_sdw_utils.h>
#define CODEC_NAME_SIZE 8
+#define CS_AMP_CHANNELS_PER_AMP 4
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
{
@@ -48,6 +49,51 @@ int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai
}
EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_rtd_init, "SND_SOC_SDW_UTILS");
+int asoc_sdw_cs_spk_feedback_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai)
+{
+ const struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ const struct snd_soc_dai_link_ch_map *ch_map;
+ const struct snd_soc_dai_link_component *codec_dlc;
+ struct snd_soc_dai *codec_dai;
+ u8 ch_slot[8] = {};
+ unsigned int amps_per_bus, ch_per_amp, mask;
+ int i, ret;
+
+ WARN_ON(dai_link->num_cpus > ARRAY_SIZE(ch_slot));
+
+ /*
+ * CS35L56 has 4 TX channels. When the capture is aggregated the
+ * same bus slots will be allocated to all the amps on a bus. Only
+ * one amp on that bus can be transmitting in each slot so divide
+ * the available 4 slots between all the amps on a bus.
+ */
+ amps_per_bus = dai_link->num_codecs / dai_link->num_cpus;
+ if ((amps_per_bus == 0) || (amps_per_bus > CS_AMP_CHANNELS_PER_AMP)) {
+ dev_err(rtd->card->dev, "Illegal num_codecs:%u / num_cpus:%u\n",
+ dai_link->num_codecs, dai_link->num_cpus);
+ return -EINVAL;
+ }
+
+ ch_per_amp = CS_AMP_CHANNELS_PER_AMP / amps_per_bus;
+
+ for_each_rtd_ch_maps(rtd, i, ch_map) {
+ codec_dlc = snd_soc_link_to_codec(rtd->dai_link, i);
+ codec_dai = snd_soc_find_dai(codec_dlc);
+ mask = GENMASK(ch_per_amp - 1, 0) << ch_slot[ch_map->cpu];
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0, mask, 4, 32);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set TDM slot:%d\n", ret);
+ return ret;
+ }
+
+ ch_slot[ch_map->cpu] += ch_per_amp;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS(asoc_sdw_cs_spk_feedback_rtd_init, "SND_SOC_SDW_UTILS");
+
int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 937fa3ce59df..5175818ff2c1 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -488,10 +488,10 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.part_id = 0x3556,
.dais = {
{
- .direction = {true, true},
+ .direction = {true, false},
.dai_name = "cs35l56-sdw1",
.dai_type = SOC_SDW_DAI_TYPE_AMP,
- .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
+ .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,
@@ -499,8 +499,15 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.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 = 1,
+ .dai_num = 2,
},
{
.part_id = 0x4242,
@@ -579,8 +586,20 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.dai_type = SOC_SDW_DAI_TYPE_JACK,
.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
},
+ {
+ .direction = {true, false},
+ .dai_name = "sdw-mockup-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_AMP,
+ .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
+ },
+ {
+ .direction = {false, true},
+ .dai_name = "sdw-mockup-aif1",
+ .dai_type = SOC_SDW_DAI_TYPE_MIC,
+ .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
+ },
},
- .dai_num = 1,
+ .dai_num = 3,
},
{
.part_id = 0xaa55, /* headset codec mockup */
diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c
index 8e9546fe7428..235427d69061 100644
--- a/sound/soc/soc-card.c
+++ b/sound/soc/soc-card.c
@@ -15,18 +15,8 @@
static inline int _soc_card_ret(struct snd_soc_card *card,
const char *func, int ret)
{
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- case 0:
- break;
- default:
- dev_err(card->dev,
- "ASoC: error at %s on %s: %d\n",
- func, card->name, ret);
- }
-
- return ret;
+ return snd_soc_ret(card->dev, ret,
+ "at %s() on %s\n", func, card->name);
}
struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
@@ -219,7 +209,7 @@ int snd_soc_card_set_bias_level(struct snd_soc_card *card,
{
int ret = 0;
- if (card && card->set_bias_level)
+ if (card->set_bias_level)
ret = card->set_bias_level(card, dapm, level);
return soc_card_ret(card, ret);
@@ -231,7 +221,7 @@ int snd_soc_card_set_bias_level_post(struct snd_soc_card *card,
{
int ret = 0;
- if (card && card->set_bias_level_post)
+ if (card->set_bias_level_post)
ret = card->set_bias_level_post(card, dapm, level);
return soc_card_ret(card, ret);
diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c
index b67ef78f405c..25f5e543ae8d 100644
--- a/sound/soc/soc-component.c
+++ b/sound/soc/soc-component.c
@@ -13,32 +13,20 @@
#include <sound/soc.h>
#include <linux/bitops.h>
-#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret, -1)
-#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret(dai, __func__, ret, reg)
-static inline int _soc_component_ret(struct snd_soc_component *component,
- const char *func, int ret, int reg)
-{
- /* Positive/Zero values are not errors */
- if (ret >= 0)
- return ret;
-
- /* Negative values might be errors */
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- break;
- default:
- if (reg == -1)
- dev_err(component->dev,
- "ASoC: error at %s on %s: %d\n",
- func, component->name, ret);
- else
- dev_err(component->dev,
- "ASoC: error at %s on %s for register: [0x%08x] %d\n",
- func, component->name, reg, ret);
- }
+#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret)
+static inline int _soc_component_ret(struct snd_soc_component *component, const char *func, int ret)
+{
+ return snd_soc_ret(component->dev, ret,
+ "at %s() on %s\n", func, component->name);
+}
- return ret;
+#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret_reg_rw(dai, __func__, ret, reg)
+static inline int _soc_component_ret_reg_rw(struct snd_soc_component *component,
+ const char *func, int ret, int reg)
+{
+ return snd_soc_ret(component->dev, ret,
+ "at %s() on %s for register: [0x%08x]\n",
+ func, component->name, reg);
}
static inline int soc_component_field_shift(struct snd_soc_component *component,
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 563dc0767c17..01d1d6bee28c 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -148,7 +148,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
snd_soc_dpcm_mutex_lock(fe);
/* calculate valid and active FE <-> BE dpcms */
- dpcm_process_paths(fe, stream, &list, 1);
+ dpcm_add_paths(fe, stream, &list);
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index a1dace4bb616..3f97d1f132c6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -32,6 +32,7 @@
#include <linux/of_graph.h>
#include <linux/dmi.h>
#include <linux/acpi.h>
+#include <linux/string_choices.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -430,7 +431,7 @@ void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
codec_dai->driver->playback.stream_name,
snd_soc_dai_stream_active(codec_dai, playback) ?
"active" : "inactive",
- rtd->pop_wait ? "yes" : "no");
+ str_yes_no(rtd->pop_wait));
/* are we waiting on this codec DAI stream */
if (rtd->pop_wait == 1) {
@@ -1449,23 +1450,46 @@ int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
{
struct snd_soc_dai *cpu_dai;
struct snd_soc_dai *codec_dai;
+ unsigned int ext_fmt;
unsigned int i;
int ret;
if (!dai_fmt)
return 0;
+ /*
+ * dai_fmt has 4 types
+ * 1. SND_SOC_DAIFMT_FORMAT_MASK
+ * 2. SND_SOC_DAIFMT_CLOCK
+ * 3. SND_SOC_DAIFMT_INV
+ * 4. SND_SOC_DAIFMT_CLOCK_PROVIDER
+ *
+ * 4. CLOCK_PROVIDER is set from Codec perspective in dai_fmt. So it will be flipped
+ * when this function calls set_fmt() for CPU (CBx_CFx -> Bx_Cx). see below.
+ * This mean, we can't set CPU/Codec both are clock consumer for example.
+ * New idea handles 4. in each dai->ext_fmt. It can keep compatibility.
+ *
+ * Legacy
+ * dai_fmt includes 1, 2, 3, 4
+ *
+ * New idea
+ * dai_fmt includes 1, 2, 3
+ * ext_fmt includes 4
+ */
for_each_rtd_codec_dais(rtd, i, codec_dai) {
- ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
+ ext_fmt = rtd->dai_link->codecs[i].ext_fmt;
+ ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt | ext_fmt);
if (ret != 0 && ret != -ENOTSUPP)
return ret;
}
/* Flip the polarity for the "CPU" end of link */
+ /* Will effect only for 4. SND_SOC_DAIFMT_CLOCK_PROVIDER */
dai_fmt = snd_soc_daifmt_clock_provider_flipped(dai_fmt);
for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
- ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
+ ext_fmt = rtd->dai_link->cpus[i].ext_fmt;
+ ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt | ext_fmt);
if (ret != 0 && ret != -ENOTSUPP)
return ret;
}
@@ -1644,18 +1668,8 @@ static int soc_probe_component(struct snd_soc_card *card,
ret = snd_soc_dapm_add_routes(dapm,
component->driver->dapm_routes,
component->driver->num_dapm_routes);
- if (ret < 0) {
- if (card->disable_route_checks) {
- dev_info(card->dev,
- "%s: disable_route_checks set, ignoring errors on add_routes\n",
- __func__);
- } else {
- dev_err(card->dev,
- "%s: snd_soc_dapm_add_routes failed: %d\n",
- __func__, ret);
- goto err_probe;
- }
- }
+ if (ret < 0)
+ goto err_probe;
/* see for_each_card_components */
list_add(&component->card_list, &card->component_dev_list);
@@ -1874,7 +1888,6 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str)
/**
* snd_soc_set_dmi_name() - Register DMI names to card
* @card: The card to register DMI names
- * @flavour: The flavour "differentiator" for the card amongst its peers.
*
* An Intel machine driver may be used by many different devices but are
* difficult for userspace to differentiate, since machine drivers usually
@@ -1902,7 +1915,7 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str)
*
* Returns 0 on success, otherwise a negative error code.
*/
-int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
+static int snd_soc_set_dmi_name(struct snd_soc_card *card)
{
const char *vendor, *product, *board;
@@ -1946,16 +1959,16 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour)
return 0;
}
- /* Add flavour to dmi long name */
- if (flavour)
- append_dmi_string(card, flavour);
-
/* set the card long name */
card->long_name = card->dmi_longname;
return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name);
+#else
+static inline int snd_soc_set_dmi_name(struct snd_soc_card *card)
+{
+ return 0;
+}
#endif /* CONFIG_DMI */
static void soc_check_tplg_fes(struct snd_soc_card *card)
@@ -2234,18 +2247,8 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
ret = snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
- if (ret < 0) {
- if (card->disable_route_checks) {
- dev_info(card->dev,
- "%s: disable_route_checks set, ignoring errors on add_routes\n",
- __func__);
- } else {
- dev_err(card->dev,
- "%s: snd_soc_dapm_add_routes failed: %d\n",
- __func__, ret);
- goto probe_end;
- }
- }
+ if (ret < 0)
+ goto probe_end;
ret = snd_soc_dapm_add_routes(&card->dapm, card->of_dapm_routes,
card->num_of_dapm_routes);
@@ -2253,7 +2256,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
goto probe_end;
/* try to set some sane longname if DMI is available */
- snd_soc_set_dmi_name(card, NULL);
+ snd_soc_set_dmi_name(card);
soc_setup_card_name(card, card->snd_card->shortname,
card->name, NULL);
@@ -3043,7 +3046,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop)
unsigned int i, nb_controls;
int ret;
- if (!of_property_read_bool(dev->of_node, prop))
+ if (!of_property_present(dev->of_node, prop))
return 0;
strings = devm_kcalloc(dev, nb_controls_max,
@@ -3117,23 +3120,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np,
if (rx_mask)
snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask);
- if (of_property_read_bool(np, "dai-tdm-slot-num")) {
- ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
- if (ret)
- return ret;
-
- if (slots)
- *slots = val;
- }
-
- if (of_property_read_bool(np, "dai-tdm-slot-width")) {
- ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
- if (ret)
- return ret;
+ ret = of_property_read_u32(np, "dai-tdm-slot-num", &val);
+ if (ret && ret != -EINVAL)
+ return ret;
+ if (!ret && slots)
+ *slots = val;
- if (slot_width)
- *slot_width = val;
- }
+ ret = of_property_read_u32(np, "dai-tdm-slot-width", &val);
+ if (ret && ret != -EINVAL)
+ return ret;
+ if (!ret && slot_width)
+ *slot_width = val;
return 0;
}
@@ -3389,6 +3386,9 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
char prop[128];
unsigned int bit, frame;
+ if (!np)
+ return 0;
+
if (!prefix)
prefix = "";
@@ -3397,12 +3397,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
* check "[prefix]frame-master"
*/
snprintf(prop, sizeof(prop), "%sbitclock-master", prefix);
- bit = of_property_read_bool(np, prop);
+ bit = of_property_present(np, prop);
if (bit && bitclkmaster)
*bitclkmaster = of_parse_phandle(np, prop, 0);
snprintf(prop, sizeof(prop), "%sframe-master", prefix);
- frame = of_property_read_bool(np, prop);
+ frame = of_property_present(np, prop);
if (frame && framemaster)
*framemaster = of_parse_phandle(np, prop, 0);
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 34ba1a93a4c9..a210089747d0 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -14,22 +14,8 @@
static inline int _soc_dai_ret(const struct snd_soc_dai *dai,
const char *func, int ret)
{
- /* Positive, Zero values are not errors */
- if (ret >= 0)
- return ret;
-
- /* Negative values might be errors */
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- break;
- default:
- dev_err(dai->dev,
- "ASoC: error at %s on %s: %d\n",
- func, dai->name, ret);
- }
-
- return ret;
+ return snd_soc_ret(dai->dev, ret,
+ "at %s() on %s\n", func, dai->name);
}
/*
@@ -275,10 +261,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
if (dai->driver->ops &&
dai->driver->ops->xlate_tdm_slot_mask)
- dai->driver->ops->xlate_tdm_slot_mask(slots,
- &tx_mask, &rx_mask);
+ ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
else
- snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
+ if (ret)
+ goto err;
for_each_pcm_streams(stream)
snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
@@ -287,6 +274,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
dai->driver->ops->set_tdm_slot)
ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
slots, slot_width);
+err:
return soc_dai_ret(dai, ret);
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
@@ -360,6 +348,30 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
+int snd_soc_dai_prepare(struct snd_soc_dai *dai,
+ struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ if (!snd_soc_dai_stream_valid(dai, substream->stream))
+ return 0;
+
+ if (dai->driver->ops &&
+ dai->driver->ops->prepare)
+ ret = dai->driver->ops->prepare(substream, dai);
+
+ return soc_dai_ret(dai, ret);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_prepare);
+
+int snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai *dai)
+{
+ if (dai->driver->ops)
+ return dai->driver->ops->mute_unmute_on_trigger;
+
+ return 0;
+}
+
/**
* snd_soc_dai_digital_mute - configure DAI system or master clock.
* @dai: DAI
@@ -577,14 +589,9 @@ int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
int i, ret;
for_each_rtd_dais(rtd, i, dai) {
- if (!snd_soc_dai_stream_valid(dai, substream->stream))
- continue;
- if (dai->driver->ops &&
- dai->driver->ops->prepare) {
- ret = dai->driver->ops->prepare(substream, dai);
- if (ret < 0)
- return soc_dai_ret(dai, ret);
- }
+ ret = snd_soc_dai_prepare(dai, substream);
+ if (ret < 0)
+ return ret;
}
return 0;
@@ -621,7 +628,7 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
if (ret < 0)
break;
- if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger)
+ if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
snd_soc_dai_digital_mute(dai, 0, substream->stream);
soc_dai_mark_push(dai, substream, trigger);
@@ -634,7 +641,7 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
if (rollback && !soc_dai_mark_match(dai, substream, trigger))
continue;
- if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger)
+ if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
snd_soc_dai_digital_mute(dai, 1, substream->stream);
r = soc_dai_trigger(dai, substream, cmd);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 99521c784a9b..b7818388984e 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -317,7 +317,6 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
snd_soc_dapm_mutex_unlock(card);
}
-EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
/* create a new dapm widget */
static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
@@ -730,7 +729,7 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
if (ret != 0)
goto out;
- if (!card || dapm != &card->dapm)
+ if (dapm != &card->dapm)
ret = snd_soc_dapm_force_bias_level(dapm, level);
if (ret != 0)
@@ -1744,9 +1743,8 @@ static void dapm_seq_run(struct snd_soc_card *card,
soc_dapm_async_complete(d);
}
-static void dapm_widget_update(struct snd_soc_card *card)
+static void dapm_widget_update(struct snd_soc_card *card, struct snd_soc_dapm_update *update)
{
- struct snd_soc_dapm_update *update = card->update;
struct snd_soc_dapm_widget_list *wlist;
struct snd_soc_dapm_widget *w = NULL;
unsigned int wi;
@@ -1952,7 +1950,8 @@ static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
* o Input pin to Output pin (bypass, sidetone)
* o DAC to ADC (loopback).
*/
-static int dapm_power_widgets(struct snd_soc_card *card, int event)
+static int dapm_power_widgets(struct snd_soc_card *card, int event,
+ struct snd_soc_dapm_update *update)
{
struct snd_soc_dapm_widget *w;
struct snd_soc_dapm_context *d;
@@ -2060,7 +2059,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
/* Power down widgets first; try to avoid amplifying pops. */
dapm_seq_run(card, &down_list, event, false);
- dapm_widget_update(card);
+ dapm_widget_update(card, update);
/* Now power up. */
dapm_seq_run(card, &up_list, event, true);
@@ -2333,7 +2332,9 @@ static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
/* test and update the power status of a mux widget */
static int soc_dapm_mux_update_power(struct snd_soc_card *card,
- struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+ struct snd_kcontrol *kcontrol,
+ struct snd_soc_dapm_update *update,
+ int mux, struct soc_enum *e)
{
struct snd_soc_dapm_path *path;
int found = 0;
@@ -2354,7 +2355,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card,
}
if (found)
- dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
+ dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP, update);
return found;
}
@@ -2367,9 +2368,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
int ret;
snd_soc_dapm_mutex_lock(card);
- card->update = update;
- ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
- card->update = NULL;
+ ret = soc_dapm_mux_update_power(card, kcontrol, update, mux, e);
snd_soc_dapm_mutex_unlock(card);
if (ret > 0)
snd_soc_dpcm_runtime_update(card);
@@ -2380,6 +2379,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
struct snd_kcontrol *kcontrol,
+ struct snd_soc_dapm_update *update,
int connect, int rconnect)
{
struct snd_soc_dapm_path *path;
@@ -2419,7 +2419,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
}
if (found)
- dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
+ dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP, update);
return found;
}
@@ -2432,9 +2432,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
int ret;
snd_soc_dapm_mutex_lock(card);
- card->update = update;
- ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
- card->update = NULL;
+ ret = soc_dapm_mixer_update_power(card, kcontrol, update, connect, -1);
snd_soc_dapm_mutex_unlock(card);
if (ret > 0)
snd_soc_dpcm_runtime_update(card);
@@ -2690,7 +2688,7 @@ int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
if (!snd_soc_card_is_instantiated(dapm->card))
return 0;
- return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
+ return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP, NULL);
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
@@ -2783,7 +2781,6 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
return ret;
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s)
{
@@ -3360,7 +3357,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
dapm_debugfs_add_widget(w);
}
- dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
+ dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP, NULL);
snd_soc_dapm_mutex_unlock(card);
return 0;
}
@@ -3449,6 +3446,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val, rval = 0;
int connect, rconnect = -1, change, reg_change = 0;
struct snd_soc_dapm_update update = {};
+ struct snd_soc_dapm_update *pupdate = NULL;
int ret = 0;
val = (ucontrol->value.integer.value[0] & mask);
@@ -3497,13 +3495,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
update.reg = reg;
update.mask = mask << shift;
update.val = val;
- card->update = &update;
+ pupdate = &update;
}
-
- ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
- rconnect);
-
- card->update = NULL;
+ ret = soc_dapm_mixer_update_power(card, kcontrol, pupdate, connect, rconnect);
}
snd_soc_dapm_mutex_unlock(card);
@@ -3570,6 +3564,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
unsigned int val, change, reg_change = 0;
unsigned int mask;
struct snd_soc_dapm_update update = {};
+ struct snd_soc_dapm_update *pupdate = NULL;
int ret = 0;
if (item[0] >= e->items)
@@ -3597,12 +3592,9 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
update.reg = e->reg;
update.mask = mask;
update.val = val;
- card->update = &update;
+ pupdate = &update;
}
-
- ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
-
- card->update = NULL;
+ ret = soc_dapm_mux_update_power(card, kcontrol, pupdate, item[0], e);
}
snd_soc_dapm_mutex_unlock(card);
@@ -4013,6 +4005,18 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
break;
case SND_SOC_DAPM_POST_PMU:
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
+
+ snd_soc_dai_prepare(source, substream);
+ }
+
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ snd_soc_dai_prepare(sink, substream);
+ }
+
snd_soc_dapm_widget_for_each_sink_path(w, path) {
sink = path->sink->priv;
@@ -4516,7 +4520,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
for_each_rtd_dais(rtd, i, dai)
soc_dapm_dai_stream_event(dai, stream, event);
- dapm_power_widgets(rtd->card, event);
+ dapm_power_widgets(rtd->card, event, NULL);
}
/**
@@ -4853,7 +4857,6 @@ void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
/* see for_each_card_dapms */
list_add(&dapm->list, &card->dapm_list);
}
-EXPORT_SYMBOL_GPL(snd_soc_dapm_init);
static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
{
diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c
index 7f1f1bc717e2..02fd68f2e702 100644
--- a/sound/soc/soc-link.c
+++ b/sound/soc/soc-link.c
@@ -12,22 +12,8 @@
static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd,
const char *func, int ret)
{
- /* Positive, Zero values are not errors */
- if (ret >= 0)
- return ret;
-
- /* Negative values might be errors */
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- break;
- default:
- dev_err(rtd->dev,
- "ASoC: error at %s on %s: %d\n",
- func, rtd->dai_link->name, ret);
- }
-
- return ret;
+ return snd_soc_ret(rtd->dev, ret,
+ "at %s() on %s\n", func, rtd->dai_link->name);
}
/*
diff --git a/sound/soc/soc-ops-test.c b/sound/soc/soc-ops-test.c
new file mode 100644
index 000000000000..dc1e482bba6a
--- /dev/null
+++ b/sound/soc/soc-ops-test.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (C) 2025 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/device.h>
+#include <kunit/test.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+#include <sound/asound.h>
+#include <sound/control.h>
+#include <sound/soc.h>
+#include <sound/soc-component.h>
+
+enum soc_ops_test_control_layout {
+ SOC_OPS_TEST_SINGLE,
+ SOC_OPS_TEST_DOUBLE,
+ SOC_OPS_TEST_DOUBLE_R,
+};
+
+#define TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert) \
+ .mc = { \
+ .min = xmin, .max = xmax, .platform_max = xpmax, \
+ .reg = 0, .shift = 0, .sign_bit = xsign, .invert = xinvert, \
+ .rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? 1 : 0, \
+ .rshift = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? 16 : 0, \
+ }
+
+#define TEST_UINFO(clayout, ctype, cmin, cmax) \
+ .uinfo = { \
+ .type = SNDRV_CTL_ELEM_TYPE_##ctype, \
+ .count = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_SINGLE ? 1 : 2, \
+ .value.integer.min = cmin, \
+ .value.integer.max = cmax, \
+ }
+
+#define ITEST(cname, clayout, ctype, cfunc, cmin, cmax, \
+ xmin, xmax, xpmax, xsign, xinvert) \
+ { \
+ .name = cname, \
+ .func_name = #cfunc, \
+ .layout = SOC_OPS_TEST_##clayout, \
+ .info = snd_soc_info_##cfunc, \
+ TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \
+ TEST_UINFO(clayout, ctype, cmin, cmax), \
+ }
+
+#define ATEST(clayout, cfunc, cctl, cret, cinit, \
+ xmask, xreg, xmin, xmax, xpmax, xsign, xinvert) \
+ { \
+ .func_name = #cfunc, \
+ .layout = SOC_OPS_TEST_##clayout, \
+ .put = snd_soc_put_##cfunc, \
+ .get = snd_soc_get_##cfunc, \
+ TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \
+ .lctl = cctl, .rctl = cctl, \
+ .lmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \
+ (xmask) | (xmask) << 16 : (xmask), \
+ .rmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xmask) : 0, \
+ .init = cinit ? 0xFFFFFFFF : 0x00000000, \
+ .lreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \
+ (xreg) | (xreg) << 16 : (xreg), \
+ .rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xreg) : 0, \
+ .ret = cret, \
+ }
+
+struct soc_ops_test_priv {
+ struct kunit *test;
+
+ struct snd_soc_component component;
+};
+
+struct info_test_param {
+ const char * const name;
+ const char * const func_name;
+ enum soc_ops_test_control_layout layout;
+ struct soc_mixer_control mc;
+ int (*info)(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info);
+
+ struct snd_ctl_elem_info uinfo;
+};
+
+struct access_test_param {
+ const char * const func_name;
+ enum soc_ops_test_control_layout layout;
+ struct soc_mixer_control mc;
+ int (*put)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value);
+ int (*get)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value);
+
+ unsigned int init;
+ unsigned int lmask;
+ unsigned int rmask;
+ unsigned int lreg;
+ unsigned int rreg;
+ long lctl;
+ long rctl;
+ int ret;
+};
+
+static const struct info_test_param all_info_test_params[] = {
+ // Handling of volume control name for types
+ ITEST("Test Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Volume Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Control", DOUBLE_R, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Volume", DOUBLE_R, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Volume Control", DOUBLE_R, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Volume", DOUBLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Volume Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0),
+ ITEST("Test Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 1),
+ ITEST("Test Volume Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1),
+ ITEST("Test Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1),
+ ITEST("Test Volume", DOUBLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 1),
+ ITEST("Test Volume Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1),
+ ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 2, 0, 2, 0, 0, 0),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 2, 0, 2, 0, 0, 0),
+ ITEST("Test Volume Control", SINGLE, INTEGER, volsw, 0, 2, 0, 2, 0, 0, 0),
+ ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 1, 0, 2, 1, 0, 0),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 1, 0, 2, 1, 0, 0),
+ ITEST("Test Volume Control", SINGLE, INTEGER, volsw, 0, 1, 0, 2, 1, 0, 0),
+ // Negative minimums
+ ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 20, -10, 10, 0, 4, 0),
+ ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 15, -10, 10, 15, 4, 0),
+ ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 20, -10, 10, 0, 4, 1),
+ ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 15, -10, 10, 15, 4, 1),
+ // SX control volume control naming
+ ITEST("Test Control", SINGLE, BOOLEAN, volsw_sx, 0, 1, 0xF, 1, 0, 0, 0),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw_sx, 0, 1, 0xF, 1, 0, 0, 0),
+ ITEST("Test Volume Control", SINGLE, BOOLEAN, volsw_sx, 0, 1, 0xF, 1, 0, 0, 0),
+ ITEST("Test Control", SINGLE, INTEGER, volsw_sx, 0, 4, 0xE, 4, 0, 0, 0),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw_sx, 0, 4, 0xE, 4, 0, 0, 0),
+ ITEST("Test Volume Control", SINGLE, INTEGER, volsw_sx, 0, 4, 0xE, 4, 0, 0, 0),
+ ITEST("Test Control", SINGLE, INTEGER, volsw_sx, 0, 3, 0xE, 4, 3, 0, 0),
+ ITEST("Test Volume", SINGLE, INTEGER, volsw_sx, 0, 3, 0xE, 4, 3, 0, 0),
+ ITEST("Test Volume Control", SINGLE, INTEGER, volsw_sx, 0, 3, 0xE, 4, 3, 0, 0),
+};
+
+static const struct access_test_param all_access_test_params[] = {
+ // Single positive value controls
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 0),
+ ATEST(SINGLE, volsw, 0, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 0),
+ ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 0),
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 0),
+ ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 0),
+ ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x0F, 0, 20, 15, 0, 0),
+ // Inverted single positive value controls
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 1),
+ ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 1),
+ ATEST(SINGLE, volsw, 20, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 1),
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 1),
+ ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 1),
+ ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x05, 0, 20, 15, 0, 1),
+ ATEST(SINGLE, volsw, 10, 1, true, 0x1F, 0x0A, 0, 20, 0, 0, 0),
+ ATEST(SINGLE, volsw, 0, 1, true, 0x1F, 0x00, 0, 20, 0, 0, 0),
+ ATEST(SINGLE, volsw, 20, 1, true, 0x1F, 0x14, 0, 20, 0, 0, 0),
+ ATEST(SINGLE, volsw, 10, 1, true, 0x1F, 0x0A, 0, 20, 15, 0, 0),
+ ATEST(SINGLE, volsw, 25, -22, true, 0x1F, 0x00, 0, 20, 15, 0, 0),
+ ATEST(SINGLE, volsw, 15, 1, true, 0x1F, 0x0F, 0, 20, 15, 0, 0),
+ // Single negative value controls
+ ATEST(SINGLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 0),
+ ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 0),
+ ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 0),
+ ATEST(SINGLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x05, -10, 10, 15, 4, 0),
+ // Single non-zero minimum positive value controls
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 0),
+ ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 0),
+ ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 0),
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 0),
+ ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 0),
+ ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x19, 10, 30, 15, 0, 0),
+ // Inverted single non-zero minimum positive value controls
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 1),
+ ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 1),
+ ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 1),
+ ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 1),
+ ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 1),
+ ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x0F, 10, 30, 15, 0, 1),
+ // Double register positive value controls
+ ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw, 0, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw, 20, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 0),
+ ATEST(DOUBLE_R, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 0),
+ ATEST(DOUBLE_R, volsw, 15, 1, false, 0x1F, 0x0F, 0, 20, 15, 0, 0),
+ // Double register negative value controls
+ ATEST(DOUBLE_R, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE_R, volsw, 0, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE_R, volsw, 20, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE_R, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE_R, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE_R, volsw, 15, 1, false, 0x1F, 0x05, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE_R, volsw, 0, 1, true, 0x1F, 0x16, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE_R, volsw, 20, 1, true, 0x1F, 0x0A, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE_R, volsw, 25, -22, true, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE_R, volsw, 15, 1, true, 0x1F, 0x05, -10, 10, 15, 4, 0),
+ // Inverted double register negative value controls
+ ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 0, 4, 1),
+ ATEST(DOUBLE_R, volsw, 0, 1, true, 0x1F, 0x0A, -10, 10, 0, 4, 1),
+ ATEST(DOUBLE_R, volsw, 20, 1, true, 0x1F, 0x16, -10, 10, 0, 4, 1),
+ ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 15, 4, 1),
+ ATEST(DOUBLE_R, volsw, 25, -22, true, 0x1F, 0x00, -10, 10, 15, 4, 1),
+ ATEST(DOUBLE_R, volsw, 15, 1, true, 0x1F, 0x1B, -10, 10, 15, 4, 1),
+ // Double register non-zero minimum positive value controls
+ ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw, 0, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw, 20, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE_R, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE_R, volsw, 15, 1, false, 0x1F, 0x19, 10, 30, 15, 0, 0),
+ // Double shift positive value controls
+ ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 0, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x0F, 0, 20, 15, 0, 0),
+ // Double shift negative value controls
+ ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE, volsw, 0, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 0),
+ ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 0),
+ ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x05, -10, 10, 15, 4, 0),
+ // Inverted double shift negative value controls
+ ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 1),
+ ATEST(DOUBLE, volsw, 0, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 1),
+ ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 1),
+ ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 1),
+ ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 1),
+ ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x1B, -10, 10, 15, 4, 1),
+ // Double shift non-zero minimum positive value controls
+ ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 0, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x19, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 10, 1, true, 0x1F, 0x14, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 0, 1, true, 0x1F, 0x0A, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 20, 1, true, 0x1F, 0x1E, 10, 30, 0, 0, 0),
+ ATEST(DOUBLE, volsw, 10, 1, true, 0x1F, 0x14, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 25, -22, true, 0x1F, 0x00, 10, 30, 15, 0, 0),
+ ATEST(DOUBLE, volsw, 15, 1, true, 0x1F, 0x19, 10, 30, 15, 0, 0),
+ // Single SX all values
+ ATEST(SINGLE, volsw_sx, 0, 1, false, 0xF, 0x0F, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 1, 0, false, 0xF, 0x00, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 2, 1, false, 0xF, 0x01, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 3, 1, false, 0xF, 0x02, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 4, 1, false, 0xF, 0x03, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 5, -22, false, 0xF, 0x00, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 0, 0, true, 0xF, 0x0F, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 1, 1, true, 0xF, 0x00, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 2, 1, true, 0xF, 0x01, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 3, 1, true, 0xF, 0x02, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 4, 1, true, 0xF, 0x03, 0x0F, 4, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 5, -22, true, 0xF, 0x00, 0x0F, 4, 0, 0, 0),
+ // Inverted single SX all values
+ ATEST(SINGLE, volsw_sx, 0, 1, false, 0x1F, 0x03, 0x0F, 4, 0, 0, 1),
+ ATEST(SINGLE, volsw_sx, 1, 1, false, 0x1F, 0x02, 0x0F, 4, 0, 0, 1),
+ ATEST(SINGLE, volsw_sx, 2, 1, false, 0x1F, 0x01, 0x0F, 4, 0, 0, 1),
+ ATEST(SINGLE, volsw_sx, 3, 0, false, 0x1F, 0x00, 0x0F, 4, 0, 0, 1),
+ ATEST(SINGLE, volsw_sx, 4, 1, false, 0x1F, 0x0F, 0x0F, 4, 0, 0, 1),
+ ATEST(SINGLE, volsw_sx, 5, -22, false, 0x1F, 0x00, 0x0F, 4, 0, 0, 1),
+ // Single SX select values
+ ATEST(SINGLE, volsw_sx, 0, 1, false, 0xFF, 0x88, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 1, 1, false, 0xFF, 0x89, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 119, 1, false, 0xFF, 0xFF, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 120, 0, false, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 121, 1, false, 0xFF, 0x01, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 143, 1, false, 0xFF, 0x17, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 144, 1, false, 0xFF, 0x18, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 145, -22, false, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 0, 1, true, 0xFF, 0x88, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 1, 1, true, 0xFF, 0x89, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 119, 0, true, 0xFF, 0xFF, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 120, 1, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 121, 1, true, 0xFF, 0x01, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 143, 1, true, 0xFF, 0x17, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 144, 1, true, 0xFF, 0x18, 0x88, 144, 0, 0, 0),
+ ATEST(SINGLE, volsw_sx, 145, -22, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ // Double shift SX select values
+ ATEST(DOUBLE, volsw_sx, 0, 1, true, 0xFF, 0x88, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 1, 1, true, 0xFF, 0x89, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 119, 0, true, 0xFF, 0xFF, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 120, 1, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 121, 1, true, 0xFF, 0x01, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 143, 1, true, 0xFF, 0x17, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 144, 1, true, 0xFF, 0x18, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE, volsw_sx, 145, -22, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ // Double register SX select values
+ ATEST(DOUBLE_R, volsw_sx, 0, 1, true, 0xFF, 0x88, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 1, 1, true, 0xFF, 0x89, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 119, 0, true, 0xFF, 0xFF, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 120, 1, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 121, 1, true, 0xFF, 0x01, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 143, 1, true, 0xFF, 0x17, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 144, 1, true, 0xFF, 0x18, 0x88, 144, 0, 0, 0),
+ ATEST(DOUBLE_R, volsw_sx, 145, -22, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0),
+};
+
+static const char *control_type_str(const snd_ctl_elem_type_t type)
+{
+ switch (type) {
+ case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+ return "bool";
+ case SNDRV_CTL_ELEM_TYPE_INTEGER:
+ return "int";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *control_layout_str(const enum soc_ops_test_control_layout layout)
+{
+ switch (layout) {
+ case SOC_OPS_TEST_SINGLE:
+ return "single";
+ case SOC_OPS_TEST_DOUBLE:
+ return "double";
+ case SOC_OPS_TEST_DOUBLE_R:
+ return "double_r";
+ default:
+ return "unknown";
+ }
+};
+
+static int mock_regmap_read(void *context, const void *reg_buf,
+ const size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct soc_ops_test_priv *priv = context;
+
+ KUNIT_FAIL(priv->test, "Unexpected bus read");
+
+ return -EIO;
+}
+
+static int mock_regmap_gather_write(void *context,
+ const void *reg_buf, size_t reg_size,
+ const void *val_buf, size_t val_size)
+{
+ struct soc_ops_test_priv *priv = context;
+
+ KUNIT_FAIL(priv->test, "Unexpected bus gather_write");
+
+ return -EIO;
+}
+
+static int mock_regmap_write(void *context, const void *val_buf,
+ size_t val_size)
+{
+ struct soc_ops_test_priv *priv = context;
+
+ KUNIT_FAIL(priv->test, "Unexpected bus write");
+
+ return -EIO;
+}
+
+static const struct regmap_bus mock_regmap_bus = {
+ .read = mock_regmap_read,
+ .write = mock_regmap_write,
+ .gather_write = mock_regmap_gather_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+static const struct regmap_config mock_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_format_endian = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+ .max_register = 0x1,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int soc_ops_test_init(struct kunit *test)
+{
+ struct soc_ops_test_priv *priv;
+ struct regmap *regmap;
+ struct device *dev;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->test = test;
+
+ dev = kunit_device_register(test, "soc_ops_test_drv");
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
+
+ regmap = devm_regmap_init(dev, &mock_regmap_bus, priv, &mock_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* No actual hardware, we just use the cache */
+ regcache_cache_only(regmap, true);
+
+ priv->component.dev = dev;
+ priv->component.regmap = regmap;
+ mutex_init(&priv->component.io_mutex);
+
+ test->priv = priv;
+
+ return 0;
+}
+
+static void soc_ops_test_exit(struct kunit *test)
+{
+ struct soc_ops_test_priv *priv = test->priv;
+
+ kunit_device_unregister(test, priv->component.dev);
+}
+
+static void info_test_desc(const struct info_test_param *param, char *desc)
+{
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE,
+ "%s %s %s: ctl range: %ld->%ld, reg range: %d->%d(%d), sign: %d, inv: %d",
+ control_layout_str(param->layout), param->func_name,
+ control_type_str(param->uinfo.type),
+ param->uinfo.value.integer.min, param->uinfo.value.integer.max,
+ param->mc.min, param->mc.max, param->mc.platform_max,
+ param->mc.sign_bit, param->mc.invert);
+}
+
+static void soc_ops_test_info(struct kunit *test)
+{
+ struct soc_ops_test_priv *priv = test->priv;
+ const struct info_test_param *param = test->param_value;
+ const struct snd_ctl_elem_info *target = &param->uinfo;
+ struct snd_ctl_elem_info result;
+ struct snd_kcontrol kctl = {
+ .private_data = &priv->component,
+ .private_value = (unsigned long)&param->mc,
+ };
+ int ret;
+
+ strscpy(kctl.id.name, param->name, sizeof(kctl.id.name));
+
+ ret = param->info(&kctl, &result);
+ KUNIT_ASSERT_FALSE(test, ret);
+
+ KUNIT_EXPECT_EQ(test, result.count, target->count);
+ KUNIT_EXPECT_EQ(test, result.type, target->type);
+ KUNIT_EXPECT_EQ(test, result.value.integer.min, target->value.integer.min);
+ KUNIT_EXPECT_EQ(test, result.value.integer.max, target->value.integer.max);
+}
+
+static void access_test_desc(const struct access_test_param *param, char *desc)
+{
+ if (param->ret < 0) {
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE,
+ "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> err: %d",
+ control_layout_str(param->layout), param->func_name,
+ param->lctl, param->rctl,
+ param->mc.min, param->mc.max, param->mc.platform_max,
+ param->mc.sign_bit, param->mc.invert,
+ param->ret);
+ } else {
+ snprintf(desc, KUNIT_PARAM_DESC_SIZE,
+ "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> %#x,%#x",
+ control_layout_str(param->layout), param->func_name,
+ param->lctl, param->rctl,
+ param->mc.min, param->mc.max, param->mc.platform_max,
+ param->mc.sign_bit, param->mc.invert,
+ param->lreg, param->rreg);
+ }
+}
+
+static void soc_ops_test_access(struct kunit *test)
+{
+ struct soc_ops_test_priv *priv = test->priv;
+ const struct access_test_param *param = test->param_value;
+ struct snd_kcontrol kctl = {
+ .private_data = &priv->component,
+ .private_value = (unsigned long)&param->mc,
+ };
+ struct snd_ctl_elem_value result;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_write(priv->component.regmap, 0x0, param->init);
+ KUNIT_ASSERT_FALSE(test, ret);
+ ret = regmap_write(priv->component.regmap, 0x1, param->init);
+ KUNIT_ASSERT_FALSE(test, ret);
+
+ result.value.integer.value[0] = param->lctl;
+ result.value.integer.value[1] = param->rctl;
+
+ ret = param->put(&kctl, &result);
+ KUNIT_ASSERT_EQ(test, ret, param->ret);
+ if (ret < 0)
+ return;
+
+ ret = regmap_read(priv->component.regmap, 0x0, &val);
+ KUNIT_ASSERT_FALSE(test, ret);
+ KUNIT_EXPECT_EQ(test, val, (param->init & ~param->lmask) | param->lreg);
+
+ ret = regmap_read(priv->component.regmap, 0x1, &val);
+ KUNIT_ASSERT_FALSE(test, ret);
+ KUNIT_EXPECT_EQ(test, val, (param->init & ~param->rmask) | param->rreg);
+
+ result.value.integer.value[0] = 0;
+ result.value.integer.value[1] = 0;
+
+ ret = param->get(&kctl, &result);
+ KUNIT_ASSERT_GE(test, ret, 0);
+
+ KUNIT_EXPECT_EQ(test, result.value.integer.value[0], param->lctl);
+ if (param->layout != SOC_OPS_TEST_SINGLE)
+ KUNIT_EXPECT_EQ(test, result.value.integer.value[1], param->rctl);
+ else
+ KUNIT_EXPECT_EQ(test, result.value.integer.value[1], 0);
+}
+
+KUNIT_ARRAY_PARAM(all_info_tests, all_info_test_params, info_test_desc);
+KUNIT_ARRAY_PARAM(all_access_tests, all_access_test_params, access_test_desc);
+
+static struct kunit_case soc_ops_test_cases[] = {
+ KUNIT_CASE_PARAM(soc_ops_test_info, all_info_tests_gen_params),
+ KUNIT_CASE_PARAM(soc_ops_test_access, all_access_tests_gen_params),
+ {}
+};
+
+static struct kunit_suite soc_ops_test_suite = {
+ .name = "soc-ops",
+ .init = soc_ops_test_init,
+ .exit = soc_ops_test_exit,
+ .test_cases = soc_ops_test_cases,
+};
+
+kunit_test_suites(&soc_ops_test_suite);
+
+MODULE_DESCRIPTION("ASoC soc-ops kunit test");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index 19928f098d8d..8d4dd11c9aef 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -24,7 +24,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <sound/soc-dpcm.h>
#include <sound/initval.h>
/**
@@ -38,7 +37,7 @@
* Returns 0 for success.
*/
int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+ struct snd_ctl_elem_info *uinfo)
{
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -57,7 +56,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
* Returns 0 for success.
*/
int snd_soc_get_enum_double(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);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -88,7 +87,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
* Returns 0 for success.
*/
int snd_soc_put_enum_double(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);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
@@ -111,95 +110,183 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
-/**
- * snd_soc_read_signed - Read a codec register and interpret as signed value
- * @component: component
- * @reg: Register to read
- * @mask: Mask to use after shifting the register value
- * @shift: Right shift of register value
- * @sign_bit: Bit that describes if a number is negative or not.
- * @signed_val: Pointer to where the read value should be stored
- *
- * This functions reads a codec register. The register value is shifted right
- * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
- * the given registervalue into a signed integer if sign_bit is non-zero.
- *
- * Returns 0 on sucess, otherwise an error value
- */
-static int snd_soc_read_signed(struct snd_soc_component *component,
- unsigned int reg, unsigned int mask, unsigned int shift,
- unsigned int sign_bit, int *signed_val)
+static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val,
+ unsigned int mask, unsigned int shift, int max)
+{
+ int val = (reg_val >> shift) & mask;
+
+ if (mc->sign_bit)
+ val = sign_extend32(val, mc->sign_bit);
+
+ val -= mc->min;
+
+ if (mc->invert)
+ val = max - val;
+
+ return val & mask;
+}
+
+static unsigned int soc_mixer_ctl_to_reg(struct soc_mixer_control *mc, int val,
+ unsigned int mask, unsigned int shift,
+ int max)
+{
+ unsigned int reg_val;
+
+ if (mc->invert)
+ val = max - val;
+
+ reg_val = val + mc->min;
+
+ return (reg_val & mask) << shift;
+}
+
+static int soc_mixer_valid_ctl(struct soc_mixer_control *mc, long val, int max)
{
+ if (val < 0)
+ return -EINVAL;
+
+ if (mc->platform_max && val > mc->platform_max)
+ return -EINVAL;
+
+ if (val > max)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int soc_mixer_mask(struct soc_mixer_control *mc)
+{
+ if (mc->sign_bit)
+ return GENMASK(mc->sign_bit, 0);
+ else
+ return GENMASK(fls(mc->max) - 1, 0);
+}
+
+static int soc_mixer_sx_mask(struct soc_mixer_control *mc)
+{
+ // min + max will take us 1-bit over the size of the mask
+ return GENMASK(fls(mc->min + mc->max) - 2, 0);
+}
+
+static int soc_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo,
+ struct soc_mixer_control *mc, int max)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+ if (max == 1) {
+ /* Even two value controls ending in Volume should be integer */
+ const char *vol_string = strstr(kcontrol->id.name, " Volume");
+
+ if (!vol_string || strcmp(vol_string, " Volume"))
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ }
+
+ if (mc->platform_max && mc->platform_max < max)
+ max = mc->platform_max;
+
+ uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max;
+
+ return 0;
+}
+
+static int soc_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc, int mask, int max)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int val1, val_mask;
+ unsigned int val2 = 0;
+ bool double_r = false;
int ret;
- unsigned int val;
- val = snd_soc_component_read(component, reg);
- val = (val >> shift) & mask;
+ ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max);
+ if (ret)
+ return ret;
- if (!sign_bit) {
- *signed_val = val;
- return 0;
+ val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0],
+ mask, mc->shift, max);
+ val_mask = mask << mc->shift;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max);
+ if (ret)
+ return ret;
+
+ if (mc->reg == mc->rreg) {
+ val1 |= soc_mixer_ctl_to_reg(mc,
+ ucontrol->value.integer.value[1],
+ mask, mc->rshift, max);
+ val_mask |= mask << mc->rshift;
+ } else {
+ val2 = soc_mixer_ctl_to_reg(mc,
+ ucontrol->value.integer.value[1],
+ mask, mc->shift, max);
+ double_r = true;
+ }
}
- /* non-negative number */
- if (!(val & BIT(sign_bit))) {
- *signed_val = val;
- return 0;
+ ret = snd_soc_component_update_bits(component, mc->reg, val_mask, val1);
+ if (ret < 0)
+ return ret;
+
+ if (double_r) {
+ int err = snd_soc_component_update_bits(component, mc->rreg,
+ val_mask, val2);
+ /* Don't drop change flag */
+ if (err)
+ return err;
}
- ret = val;
+ return ret;
+}
- /*
- * The register most probably does not contain a full-sized int.
- * Instead we have an arbitrary number of bits in a signed
- * representation which has to be translated into a full-sized int.
- * This is done by filling up all bits above the sign-bit.
- */
- ret |= ~((int)(BIT(sign_bit) - 1));
+static int soc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol,
+ struct soc_mixer_control *mc, int mask, int max)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int reg_val;
+ int val;
+
+ reg_val = snd_soc_component_read(component, mc->reg);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
+
+ ucontrol->value.integer.value[0] = val;
- *signed_val = ret;
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (mc->reg == mc->rreg) {
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max);
+ } else {
+ reg_val = snd_soc_component_read(component, mc->rreg);
+ val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max);
+ }
+
+ ucontrol->value.integer.value[1] = val;
+ }
return 0;
}
/**
- * snd_soc_info_volsw - single mixer info callback
+ * snd_soc_info_volsw - single mixer info callback with range.
* @kcontrol: mixer control
* @uinfo: control element information
*
- * Callback to provide information about a single mixer control, or a double
- * mixer control that spans 2 registers.
+ * Callback to provide information, with a range, about a single mixer control,
+ * or a double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+ struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- const char *vol_string = NULL;
- int max;
- max = uinfo->value.integer.max = mc->max - mc->min;
- if (mc->platform_max && mc->platform_max < max)
- max = mc->platform_max;
-
- if (max == 1) {
- /* Even two value controls ending in Volume should always be integer */
- vol_string = strstr(kcontrol->id.name, " Volume");
- if (vol_string && !strcmp(vol_string, " Volume"))
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- else
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- } else {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- }
-
- uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = max;
-
- return 0;
+ return soc_info_volsw(kcontrol, uinfo, mc, mc->max - mc->min);
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
@@ -221,165 +308,50 @@ int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol,
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- int max;
-
- if (mc->platform_max)
- max = mc->platform_max;
- else
- max = mc->max;
-
- if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- else
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = max;
-
- return 0;
+ return soc_info_volsw(kcontrol, uinfo, mc, mc->max);
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw_sx);
/**
- * snd_soc_get_volsw - single mixer get callback
+ * snd_soc_get_volsw - single mixer get callback with range
* @kcontrol: mixer control
* @ucontrol: control element information
*
- * Callback to get the value of a single mixer control, or a double mixer
- * control that spans 2 registers.
+ * Callback to get the value, within a range, of a single mixer control, or a
+ * double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int snd_soc_get_volsw(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);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- int sign_bit = mc->sign_bit;
- unsigned int mask = (1ULL << fls(max)) - 1;
- unsigned int invert = mc->invert;
- int val;
- int ret;
-
- if (sign_bit)
- mask = BIT(sign_bit + 1) - 1;
-
- ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[0] = val - min;
- if (invert)
- ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
+ unsigned int mask = soc_mixer_mask(mc);
- if (snd_soc_volsw_is_stereo(mc)) {
- if (reg == reg2)
- ret = snd_soc_read_signed(component, reg, mask, rshift,
- sign_bit, &val);
- else
- ret = snd_soc_read_signed(component, reg2, mask, shift,
- sign_bit, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[1] = val - min;
- if (invert)
- ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- }
-
- return 0;
+ return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min);
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
/**
- * snd_soc_put_volsw - single mixer put callback
+ * snd_soc_put_volsw - single mixer put callback with range
* @kcontrol: mixer control
* @ucontrol: control element information
*
- * Callback to set the value of a single mixer control, or a double mixer
- * control that spans 2 registers.
+ * Callback to set the value , within a range, of a single mixer control, or
+ * a double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int snd_soc_put_volsw(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);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- unsigned int sign_bit = mc->sign_bit;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- int err, ret;
- bool type_2r = false;
- unsigned int val2 = 0;
- unsigned int val, val_mask;
-
- if (sign_bit)
- mask = BIT(sign_bit + 1) - 1;
-
- if (ucontrol->value.integer.value[0] < 0)
- return -EINVAL;
- val = ucontrol->value.integer.value[0];
- if (mc->platform_max && ((int)val + min) > mc->platform_max)
- return -EINVAL;
- if (val > max - min)
- return -EINVAL;
- val = (val + min) & mask;
- if (invert)
- val = max - val;
- val_mask = mask << shift;
- val = val << shift;
- if (snd_soc_volsw_is_stereo(mc)) {
- if (ucontrol->value.integer.value[1] < 0)
- return -EINVAL;
- val2 = ucontrol->value.integer.value[1];
- if (mc->platform_max && ((int)val2 + min) > mc->platform_max)
- return -EINVAL;
- if (val2 > max - min)
- return -EINVAL;
- val2 = (val2 + min) & mask;
- if (invert)
- val2 = max - val2;
- if (reg == reg2) {
- val_mask |= mask << rshift;
- val |= val2 << rshift;
- } else {
- val2 = val2 << shift;
- type_2r = true;
- }
- }
- err = snd_soc_component_update_bits(component, reg, val_mask, val);
- if (err < 0)
- return err;
- ret = err;
-
- if (type_2r) {
- err = snd_soc_component_update_bits(component, reg2, val_mask,
- val2);
- /* Don't discard any error code or drop change flag */
- if (ret == 0 || err < 0) {
- ret = err;
- }
- }
+ unsigned int mask = soc_mixer_mask(mc);
- return ret;
+ return soc_put_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
@@ -394,30 +366,13 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
* Returns 0 for success.
*/
int snd_soc_get_volsw_sx(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);
struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- unsigned int mask = (1U << (fls(min + max) - 1)) - 1;
- unsigned int val;
-
- val = snd_soc_component_read(component, reg);
- ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- val = snd_soc_component_read(component, reg2);
- val = ((val >> rshift) - min) & mask;
- ucontrol->value.integer.value[1] = val;
- }
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int mask = soc_mixer_sx_mask(mc);
- return 0;
+ return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max);
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
@@ -433,212 +388,40 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
-
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- unsigned int mask = (1U << (fls(min + max) - 1)) - 1;
- int err = 0;
- int ret;
- unsigned int val, val_mask;
-
- if (ucontrol->value.integer.value[0] < 0)
- return -EINVAL;
- val = ucontrol->value.integer.value[0];
- if (mc->platform_max && val > mc->platform_max)
- return -EINVAL;
- if (val > max)
- return -EINVAL;
- val_mask = mask << shift;
- val = (val + min) & mask;
- val = val << shift;
-
- err = snd_soc_component_update_bits(component, reg, val_mask, val);
- if (err < 0)
- return err;
- ret = err;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- unsigned int val2 = ucontrol->value.integer.value[1];
-
- if (mc->platform_max && val2 > mc->platform_max)
- return -EINVAL;
- if (val2 > max)
- return -EINVAL;
-
- val_mask = mask << rshift;
- val2 = (val2 + min) & mask;
- val2 = val2 << rshift;
-
- err = snd_soc_component_update_bits(component, reg2, val_mask,
- val2);
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int mask = soc_mixer_sx_mask(mc);
- /* Don't discard any error code or drop change flag */
- if (ret == 0 || err < 0) {
- ret = err;
- }
- }
- return ret;
+ return soc_put_volsw(kcontrol, ucontrol, mc, mask, mc->max);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
-/**
- * snd_soc_info_volsw_range - single mixer info callback with range.
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information, within a range, about a single
- * mixer control.
- *
- * returns 0 for success.
- */
-int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl)
{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int platform_max;
- int min = mc->min;
+ struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct snd_ctl_elem_value uctl;
+ int ret;
if (!mc->platform_max)
- mc->platform_max = mc->max;
- platform_max = mc->platform_max;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max - min;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
-
-/**
- * snd_soc_put_volsw_range - single mixer put value callback with range.
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value, within a range, for a single mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int rreg = mc->rreg;
- unsigned int shift = mc->shift;
- int min = mc->min;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- unsigned int val, val_mask;
- int err, ret, tmp;
-
- tmp = ucontrol->value.integer.value[0];
- if (tmp < 0)
- return -EINVAL;
- if (mc->platform_max && tmp > mc->platform_max)
- return -EINVAL;
- if (tmp > mc->max - mc->min)
- return -EINVAL;
+ return 0;
- if (invert)
- val = (max - ucontrol->value.integer.value[0]) & mask;
- else
- val = ((ucontrol->value.integer.value[0] + min) & mask);
- val_mask = mask << shift;
- val = val << shift;
+ ret = kctl->get(kctl, &uctl);
+ if (ret < 0)
+ return ret;
- err = snd_soc_component_update_bits(component, reg, val_mask, val);
- if (err < 0)
- return err;
- ret = err;
+ if (uctl.value.integer.value[0] > mc->platform_max)
+ uctl.value.integer.value[0] = mc->platform_max;
- if (snd_soc_volsw_is_stereo(mc)) {
- tmp = ucontrol->value.integer.value[1];
- if (tmp < 0)
- return -EINVAL;
- if (mc->platform_max && tmp > mc->platform_max)
- return -EINVAL;
- if (tmp > mc->max - mc->min)
- return -EINVAL;
+ if (snd_soc_volsw_is_stereo(mc) &&
+ uctl.value.integer.value[1] > mc->platform_max)
+ uctl.value.integer.value[1] = mc->platform_max;
- if (invert)
- val = (max - ucontrol->value.integer.value[1]) & mask;
- else
- val = ((ucontrol->value.integer.value[1] + min) & mask);
- val_mask = mask << shift;
- val = val << shift;
-
- err = snd_soc_component_update_bits(component, rreg, val_mask,
- val);
- /* Don't discard any error code or drop change flag */
- if (ret == 0 || err < 0) {
- ret = err;
- }
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
-
-/**
- * snd_soc_get_volsw_range - single mixer get callback with range
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value, within a range, of a single mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int rreg = mc->rreg;
- unsigned int shift = mc->shift;
- int min = mc->min;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- unsigned int val;
-
- val = snd_soc_component_read(component, reg);
- ucontrol->value.integer.value[0] = (val >> shift) & mask;
- if (invert)
- ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
- else
- ucontrol->value.integer.value[0] =
- ucontrol->value.integer.value[0] - min;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- val = snd_soc_component_read(component, rreg);
- ucontrol->value.integer.value[1] = (val >> shift) & mask;
- if (invert)
- ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- else
- ucontrol->value.integer.value[1] =
- ucontrol->value.integer.value[1] - min;
- }
+ ret = kctl->put(kctl, &uctl);
+ if (ret < 0)
+ return ret;
return 0;
}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
/**
* snd_soc_limit_volume - Set new limit to an existing volume control.
@@ -649,8 +432,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
*
* Return 0 for success, else error.
*/
-int snd_soc_limit_volume(struct snd_soc_card *card,
- const char *name, int max)
+int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max)
{
struct snd_kcontrol *kctl;
int ret = -EINVAL;
@@ -661,12 +443,15 @@ int snd_soc_limit_volume(struct snd_soc_card *card,
kctl = snd_soc_card_get_kcontrol(card, name);
if (kctl) {
- struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kctl->private_value;
+
if (max <= mc->max - mc->min) {
mc->platform_max = max;
- ret = 0;
+ ret = snd_soc_clip_to_platform_max(kctl);
}
}
+
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
@@ -726,8 +511,8 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_bytes *params = (void *)kcontrol->private_value;
- int ret, len;
unsigned int val, mask;
+ int ret, len;
if (!component->regmap || !params->num_regs)
return -EINVAL;
@@ -758,15 +543,13 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
break;
case 2:
mask = ~params->mask;
- ret = regmap_parse_val(component->regmap,
- &mask, &mask);
+ ret = regmap_parse_val(component->regmap, &mask, &mask);
if (ret != 0)
return ret;
((u16 *)data)[0] &= mask;
- ret = regmap_parse_val(component->regmap,
- &val, &val);
+ ret = regmap_parse_val(component->regmap, &val, &val);
if (ret != 0)
return ret;
@@ -774,15 +557,13 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
break;
case 4:
mask = ~params->mask;
- ret = regmap_parse_val(component->regmap,
- &mask, &mask);
+ ret = regmap_parse_val(component->regmap, &mask, &mask);
if (ret != 0)
return ret;
((u32 *)data)[0] &= mask;
- ret = regmap_parse_val(component->regmap,
- &val, &val);
+ ret = regmap_parse_val(component->regmap, &val, &val);
if (ret != 0)
return ret;
@@ -798,7 +579,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *ucontrol)
+ struct snd_ctl_elem_info *ucontrol)
{
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
@@ -810,7 +591,7 @@ int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext);
int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag,
- unsigned int size, unsigned int __user *tlv)
+ unsigned int size, unsigned int __user *tlv)
{
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
unsigned int count = size < params->max ? size : params->max;
@@ -826,6 +607,7 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag,
ret = params->put(kcontrol, tlv, count);
break;
}
+
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback);
@@ -835,17 +617,19 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback);
* @kcontrol: mreg control
* @uinfo: control element information
*
- * Callback to provide information of a control that can
- * span multiple codec registers which together
- * forms a single signed value in a MSB/LSB manner.
+ * Callback to provide information of a control that can span multiple
+ * codec registers which together forms a single signed value. Note
+ * that unlike the non-xr variant of sx controls these may or may not
+ * include the sign bit, depending on nbits, and there is no shift.
*
* Returns 0 for success.
*/
int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+ struct snd_ctl_elem_info *uinfo)
{
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
+
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = mc->min;
@@ -860,16 +644,17 @@ EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
* @kcontrol: mreg control
* @ucontrol: control element information
*
- * Callback to get the value of a control that can span
- * multiple codec registers which together forms a single
- * signed value in a MSB/LSB manner. The control supports
- * specifying total no of bits used to allow for bitfields
- * across the multiple codec registers.
+ * Callback to get the value of a control that can span multiple codec
+ * registers which together forms a single signed value. The control
+ * supports specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers. Note that unlike the non-xr
+ * variant of sx controls these may or may not include the sign bit,
+ * depending on nbits, and there is no shift.
*
* Returns 0 for success.
*/
int snd_soc_get_xr_sx(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);
struct soc_mreg_control *mc =
@@ -877,23 +662,21 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
unsigned int regbase = mc->regbase;
unsigned int regcount = mc->regcount;
unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
- unsigned int regwmask = (1UL<<regwshift)-1;
- unsigned int invert = mc->invert;
- unsigned long mask = (1UL<<mc->nbits)-1;
- long min = mc->min;
- long max = mc->max;
+ unsigned int regwmask = GENMASK(regwshift - 1, 0);
+ unsigned long mask = GENMASK(mc->nbits - 1, 0);
long val = 0;
unsigned int i;
for (i = 0; i < regcount; i++) {
- unsigned int regval = snd_soc_component_read(component, regbase+i);
- val |= (regval & regwmask) << (regwshift*(regcount-i-1));
+ unsigned int regval = snd_soc_component_read(component, regbase + i);
+
+ val |= (regval & regwmask) << (regwshift * (regcount - i - 1));
}
val &= mask;
- if (min < 0 && val > max)
+ if (mc->min < 0 && val > mc->max)
val |= ~mask;
- if (invert)
- val = max - val;
+ if (mc->invert)
+ val = mc->max - val;
ucontrol->value.integer.value[0] = val;
return 0;
@@ -905,16 +688,17 @@ EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
* @kcontrol: mreg control
* @ucontrol: control element information
*
- * Callback to set the value of a control that can span
- * multiple codec registers which together forms a single
- * signed value in a MSB/LSB manner. The control supports
- * specifying total no of bits used to allow for bitfields
- * across the multiple codec registers.
+ * Callback to set the value of a control that can span multiple codec
+ * registers which together forms a single signed value. The control
+ * supports specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers. Note that unlike the non-xr
+ * variant of sx controls these may or may not include the sign bit,
+ * depending on nbits, and there is no shift.
*
* Returns 0 for success.
*/
int snd_soc_put_xr_sx(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);
struct soc_mreg_control *mc =
@@ -922,24 +706,25 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
unsigned int regbase = mc->regbase;
unsigned int regcount = mc->regcount;
unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
- unsigned int regwmask = (1UL<<regwshift)-1;
- unsigned int invert = mc->invert;
- unsigned long mask = (1UL<<mc->nbits)-1;
- long max = mc->max;
+ unsigned int regwmask = GENMASK(regwshift - 1, 0);
+ unsigned long mask = GENMASK(mc->nbits - 1, 0);
long val = ucontrol->value.integer.value[0];
int ret = 0;
unsigned int i;
if (val < mc->min || val > mc->max)
return -EINVAL;
- if (invert)
- val = max - val;
+ if (mc->invert)
+ val = mc->max - val;
val &= mask;
for (i = 0; i < regcount; i++) {
- unsigned int regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
- unsigned int regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
- int err = snd_soc_component_update_bits(component, regbase+i,
+ unsigned int regval = (val >> (regwshift * (regcount - i - 1))) &
+ regwmask;
+ unsigned int regmask = (mask >> (regwshift * (regcount - i - 1))) &
+ regwmask;
+ int err = snd_soc_component_update_bits(component, regbase + i,
regmask, regval);
+
if (err < 0)
return err;
if (err > 0)
@@ -960,22 +745,21 @@ EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
* Returns 0 for success.
*/
int snd_soc_get_strobe(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);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int shift = mc->shift;
- unsigned int mask = 1 << shift;
unsigned int invert = mc->invert != 0;
+ unsigned int mask = BIT(mc->shift);
unsigned int val;
- val = snd_soc_component_read(component, reg);
+ val = snd_soc_component_read(component, mc->reg);
val &= mask;
- if (shift != 0 && val != 0)
- val = val >> shift;
+ if (mc->shift != 0 && val != 0)
+ val = val >> mc->shift;
+
ucontrol->value.enumerated.item[0] = val ^ invert;
return 0;
@@ -993,24 +777,22 @@ EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
* Returns 1 for success.
*/
int snd_soc_put_strobe(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);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int shift = mc->shift;
- unsigned int mask = 1 << shift;
- unsigned int invert = mc->invert != 0;
unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
+ unsigned int invert = mc->invert != 0;
+ unsigned int mask = BIT(mc->shift);
unsigned int val1 = (strobe ^ invert) ? mask : 0;
unsigned int val2 = (strobe ^ invert) ? 0 : mask;
- int err;
+ int ret;
- err = snd_soc_component_update_bits(component, reg, mask, val1);
- if (err < 0)
- return err;
+ ret = snd_soc_component_update_bits(component, mc->reg, mask, val1);
+ if (ret < 0)
+ return ret;
- return snd_soc_component_update_bits(component, reg, mask, val2);
+ return snd_soc_component_update_bits(component, mc->reg, mask, val2);
}
EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 1150455619aa..4308a6cbb2e6 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -30,28 +30,13 @@
static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd,
const char *func, int ret)
{
- /* Positive, Zero values are not errors */
- if (ret >= 0)
- return ret;
-
- /* Negative values might be errors */
- switch (ret) {
- case -EPROBE_DEFER:
- case -ENOTSUPP:
- case -EINVAL:
- break;
- default:
- dev_err(rtd->dev,
- "ASoC: error at %s on %s: %d\n",
- func, rtd->dai_link->name, ret);
- }
-
- return ret;
+ return snd_soc_ret(rtd->dev, ret,
+ "at %s() on %s\n", func, rtd->dai_link->name);
}
/* is the current PCM operation for this FE ? */
#if 0
-static int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
+static int snd_soc_dpcm_can_fe_update(struct snd_soc_pcm_runtime *fe, int stream)
{
if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
return 1;
@@ -60,7 +45,7 @@ static int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream
#endif
/* is the current PCM operation for this BE ? */
-static int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+static int snd_soc_dpcm_can_be_update(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream)
{
if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
@@ -159,7 +144,6 @@ static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd)
return (rtd)->dai_link->num_codecs == 1 ? snd_soc_rtd_to_codec(rtd, 0)->name : "multicodec";
}
-#ifdef CONFIG_DEBUG_FS
static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
{
switch (state) {
@@ -188,6 +172,7 @@ static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
return "unknown";
}
+#ifdef CONFIG_DEBUG_FS
static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
int stream, char *buf, size_t size)
{
@@ -253,11 +238,9 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
int stream;
char *buf;
- if (fe->dai_link->num_cpus > 1) {
- dev_err(fe->dev,
+ if (fe->dai_link->num_cpus > 1)
+ return snd_soc_ret(fe->dev, -EINVAL,
"%s doesn't support Multi CPU yet\n", __func__);
- return -EINVAL;
- }
buf = kmalloc(out_count, GFP_KERNEL);
if (!buf)
@@ -417,8 +400,7 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
}
/* DPCM stream event, send event to FE and all active BEs. */
-int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
- int event)
+void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event)
{
struct snd_soc_dpcm *dpcm;
@@ -439,8 +421,6 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
}
snd_soc_dapm_stream_event(fe, dir, event);
-
- return 0;
}
static void soc_pcm_set_dai_params(struct snd_soc_dai *dai,
@@ -475,12 +455,9 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
ret = snd_pcm_hw_constraint_single(substream->runtime, \
SNDRV_PCM_HW_PARAM_##NAME,\
soc_dai->symmetric_##name); \
- if (ret < 0) { \
- dev_err(soc_dai->dev, \
- "ASoC: Unable to apply %s constraint: %d\n",\
- #name, ret); \
- return ret; \
- } \
+ if (ret < 0) \
+ return snd_soc_ret(soc_dai->dev, ret, \
+ "Unable to apply %s constraint\n", #name); \
}
__soc_pcm_apply_symmetry(rate, RATE);
@@ -511,12 +488,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
for_each_rtd_cpu_dais(rtd, i, cpu_dai) \
if (!snd_soc_dai_is_dummy(cpu_dai) && \
cpu_dai->symmetric_##xxx && \
- cpu_dai->symmetric_##xxx != d.symmetric_##xxx) { \
- dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \
- #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \
- d.name, d.symmetric_##xxx); \
- return -EINVAL; \
- }
+ cpu_dai->symmetric_##xxx != d.symmetric_##xxx) \
+ return snd_soc_ret(rtd->dev, -EINVAL, \
+ "unmatched %s symmetry: %s:%d - %s:%d\n", \
+ #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \
+ d.name, d.symmetric_##xxx);
/* reject unmatched parameters when applying symmetry */
__soc_pcm_params_symmetry(rate);
@@ -627,13 +603,8 @@ static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw,
static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw,
const struct snd_soc_pcm_stream *p)
{
- hw->formats &= p->formats;
-}
-
-static void soc_pcm_hw_update_subformat(struct snd_pcm_hardware *hw,
- const struct snd_soc_pcm_stream *p)
-{
- hw->subformats &= p->subformats;
+ hw->formats &= p->formats;
+ hw->subformats &= p->subformats;
}
/**
@@ -674,7 +645,6 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
soc_pcm_hw_update_chan(hw, cpu_stream);
soc_pcm_hw_update_rate(hw, cpu_stream);
soc_pcm_hw_update_format(hw, cpu_stream);
- soc_pcm_hw_update_subformat(hw, cpu_stream);
}
cpu_chan_min = hw->channels_min;
cpu_chan_max = hw->channels_max;
@@ -696,7 +666,6 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
soc_pcm_hw_update_chan(hw, codec_stream);
soc_pcm_hw_update_rate(hw, codec_stream);
soc_pcm_hw_update_format(hw, codec_stream);
- soc_pcm_hw_update_subformat(hw, codec_stream);
}
/* Verify both a valid CPU DAI and a valid CODEC DAI were found */
@@ -861,9 +830,8 @@ static int soc_hw_sanity_check(struct snd_pcm_substream *substream)
return 0;
config_err:
- dev_err(dev, "ASoC: %s <-> %s No matching %s\n",
- name_codec, name_cpu, err_msg);
- return -EINVAL;
+ return snd_soc_ret(dev, -EINVAL,
+ "%s <-> %s No matching %s\n", name_codec, name_cpu, err_msg);
}
/*
@@ -981,12 +949,18 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd,
SND_SOC_DAPM_STREAM_START);
for_each_rtd_dais(rtd, i, dai) {
- if (dai->driver->ops && !dai->driver->ops->mute_unmute_on_trigger)
+ if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai))
snd_soc_dai_digital_mute(dai, 0, substream->stream);
}
out:
- return soc_pcm_ret(rtd, ret);
+ /*
+ * Don't use soc_pcm_ret() on .prepare callback to lower error log severity
+ *
+ * We don't want to log an error since we do not want to give userspace a way to do a
+ * denial-of-service attack on the syslog / diskspace.
+ */
+ return ret;
}
/* PCM prepare ops for non-DPCM streams */
@@ -998,6 +972,13 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
snd_soc_dpcm_mutex_lock(rtd);
ret = __soc_pcm_prepare(rtd, substream);
snd_soc_dpcm_mutex_unlock(rtd);
+
+ /*
+ * Don't use soc_pcm_ret() on .prepare callback to lower error log severity
+ *
+ * We don't want to log an error since we do not want to give userspace a way to do a
+ * denial-of-service attack on the syslog / diskspace.
+ */
return ret;
}
@@ -1026,7 +1007,7 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
soc_pcm_set_dai_params(dai, NULL);
if (snd_soc_dai_stream_active(dai, substream->stream) == 1) {
- if (dai->driver->ops && !dai->driver->ops->mute_unmute_on_trigger)
+ if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai))
snd_soc_dai_digital_mute(dai, 1, substream->stream);
}
}
@@ -1074,10 +1055,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
* function can also be called multiple times and can allocate buffers
* (using snd_pcm_lib_* ). It's non-atomic.
*/
-static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd,
- struct snd_pcm_substream *substream,
+static int __soc_pcm_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 *cpu_dai;
struct snd_soc_dai *codec_dai;
struct snd_pcm_hw_params tmp_params;
@@ -1183,7 +1164,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
int ret;
snd_soc_dpcm_mutex_lock(rtd);
- ret = __soc_pcm_hw_params(rtd, substream, params);
+ ret = __soc_pcm_hw_params(substream, params);
snd_soc_dpcm_mutex_unlock(rtd);
return ret;
}
@@ -1313,19 +1294,18 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
snd_soc_dpcm_mutex_assert_held(fe);
/* only add new dpcms */
- for_each_dpcm_be(fe, stream, dpcm) {
- if (dpcm->be == be && dpcm->fe == fe)
+ for_each_dpcm_be(fe, stream, dpcm)
+ if (dpcm->be == be)
return 0;
- }
fe_substream = snd_soc_dpcm_get_substream(fe, stream);
be_substream = snd_soc_dpcm_get_substream(be, stream);
- if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic) {
- dev_err(be->dev, "%s: FE is atomic but BE is nonatomic, invalid configuration\n",
- __func__);
- return -EINVAL;
- }
+ if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic)
+ return snd_soc_ret(be->dev, -EINVAL,
+ "%s: %s is atomic but %s is nonatomic, invalid configuration\n",
+ __func__, fe->dai_link->name, be->dai_link->name);
+
if (fe_substream->pcm->nonatomic && !be_substream->pcm->nonatomic) {
dev_dbg(be->dev, "FE is nonatomic but BE is not, forcing BE as nonatomic\n");
be_substream->pcm->nonatomic = 1;
@@ -1495,11 +1475,9 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0);
int paths;
- if (fe->dai_link->num_cpus > 1) {
- dev_err(fe->dev,
+ if (fe->dai_link->num_cpus > 1)
+ return snd_soc_ret(fe->dev, -EINVAL,
"%s doesn't support Multi CPU yet\n", __func__);
- return -EINVAL;
- }
/* get number of valid DAI paths and their widgets */
paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
@@ -1565,8 +1543,8 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
return prune;
}
-static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
- struct snd_soc_dapm_widget_list **list_)
+int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
+ struct snd_soc_dapm_widget_list **list_)
{
struct snd_soc_card *card = fe->card;
struct snd_soc_dapm_widget_list *list = *list_;
@@ -1631,19 +1609,6 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
return new;
}
-/*
- * Find the corresponding BE DAIs that source or sink audio to this
- * FE substream.
- */
-int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
- int stream, struct snd_soc_dapm_widget_list **list, int new)
-{
- if (new)
- return dpcm_add_paths(fe, stream, list);
- else
- return dpcm_prune_paths(fe, stream, list);
-}
-
void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
@@ -1667,13 +1632,13 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
return;
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
if (be->dpcm[stream].users == 0) {
- dev_err(be->dev, "ASoC: no users %s at close - state %d\n",
+ dev_err(be->dev, "ASoC: no users %s at close - state %s\n",
snd_pcm_direction_name(stream),
- be->dpcm[stream].state);
+ dpcm_state_string(be->dpcm[stream].state));
continue;
}
@@ -1717,14 +1682,14 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
}
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
/* first time the dpcm is open ? */
if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) {
- dev_err(be->dev, "ASoC: too many users %s at open %d\n",
+ dev_err(be->dev, "ASoC: too many users %s at open %s\n",
snd_pcm_direction_name(stream),
- be->dpcm[stream].state);
+ dpcm_state_string(be->dpcm[stream].state));
continue;
}
@@ -1743,9 +1708,9 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
if (err < 0) {
be->dpcm[stream].users--;
if (be->dpcm[stream].users < 0)
- dev_err(be->dev, "ASoC: no users %s at unwind %d\n",
+ dev_err(be->dev, "ASoC: no users %s at unwind %s\n",
snd_pcm_direction_name(stream),
- be->dpcm[stream].state);
+ dpcm_state_string(be->dpcm[stream].state));
be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
goto unwind;
@@ -1793,7 +1758,6 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream)
soc_pcm_hw_update_rate(hw, cpu_stream);
soc_pcm_hw_update_chan(hw, cpu_stream);
soc_pcm_hw_update_format(hw, cpu_stream);
- soc_pcm_hw_update_subformat(hw, cpu_stream);
}
}
@@ -1831,7 +1795,6 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream)
codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
soc_pcm_hw_update_format(hw, codec_stream);
- soc_pcm_hw_update_subformat(hw, codec_stream);
}
}
}
@@ -2044,7 +2007,7 @@ void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
snd_soc_dpcm_get_substream(be, stream);
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
/* only free hw when no longer used - check all FEs */
@@ -2110,7 +2073,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
be_substream = snd_soc_dpcm_get_substream(be, stream);
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
/* copy params for each dpcm */
@@ -2138,7 +2101,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
dev_dbg(be->dev, "ASoC: hw_params BE %s\n",
be->dai_link->name);
- ret = __soc_pcm_hw_params(be, be_substream, &hw_params);
+ ret = __soc_pcm_hw_params(be_substream, &hw_params);
if (ret < 0)
goto unwind;
@@ -2155,7 +2118,7 @@ unwind:
be = dpcm->be;
be_substream = snd_soc_dpcm_get_substream(be, stream);
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
/* only allow hw_free() if no connected FEs are running */
@@ -2194,7 +2157,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
params_channels(params), params_format(params));
/* call hw_params on the frontend */
- ret = __soc_pcm_hw_params(fe, substream, params);
+ ret = __soc_pcm_hw_params(substream, params);
if (ret < 0)
dpcm_be_dai_hw_free(fe, stream);
else
@@ -2225,7 +2188,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
snd_pcm_stream_lock_irqsave_nested(be_substream, flags);
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
goto next;
dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n",
@@ -2390,23 +2353,23 @@ static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
ret = soc_pcm_trigger(substream, cmd);
if (ret < 0)
- return ret;
+ goto end;
ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
- return ret;
}
-
/* call trigger on the frontend after the backend. */
- ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
- if (ret < 0)
- return ret;
-
- dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
- fe->dai_link->name, cmd);
+ else {
+ ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+ if (ret < 0)
+ goto end;
- ret = soc_pcm_trigger(substream, cmd);
+ dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
+ fe->dai_link->name, cmd);
- return ret;
+ ret = soc_pcm_trigger(substream, cmd);
+ }
+end:
+ return snd_soc_ret(fe->dev, ret, "trigger FE cmd: %d failed\n", cmd);
}
static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -2414,46 +2377,17 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
int stream = substream->stream;
int ret = 0;
+ int fe_first;
enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
switch (trigger) {
case SND_SOC_DPCM_TRIGGER_PRE:
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_DRAIN:
- ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
- break;
- default:
- ret = -EINVAL;
- break;
- }
+ fe_first = true;
break;
case SND_SOC_DPCM_TRIGGER_POST:
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_DRAIN:
- ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
- break;
- default:
- ret = -EINVAL;
- break;
- }
+ fe_first = false;
break;
default:
dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
@@ -2462,12 +2396,26 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
goto out;
}
- if (ret < 0) {
- dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n",
- cmd, ret);
- goto out;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_DRAIN:
+ ret = dpcm_dai_trigger_fe_be(substream, cmd, fe_first);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = dpcm_dai_trigger_fe_be(substream, cmd, !fe_first);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
+ if (ret < 0)
+ goto out;
+
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
@@ -2517,7 +2465,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
snd_soc_dpcm_get_substream(be, stream);
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
if (!snd_soc_dpcm_can_be_prepared(fe, be, stream))
@@ -2539,7 +2487,13 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
}
- return soc_pcm_ret(fe, ret);
+ /*
+ * Don't use soc_pcm_ret() on .prepare callback to lower error log severity
+ *
+ * We don't want to log an error since we do not want to give userspace a way to do a
+ * denial-of-service attack on the syslog / diskspace.
+ */
+ return ret;
}
static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
@@ -2579,7 +2533,13 @@ out:
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
snd_soc_dpcm_mutex_unlock(fe);
- return soc_pcm_ret(fe, ret);
+ /*
+ * Don't use soc_pcm_ret() on .prepare callback to lower error log severity
+ *
+ * We don't want to log an error since we do not want to give userspace a way to do a
+ * denial-of-service attack on the syslog / diskspace.
+ */
+ return ret;
}
static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
@@ -2612,8 +2572,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
/* Only start the BE if the FE is ready */
if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) {
- dev_err(fe->dev, "ASoC: FE %s is not ready %d\n",
- fe->dai_link->name, fe->dpcm[stream].state);
+ dev_err(fe->dev, "ASoC: FE %s is not ready %s\n",
+ fe->dai_link->name, dpcm_state_string(fe->dpcm[stream].state));
ret = -EINVAL;
goto disconnect;
}
@@ -2663,7 +2623,7 @@ disconnect:
struct snd_soc_pcm_runtime *be = dpcm->be;
/* is this op for this BE ? */
- if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE ||
@@ -2683,11 +2643,9 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
if (!fe->dai_link->dynamic)
return 0;
- if (fe->dai_link->num_cpus > 1) {
- dev_err(fe->dev,
+ if (fe->dai_link->num_cpus > 1)
+ return snd_soc_ret(fe->dev, -EINVAL,
"%s doesn't support Multi CPU yet\n", __func__);
- return -EINVAL;
- }
/* only check active links */
if (!snd_soc_dai_active(snd_soc_rtd_to_cpu(fe, 0)))
@@ -2714,7 +2672,14 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
return paths;
/* update any playback/capture paths */
- count = dpcm_process_paths(fe, stream, &list, new);
+ /*
+ * Find the corresponding BE DAIs that source or sink audio to this
+ * FE substream.
+ */
+ if (new)
+ count = dpcm_add_paths(fe, stream, &list);
+ else
+ count = dpcm_prune_paths(fe, stream, &list);
if (count) {
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
if (new)
@@ -2758,7 +2723,8 @@ int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
out:
snd_soc_dpcm_mutex_unlock(card);
- return ret;
+
+ return snd_soc_ret(card->dev, ret, "%s() failed\n", __func__);
}
EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
@@ -2805,7 +2771,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
goto open_end;
/* calculate valid and active FE <-> BE dpcms */
- dpcm_process_paths(fe, stream, &list, 1);
+ dpcm_add_paths(fe, stream, &list);
ret = dpcm_fe_dai_startup(fe_substream);
if (ret < 0)
@@ -2832,10 +2798,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
int has_capture = 0;
int i;
- if (dai_link->dynamic && dai_link->num_cpus > 1) {
- dev_err(rtd->dev, "DPCM doesn't support Multi CPU for Front-Ends yet\n");
- return -EINVAL;
- }
+ if (dai_link->dynamic && dai_link->num_cpus > 1)
+ return snd_soc_ret(rtd->dev, -EINVAL,
+ "DPCM doesn't support Multi CPU for Front-Ends yet\n");
/* Adapt stream for codec2codec links */
cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE);
@@ -2877,12 +2842,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
if (dai_link->capture_only)
has_playback = 0;
- if (!has_playback && !has_capture) {
- dev_err(rtd->dev, "substream %s has no playback, no capture\n",
- dai_link->stream_name);
-
- return -EINVAL;
- }
+ if (!has_playback && !has_capture)
+ return snd_soc_ret(rtd->dev, -EINVAL,
+ "substream %s has no playback, no capture\n", dai_link->stream_name);
*playback = has_playback;
*capture = has_capture;
@@ -2922,11 +2884,10 @@ static int soc_create_pcm(struct snd_pcm **pcm,
ret = snd_pcm_new(rtd->card->snd_card, new_name, rtd->id, playback,
capture, pcm);
}
- if (ret < 0) {
- dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n",
- new_name, rtd->dai_link->name, ret);
- return ret;
- }
+ if (ret < 0)
+ return snd_soc_ret(rtd->dev, ret,
+ "can't create pcm %s for dailink %s\n", new_name, rtd->dai_link->name);
+
dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n", rtd->id, new_name);
return 0;
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 43003d2d3666..7b0b8531bb32 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -131,8 +131,8 @@ static const struct snd_soc_tplg_kcontrol_ops io_ops[] = {
snd_soc_put_enum_double, NULL},
{SND_SOC_TPLG_CTL_BYTES, snd_soc_bytes_get,
snd_soc_bytes_put, snd_soc_bytes_info},
- {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw_range,
- snd_soc_put_volsw_range, snd_soc_info_volsw_range},
+ {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw,
+ snd_soc_put_volsw, snd_soc_info_volsw},
{SND_SOC_TPLG_CTL_VOLSW_XR_SX, snd_soc_get_xr_sx,
snd_soc_put_xr_sx, snd_soc_info_xr_sx},
{SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe,
@@ -220,15 +220,6 @@ static int get_widget_id(int tplg_type)
return -EINVAL;
}
-static inline void soc_bind_err(struct soc_tplg *tplg,
- struct snd_soc_tplg_ctl_hdr *hdr, int index)
-{
- dev_err(tplg->dev,
- "ASoC: invalid control type (g,p,i) %d:%d:%d index %d at 0x%lx\n",
- hdr->ops.get, hdr->ops.put, hdr->ops.info, index,
- soc_tplg_get_offset(tplg));
-}
-
static inline void soc_control_err(struct soc_tplg *tplg,
struct snd_soc_tplg_ctl_hdr *hdr, const char *name)
{
@@ -678,6 +669,7 @@ static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcon
sm->min = le32_to_cpu(mc->min);
sm->invert = le32_to_cpu(mc->invert);
sm->platform_max = le32_to_cpu(mc->platform_max);
+ sm->num_channels = le32_to_cpu(mc->num_channels);
/* map io handlers */
err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg);
@@ -992,35 +984,26 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
return -EINVAL;
}
- switch (le32_to_cpu(control_hdr->ops.info)) {
- case SND_SOC_TPLG_CTL_VOLSW:
- case SND_SOC_TPLG_CTL_STROBE:
- case SND_SOC_TPLG_CTL_VOLSW_SX:
- case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
- case SND_SOC_TPLG_CTL_RANGE:
- case SND_SOC_TPLG_DAPM_CTL_VOLSW:
- case SND_SOC_TPLG_DAPM_CTL_PIN:
+ switch (le32_to_cpu(control_hdr->type)) {
+ case SND_SOC_TPLG_TYPE_MIXER:
ret = soc_tplg_dmixer_create(tplg, le32_to_cpu(hdr->payload_size));
break;
- case SND_SOC_TPLG_CTL_ENUM:
- case SND_SOC_TPLG_CTL_ENUM_VALUE:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+ case SND_SOC_TPLG_TYPE_ENUM:
ret = soc_tplg_denum_create(tplg, le32_to_cpu(hdr->payload_size));
break;
- case SND_SOC_TPLG_CTL_BYTES:
+ case SND_SOC_TPLG_TYPE_BYTES:
ret = soc_tplg_dbytes_create(tplg, le32_to_cpu(hdr->payload_size));
break;
default:
- soc_bind_err(tplg, control_hdr, i);
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
+
if (ret < 0) {
- dev_err(tplg->dev, "ASoC: invalid control\n");
+ dev_err(tplg->dev, "ASoC: invalid control type: %d, index: %d at 0x%lx\n",
+ control_hdr->type, i, soc_tplg_get_offset(tplg));
return ret;
}
-
}
return 0;
@@ -1101,14 +1084,8 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
}
ret = snd_soc_dapm_add_routes(dapm, route, 1);
- if (ret) {
- if (!dapm->card->disable_route_checks) {
- dev_err(tplg->dev, "ASoC: dapm_add_routes failed: %d\n", ret);
- break;
- }
- dev_info(tplg->dev,
- "ASoC: disable_route_checks set, ignoring dapm_add_routes errors\n");
- }
+ if (ret)
+ break;
}
return ret;
@@ -1190,13 +1167,9 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
for (i = 0; i < le32_to_cpu(w->num_kcontrols); i++) {
control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
- switch (le32_to_cpu(control_hdr->ops.info)) {
- case SND_SOC_TPLG_CTL_VOLSW:
- case SND_SOC_TPLG_CTL_STROBE:
- case SND_SOC_TPLG_CTL_VOLSW_SX:
- case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
- case SND_SOC_TPLG_CTL_RANGE:
- case SND_SOC_TPLG_DAPM_CTL_VOLSW:
+
+ switch (le32_to_cpu(control_hdr->type)) {
+ case SND_SOC_TPLG_TYPE_MIXER:
/* volume mixer */
kc[i].index = mixer_count;
kcontrol_type[i] = SND_SOC_TPLG_TYPE_MIXER;
@@ -1205,11 +1178,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
if (ret < 0)
goto hdr_err;
break;
- case SND_SOC_TPLG_CTL_ENUM:
- case SND_SOC_TPLG_CTL_ENUM_VALUE:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
- case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
+ case SND_SOC_TPLG_TYPE_ENUM:
/* enumerated mixer */
kc[i].index = enum_count;
kcontrol_type[i] = SND_SOC_TPLG_TYPE_ENUM;
@@ -1218,7 +1187,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
if (ret < 0)
goto hdr_err;
break;
- case SND_SOC_TPLG_CTL_BYTES:
+ case SND_SOC_TPLG_TYPE_BYTES:
/* bytes control */
kc[i].index = bytes_count;
kcontrol_type[i] = SND_SOC_TPLG_TYPE_BYTES;
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index aa93e77ac937..5e3e4f14c392 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -7,7 +7,7 @@
// Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
// Liam Girdwood <lrg@slimlogic.co.uk>
-#include <linux/platform_device.h>
+#include <linux/device/faux.h>
#include <linux/export.h>
#include <linux/math.h>
#include <sound/core.h>
@@ -15,6 +15,33 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
+int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ /* Positive, Zero values are not errors */
+ if (ret >= 0)
+ return ret;
+
+ /* Negative values might be errors */
+ switch (ret) {
+ case -EPROBE_DEFER:
+ case -ENOTSUPP:
+ case -EOPNOTSUPP:
+ break;
+ default:
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ dev_err(dev, "ASoC error (%d): %pV", ret, &vaf);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_ret);
+
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots)
{
return sample_size * channels * tdm_slots;
@@ -235,48 +262,38 @@ struct snd_soc_dai_link_component snd_soc_dummy_dlc = {
};
EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc);
-static int snd_soc_dummy_probe(struct platform_device *pdev)
+static int snd_soc_dummy_probe(struct faux_device *fdev)
{
int ret;
- ret = devm_snd_soc_register_component(&pdev->dev,
+ ret = devm_snd_soc_register_component(&fdev->dev,
&dummy_codec, &dummy_dai, 1);
if (ret < 0)
return ret;
- ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform,
+ ret = devm_snd_soc_register_component(&fdev->dev, &dummy_platform,
NULL, 0);
return ret;
}
-static struct platform_driver soc_dummy_driver = {
- .driver = {
- .name = "snd-soc-dummy",
- },
+static struct faux_device_ops soc_dummy_ops = {
.probe = snd_soc_dummy_probe,
};
-static struct platform_device *soc_dummy_dev;
+static struct faux_device *soc_dummy_dev;
int __init snd_soc_util_init(void)
{
- int ret;
-
- soc_dummy_dev =
- platform_device_register_simple("snd-soc-dummy", -1, NULL, 0);
- if (IS_ERR(soc_dummy_dev))
- return PTR_ERR(soc_dummy_dev);
+ soc_dummy_dev = faux_device_create("snd-soc-dummy", NULL,
+ &soc_dummy_ops);
+ if (!soc_dummy_dev)
+ return -ENODEV;
- ret = platform_driver_register(&soc_dummy_driver);
- if (ret != 0)
- platform_device_unregister(soc_dummy_dev);
-
- return ret;
+ return 0;
}
void snd_soc_util_exit(void)
{
- platform_driver_unregister(&soc_dummy_driver);
- platform_device_unregister(soc_dummy_dev);
+ faux_device_destroy(soc_dummy_dev);
}
diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig
index f4cafe801017..3ea82fa72e35 100644
--- a/sound/soc/sof/amd/Kconfig
+++ b/sound/soc/sof/amd/Kconfig
@@ -32,6 +32,7 @@ config SND_SOC_SOF_AMD_COMMON
config SND_SOC_SOF_AMD_RENOIR
tristate "SOF support for RENOIR"
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 Renoir platform
@@ -39,6 +40,7 @@ config SND_SOC_SOF_AMD_RENOIR
config SND_SOC_SOF_AMD_VANGOGH
tristate "SOF support for VANGOGH"
depends on SND_SOC_SOF_PCI
+ depends on AMD_NODE
select SND_SOC_SOF_AMD_COMMON
help
Select this option for SOF support
@@ -49,6 +51,7 @@ config SND_SOC_SOF_AMD_VANGOGH
config SND_SOC_SOF_AMD_REMBRANDT
tristate "SOF support for REMBRANDT"
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 Rembrandt platform
@@ -81,6 +84,7 @@ config SND_SOC_SOF_AMD_SOUNDWIRE
config SND_SOC_SOF_AMD_ACP63
tristate "SOF support for ACP6.3 platform"
depends on SND_SOC_SOF_PCI
+ depends on AMD_NODE
select SND_SOC_SOF_AMD_COMMON
select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE
help
@@ -92,6 +96,7 @@ config SND_SOC_SOF_AMD_ACP63
config SND_SOC_SOF_AMD_ACP70
tristate "SOF support for ACP7.0 platform"
depends on SND_SOC_SOF_PCI
+ depends on AMD_NODE
select SND_SOC_SOF_AMD_COMMON
help
Select this option for SOF support on
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index 5f371d9263f3..22d4b807e1bb 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -165,8 +165,9 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
int dsp_msg, dsp_ack;
unsigned int status;
- if (sdev->first_boot && sdev->fw_state != SOF_FW_BOOT_COMPLETE) {
+ if (unlikely(sdev->first_boot && sdev->fw_state != SOF_FW_BOOT_COMPLETE)) {
acp_mailbox_read(sdev, sdev->dsp_box.offset, &status, sizeof(status));
+
if ((status & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
snd_sof_dsp_panic(sdev, sdev->dsp_box.offset + sizeof(status),
true);
@@ -188,13 +189,21 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
if (dsp_ack) {
- spin_lock_irq(&sdev->ipc_lock);
- /* handle immediate reply from DSP core */
- acp_dsp_ipc_get_reply(sdev);
- snd_sof_ipc_reply(sdev, 0);
- /* set the done bit */
- acp_dsp_ipc_dsp_done(sdev);
- spin_unlock_irq(&sdev->ipc_lock);
+ if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) {
+ spin_lock_irq(&sdev->ipc_lock);
+
+ /* handle immediate reply from DSP core */
+ acp_dsp_ipc_get_reply(sdev);
+ snd_sof_ipc_reply(sdev, 0);
+ /* set the done bit */
+ acp_dsp_ipc_dsp_done(sdev);
+
+ spin_unlock_irq(&sdev->ipc_lock);
+ } else {
+ dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_BOOT_COMPLETE: %#x\n",
+ dsp_ack);
+ }
+
ipc_irq = true;
}
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 33648ff8b833..7c6d647fa253 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -16,6 +16,8 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <asm/amd_node.h>
+
#include "../ops.h"
#include "acp.h"
#include "acp-dsp-offset.h"
@@ -27,6 +29,7 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
static struct acp_quirk_entry quirk_valve_galileo = {
.signed_fw_image = true,
.skip_iram_dram_size_mod = true,
+ .post_fw_run_delay = true,
};
const struct dmi_system_id acp_sof_quirk_table[] = {
@@ -42,24 +45,6 @@ const struct dmi_system_id acp_sof_quirk_table[] = {
};
EXPORT_SYMBOL_GPL(acp_sof_quirk_table);
-static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data)
-{
- pci_write_config_dword(dev, 0x60, smn_addr);
- pci_write_config_dword(dev, 0x64, data);
-
- return 0;
-}
-
-static int smn_read(struct pci_dev *dev, u32 smn_addr)
-{
- u32 data = 0;
-
- pci_write_config_dword(dev, 0x60, smn_addr);
- pci_read_config_dword(dev, 0x64, &data);
-
- return data;
-}
-
static void init_dma_descriptor(struct acp_dev_data *adata)
{
struct snd_sof_dev *sdev = adata->dev;
@@ -208,11 +193,11 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr,
static int psp_mbox_ready(struct acp_dev_data *adata, bool ack)
{
struct snd_sof_dev *sdev = adata->dev;
- int ret;
- u32 data;
+ int ret, data;
+
+ ret = read_poll_timeout(smn_read_register, data, data > 0 && data & MBOX_READY_MASK,
+ MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_114_REG);
- ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US,
- ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG);
if (!ret)
return 0;
@@ -240,8 +225,8 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
return -EINVAL;
/* Get a non-zero Doorbell value from PSP */
- ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false,
- adata->smn_dev, MP0_C2PMSG_73_REG);
+ ret = read_poll_timeout(smn_read_register, data, data > 0, MBOX_DELAY_US,
+ ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_73_REG);
if (ret) {
dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG);
@@ -253,10 +238,14 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd)
if (ret)
return ret;
- smn_write(adata->smn_dev, MP0_C2PMSG_114_REG, cmd);
+ ret = amd_smn_write(0, MP0_C2PMSG_114_REG, cmd);
+ if (ret)
+ return ret;
/* Ring the Doorbell for PSP */
- smn_write(adata->smn_dev, MP0_C2PMSG_73_REG, data);
+ ret = amd_smn_write(0, MP0_C2PMSG_73_REG, data);
+ if (ret)
+ return ret;
/* Check MBOX ready as PSP ack */
ret = psp_mbox_ready(adata, 1);
@@ -770,16 +759,10 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
adata->pci_rev = pci->revision;
mutex_init(&adata->acp_lock);
sdev->pdata->hw_pdata = adata;
- adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL);
- if (!adata->smn_dev) {
- dev_err(sdev->dev, "Failed to get host bridge device\n");
- ret = -ENODEV;
- goto unregister_dev;
- }
ret = acp_init(sdev);
if (ret < 0)
- goto free_smn_dev;
+ goto unregister_dev;
sdev->ipc_irq = pci->irq;
ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread,
@@ -787,7 +770,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
if (ret < 0) {
dev_err(sdev->dev, "failed to register IRQ %d\n",
sdev->ipc_irq);
- goto free_smn_dev;
+ goto unregister_dev;
}
/* scan SoundWire capabilities exposed by DSDT */
@@ -800,7 +783,6 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
if (ret < 0) {
dev_err(sdev->dev, "error: SoundWire probe error\n");
free_irq(sdev->ipc_irq, sdev);
- pci_dev_put(adata->smn_dev);
return ret;
}
@@ -846,8 +828,6 @@ skip_soundwire:
free_ipc_irq:
free_irq(sdev->ipc_irq, sdev);
-free_smn_dev:
- pci_dev_put(adata->smn_dev);
unregister_dev:
platform_device_unregister(adata->dmic_dev);
return ret;
@@ -858,9 +838,6 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev)
{
struct acp_dev_data *adata = sdev->pdata->hw_pdata;
- if (adata->smn_dev)
- pci_dev_put(adata->smn_dev);
-
if (adata->sdw)
amd_sof_sdw_exit(sdev);
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index 800594440f73..d084db34eed8 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -197,7 +197,6 @@ struct acp_dsp_stream {
struct sof_amd_acp_desc {
const char *name;
- unsigned int host_bridge_id;
u32 pgfsm_base;
u32 ext_intr_enb;
u32 ext_intr_cntl;
@@ -220,6 +219,7 @@ struct sof_amd_acp_desc {
struct acp_quirk_entry {
bool signed_fw_image;
bool skip_iram_dram_size_mod;
+ bool post_fw_run_delay;
};
/* Common device data struct for ACP devices */
@@ -255,7 +255,6 @@ struct acp_dev_data {
struct dma_descriptor dscr_info[ACP_MAX_DESC];
struct acp_dsp_stream stream_buf[ACP_MAX_STREAM];
struct acp_dsp_stream *dtrace_stream;
- struct pci_dev *smn_dev;
struct acp_dsp_stream *probe_stream;
bool enable_fw_debug;
bool is_dram_in_use;
diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c
index ffe7c755d655..21ffdfdcf03d 100644
--- a/sound/soc/sof/amd/pci-acp63.c
+++ b/sound/soc/sof/amd/pci-acp63.c
@@ -28,7 +28,6 @@
#define ACP6x_REG_END 0x125C000
static const struct sof_amd_acp_desc acp63_chip_info = {
- .host_bridge_id = HOST_BRIDGE_ACP63,
.pgfsm_base = ACP6X_PGFSM_BASE,
.ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB,
.ext_intr_cntl = ACP6X_EXTERNAL_INTR_CNTL,
@@ -105,7 +104,7 @@ static struct pci_driver snd_sof_pci_amd_acp63_driver = {
.probe = acp63_pci_probe,
.remove = acp63_pci_remove,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_amd_acp63_driver);
diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c
index 3647ec992e95..8fa1170a2161 100644
--- a/sound/soc/sof/amd/pci-acp70.c
+++ b/sound/soc/sof/amd/pci-acp70.c
@@ -28,7 +28,6 @@
#define ACP70_REG_END 0x125C000
static const struct sof_amd_acp_desc acp70_chip_info = {
- .host_bridge_id = HOST_BRIDGE_ACP70,
.pgfsm_base = ACP70_PGFSM_BASE,
.ext_intr_enb = ACP70_EXTERNAL_INTR_ENB,
.ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL,
@@ -101,7 +100,7 @@ static struct pci_driver snd_sof_pci_amd_acp70_driver = {
.probe = acp70_pci_probe,
.remove = acp70_pci_remove,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_amd_acp70_driver);
diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c
index cbb4d5282664..0233b6ba2d2e 100644
--- a/sound/soc/sof/amd/pci-rmb.c
+++ b/sound/soc/sof/amd/pci-rmb.c
@@ -28,7 +28,6 @@
#define ACP6X_FUTURE_REG_ACLK_0 0x1854
static const struct sof_amd_acp_desc rembrandt_chip_info = {
- .host_bridge_id = HOST_BRIDGE_RMB,
.pgfsm_base = ACP6X_PGFSM_BASE,
.ext_intr_stat = ACP6X_EXT_INTR_STAT,
.dsp_intr_base = ACP6X_DSP_SW_INTR_BASE,
diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c
index b7d558cb1fd7..2b7fbcf11b55 100644
--- a/sound/soc/sof/amd/pci-rn.c
+++ b/sound/soc/sof/amd/pci-rn.c
@@ -28,7 +28,6 @@
#define ACP3X_FUTURE_REG_ACLK_0 0x1860
static const struct sof_amd_acp_desc renoir_chip_info = {
- .host_bridge_id = HOST_BRIDGE_CZN,
.pgfsm_base = ACP3X_PGFSM_BASE,
.ext_intr_stat = ACP3X_EXT_INTR_STAT,
.dsp_intr_base = ACP3X_DSP_SW_INTR_BASE,
@@ -98,7 +97,7 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = {
.probe = acp_pci_rn_probe,
.remove = acp_pci_rn_remove,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_amd_rn_driver);
diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c
index 53f64d6bc91b..6ef692becfb9 100644
--- a/sound/soc/sof/amd/pci-vangogh.c
+++ b/sound/soc/sof/amd/pci-vangogh.c
@@ -13,11 +13,9 @@
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/platform_device.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"
@@ -27,7 +25,6 @@
static const struct sof_amd_acp_desc vangogh_chip_info = {
.name = "vangogh",
- .host_bridge_id = HOST_BRIDGE_VGH,
.pgfsm_base = ACP5X_PGFSM_BASE,
.ext_intr_stat = ACP5X_EXT_INTR_STAT,
.dsp_intr_base = ACP5X_DSP_SW_INTR_BASE,
@@ -93,7 +90,7 @@ static struct pci_driver snd_sof_pci_amd_vgh_driver = {
.probe = acp_pci_vgh_probe,
.remove = acp_pci_vgh_remove,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_amd_vgh_driver);
diff --git a/sound/soc/sof/amd/vangogh.c b/sound/soc/sof/amd/vangogh.c
index 8e2672106ac6..6ed5f9aaa414 100644
--- a/sound/soc/sof/amd/vangogh.c
+++ b/sound/soc/sof/amd/vangogh.c
@@ -11,13 +11,10 @@
* Hardware interface for Audio DSP on Vangogh platform
*/
-#include <linux/platform_device.h>
+#include <linux/delay.h>
#include <linux/module.h>
-#include "../ops.h"
-#include "../sof-audio.h"
#include "acp.h"
-#include "acp-dsp-offset.h"
#define I2S_HS_INSTANCE 0
#define I2S_BT_INSTANCE 1
@@ -136,6 +133,20 @@ static struct snd_soc_dai_driver vangogh_sof_dai[] = {
},
};
+static int sof_vangogh_post_fw_run_delay(struct snd_sof_dev *sdev)
+{
+ /*
+ * Resuming from suspend in some cases my 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;
+}
+
/* Vangogh ops */
struct snd_sof_dsp_ops sof_vangogh_ops;
EXPORT_SYMBOL_NS(sof_vangogh_ops, "SND_SOC_SOF_AMD_COMMON");
@@ -157,6 +168,9 @@ int sof_vangogh_ops_init(struct snd_sof_dev *sdev)
if (quirks->signed_fw_image)
sof_vangogh_ops.load_firmware = acp_sof_load_signed_firmware;
+
+ if (quirks->post_fw_run_delay)
+ sof_vangogh_ops.post_fw_run = sof_vangogh_post_fw_run_delay;
}
return 0;
diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig
index 4751b04d5e6f..327e2df94a58 100644
--- a/sound/soc/sof/imx/Kconfig
+++ b/sound/soc/sof/imx/Kconfig
@@ -32,22 +32,13 @@ config SND_SOC_SOF_IMX8
Say Y if you have such a device.
If unsure select "N".
-config SND_SOC_SOF_IMX8M
- tristate "SOF support for i.MX8M"
+config SND_SOC_SOF_IMX9
+ tristate "SOF support for i.MX9"
depends on IMX_DSP
select SND_SOC_SOF_IMX_COMMON
help
- This adds support for Sound Open Firmware for NXP i.MX8M platforms.
- Say Y if you have such a device.
- If unsure select "N".
-
-config SND_SOC_SOF_IMX8ULP
- tristate "SOF support for i.MX8ULP"
- depends on IMX_DSP
- select SND_SOC_SOF_IMX_COMMON
- help
- This adds support for Sound Open Firmware for NXP i.MX8ULP platforms.
- Say Y if you have such a device.
+ This adds support for Sound Open Firmware for NXP i.MX9 platforms.
+ Say Y if you need such a device.
If unsure select "N".
endif ## SND_SOC_SOF_IMX_TOPLEVEL
diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile
index be0bf0736dfa..74b5ecad8fe8 100644
--- a/sound/soc/sof/imx/Makefile
+++ b/sound/soc/sof/imx/Makefile
@@ -1,11 +1,9 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-imx8-y := imx8.o
-snd-sof-imx8m-y := imx8m.o
-snd-sof-imx8ulp-y := imx8ulp.o
+snd-sof-imx9-y := imx9.o
snd-sof-imx-common-y := imx-common.o
obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o
-obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o
-obj-$(CONFIG_SND_SOC_SOF_IMX8ULP) += snd-sof-imx8ulp.o
+obj-$(CONFIG_SND_SOC_SOF_IMX9) += snd-sof-imx9.o
obj-$(CONFIG_SND_SOC_SOF_IMX_COMMON) += imx-common.o
diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c
index fce6d9cf6a6b..62bf707aa909 100644
--- a/sound/soc/sof/imx/imx-common.c
+++ b/sound/soc/sof/imx/imx-common.c
@@ -1,11 +1,16 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright 2020 NXP
+// Copyright 2020-2025 NXP
//
// Common helpers for the audio DSP on i.MX8
+#include <linux/firmware/imx/dsp.h>
#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pm_domain.h>
#include <sound/sof/xtensa.h>
+
#include "../ops.h"
#include "imx-common.h"
@@ -74,5 +79,428 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags)
}
EXPORT_SYMBOL(imx8_dump);
+static void imx_handle_reply(struct imx_dsp_ipc *ipc)
+{
+ struct snd_sof_dev *sdev;
+ unsigned long flags;
+
+ sdev = imx_dsp_get_data(ipc);
+
+ spin_lock_irqsave(&sdev->ipc_lock, flags);
+ snd_sof_ipc_process_reply(sdev, 0);
+ spin_unlock_irqrestore(&sdev->ipc_lock, flags);
+}
+
+static void imx_handle_request(struct imx_dsp_ipc *ipc)
+{
+ struct snd_sof_dev *sdev;
+ u32 panic_code;
+
+ sdev = imx_dsp_get_data(ipc);
+
+ if (get_chip_info(sdev)->ipc_info.has_panic_code) {
+ sof_mailbox_read(sdev, sdev->debug_box.offset + 0x4,
+ &panic_code,
+ sizeof(panic_code));
+
+ if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+ snd_sof_dsp_panic(sdev, panic_code, true);
+ return;
+ }
+ }
+
+ snd_sof_ipc_msgs_rx(sdev);
+}
+
+static struct imx_dsp_ops imx_ipc_ops = {
+ .handle_reply = imx_handle_reply,
+ .handle_request = imx_handle_request,
+};
+
+static int imx_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+{
+ struct imx_common_data *common = sdev->pdata->hw_pdata;
+
+ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size);
+ imx_dsp_ring_doorbell(common->ipc_handle, 0x0);
+
+ return 0;
+}
+
+static int imx_get_bar_index(struct snd_sof_dev *sdev, u32 type)
+{
+ switch (type) {
+ case SOF_FW_BLK_TYPE_IRAM:
+ case SOF_FW_BLK_TYPE_SRAM:
+ return type;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int imx_get_mailbox_offset(struct snd_sof_dev *sdev)
+{
+ return get_chip_info(sdev)->ipc_info.boot_mbox_offset;
+}
+
+static int imx_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+{
+ return get_chip_info(sdev)->ipc_info.window_offset;
+}
+
+static int imx_set_power_state(struct snd_sof_dev *sdev,
+ const struct sof_dsp_power_state *target)
+{
+ sdev->dsp_power_state = *target;
+
+ return 0;
+}
+
+static int imx_common_resume(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ int ret, i;
+
+ common = sdev->pdata->hw_pdata;
+
+ ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
+ if (ret)
+ dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
+
+ for (i = 0; i < DSP_MU_CHAN_NUM; i++)
+ imx_dsp_request_channel(common->ipc_handle, i);
+
+ /* done. If need be, core will be started by SOF core immediately after */
+ return 0;
+}
+
+static int imx_common_suspend(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ int i, ret;
+
+ common = sdev->pdata->hw_pdata;
+
+ ret = imx_chip_core_shutdown(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to shutdown core: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < DSP_MU_CHAN_NUM; i++)
+ imx_dsp_free_channel(common->ipc_handle, i);
+
+ clk_bulk_disable_unprepare(common->clk_num, common->clks);
+
+ return 0;
+}
+
+static int imx_runtime_resume(struct snd_sof_dev *sdev)
+{
+ const struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D0,
+ };
+ int ret;
+
+ ret = imx_common_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to runtime common resume: %d\n", ret);
+ return ret;
+ }
+
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int imx_resume(struct snd_sof_dev *sdev)
+{
+ const struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D0,
+ };
+ int ret;
+
+ ret = imx_common_resume(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to common resume: %d\n", ret);
+ return ret;
+ }
+
+ if (pm_runtime_suspended(sdev->dev)) {
+ pm_runtime_disable(sdev->dev);
+ pm_runtime_set_active(sdev->dev);
+ pm_runtime_mark_last_busy(sdev->dev);
+ pm_runtime_enable(sdev->dev);
+ pm_runtime_idle(sdev->dev);
+ }
+
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int imx_runtime_suspend(struct snd_sof_dev *sdev)
+{
+ const struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D3,
+ };
+ int ret;
+
+ ret = imx_common_suspend(sdev);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to runtime common suspend: %d\n", ret);
+
+ return snd_sof_dsp_set_power_state(sdev, &target_state);
+}
+
+static int imx_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
+{
+ const struct sof_dsp_power_state target_power_state = {
+ .state = target_state,
+ };
+ int ret;
+
+ if (!pm_runtime_suspended(sdev->dev)) {
+ ret = imx_common_suspend(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to common suspend: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return snd_sof_dsp_set_power_state(sdev, &target_power_state);
+}
+
+static int imx_region_name_to_blk_type(const char *region_name)
+{
+ if (!strcmp(region_name, "iram"))
+ return SOF_FW_BLK_TYPE_IRAM;
+ else if (!strcmp(region_name, "dram"))
+ return SOF_FW_BLK_TYPE_DRAM;
+ else if (!strcmp(region_name, "sram"))
+ return SOF_FW_BLK_TYPE_SRAM;
+ else
+ return -EINVAL;
+}
+
+static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_info *chip_info;
+ struct reserved_mem *reserved;
+ struct platform_device *pdev;
+ struct device_node *res_np;
+ phys_addr_t base, size;
+ struct resource *res;
+ int i, blk_type, ret;
+
+ pdev = to_platform_device(sdev->dev);
+ chip_info = get_chip_info(sdev);
+
+ for (i = 0; chip_info->memory[i].name; i++) {
+ blk_type = imx_region_name_to_blk_type(chip_info->memory[i].name);
+ if (blk_type < 0)
+ return dev_err_probe(sdev->dev, blk_type,
+ "no blk type for region %s\n",
+ chip_info->memory[i].name);
+
+ if (!chip_info->memory[i].reserved) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ chip_info->memory[i].name);
+ if (!res)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to fetch %s resource\n",
+ chip_info->memory[i].name);
+
+ base = res->start;
+ size = resource_size(res);
+ } else {
+ ret = of_property_match_string(pdev->dev.of_node,
+ "memory-region-names",
+ chip_info->memory[i].name);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "no valid index for %s\n",
+ chip_info->memory[i].name);
+
+ res_np = of_parse_phandle(pdev->dev.of_node,
+ "memory-region",
+ ret);
+ if (!res_np)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to parse phandle %s\n",
+ chip_info->memory[i].name);
+
+ reserved = of_reserved_mem_lookup(res_np);
+ of_node_put(res_np);
+ if (!reserved)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to get %s reserved\n",
+ chip_info->memory[i].name);
+
+ base = reserved->base;
+ size = reserved->size;
+ }
+
+ sdev->bar[blk_type] = devm_ioremap(sdev->dev, base, size);
+ if (!sdev->bar[blk_type])
+ return dev_err_probe(sdev->dev,
+ -ENOMEM,
+ "failed to ioremap %s region\n",
+ chip_info->memory[i].name);
+ }
+
+ return 0;
+}
+
+static void imx_unregister_action(void *data)
+{
+ struct imx_common_data *common;
+ struct snd_sof_dev *sdev;
+
+ sdev = data;
+ common = sdev->pdata->hw_pdata;
+
+ if (get_chip_info(sdev)->has_dma_reserved)
+ of_reserved_mem_device_release(sdev->dev);
+
+ platform_device_unregister(common->ipc_dev);
+}
+
+static int imx_probe(struct snd_sof_dev *sdev)
+{
+ struct dev_pm_domain_attach_data domain_data = {
+ .pd_names = NULL, /* no filtering */
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ };
+ struct imx_common_data *common;
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = to_platform_device(sdev->dev);
+
+ common = devm_kzalloc(sdev->dev, sizeof(*common), GFP_KERNEL);
+ if (!common)
+ return dev_err_probe(sdev->dev, -ENOMEM,
+ "failed to allocate common data\n");
+ sdev->pdata->hw_pdata = common;
+
+ common->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
+ PLATFORM_DEVID_NONE,
+ pdev, sizeof(*pdev));
+ if (IS_ERR(common->ipc_dev))
+ return dev_err_probe(sdev->dev, PTR_ERR(common->ipc_dev),
+ "failed to create IPC device\n");
+
+ if (get_chip_info(sdev)->has_dma_reserved) {
+ ret = of_reserved_mem_device_init_by_name(sdev->dev,
+ pdev->dev.of_node,
+ "dma");
+ if (ret) {
+ platform_device_unregister(common->ipc_dev);
+
+ return dev_err_probe(sdev->dev, ret,
+ "failed to bind DMA region\n");
+ }
+ }
+
+ /* let the devres API take care of the cleanup */
+ ret = devm_add_action_or_reset(sdev->dev,
+ imx_unregister_action,
+ sdev);
+ if (ret)
+ return dev_err_probe(sdev->dev, ret, "failed to add devm action\n");
+
+ common->ipc_handle = dev_get_drvdata(&common->ipc_dev->dev);
+ if (!common->ipc_handle)
+ return dev_err_probe(sdev->dev, -EPROBE_DEFER,
+ "failed to fetch IPC handle\n");
+
+ ret = imx_parse_ioremap_memory(sdev);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "failed to parse/ioremap memory regions\n");
+
+ if (!sdev->dev->pm_domain) {
+ ret = devm_pm_domain_attach_list(sdev->dev,
+ &domain_data, &common->pd_list);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret, "failed to attach PDs\n");
+ }
+
+ ret = devm_clk_bulk_get_all(sdev->dev, &common->clks);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret, "failed to fetch clocks\n");
+ common->clk_num = ret;
+
+ ret = clk_bulk_prepare_enable(common->clk_num, common->clks);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret, "failed to enable clocks\n");
+
+ common->ipc_handle->ops = &imx_ipc_ops;
+ imx_dsp_set_data(common->ipc_handle, sdev);
+
+ sdev->num_cores = 1;
+ sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
+ sdev->dsp_box.offset = get_chip_info(sdev)->ipc_info.boot_mbox_offset;
+
+ return imx_chip_probe(sdev);
+}
+
+static void imx_remove(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ int ret;
+
+ common = sdev->pdata->hw_pdata;
+
+ if (!pm_runtime_suspended(sdev->dev)) {
+ ret = imx_chip_core_shutdown(sdev);
+ if (ret < 0)
+ dev_err(sdev->dev, "failed to shutdown core: %d\n", ret);
+
+ clk_bulk_disable_unprepare(common->clk_num, common->clks);
+ }
+}
+
+const struct snd_sof_dsp_ops sof_imx_ops = {
+ .probe = imx_probe,
+ .remove = imx_remove,
+
+ .run = imx_chip_core_kick,
+ .reset = imx_chip_core_reset,
+
+ .block_read = sof_block_read,
+ .block_write = sof_block_write,
+
+ .mailbox_read = sof_mailbox_read,
+ .mailbox_write = sof_mailbox_write,
+
+ .send_msg = imx_send_msg,
+ .get_mailbox_offset = imx_get_mailbox_offset,
+ .get_window_offset = imx_get_window_offset,
+
+ .ipc_msg_data = sof_ipc_msg_data,
+ .set_stream_data_offset = sof_set_stream_data_offset,
+
+ .get_bar_index = imx_get_bar_index,
+ .load_firmware = snd_sof_load_firmware_memcpy,
+
+ .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+
+ .pcm_open = sof_stream_pcm_open,
+ .pcm_close = sof_stream_pcm_close,
+
+ .runtime_suspend = imx_runtime_suspend,
+ .runtime_resume = imx_runtime_resume,
+ .suspend = imx_suspend,
+ .resume = imx_resume,
+
+ .set_power_state = imx_set_power_state,
+
+ .hw_info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+};
+EXPORT_SYMBOL(sof_imx_ops);
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF helpers for IMX platforms");
diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h
index 13d7f3ef675e..9bd711dbb5d0 100644
--- a/sound/soc/sof/imx/imx-common.h
+++ b/sound/soc/sof/imx/imx-common.h
@@ -4,10 +4,159 @@
#define __IMX_COMMON_H__
#include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <sound/sof/xtensa.h>
+
+#include "../sof-of-dev.h"
+#include "../ops.h"
#define EXCEPT_MAX_HDR_SIZE 0x400
#define IMX8_STACK_DUMP_SIZE 32
+/* chip_info refers to the data stored in struct sof_dev_desc's chip_info */
+#define get_chip_info(sdev)\
+ ((const struct imx_chip_info *)((sdev)->pdata->desc->chip_info))
+
+/* chip_pdata refers to the data stored in struct imx_common_data's chip_pdata */
+#define get_chip_pdata(sdev)\
+ (((struct imx_common_data *)((sdev)->pdata->hw_pdata))->chip_pdata)
+
+/* can be used if:
+ * 1) The only supported IPC version is IPC3.
+ * 2) The default paths/FW name match values below.
+ *
+ * otherwise, just explicitly declare the structure
+ */
+#define IMX_SOF_DEV_DESC(mach_name, of_machs, \
+ mach_chip_info, mach_ops, mach_ops_init) \
+static struct sof_dev_desc sof_of_##mach_name##_desc = { \
+ .of_machines = of_machs, \
+ .chip_info = mach_chip_info, \
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), \
+ .ipc_default = SOF_IPC_TYPE_3, \
+ .default_fw_path = { \
+ [SOF_IPC_TYPE_3] = "imx/sof", \
+ }, \
+ .default_tplg_path = { \
+ [SOF_IPC_TYPE_3] = "imx/sof-tplg", \
+ }, \
+ .default_fw_filename = { \
+ [SOF_IPC_TYPE_3] = "sof-" #mach_name ".ri", \
+ }, \
+ .ops = mach_ops, \
+ .ops_init = mach_ops_init, \
+}
+
+/* to be used alongside IMX_SOF_DEV_DESC() */
+#define IMX_SOF_DEV_DESC_NAME(mach_name) sof_of_##mach_name##_desc
+
+/* dai driver entry w/ playback and capture caps. If one direction is missing
+ * then set the channels to 0.
+ */
+#define IMX_SOF_DAI_DRV_ENTRY(dai_name, pb_cmin, pb_cmax, cap_cmin, cap_cmax) \
+{ \
+ .name = dai_name, \
+ .playback = { \
+ .channels_min = pb_cmin, \
+ .channels_max = pb_cmax, \
+ }, \
+ .capture = { \
+ .channels_min = cap_cmin, \
+ .channels_max = cap_cmax, \
+ }, \
+}
+
+/* use if playback and capture have the same min/max channel count */
+#define IMX_SOF_DAI_DRV_ENTRY_BIDIR(dai_name, cmin, cmax)\
+ IMX_SOF_DAI_DRV_ENTRY(dai_name, cmin, cmax, cmin, cmax)
+
+struct imx_ipc_info {
+ /* true if core is able to write a panic code to the debug box */
+ bool has_panic_code;
+ /* offset to mailbox in which firmware initially writes FW_READY */
+ int boot_mbox_offset;
+ /* offset to region at which the mailboxes start */
+ int window_offset;
+};
+
+struct imx_chip_ops {
+ /* called after clocks and PDs are enabled */
+ int (*probe)(struct snd_sof_dev *sdev);
+ /* used directly by the SOF core */
+ int (*core_kick)(struct snd_sof_dev *sdev);
+ /* called during suspend()/remove() before clocks are disabled */
+ int (*core_shutdown)(struct snd_sof_dev *sdev);
+ /* used directly by the SOF core */
+ int (*core_reset)(struct snd_sof_dev *sdev);
+};
+
+struct imx_memory_info {
+ const char *name;
+ bool reserved;
+};
+
+struct imx_chip_info {
+ struct imx_ipc_info ipc_info;
+ /* does the chip have a reserved memory region for DMA? */
+ bool has_dma_reserved;
+ struct imx_memory_info *memory;
+ struct snd_soc_dai_driver *drv;
+ int num_drv;
+ /* optional */
+ const struct imx_chip_ops *ops;
+};
+
+struct imx_common_data {
+ struct platform_device *ipc_dev;
+ struct imx_dsp_ipc *ipc_handle;
+ /* core may have no clocks */
+ struct clk_bulk_data *clks;
+ int clk_num;
+ /* core may have no PDs */
+ struct dev_pm_domain_list *pd_list;
+ void *chip_pdata;
+};
+
+static inline int imx_chip_core_kick(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->core_kick)
+ return ops->core_kick(sdev);
+
+ return 0;
+}
+
+static inline int imx_chip_core_shutdown(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->core_shutdown)
+ return ops->core_shutdown(sdev);
+
+ return 0;
+}
+
+static inline int imx_chip_core_reset(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->core_reset)
+ return ops->core_reset(sdev);
+
+ return 0;
+}
+
+static inline int imx_chip_probe(struct snd_sof_dev *sdev)
+{
+ const struct imx_chip_ops *ops = get_chip_info(sdev)->ops;
+
+ if (ops && ops->probe)
+ return ops->probe(sdev);
+
+ return 0;
+}
+
void imx8_get_registers(struct snd_sof_dev *sdev,
struct sof_ipc_dsp_oops_xtensa *xoops,
struct sof_ipc_panic_info *panic_info,
@@ -15,4 +164,6 @@ void imx8_get_registers(struct snd_sof_dev *sdev,
void imx8_dump(struct snd_sof_dev *sdev, u32 flags);
+extern const struct snd_sof_dsp_ops sof_imx_ops;
+
#endif
diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c
index 0b85b29d1067..ab07512e511d 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -1,140 +1,72 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
-// Copyright 2019 NXP
+// Copyright 2019-2025 NXP
//
// Author: Daniel Baluta <daniel.baluta@nxp.com>
//
// Hardware interface for audio DSP on i.MX8
-#include <linux/firmware.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/pm_domain.h>
-
-#include <linux/module.h>
-#include <sound/sof.h>
-#include <sound/sof/xtensa.h>
-#include <linux/firmware/imx/ipc.h>
-#include <linux/firmware/imx/dsp.h>
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/arm-smccc.h>
#include <linux/firmware/imx/svc/misc.h>
-#include <dt-bindings/firmware/imx/rsrc.h>
-#include "../ops.h"
-#include "../sof-of-dev.h"
-#include "imx-common.h"
+#include <linux/mfd/syscon.h>
-/* DSP memories */
-#define IRAM_OFFSET 0x10000
-#define IRAM_SIZE (2 * 1024)
-#define DRAM0_OFFSET 0x0
-#define DRAM0_SIZE (32 * 1024)
-#define DRAM1_OFFSET 0x8000
-#define DRAM1_SIZE (32 * 1024)
-#define SYSRAM_OFFSET 0x18000
-#define SYSRAM_SIZE (256 * 1024)
-#define SYSROM_OFFSET 0x58000
-#define SYSROM_SIZE (192 * 1024)
+#include "imx-common.h"
+/* imx8/imx8x macros */
#define RESET_VECTOR_VADDR 0x596f8000
-#define MBOX_OFFSET 0x800000
-#define MBOX_SIZE 0x1000
-
-struct imx8_priv {
- struct device *dev;
- struct snd_sof_dev *sdev;
-
- /* DSP IPC handler */
- struct imx_dsp_ipc *dsp_ipc;
- struct platform_device *ipc_dev;
-
- /* System Controller IPC handler */
- struct imx_sc_ipc *sc_ipc;
-
- /* Power domain handling */
- int num_domains;
- struct device **pd_dev;
- struct device_link **link;
-
- struct clk_bulk_data *clks;
- int clk_num;
-};
-
-static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev)
-{
- return MBOX_OFFSET;
-}
-
-static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id)
-{
- return MBOX_OFFSET;
-}
-
-static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc)
-{
- struct imx8_priv *priv = imx_dsp_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- snd_sof_ipc_process_reply(priv->sdev, 0);
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc)
-{
- struct imx8_priv *priv = imx_dsp_get_data(ipc);
- u32 p; /* panic code */
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
-
- /* Check to see if the message is a panic code (0x0dead***) */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
- snd_sof_dsp_panic(priv->sdev, p, true);
- else
- snd_sof_ipc_msgs_rx(priv->sdev);
-}
-
-static struct imx_dsp_ops dsp_ops = {
- .handle_reply = imx8_dsp_handle_reply,
- .handle_request = imx8_dsp_handle_request,
+/* imx8m macros */
+#define IMX8M_DAP_DEBUG 0x28800000
+#define IMX8M_DAP_DEBUG_SIZE (64 * 1024)
+#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020)
+#define IMX8M_PWRCTL_CORERESET BIT(16)
+
+#define AudioDSP_REG0 0x100
+#define AudioDSP_REG1 0x104
+#define AudioDSP_REG2 0x108
+#define AudioDSP_REG3 0x10c
+
+#define AudioDSP_REG2_RUNSTALL BIT(5)
+
+/* imx8ulp macros */
+#define FSL_SIP_HIFI_XRDC 0xc200000e
+#define SYSCTRL0 0x8
+#define EXECUTE_BIT BIT(13)
+#define RESET_BIT BIT(16)
+#define HIFI4_CLK_BIT BIT(17)
+#define PB_CLK_BIT BIT(18)
+#define PLAT_CLK_BIT BIT(19)
+#define DEBUG_LOGIC_BIT BIT(25)
+
+struct imx8m_chip_data {
+ void __iomem *dap;
+ struct regmap *regmap;
};
-static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
-{
- struct imx8_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
- imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
-
- return 0;
-}
-
/*
* DSP control.
*/
static int imx8x_run(struct snd_sof_dev *sdev)
{
- struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata;
int ret;
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_SEL, 1);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset source select\n");
return ret;
}
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_AUDIO, 0x80);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset of AUDIO\n");
return ret;
}
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_PERIPH, 0x5A);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset of PERIPH %d\n",
@@ -142,14 +74,14 @@ static int imx8x_run(struct snd_sof_dev *sdev)
return ret;
}
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_IRQ, 0x51);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset of IRQ\n");
return ret;
}
- imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true,
+ imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
RESET_VECTOR_VADDR);
return 0;
@@ -157,17 +89,16 @@ static int imx8x_run(struct snd_sof_dev *sdev)
static int imx8_run(struct snd_sof_dev *sdev)
{
- struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata;
int ret;
- ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP,
+ ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP,
IMX_SC_C_OFS_SEL, 0);
if (ret < 0) {
dev_err(sdev->dev, "Error system address offset source select\n");
return ret;
}
- imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true,
+ imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true,
RESET_VECTOR_VADDR);
return 0;
@@ -175,429 +106,273 @@ static int imx8_run(struct snd_sof_dev *sdev)
static int imx8_probe(struct snd_sof_dev *sdev)
{
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
- struct device_node *np = pdev->dev.of_node;
- struct device_node *res_node;
- struct resource *mmio;
- struct imx8_priv *priv;
- struct resource res;
- u32 base, size;
- int ret = 0;
- int i;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- sdev->num_cores = 1;
- sdev->pdata->hw_pdata = priv;
- priv->dev = sdev->dev;
- priv->sdev = sdev;
-
- /* power up device associated power domains */
- priv->num_domains = of_count_phandle_with_args(np, "power-domains",
- "#power-domain-cells");
- if (priv->num_domains < 0) {
- dev_err(sdev->dev, "no power-domains property in %pOF\n", np);
- return priv->num_domains;
- }
-
- priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains,
- sizeof(*priv->pd_dev), GFP_KERNEL);
- if (!priv->pd_dev)
- return -ENOMEM;
-
- priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains,
- sizeof(*priv->link), GFP_KERNEL);
- if (!priv->link)
- return -ENOMEM;
-
- for (i = 0; i < priv->num_domains; i++) {
- priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i);
- if (IS_ERR(priv->pd_dev[i])) {
- ret = PTR_ERR(priv->pd_dev[i]);
- goto exit_unroll_pm;
- }
- priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i],
- DL_FLAG_STATELESS |
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_RPM_ACTIVE);
- if (!priv->link[i]) {
- ret = -ENOMEM;
- dev_pm_domain_detach(priv->pd_dev[i], false);
- goto exit_unroll_pm;
- }
- }
-
- ret = imx_scu_get_handle(&priv->sc_ipc);
- if (ret) {
- dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n",
- ret);
- goto exit_unroll_pm;
- }
+ struct imx_sc_ipc *sc_ipc_handle;
+ struct imx_common_data *common;
+ int ret;
- priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
- PLATFORM_DEVID_NONE,
- pdev, sizeof(*pdev));
- if (IS_ERR(priv->ipc_dev)) {
- ret = PTR_ERR(priv->ipc_dev);
- goto exit_unroll_pm;
- }
+ common = sdev->pdata->hw_pdata;
- priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
- if (!priv->dsp_ipc) {
- /* DSP IPC driver not probed yet, try later */
- ret = -EPROBE_DEFER;
- dev_err(sdev->dev, "Failed to get drvdata\n");
- goto exit_pdev_unregister;
- }
+ ret = imx_scu_get_handle(&sc_ipc_handle);
+ if (ret < 0)
+ return dev_err_probe(sdev->dev, ret,
+ "failed to fetch SC IPC handle\n");
- imx_dsp_set_data(priv->dsp_ipc, priv);
- priv->dsp_ipc->ops = &dsp_ops;
-
- /* DSP base */
- mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mmio) {
- base = mmio->start;
- size = resource_size(mmio);
- } else {
- dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
- ret = -EINVAL;
- goto exit_pdev_unregister;
- }
+ common->chip_pdata = sc_ipc_handle;
- sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
- if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
- dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
- base, size);
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
- sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
+ return 0;
+}
- res_node = of_parse_phandle(np, "memory-region", 0);
- if (!res_node) {
- dev_err(&pdev->dev, "failed to get memory region node\n");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
+static int imx8m_reset(struct snd_sof_dev *sdev)
+{
+ struct imx8m_chip_data *chip;
+ u32 pwrctl;
- ret = of_address_to_resource(res_node, 0, &res);
- of_node_put(res_node);
- if (ret) {
- dev_err(&pdev->dev, "failed to get reserved region address\n");
- goto exit_pdev_unregister;
- }
+ chip = get_chip_pdata(sdev);
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- resource_size(&res));
- if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
- dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
- base, size);
- ret = -ENOMEM;
- goto exit_pdev_unregister;
- }
- sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
+ /* put DSP into reset and stall */
+ pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL);
+ pwrctl |= IMX8M_PWRCTL_CORERESET;
+ writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL);
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
+ /* keep reset asserted for 10 cycles */
+ usleep_range(1, 2);
- ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
- priv->clk_num = ret;
+ regmap_update_bits(chip->regmap, AudioDSP_REG2,
+ AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL);
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
+ /* take the DSP out of reset and keep stalled for FW loading */
+ pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL);
+ pwrctl &= ~IMX8M_PWRCTL_CORERESET;
+ writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL);
return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
-exit_unroll_pm:
- while (--i >= 0) {
- device_link_del(priv->link[i]);
- dev_pm_domain_detach(priv->pd_dev[i], false);
- }
-
- return ret;
}
-static void imx8_remove(struct snd_sof_dev *sdev)
+static int imx8m_run(struct snd_sof_dev *sdev)
{
- struct imx8_priv *priv = sdev->pdata->hw_pdata;
- int i;
+ struct imx8m_chip_data *chip = get_chip_pdata(sdev);
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-
- for (i = 0; i < priv->num_domains; i++) {
- device_link_del(priv->link[i]);
- dev_pm_domain_detach(priv->pd_dev[i], false);
- }
-}
+ regmap_update_bits(chip->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0);
-/* on i.MX8 there is 1 to 1 match between type and BAR idx */
-static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- /* Only IRAM and SRAM bars are valid */
- switch (type) {
- case SOF_FW_BLK_TYPE_IRAM:
- case SOF_FW_BLK_TYPE_SRAM:
- return type;
- default:
- return -EINVAL;
- }
+ return 0;
}
-static void imx8_suspend(struct snd_sof_dev *sdev)
+static int imx8m_probe(struct snd_sof_dev *sdev)
{
- int i;
- struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
+ struct imx_common_data *common;
+ struct imx8m_chip_data *chip;
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
+ common = sdev->pdata->hw_pdata;
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
-}
+ chip = devm_kzalloc(sdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return dev_err_probe(sdev->dev, -ENOMEM,
+ "failed to allocate chip data\n");
-static int imx8_resume(struct snd_sof_dev *sdev)
-{
- struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata;
- int ret;
- int i;
+ chip->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE);
+ if (!chip->dap)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to ioremap DAP\n");
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
+ chip->regmap = syscon_regmap_lookup_by_phandle(sdev->dev->of_node, "fsl,dsp-ctrl");
+ if (IS_ERR(chip->regmap))
+ return dev_err_probe(sdev->dev, PTR_ERR(chip->regmap),
+ "failed to fetch dsp ctrl regmap\n");
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_request_channel(priv->dsp_ipc, i);
+ common->chip_pdata = chip;
return 0;
}
-static int imx8_dsp_runtime_resume(struct snd_sof_dev *sdev)
+static int imx8ulp_run(struct snd_sof_dev *sdev)
{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
+ struct regmap *regmap = get_chip_pdata(sdev);
- ret = imx8_resume(sdev);
- if (ret < 0)
- return ret;
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
+ /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */
+ regmap_update_bits(regmap, SYSCTRL0, RESET_BIT, 0);
-static int imx8_dsp_runtime_suspend(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D3,
- };
+ /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/
+ regmap_update_bits(regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0);
- imx8_suspend(sdev);
+ /* Stall HIFI4 DSP Execution: 1 stall, 0 run */
+ regmap_update_bits(regmap, SYSCTRL0, EXECUTE_BIT, 0);
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
+ return 0;
}
-static int imx8_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
+static int imx8ulp_reset(struct snd_sof_dev *sdev)
{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = target_state,
- };
+ struct arm_smccc_res smc_res;
+ struct regmap *regmap;
- if (!pm_runtime_suspended(sdev->dev))
- imx8_suspend(sdev);
+ regmap = get_chip_pdata(sdev);
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
+ /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */
+ regmap_update_bits(regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT);
-static int imx8_dsp_resume(struct snd_sof_dev *sdev)
-{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
+ /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */
+ regmap_update_bits(regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT);
- ret = imx8_resume(sdev);
- if (ret < 0)
- return ret;
+ /* HiFi4 Clock Enable: 1 enabled, 0 disabled */
+ regmap_update_bits(regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT);
- if (pm_runtime_suspended(sdev->dev)) {
- pm_runtime_disable(sdev->dev);
- pm_runtime_set_active(sdev->dev);
- pm_runtime_mark_last_busy(sdev->dev);
- pm_runtime_enable(sdev->dev);
- pm_runtime_idle(sdev->dev);
- }
+ regmap_update_bits(regmap, SYSCTRL0, RESET_BIT, RESET_BIT);
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
+ usleep_range(1, 2);
-static struct snd_soc_dai_driver imx8_dai[] = {
-{
- .name = "esai0",
- .playback = {
- .channels_min = 1,
- .channels_max = 8,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- },
-},
-{
- .name = "sai1",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-};
+ /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */
+ regmap_update_bits(regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT);
+ usleep_range(1, 2);
-static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev,
- const struct sof_dsp_power_state *target_state)
-{
- sdev->dsp_power_state = *target_state;
+ arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_res);
- return 0;
+ return smc_res.a0;
}
-/* i.MX8 ops */
-static const struct snd_sof_dsp_ops sof_imx8_ops = {
- /* probe and remove */
- .probe = imx8_probe,
- .remove = imx8_remove,
- /* DSP core boot */
- .run = imx8_run,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
+static int imx8ulp_probe(struct snd_sof_dev *sdev)
+{
+ struct imx_common_data *common;
+ struct regmap *regmap;
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
+ common = sdev->pdata->hw_pdata;
- /* ipc */
- .send_msg = imx8_send_msg,
- .get_mailbox_offset = imx8_get_mailbox_offset,
- .get_window_offset = imx8_get_window_offset,
+ regmap = syscon_regmap_lookup_by_phandle(sdev->dev->of_node, "fsl,dsp-ctrl");
+ if (IS_ERR(regmap))
+ return dev_err_probe(sdev->dev, PTR_ERR(regmap),
+ "failed to fetch dsp ctrl regmap\n");
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
+ common->chip_pdata = regmap;
- .get_bar_index = imx8_get_bar_index,
+ return 0;
+}
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
+static struct snd_soc_dai_driver imx8_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("esai0", 1, 8),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32),
+};
- /* Debug information */
- .dbg_dump = imx8_dump,
- .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+static struct snd_soc_dai_driver imx8m_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai2", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai5", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai7", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY("micfil", 0, 0, 1, 8),
+};
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
+static struct snd_soc_dai_driver imx8ulp_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai5", 1, 32),
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32),
+};
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
+static struct snd_sof_dsp_ops sof_imx8_ops;
- /* DAI drivers */
- .drv = imx8_dai,
- .num_drv = ARRAY_SIZE(imx8_dai),
+static int imx8_ops_init(struct snd_sof_dev *sdev)
+{
+ /* first copy from template */
+ memcpy(&sof_imx8_ops, &sof_imx_ops, sizeof(sof_imx_ops));
- /* ALSA HW info flags */
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+ /* then set common imx8 ops */
+ sof_imx8_ops.dbg_dump = imx8_dump;
+ sof_imx8_ops.dsp_arch_ops = &sof_xtensa_arch_ops;
+ sof_imx8_ops.debugfs_add_region_item =
+ snd_sof_debugfs_add_region_item_iomem;
- /* PM */
- .runtime_suspend = imx8_dsp_runtime_suspend,
- .runtime_resume = imx8_dsp_runtime_resume,
+ /* ... and finally set DAI driver */
+ sof_imx8_ops.drv = get_chip_info(sdev)->drv;
+ sof_imx8_ops.num_drv = get_chip_info(sdev)->num_drv;
- .suspend = imx8_dsp_suspend,
- .resume = imx8_dsp_resume,
+ return 0;
+}
- .set_power_state = imx8_dsp_set_power_state,
+static const struct imx_chip_ops imx8_chip_ops = {
+ .probe = imx8_probe,
+ .core_kick = imx8_run,
};
-/* i.MX8X ops */
-static const struct snd_sof_dsp_ops sof_imx8x_ops = {
- /* probe and remove */
- .probe = imx8_probe,
- .remove = imx8_remove,
- /* DSP core boot */
- .run = imx8x_run,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
-
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
-
- /* ipc */
- .send_msg = imx8_send_msg,
- .get_mailbox_offset = imx8_get_mailbox_offset,
- .get_window_offset = imx8_get_window_offset,
-
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
+static const struct imx_chip_ops imx8x_chip_ops = {
+ .probe = imx8_probe,
+ .core_kick = imx8x_run,
+};
- .get_bar_index = imx8_get_bar_index,
+static const struct imx_chip_ops imx8m_chip_ops = {
+ .probe = imx8m_probe,
+ .core_kick = imx8m_run,
+ .core_reset = imx8m_reset,
+};
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
+static const struct imx_chip_ops imx8ulp_chip_ops = {
+ .probe = imx8ulp_probe,
+ .core_kick = imx8ulp_run,
+ .core_reset = imx8ulp_reset,
+};
- /* Debug information */
- .dbg_dump = imx8_dump,
- .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
+static struct imx_memory_info imx8_memory_regions[] = {
+ { .name = "iram", .reserved = false },
+ { .name = "sram", .reserved = true },
+ { }
+};
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
+static struct imx_memory_info imx8m_memory_regions[] = {
+ { .name = "iram", .reserved = false },
+ { .name = "sram", .reserved = true },
+ { }
+};
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
+static struct imx_memory_info imx8ulp_memory_regions[] = {
+ { .name = "iram", .reserved = false },
+ { .name = "sram", .reserved = true },
+ { }
+};
- /* DAI drivers */
+static const struct imx_chip_info imx8_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .memory = imx8_memory_regions,
.drv = imx8_dai,
.num_drv = ARRAY_SIZE(imx8_dai),
+ .ops = &imx8_chip_ops,
+};
- /* PM */
- .runtime_suspend = imx8_dsp_runtime_suspend,
- .runtime_resume = imx8_dsp_runtime_resume,
-
- .suspend = imx8_dsp_suspend,
- .resume = imx8_dsp_resume,
+static const struct imx_chip_info imx8x_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .memory = imx8_memory_regions,
+ .drv = imx8_dai,
+ .num_drv = ARRAY_SIZE(imx8_dai),
+ .ops = &imx8x_chip_ops,
+};
- .set_power_state = imx8_dsp_set_power_state,
+static const struct imx_chip_info imx8m_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .memory = imx8m_memory_regions,
+ .drv = imx8m_dai,
+ .num_drv = ARRAY_SIZE(imx8m_dai),
+ .ops = &imx8m_chip_ops,
+};
- /* ALSA HW info flags */
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
+static const struct imx_chip_info imx8ulp_chip_info = {
+ .ipc_info = {
+ .has_panic_code = true,
+ .boot_mbox_offset = 0x800000,
+ .window_offset = 0x800000,
+ },
+ .has_dma_reserved = true,
+ .memory = imx8ulp_memory_regions,
+ .drv = imx8ulp_dai,
+ .num_drv = ARRAY_SIZE(imx8ulp_dai),
+ .ops = &imx8ulp_chip_ops,
};
static struct snd_sof_of_mach sof_imx8_machs[] = {
@@ -607,50 +382,70 @@ static struct snd_sof_of_mach sof_imx8_machs[] = {
.drv_name = "asoc-audio-graph-card2",
},
{
+ .compatible = "fsl,imx8qxp-mek-wcpu",
+ .sof_tplg_filename = "sof-imx8-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
+ },
+ {
.compatible = "fsl,imx8qm-mek",
.sof_tplg_filename = "sof-imx8-wm8960.tplg",
.drv_name = "asoc-audio-graph-card2",
},
- {}
-};
-
-static struct sof_dev_desc sof_of_imx8qxp_desc = {
- .of_machines = sof_imx8_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
+ {
+ .compatible = "fsl,imx8qm-mek-revd",
+ .sof_tplg_filename = "sof-imx8-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
+ {
+ .compatible = "fsl,imx8qxp-mek-bb",
+ .sof_tplg_filename = "sof-imx8-cs42888.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8x.ri",
+ {
+ .compatible = "fsl,imx8qm-mek-bb",
+ .sof_tplg_filename = "sof-imx8-cs42888.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8x_ops,
-};
-
-static struct sof_dev_desc sof_of_imx8qm_desc = {
- .of_machines = sof_imx8_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
+ {
+ .compatible = "fsl,imx8mp-evk",
+ .sof_tplg_filename = "sof-imx8mp-wm8960.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
+ {
+ .compatible = "fsl,imx8mp-evk-revb4",
+ .sof_tplg_filename = "sof-imx8mp-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8.ri",
+ {
+ .compatible = "fsl,imx8ulp-evk",
+ .sof_tplg_filename = "sof-imx8ulp-btsco.tplg",
+ .drv_name = "asoc-audio-graph-card2",
},
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8_ops,
+ {}
};
+IMX_SOF_DEV_DESC(imx8, sof_imx8_machs, &imx8_chip_info, &sof_imx8_ops, imx8_ops_init);
+IMX_SOF_DEV_DESC(imx8x, sof_imx8_machs, &imx8x_chip_info, &sof_imx8_ops, imx8_ops_init);
+IMX_SOF_DEV_DESC(imx8m, sof_imx8_machs, &imx8m_chip_info, &sof_imx8_ops, imx8_ops_init);
+IMX_SOF_DEV_DESC(imx8ulp, sof_imx8_machs, &imx8ulp_chip_info, &sof_imx8_ops, imx8_ops_init);
+
static const struct of_device_id sof_of_imx8_ids[] = {
- { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc},
- { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc},
+ {
+ .compatible = "fsl,imx8qxp-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8x),
+ },
+ {
+ .compatible = "fsl,imx8qm-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8),
+ },
+ {
+ .compatible = "fsl,imx8mp-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8m),
+ },
+ {
+ .compatible = "fsl,imx8ulp-dsp",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx8ulp),
+ },
{ }
};
MODULE_DEVICE_TABLE(of, sof_of_imx8_ids);
@@ -661,7 +456,7 @@ static struct platform_driver snd_sof_of_imx8_driver = {
.remove = sof_of_remove,
.driver = {
.name = "sof-audio-of-imx8",
- .pm = &sof_of_pm,
+ .pm = pm_ptr(&sof_of_pm),
.of_match_table = sof_of_imx8_ids,
},
};
diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c
deleted file mode 100644
index ff42743efa79..000000000000
--- a/sound/soc/sof/imx/imx8m.c
+++ /dev/null
@@ -1,519 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-//
-// Copyright 2020 NXP
-//
-// Author: Daniel Baluta <daniel.baluta@nxp.com>
-//
-// Hardware interface for audio DSP on i.MX8M
-
-#include <linux/bits.h>
-#include <linux/firmware.h>
-#include <linux/mfd/syscon.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/regmap.h>
-
-#include <linux/module.h>
-#include <sound/sof.h>
-#include <sound/sof/xtensa.h>
-#include <linux/firmware/imx/dsp.h>
-
-#include "../ops.h"
-#include "../sof-of-dev.h"
-#include "imx-common.h"
-
-#define MBOX_OFFSET 0x800000
-#define MBOX_SIZE 0x1000
-
-/* DAP registers */
-#define IMX8M_DAP_DEBUG 0x28800000
-#define IMX8M_DAP_DEBUG_SIZE (64 * 1024)
-#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020)
-#define IMX8M_PWRCTL_CORERESET BIT(16)
-
-/* DSP audio mix registers */
-#define AudioDSP_REG0 0x100
-#define AudioDSP_REG1 0x104
-#define AudioDSP_REG2 0x108
-#define AudioDSP_REG3 0x10c
-
-#define AudioDSP_REG2_RUNSTALL BIT(5)
-
-struct imx8m_priv {
- struct device *dev;
- struct snd_sof_dev *sdev;
-
- /* DSP IPC handler */
- struct imx_dsp_ipc *dsp_ipc;
- struct platform_device *ipc_dev;
-
- struct clk_bulk_data *clks;
- int clk_num;
-
- void __iomem *dap;
- struct regmap *regmap;
-};
-
-static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev)
-{
- return MBOX_OFFSET;
-}
-
-static int imx8m_get_window_offset(struct snd_sof_dev *sdev, u32 id)
-{
- return MBOX_OFFSET;
-}
-
-static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc)
-{
- struct imx8m_priv *priv = imx_dsp_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- snd_sof_ipc_process_reply(priv->sdev, 0);
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc)
-{
- struct imx8m_priv *priv = imx_dsp_get_data(ipc);
- u32 p; /* Panic code */
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
-
- /* Check to see if the message is a panic code (0x0dead***) */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
- snd_sof_dsp_panic(priv->sdev, p, true);
- else
- snd_sof_ipc_msgs_rx(priv->sdev);
-}
-
-static struct imx_dsp_ops imx8m_dsp_ops = {
- .handle_reply = imx8m_dsp_handle_reply,
- .handle_request = imx8m_dsp_handle_request,
-};
-
-static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
-{
- struct imx8m_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
- imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
-
- return 0;
-}
-
-/*
- * DSP control.
- */
-static int imx8m_run(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
-
- regmap_update_bits(priv->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0);
-
- return 0;
-}
-
-static int imx8m_reset(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
- u32 pwrctl;
-
- /* put DSP into reset and stall */
- pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL);
- pwrctl |= IMX8M_PWRCTL_CORERESET;
- writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL);
-
- /* keep reset asserted for 10 cycles */
- usleep_range(1, 2);
-
- regmap_update_bits(priv->regmap, AudioDSP_REG2,
- AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL);
-
- /* take the DSP out of reset and keep stalled for FW loading */
- pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL);
- pwrctl &= ~IMX8M_PWRCTL_CORERESET;
- writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL);
-
- return 0;
-}
-
-static int imx8m_probe(struct snd_sof_dev *sdev)
-{
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
- struct device_node *np = pdev->dev.of_node;
- struct device_node *res_node;
- struct resource *mmio;
- struct imx8m_priv *priv;
- struct resource res;
- u32 base, size;
- int ret = 0;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- sdev->num_cores = 1;
- sdev->pdata->hw_pdata = priv;
- priv->dev = sdev->dev;
- priv->sdev = sdev;
-
- priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
- PLATFORM_DEVID_NONE,
- pdev, sizeof(*pdev));
- if (IS_ERR(priv->ipc_dev))
- return PTR_ERR(priv->ipc_dev);
-
- priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
- if (!priv->dsp_ipc) {
- /* DSP IPC driver not probed yet, try later */
- ret = -EPROBE_DEFER;
- dev_err(sdev->dev, "Failed to get drvdata\n");
- goto exit_pdev_unregister;
- }
-
- imx_dsp_set_data(priv->dsp_ipc, priv);
- priv->dsp_ipc->ops = &imx8m_dsp_ops;
-
- /* DSP base */
- mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mmio) {
- base = mmio->start;
- size = resource_size(mmio);
- } else {
- dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
- ret = -EINVAL;
- goto exit_pdev_unregister;
- }
-
- priv->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE);
- if (!priv->dap) {
- dev_err(sdev->dev, "error: failed to map DAP debug memory area");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
- if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
- dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
- base, size);
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
- sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
-
- res_node = of_parse_phandle(np, "memory-region", 0);
- if (!res_node) {
- dev_err(&pdev->dev, "failed to get memory region node\n");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
-
- ret = of_address_to_resource(res_node, 0, &res);
- of_node_put(res_node);
- if (ret) {
- dev_err(&pdev->dev, "failed to get reserved region address\n");
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- resource_size(&res));
- if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
- dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
- base, size);
- ret = -ENOMEM;
- goto exit_pdev_unregister;
- }
- sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
-
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
-
- priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl");
- if (IS_ERR(priv->regmap)) {
- dev_err(sdev->dev, "cannot find dsp-ctrl registers");
- ret = PTR_ERR(priv->regmap);
- goto exit_pdev_unregister;
- }
-
- ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
- priv->clk_num = ret;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
-
- return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
- return ret;
-}
-
-static void imx8m_remove(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = sdev->pdata->hw_pdata;
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-}
-
-/* on i.MX8 there is 1 to 1 match between type and BAR idx */
-static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- /* Only IRAM and SRAM bars are valid */
- switch (type) {
- case SOF_FW_BLK_TYPE_IRAM:
- case SOF_FW_BLK_TYPE_SRAM:
- return type;
- default:
- return -EINVAL;
- }
-}
-
-static struct snd_soc_dai_driver imx8m_dai[] = {
-{
- .name = "sai1",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "sai3",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
-},
-{
- .name = "micfil",
- .capture = {
- .channels_min = 1,
- .channels_max = 8,
- },
-},
-};
-
-static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev,
- const struct sof_dsp_power_state *target_state)
-{
- sdev->dsp_power_state = *target_state;
-
- return 0;
-}
-
-static int imx8m_resume(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
- int ret;
- int i;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_request_channel(priv->dsp_ipc, i);
-
- return 0;
-}
-
-static void imx8m_suspend(struct snd_sof_dev *sdev)
-{
- struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata;
- int i;
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
-}
-
-static int imx8m_dsp_runtime_resume(struct snd_sof_dev *sdev)
-{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
-
- ret = imx8m_resume(sdev);
- if (ret < 0)
- return ret;
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8m_dsp_runtime_suspend(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D3,
- };
-
- imx8m_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8m_dsp_resume(struct snd_sof_dev *sdev)
-{
- int ret;
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- };
-
- ret = imx8m_resume(sdev);
- if (ret < 0)
- return ret;
-
- if (pm_runtime_suspended(sdev->dev)) {
- pm_runtime_disable(sdev->dev);
- pm_runtime_set_active(sdev->dev);
- pm_runtime_mark_last_busy(sdev->dev);
- pm_runtime_enable(sdev->dev);
- pm_runtime_idle(sdev->dev);
- }
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = target_state,
- };
-
- if (!pm_runtime_suspended(sdev->dev))
- imx8m_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-/* i.MX8 ops */
-static const struct snd_sof_dsp_ops sof_imx8m_ops = {
- /* probe and remove */
- .probe = imx8m_probe,
- .remove = imx8m_remove,
- /* DSP core boot */
- .run = imx8m_run,
- .reset = imx8m_reset,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
-
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
-
- /* ipc */
- .send_msg = imx8m_send_msg,
- .get_mailbox_offset = imx8m_get_mailbox_offset,
- .get_window_offset = imx8m_get_window_offset,
-
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
-
- .get_bar_index = imx8m_get_bar_index,
-
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
-
- /* Debug information */
- .dbg_dump = imx8_dump,
- .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem,
-
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
-
- /* DAI drivers */
- .drv = imx8m_dai,
- .num_drv = ARRAY_SIZE(imx8m_dai),
-
- .suspend = imx8m_dsp_suspend,
- .resume = imx8m_dsp_resume,
-
- .runtime_suspend = imx8m_dsp_runtime_suspend,
- .runtime_resume = imx8m_dsp_runtime_resume,
-
- .set_power_state = imx8m_dsp_set_power_state,
-
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
-};
-
-static struct snd_sof_of_mach sof_imx8mp_machs[] = {
- {
- .compatible = "fsl,imx8mp-evk",
- .sof_tplg_filename = "sof-imx8mp-wm8960.tplg",
- .drv_name = "asoc-audio-graph-card2",
- },
- {}
-};
-
-static struct sof_dev_desc sof_of_imx8mp_desc = {
- .of_machines = sof_imx8mp_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
- },
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
- },
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8m.ri",
- },
- .nocodec_tplg_filename = "sof-imx8-nocodec.tplg",
- .ops = &sof_imx8m_ops,
-};
-
-static const struct of_device_id sof_of_imx8m_ids[] = {
- { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc},
- { }
-};
-MODULE_DEVICE_TABLE(of, sof_of_imx8m_ids);
-
-/* DT driver definition */
-static struct platform_driver snd_sof_of_imx8m_driver = {
- .probe = sof_of_probe,
- .remove = sof_of_remove,
- .driver = {
- .name = "sof-audio-of-imx8m",
- .pm = &sof_of_pm,
- .of_match_table = sof_of_imx8m_ids,
- },
-};
-module_platform_driver(snd_sof_of_imx8m_driver);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("SOF support for IMX8M platforms");
-MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c
deleted file mode 100644
index 6965791ab6ef..000000000000
--- a/sound/soc/sof/imx/imx8ulp.c
+++ /dev/null
@@ -1,521 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
-//
-// Copyright 2021-2022 NXP
-//
-// Author: Peng Zhang <peng.zhang_8@nxp.com>
-//
-// Hardware interface for audio DSP on i.MX8ULP
-
-#include <linux/arm-smccc.h>
-#include <linux/clk.h>
-#include <linux/firmware.h>
-#include <linux/firmware/imx/dsp.h>
-#include <linux/firmware/imx/ipc.h>
-#include <linux/firmware/imx/svc/misc.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/of_reserved_mem.h>
-
-#include <sound/sof.h>
-#include <sound/sof/xtensa.h>
-
-#include "../ops.h"
-#include "../sof-of-dev.h"
-#include "imx-common.h"
-
-#define FSL_SIP_HIFI_XRDC 0xc200000e
-
-/* SIM Domain register */
-#define SYSCTRL0 0x8
-#define EXECUTE_BIT BIT(13)
-#define RESET_BIT BIT(16)
-#define HIFI4_CLK_BIT BIT(17)
-#define PB_CLK_BIT BIT(18)
-#define PLAT_CLK_BIT BIT(19)
-#define DEBUG_LOGIC_BIT BIT(25)
-
-#define MBOX_OFFSET 0x800000
-#define MBOX_SIZE 0x1000
-
-struct imx8ulp_priv {
- struct device *dev;
- struct snd_sof_dev *sdev;
-
- /* DSP IPC handler */
- struct imx_dsp_ipc *dsp_ipc;
- struct platform_device *ipc_dev;
-
- struct regmap *regmap;
- struct clk_bulk_data *clks;
- int clk_num;
-};
-
-static void imx8ulp_sim_lpav_start(struct imx8ulp_priv *priv)
-{
- /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */
- regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, 0);
-
- /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/
- regmap_update_bits(priv->regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0);
-
- /* Stall HIFI4 DSP Execution: 1 stall, 0 run */
- regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, 0);
-}
-
-static int imx8ulp_get_mailbox_offset(struct snd_sof_dev *sdev)
-{
- return MBOX_OFFSET;
-}
-
-static int imx8ulp_get_window_offset(struct snd_sof_dev *sdev, u32 id)
-{
- return MBOX_OFFSET;
-}
-
-static void imx8ulp_dsp_handle_reply(struct imx_dsp_ipc *ipc)
-{
- struct imx8ulp_priv *priv = imx_dsp_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
-
- snd_sof_ipc_process_reply(priv->sdev, 0);
-
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void imx8ulp_dsp_handle_request(struct imx_dsp_ipc *ipc)
-{
- struct imx8ulp_priv *priv = imx_dsp_get_data(ipc);
- u32 p; /* panic code */
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p));
-
- /* Check to see if the message is a panic code (0x0dead***) */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC)
- snd_sof_dsp_panic(priv->sdev, p, true);
- else
- snd_sof_ipc_msgs_rx(priv->sdev);
-}
-
-static struct imx_dsp_ops dsp_ops = {
- .handle_reply = imx8ulp_dsp_handle_reply,
- .handle_request = imx8ulp_dsp_handle_request,
-};
-
-static int imx8ulp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
- imx_dsp_ring_doorbell(priv->dsp_ipc, 0);
-
- return 0;
-}
-
-static int imx8ulp_run(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- imx8ulp_sim_lpav_start(priv);
-
- return 0;
-}
-
-static int imx8ulp_reset(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
- struct arm_smccc_res smc_resource;
-
- /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */
- regmap_update_bits(priv->regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT);
-
- /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */
- regmap_update_bits(priv->regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT);
-
- /* HiFi4 Clock Enable: 1 enabled, 0 disabled */
- regmap_update_bits(priv->regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT);
-
- regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, RESET_BIT);
- usleep_range(1, 2);
-
- /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */
- regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT);
- usleep_range(1, 2);
-
- arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_resource);
-
- return 0;
-}
-
-static int imx8ulp_probe(struct snd_sof_dev *sdev)
-{
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
- struct device_node *np = pdev->dev.of_node;
- struct device_node *res_node;
- struct resource *mmio;
- struct imx8ulp_priv *priv;
- struct resource res;
- u32 base, size;
- int ret = 0;
-
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- sdev->num_cores = 1;
- sdev->pdata->hw_pdata = priv;
- priv->dev = sdev->dev;
- priv->sdev = sdev;
-
- /* System integration module(SIM) control dsp configuration */
- priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl");
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
-
- priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp",
- PLATFORM_DEVID_NONE,
- pdev, sizeof(*pdev));
- if (IS_ERR(priv->ipc_dev))
- return PTR_ERR(priv->ipc_dev);
-
- priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev);
- if (!priv->dsp_ipc) {
- /* DSP IPC driver not probed yet, try later */
- ret = -EPROBE_DEFER;
- dev_err(sdev->dev, "Failed to get drvdata\n");
- goto exit_pdev_unregister;
- }
-
- imx_dsp_set_data(priv->dsp_ipc, priv);
- priv->dsp_ipc->ops = &dsp_ops;
-
- /* DSP base */
- mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mmio) {
- base = mmio->start;
- size = resource_size(mmio);
- } else {
- dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n");
- ret = -EINVAL;
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size);
- if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) {
- dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n",
- base, size);
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
- sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM;
-
- res_node = of_parse_phandle(np, "memory-reserved", 0);
- if (!res_node) {
- dev_err(&pdev->dev, "failed to get memory region node\n");
- ret = -ENODEV;
- goto exit_pdev_unregister;
- }
-
- ret = of_address_to_resource(res_node, 0, &res);
- of_node_put(res_node);
- if (ret) {
- dev_err(&pdev->dev, "failed to get reserved region address\n");
- goto exit_pdev_unregister;
- }
-
- sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start,
- resource_size(&res));
- if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) {
- dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n",
- base, size);
- ret = -ENOMEM;
- goto exit_pdev_unregister;
- }
- sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM;
-
- /* set default mailbox offset for FW ready message */
- sdev->dsp_box.offset = MBOX_OFFSET;
-
- ret = of_reserved_mem_device_init(sdev->dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to init reserved memory region %d\n", ret);
- goto exit_pdev_unregister;
- }
-
- ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
- priv->clk_num = ret;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- goto exit_pdev_unregister;
- }
-
- return 0;
-
-exit_pdev_unregister:
- platform_device_unregister(priv->ipc_dev);
-
- return ret;
-}
-
-static void imx8ulp_remove(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = sdev->pdata->hw_pdata;
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
- platform_device_unregister(priv->ipc_dev);
-}
-
-/* on i.MX8 there is 1 to 1 match between type and BAR idx */
-static int imx8ulp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- return type;
-}
-
-static int imx8ulp_suspend(struct snd_sof_dev *sdev)
-{
- int i;
- struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata;
-
- /*Stall DSP, release in .run() */
- regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT);
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_free_channel(priv->dsp_ipc, i);
-
- clk_bulk_disable_unprepare(priv->clk_num, priv->clks);
-
- return 0;
-}
-
-static int imx8ulp_resume(struct snd_sof_dev *sdev)
-{
- struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata;
- int i, ret;
-
- ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks);
- if (ret < 0) {
- dev_err(sdev->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < DSP_MU_CHAN_NUM; i++)
- imx_dsp_request_channel(priv->dsp_ipc, i);
-
- return 0;
-}
-
-static int imx8ulp_dsp_runtime_resume(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- .substate = 0,
- };
-
- imx8ulp_resume(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8ulp_dsp_runtime_suspend(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D3,
- .substate = 0,
- };
-
- imx8ulp_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8ulp_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = target_state,
- .substate = 0,
- };
-
- if (!pm_runtime_suspended(sdev->dev))
- imx8ulp_suspend(sdev);
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static int imx8ulp_dsp_resume(struct snd_sof_dev *sdev)
-{
- const struct sof_dsp_power_state target_dsp_state = {
- .state = SOF_DSP_PM_D0,
- .substate = 0,
- };
-
- imx8ulp_resume(sdev);
-
- if (pm_runtime_suspended(sdev->dev)) {
- pm_runtime_disable(sdev->dev);
- pm_runtime_set_active(sdev->dev);
- pm_runtime_mark_last_busy(sdev->dev);
- pm_runtime_enable(sdev->dev);
- pm_runtime_idle(sdev->dev);
- }
-
- return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
-}
-
-static struct snd_soc_dai_driver imx8ulp_dai[] = {
- {
- .name = "sai5",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
- },
- {
- .name = "sai6",
- .playback = {
- .channels_min = 1,
- .channels_max = 32,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 32,
- },
- },
-};
-
-static int imx8ulp_dsp_set_power_state(struct snd_sof_dev *sdev,
- const struct sof_dsp_power_state *target_state)
-{
- sdev->dsp_power_state = *target_state;
-
- return 0;
-}
-
-/* i.MX8 ops */
-static const struct snd_sof_dsp_ops sof_imx8ulp_ops = {
- /* probe and remove */
- .probe = imx8ulp_probe,
- .remove = imx8ulp_remove,
- /* DSP core boot */
- .run = imx8ulp_run,
- .reset = imx8ulp_reset,
-
- /* Block IO */
- .block_read = sof_block_read,
- .block_write = sof_block_write,
-
- /* Module IO */
- .read64 = sof_io_read64,
-
- /* Mailbox IO */
- .mailbox_read = sof_mailbox_read,
- .mailbox_write = sof_mailbox_write,
-
- /* ipc */
- .send_msg = imx8ulp_send_msg,
- .get_mailbox_offset = imx8ulp_get_mailbox_offset,
- .get_window_offset = imx8ulp_get_window_offset,
-
- .ipc_msg_data = sof_ipc_msg_data,
- .set_stream_data_offset = sof_set_stream_data_offset,
-
- /* stream callbacks */
- .pcm_open = sof_stream_pcm_open,
- .pcm_close = sof_stream_pcm_close,
-
- /* module loading */
- .get_bar_index = imx8ulp_get_bar_index,
- /* firmware loading */
- .load_firmware = snd_sof_load_firmware_memcpy,
-
- /* Debug information */
- .dbg_dump = imx8_dump,
-
- /* Firmware ops */
- .dsp_arch_ops = &sof_xtensa_arch_ops,
-
- /* DAI drivers */
- .drv = imx8ulp_dai,
- .num_drv = ARRAY_SIZE(imx8ulp_dai),
-
- /* ALSA HW info flags */
- .hw_info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
-
- /* PM */
- .runtime_suspend = imx8ulp_dsp_runtime_suspend,
- .runtime_resume = imx8ulp_dsp_runtime_resume,
-
- .suspend = imx8ulp_dsp_suspend,
- .resume = imx8ulp_dsp_resume,
-
- .set_power_state = imx8ulp_dsp_set_power_state,
-};
-
-static struct snd_sof_of_mach sof_imx8ulp_machs[] = {
- {
- .compatible = "fsl,imx8ulp-evk",
- .sof_tplg_filename = "sof-imx8ulp-btsco.tplg",
- .drv_name = "asoc-audio-graph-card2",
- },
- {}
-};
-
-static struct sof_dev_desc sof_of_imx8ulp_desc = {
- .of_machines = sof_imx8ulp_machs,
- .ipc_supported_mask = BIT(SOF_IPC_TYPE_3),
- .ipc_default = SOF_IPC_TYPE_3,
- .default_fw_path = {
- [SOF_IPC_TYPE_3] = "imx/sof",
- },
- .default_tplg_path = {
- [SOF_IPC_TYPE_3] = "imx/sof-tplg",
- },
- .default_fw_filename = {
- [SOF_IPC_TYPE_3] = "sof-imx8ulp.ri",
- },
- .nocodec_tplg_filename = "sof-imx8ulp-nocodec.tplg",
- .ops = &sof_imx8ulp_ops,
-};
-
-static const struct of_device_id sof_of_imx8ulp_ids[] = {
- { .compatible = "fsl,imx8ulp-dsp", .data = &sof_of_imx8ulp_desc},
- { }
-};
-MODULE_DEVICE_TABLE(of, sof_of_imx8ulp_ids);
-
-/* DT driver definition */
-static struct platform_driver snd_sof_of_imx8ulp_driver = {
- .probe = sof_of_probe,
- .remove = sof_of_remove,
- .driver = {
- .name = "sof-audio-of-imx8ulp",
- .pm = &sof_of_pm,
- .of_match_table = sof_of_imx8ulp_ids,
- },
-};
-module_platform_driver(snd_sof_of_imx8ulp_driver);
-
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DESCRIPTION("SOF support for IMX8ULP platforms");
-MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
diff --git a/sound/soc/sof/imx/imx9.c b/sound/soc/sof/imx/imx9.c
new file mode 100644
index 000000000000..853155d5990a
--- /dev/null
+++ b/sound/soc/sof/imx/imx9.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/arm-smccc.h>
+
+#include "imx-common.h"
+
+#define IMX_SIP_SRC 0xC2000005
+#define IMX_SIP_SRC_M_RESET_ADDR_SET 0x03
+
+#define IMX95_CPU_VEC_FLAGS_BOOT BIT(29)
+
+#define IMX_SIP_LMM 0xC200000F
+#define IMX_SIP_LMM_BOOT 0x0
+#define IMX_SIP_LMM_SHUTDOWN 0x1
+
+#define IMX95_M7_LM_ID 0x1
+
+static struct snd_soc_dai_driver imx95_dai[] = {
+ IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32),
+};
+
+static struct snd_sof_dsp_ops sof_imx9_ops;
+
+static int imx95_ops_init(struct snd_sof_dev *sdev)
+{
+ /* first copy from template */
+ memcpy(&sof_imx9_ops, &sof_imx_ops, sizeof(sof_imx_ops));
+
+ /* ... and finally set DAI driver */
+ sof_imx9_ops.drv = get_chip_info(sdev)->drv;
+ sof_imx9_ops.num_drv = get_chip_info(sdev)->num_drv;
+
+ return 0;
+}
+
+static int imx95_chip_probe(struct snd_sof_dev *sdev)
+{
+ struct arm_smccc_res smc_res;
+ struct platform_device *pdev;
+ struct resource *res;
+
+ pdev = to_platform_device(sdev->dev);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
+ if (!res)
+ return dev_err_probe(sdev->dev, -ENODEV,
+ "failed to fetch SRAM region\n");
+
+ /* set core boot reset address */
+ arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M_RESET_ADDR_SET, res->start,
+ IMX95_CPU_VEC_FLAGS_BOOT, 0, 0, 0, 0, &smc_res);
+
+ return smc_res.a0;
+}
+
+static int imx95_core_kick(struct snd_sof_dev *sdev)
+{
+ struct arm_smccc_res smc_res;
+
+ arm_smccc_smc(IMX_SIP_LMM, IMX_SIP_LMM_BOOT,
+ IMX95_M7_LM_ID, 0, 0, 0, 0, 0, &smc_res);
+
+ return smc_res.a0;
+}
+
+static int imx95_core_shutdown(struct snd_sof_dev *sdev)
+{
+ struct arm_smccc_res smc_res;
+
+ arm_smccc_smc(IMX_SIP_LMM, IMX_SIP_LMM_SHUTDOWN,
+ IMX95_M7_LM_ID, 0, 0, 0, 0, 0, &smc_res);
+
+ return smc_res.a0;
+}
+
+static const struct imx_chip_ops imx95_chip_ops = {
+ .probe = imx95_chip_probe,
+ .core_kick = imx95_core_kick,
+ .core_shutdown = imx95_core_shutdown,
+};
+
+static struct imx_memory_info imx95_memory_regions[] = {
+ { .name = "sram", .reserved = false },
+ { }
+};
+
+static const struct imx_chip_info imx95_chip_info = {
+ .ipc_info = {
+ .boot_mbox_offset = 0x6001000,
+ .window_offset = 0x6000000,
+ },
+ .has_dma_reserved = true,
+ .memory = imx95_memory_regions,
+ .drv = imx95_dai,
+ .num_drv = ARRAY_SIZE(imx95_dai),
+ .ops = &imx95_chip_ops,
+};
+
+static struct snd_sof_of_mach sof_imx9_machs[] = {
+ {
+ .compatible = "fsl,imx95-19x19-evk",
+ .sof_tplg_filename = "sof-imx95-wm8962.tplg",
+ .drv_name = "asoc-audio-graph-card2",
+ },
+ {
+ }
+};
+
+IMX_SOF_DEV_DESC(imx95, sof_imx9_machs, &imx95_chip_info, &sof_imx9_ops, imx95_ops_init);
+
+static const struct of_device_id sof_of_imx9_ids[] = {
+ {
+ .compatible = "fsl,imx95-cm7-sof",
+ .data = &IMX_SOF_DEV_DESC_NAME(imx95),
+ },
+ {
+ },
+};
+MODULE_DEVICE_TABLE(of, sof_of_imx9_ids);
+
+static struct platform_driver snd_sof_of_imx9_driver = {
+ .probe = sof_of_probe,
+ .remove = sof_of_remove,
+ .driver = {
+ .name = "sof-audio-of-imx9",
+ .pm = pm_ptr(&sof_of_pm),
+ .of_match_table = sof_of_imx9_ids,
+ },
+};
+module_platform_driver(snd_sof_of_imx9_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF driver for imx9 platforms");
+MODULE_AUTHOR("Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>");
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index f40daa616803..675f9fc92dde 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -34,7 +34,7 @@ snd-sof-pci-intel-icl-y := pci-icl.o icl.o
snd-sof-pci-intel-tgl-y := pci-tgl.o tgl.o
snd-sof-pci-intel-mtl-y := pci-mtl.o mtl.o
snd-sof-pci-intel-lnl-y := pci-lnl.o lnl.o
-snd-sof-pci-intel-ptl-y := pci-ptl.o
+snd-sof-pci-intel-ptl-y := pci-ptl.o ptl.o
obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o
diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c
index 30e981c558c6..0d364bcdcfa9 100644
--- a/sound/soc/sof/intel/atom.c
+++ b/sound/soc/sof/intel/atom.c
@@ -78,20 +78,20 @@ void atom_dump(struct snd_sof_dev *sdev, u32 flags)
imrd = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IMRD);
dev_err(sdev->dev,
"error: ipc host -> DSP: pending %s complete %s raw 0x%llx\n",
- (panic & SHIM_IPCX_BUSY) ? "yes" : "no",
- (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic);
+ str_yes_no(panic & SHIM_IPCX_BUSY),
+ str_yes_no(panic & SHIM_IPCX_DONE), panic);
dev_err(sdev->dev,
"error: mask host: pending %s complete %s raw 0x%llx\n",
- (imrx & SHIM_IMRX_BUSY) ? "yes" : "no",
- (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx);
+ str_yes_no(imrx & SHIM_IMRX_BUSY),
+ str_yes_no(imrx & SHIM_IMRX_DONE), imrx);
dev_err(sdev->dev,
"error: ipc DSP -> host: pending %s complete %s raw 0x%llx\n",
- (status & SHIM_IPCD_BUSY) ? "yes" : "no",
- (status & SHIM_IPCD_DONE) ? "yes" : "no", status);
+ str_yes_no(status & SHIM_IPCD_BUSY),
+ str_yes_no(status & SHIM_IPCD_DONE), status);
dev_err(sdev->dev,
"error: mask DSP: pending %s complete %s raw 0x%llx\n",
- (imrd & SHIM_IMRD_BUSY) ? "yes" : "no",
- (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd);
+ str_yes_no(imrd & SHIM_IMRD_BUSY),
+ str_yes_no(imrd & SHIM_IMRD_DONE), imrd);
}
EXPORT_SYMBOL_NS(atom_dump, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index c4d92f3508b6..f1287d509835 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -266,20 +266,20 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags)
imrd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRD);
dev_err(sdev->dev,
"error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n",
- (panic & SHIM_IPCX_BUSY) ? "yes" : "no",
- (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic);
+ str_yes_no(panic & SHIM_IPCX_BUSY),
+ str_yes_no(panic & SHIM_IPCX_DONE), panic);
dev_err(sdev->dev,
"error: mask host: pending %s complete %s raw 0x%8.8x\n",
- (imrx & SHIM_IMRX_BUSY) ? "yes" : "no",
- (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx);
+ str_yes_no(imrx & SHIM_IMRX_BUSY),
+ str_yes_no(imrx & SHIM_IMRX_DONE), imrx);
dev_err(sdev->dev,
"error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n",
- (status & SHIM_IPCD_BUSY) ? "yes" : "no",
- (status & SHIM_IPCD_DONE) ? "yes" : "no", status);
+ str_yes_no(status & SHIM_IPCD_BUSY),
+ str_yes_no(status & SHIM_IPCD_DONE), status);
dev_err(sdev->dev,
"error: mask DSP: pending %s complete %s raw 0x%8.8x\n",
- (imrd & SHIM_IMRD_BUSY) ? "yes" : "no",
- (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd);
+ str_yes_no(imrd & SHIM_IMRD_BUSY),
+ str_yes_no(imrd & SHIM_IMRD_DONE), imrd);
}
/*
@@ -410,8 +410,7 @@ static int bdw_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct sof_dev_desc *desc = pdata->desc;
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
const struct sof_intel_dsp_desc *chip;
struct resource *mmio;
u32 base, size;
@@ -687,7 +686,7 @@ static struct platform_driver snd_sof_acpi_intel_bdw_driver = {
.remove = sof_acpi_remove,
.driver = {
.name = "sof-audio-acpi-intel-bdw",
- .pm = &sof_acpi_pm,
+ .pm = pm_ptr(&sof_acpi_pm),
.acpi_match_table = sof_broadwell_match,
},
};
@@ -695,6 +694,5 @@ module_platform_driver(snd_sof_acpi_intel_bdw_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Broadwell platforms");
-MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC");
MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV");
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 536d4c89d2f0..18208f77b84d 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -109,8 +109,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct sof_dev_desc *desc = pdata->desc;
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
const struct sof_intel_dsp_desc *chip;
struct resource *mmio;
u32 base, size;
@@ -468,7 +467,7 @@ static struct platform_driver snd_sof_acpi_intel_byt_driver = {
.remove = sof_acpi_remove,
.driver = {
.name = "sof-audio-acpi-intel-byt",
- .pm = &sof_acpi_pm,
+ .pm = pm_ptr(&sof_acpi_pm),
.acpi_match_table = sof_baytrail_match,
},
};
@@ -476,7 +475,6 @@ module_platform_driver(snd_sof_acpi_intel_byt_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Baytrail/Cherrytrail");
-MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC");
MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index 568f3dfe822f..2f9925830d1d 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -454,6 +454,7 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
}
EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
+MODULE_SOFTDEP("pre: snd-hda-codec-hdmi");
#endif
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 0db2a3e554fb..883d0d3bae9e 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -318,7 +318,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
ret = hda_link_dma_cleanup(substream, hext_stream, dai,
- cmd == SNDRV_PCM_TRIGGER_STOP ? false : true);
+ cmd != SNDRV_PCM_TRIGGER_STOP);
if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
return ret;
@@ -503,6 +503,12 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
int ret;
int i;
+ if (!w) {
+ dev_err(cpu_dai->dev, "%s widget not found, check amp link num in the topology\n",
+ cpu_dai->name);
+ return -EINVAL;
+ }
+
ops = hda_dai_get_ops(substream, cpu_dai);
if (!ops) {
dev_err(cpu_dai->dev, "DAI widget ops not set\n");
@@ -582,6 +588,12 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
*/
for_each_rtd_cpu_dais(rtd, i, dai) {
w = snd_soc_dai_get_widget(dai, substream->stream);
+ if (!w) {
+ dev_err(cpu_dai->dev,
+ "%s widget not found, check amp link num in the topology\n",
+ dai->name);
+ return -EINVAL;
+ }
ipc4_copier = widget_to_copier(w);
memcpy(&ipc4_copier->dma_config_tlv[cpu_dai_id], dma_config_tlv,
sizeof(*dma_config_tlv));
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index fe627bcb0531..ce561fe52bd5 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -16,6 +16,7 @@
#include <linux/bitfield.h>
#include <linux/module.h>
+#include <linux/string_choices.h>
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
@@ -42,6 +43,7 @@
* @shim_offset: offset to SHIM register base
* @ip_offset: offset to IP register base
* @shim_vs_offset: offset to vendor-specific (VS) SHIM base
+ * @mic_privacy_mask: bitmask of sublinks where mic privacy is applied
*/
struct hdac_ext2_link {
struct hdac_ext_link hext_link;
@@ -65,6 +67,8 @@ struct hdac_ext2_link {
u32 shim_offset;
u32 ip_offset;
u32 shim_vs_offset;
+
+ unsigned long mic_privacy_mask;
};
#define hdac_ext_link_to_ext2(h) container_of(h, struct hdac_ext2_link, hext_link)
@@ -90,6 +94,13 @@ struct hdac_ext2_link {
#define AZX_REG_INTEL_UAOL_IP_OFFSET 0x100
#define AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET 0xC00
+/* Microphone privacy */
+#define AZX_REG_INTEL_VS_SHIM_PVCCS 0x10
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE BIT(0)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG BIT(8)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS BIT(9)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_FMDIS BIT(10)
+
/* HDAML section - this part follows sequences in the hardware specification,
* including naming conventions and the use of the hdaml_ prefix.
* The code is intentionally minimal with limited dependencies on frameworks or
@@ -696,6 +707,20 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid,
}
ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
+ if ((h2link->mic_privacy_mask & BIT(sublink)) && !ret) {
+ u16 __iomem *pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ sublink * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+ u16 val = readw(pvccs);
+
+ writew(val | AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
+
+ if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS)
+ dev_dbg(bus->dev,
+ "sublink %d (%d:%d): Mic privacy is enabled\n",
+ sublink, alt, elid);
+ }
skip_init:
if (eml_lock)
@@ -742,6 +767,16 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid
if (--h2link->sublink_ref_count[sublink] > 0)
goto skip_shutdown;
}
+
+ if (h2link->mic_privacy_mask & BIT(sublink)) {
+ u16 __iomem *pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ sublink * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+ writew(readw(pvccs) & ~AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
+ }
+
ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
skip_shutdown:
@@ -987,6 +1022,98 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e
}
EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, "SND_SOC_SOF_HDA_MLINK");
+void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
+ unsigned long mask)
+{
+ struct hdac_ext2_link *h2link;
+
+ if (!mask)
+ return;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return;
+
+ if (__fls(mask) > h2link->slcount) {
+ dev_warn(bus->dev,
+ "%s: invalid sublink mask for %d:%d, slcount %d: %#lx\n",
+ __func__, alt, elid, h2link->slcount, mask);
+ return;
+ }
+
+ dev_dbg(bus->dev, "sublink mask for %d:%d, slcount %d: %#lx\n", alt,
+ elid, h2link->slcount, mask);
+
+ h2link->mic_privacy_mask = mask;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_set_mic_privacy_mask, "SND_SOC_SOF_HDA_MLINK");
+
+bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid)
+{
+ struct hdac_ext2_link *h2link;
+ bool changed = false;
+ u16 __iomem *pvccs;
+ int i;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return false;
+
+ /* The change in privacy state needs to be acked for each link */
+ for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
+ u16 val;
+
+ if (h2link->sublink_ref_count[i] == 0)
+ continue;
+
+ pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ i * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+ val = readw(pvccs);
+ if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG) {
+ writew(val, pvccs);
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_is_mic_privacy_changed, "SND_SOC_SOF_HDA_MLINK");
+
+bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid)
+{
+ struct hdac_ext2_link *h2link;
+ u16 __iomem *pvccs;
+ bool state;
+ int i;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return false;
+
+ for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
+ if (h2link->sublink_ref_count[i] == 0)
+ continue;
+
+ /* Return the privacy state from the first active link */
+ pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ i * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+ state = readw(pvccs) & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS;
+ dev_dbg(bus->dev, "alt: %d, elid: %d: Mic privacy is %s\n", alt,
+ elid, str_enabled_disabled(state));
+
+ return state;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_mic_privacy_state, "SND_SOC_SOF_HDA_MLINK");
+
#endif
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 5b5e484f9acf..1dd8d2092c3b 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -37,6 +37,11 @@ static bool hda_disable_rewinds;
module_param_named(disable_rewinds, hda_disable_rewinds, bool, 0444);
MODULE_PARM_DESC(disable_rewinds, "SOF HDA disable rewinds");
+static int hda_force_pause_support = -1;
+module_param_named(force_pause_support, hda_force_pause_support, int, 0444);
+MODULE_PARM_DESC(force_pause_support,
+ "Pause support: -1: Use default, 0: Disable, 1: Enable (default -1)");
+
u32 hda_dsp_get_mult_div(struct snd_sof_dev *sdev, int rate)
{
switch (rate) {
@@ -240,6 +245,16 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
if (hda_always_enable_dmi_l1 && direction == SNDRV_PCM_STREAM_CAPTURE)
runtime->hw.info &= ~SNDRV_PCM_INFO_PAUSE;
+ /*
+ * Do not advertise the PAUSE support if it is forced to be disabled via
+ * module parameter or if the pause_supported is false for the PCM
+ * device
+ */
+ if (hda_force_pause_support == 0 ||
+ (hda_force_pause_support == -1 &&
+ !spcm->stream[substream->stream].pause_supported))
+ runtime->hw.info &= ~SNDRV_PCM_INFO_PAUSE;
+
if (hda_always_enable_dmi_l1 ||
direction == SNDRV_PCM_STREAM_PLAYBACK ||
spcm->stream[substream->stream].d0i3_compatible)
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index f991785f727e..6b1ada566476 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -63,6 +63,11 @@ static int sdw_params_stream(struct device *dev,
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, params_data->substream->stream);
struct snd_sof_dai_config_data data = { 0 };
+ if (!w) {
+ dev_err(dev, "%s widget not found, check amp link num in the topology\n",
+ d->name);
+ return -EINVAL;
+ }
data.dai_index = (params_data->link_id << 8) | d->id;
data.dai_data = params_data->alh_stream_id;
data.dai_node_id = data.dai_data;
@@ -347,6 +352,27 @@ void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev)
}
EXPORT_SYMBOL_NS(hda_sdw_process_wakeen_common, "SND_SOC_SOF_INTEL_HDA_GENERIC");
+static bool hda_dsp_sdw_check_mic_privacy_irq(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->check_mic_privacy_irq)
+ return chip->check_mic_privacy_irq(sdev, true,
+ AZX_REG_ML_LEPTR_ID_SDW);
+
+ return false;
+}
+
+static void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->process_mic_privacy)
+ chip->process_mic_privacy(sdev, true, AZX_REG_ML_LEPTR_ID_SDW);
+}
+
#else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
{
@@ -378,6 +404,13 @@ static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
return false;
}
+static inline bool hda_dsp_sdw_check_mic_privacy_irq(struct snd_sof_dev *sdev)
+{
+ return false;
+}
+
+static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { }
+
#endif /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
/* pre fw run operations */
@@ -673,7 +706,13 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
if (hda_dsp_check_sdw_irq(sdev)) {
trace_sof_intel_hda_irq(sdev, "sdw");
+
hda_dsp_sdw_thread(irq, hdev->sdw);
+
+ if (hda_dsp_sdw_check_mic_privacy_irq(sdev)) {
+ trace_sof_intel_hda_irq(sdev, "mic privacy");
+ hda_dsp_sdw_process_mic_privacy(sdev);
+ }
}
if (hda_sdw_check_wakeen_irq(sdev)) {
@@ -1307,22 +1346,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
- if (sdw_mach_found) {
- /*
- * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
- * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
- * if all conditions are true:
- * a) 2 or fewer links are used by SoundWire
- * b) the NHLT table reports the presence of microphones
- */
- if (hweight_long(mach->link_mask) <= 2)
- dmic_fixup = true;
- else
- mach->mach_params.dmic_num = 0;
- } else {
- if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER)
- dmic_fixup = true;
- }
+ if (sdw_mach_found || mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER)
+ dmic_fixup = true;
if (tplg_fixup &&
dmic_fixup &&
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index ee4ccc1a5490..76154627fc17 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -913,10 +913,6 @@ extern struct snd_sof_dsp_ops sof_tgl_ops;
int sof_tgl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_icl_ops;
int sof_icl_ops_init(struct snd_sof_dev *sdev);
-extern struct snd_sof_dsp_ops sof_mtl_ops;
-int sof_mtl_ops_init(struct snd_sof_dev *sdev);
-extern struct snd_sof_dsp_ops sof_lnl_ops;
-int sof_lnl_ops_init(struct snd_sof_dev *sdev);
extern const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc apl_chip_info;
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
index 793d8539821d..2f3222040f98 100644
--- a/sound/soc/sof/intel/lnl.c
+++ b/sound/soc/sof/intel/lnl.c
@@ -20,17 +20,6 @@
#include "lnl.h"
#include <sound/hda-mlink.h>
-/* LunarLake ops */
-struct snd_sof_dsp_ops sof_lnl_ops;
-EXPORT_SYMBOL_NS(sof_lnl_ops, "SND_SOC_SOF_INTEL_LNL");
-
-static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {
- {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
- {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
- {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
- {"fw_regs", HDA_DSP_BAR, MTL_SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY},
-};
-
/* this helps allows the DSP to setup DMIC/SSP */
static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus, bool enable)
{
@@ -111,94 +100,50 @@ static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev)
return 0;
}
-int sof_lnl_ops_init(struct snd_sof_dev *sdev)
+int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
{
- struct sof_ipc4_fw_data *ipc4_data;
+ int ret;
- /* common defaults */
- memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+ ret = sof_mtl_set_ops(sdev, dsp_ops);
+ if (ret)
+ return ret;
/* probe/remove */
if (!sdev->dspless_mode_selected) {
- sof_lnl_ops.probe = lnl_hda_dsp_probe;
- sof_lnl_ops.remove = lnl_hda_dsp_remove;
+ dsp_ops->probe = lnl_hda_dsp_probe;
+ dsp_ops->remove = lnl_hda_dsp_remove;
}
- /* shutdown */
- sof_lnl_ops.shutdown = hda_dsp_shutdown;
-
- /* doorbell */
- sof_lnl_ops.irq_thread = mtl_ipc_irq_thread;
-
- /* ipc */
- sof_lnl_ops.send_msg = mtl_ipc_send_msg;
- sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
- sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
-
- /* debug */
- sof_lnl_ops.debug_map = lnl_dsp_debugfs;
- sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs);
- sof_lnl_ops.dbg_dump = mtl_dsp_dump;
- sof_lnl_ops.ipc_dump = mtl_ipc_dump;
-
- /* pre/post fw run */
- sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
- sof_lnl_ops.post_fw_run = lnl_dsp_post_fw_run;
-
- /* parse platform specific extended manifest */
- sof_lnl_ops.parse_platform_ext_manifest = NULL;
-
- /* dsp core get/put */
- /* TODO: add core_get and core_put */
+ /* post fw run */
+ dsp_ops->post_fw_run = lnl_dsp_post_fw_run;
/* PM */
if (!sdev->dspless_mode_selected) {
- sof_lnl_ops.resume = lnl_hda_dsp_resume;
- sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
+ dsp_ops->resume = lnl_hda_dsp_resume;
+ dsp_ops->runtime_resume = lnl_hda_dsp_runtime_resume;
}
- /* dsp core get/put */
- sof_lnl_ops.core_get = mtl_dsp_core_get;
- sof_lnl_ops.core_put = mtl_dsp_core_put;
-
- sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
- if (!sdev->private)
- return -ENOMEM;
-
- ipc4_data = sdev->private;
- ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
-
- ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
-
- ipc4_data->fw_context_save = true;
-
- /* External library loading support */
- ipc4_data->load_library = hda_dsp_ipc4_load_library;
-
- /* set DAI ops */
- hda_set_dai_drv_ops(sdev, &sof_lnl_ops);
-
- sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
-
return 0;
-};
-EXPORT_SYMBOL_NS(sof_lnl_ops_init, "SND_SOC_SOF_INTEL_LNL");
+}
+EXPORT_SYMBOL_NS(sof_lnl_set_ops, "SND_SOC_SOF_INTEL_LNL");
/* Check if an SDW IRQ occurred */
-static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
+bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
+EXPORT_SYMBOL_NS(lnl_dsp_check_sdw_irq, "SND_SOC_SOF_INTEL_LNL");
-static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
+int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
mtl_disable_ipc_interrupts(sdev);
return mtl_enable_interrupts(sdev, false);
}
+EXPORT_SYMBOL_NS(lnl_dsp_disable_interrupts, "SND_SOC_SOF_INTEL_LNL");
-static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
u16 wake_sts;
@@ -214,6 +159,7 @@ static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
/* filter out the range of SDIs that can be set for SoundWire */
return wake_sts & GENMASK(SDW_MAX_DEVICES, SDW_INTEL_DEV_NUM_IDA_MIN);
}
+EXPORT_SYMBOL_NS(lnl_sdw_check_wakeen_irq, "SND_SOC_SOF_INTEL_LNL");
const struct sof_intel_dsp_desc lnl_chip_info = {
.cores_num = 5,
@@ -239,26 +185,5 @@ const struct sof_intel_dsp_desc lnl_chip_info = {
.hw_ip_version = SOF_INTEL_ACE_2_0,
};
-const struct sof_intel_dsp_desc ptl_chip_info = {
- .cores_num = 5,
- .init_core_mask = BIT(0),
- .host_managed_cores_mask = BIT(0),
- .ipc_req = MTL_DSP_REG_HFIPCXIDR,
- .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
- .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
- .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
- .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
- .rom_status_reg = LNL_DSP_REG_HFDSC,
- .rom_init_timeout = 300,
- .ssp_count = MTL_SSP_COUNT,
- .d0i3_offset = MTL_HDA_VS_D0I3C,
- .read_sdw_lcount = hda_sdw_check_lcount_ext,
- .check_sdw_irq = lnl_dsp_check_sdw_irq,
- .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
- .check_ipc_irq = mtl_dsp_check_ipc_irq,
- .cl_init = mtl_dsp_cl_init,
- .power_down_dsp = mtl_power_down_dsp,
- .disable_interrupts = lnl_dsp_disable_interrupts,
- .hw_ip_version = SOF_INTEL_ACE_3_0,
-};
-EXPORT_SYMBOL_NS(ptl_chip_info, "SND_SOC_SOF_INTEL_LNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
diff --git a/sound/soc/sof/intel/lnl.h b/sound/soc/sof/intel/lnl.h
index 79101af84b2e..2837f818ac51 100644
--- a/sound/soc/sof/intel/lnl.h
+++ b/sound/soc/sof/intel/lnl.h
@@ -12,4 +12,10 @@
#define LNL_DSP_REG_HFDSC 0x160200 /* DSP core0 status */
#define LNL_DSP_REG_HFDEC 0x160204 /* DSP core0 error */
+int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
+
+bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev);
+int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev);
+bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev);
+
#endif /* __SOF_INTEL_LNL_H */
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index d07c68f431ba..2242c96bfa51 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -11,6 +11,7 @@
#include <linux/debugfs.h>
#include <linux/firmware.h>
+#include <linux/string_choices.h>
#include <sound/sof/ipc4/header.h>
#include <trace/events/sof_intel.h>
#include "../ipc4-priv.h"
@@ -95,7 +96,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
return false;
}
-int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
@@ -121,7 +122,6 @@ int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(mtl_ipc_send_msg, "SND_SOC_SOF_INTEL_MTL");
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
{
@@ -176,7 +176,7 @@ static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0)
dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n",
- enable ? "enable" : "disable");
+ str_enable_disable(enable));
}
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
@@ -209,7 +209,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0) {
dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n",
- enable ? "enable" : "disable");
+ str_enable_disable(enable));
return ret;
}
@@ -228,7 +228,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0) {
dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n",
- enable ? "enable" : "disable");
+ str_enable_disable(enable));
return ret;
}
@@ -237,7 +237,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL");
/* pre fw run operations */
-int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
+static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
u32 dsphfpwrsts;
@@ -297,9 +297,8 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, "SND_SOC_SOF_INTEL_MTL");
-int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
int ret;
@@ -324,9 +323,8 @@ int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
hda_sdw_int_enable(sdev, true);
return 0;
}
-EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, "SND_SOC_SOF_INTEL_MTL");
-void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
u32 fwsts;
@@ -342,7 +340,6 @@ void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
sof_ipc4_intel_dump_telemetry_state(sdev, flags);
}
-EXPORT_SYMBOL_NS(mtl_dsp_dump, "SND_SOC_SOF_INTEL_MTL");
static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)
{
@@ -558,7 +555,7 @@ err:
}
EXPORT_SYMBOL_NS(mtl_dsp_cl_init, "SND_SOC_SOF_INTEL_MTL");
-irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
+static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
@@ -640,21 +637,18 @@ irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, "SND_SOC_SOF_INTEL_MTL");
-int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
+static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MTL_DSP_MBOX_UPLINK_OFFSET;
}
-EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, "SND_SOC_SOF_INTEL_MTL");
-int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MTL_SRAM_WINDOW_OFFSET(id);
}
-EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, "SND_SOC_SOF_INTEL_MTL");
-void mtl_ipc_dump(struct snd_sof_dev *sdev)
+static void mtl_ipc_dump(struct snd_sof_dev *sdev)
{
u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;
@@ -670,7 +664,6 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev)
"Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n",
hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl);
}
-EXPORT_SYMBOL_NS(mtl_ipc_dump, "SND_SOC_SOF_INTEL_MTL");
static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
@@ -679,7 +672,7 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return mtl_enable_interrupts(sdev, false);
}
-int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
+static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
@@ -691,9 +684,8 @@ int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
return 0;
}
-EXPORT_SYMBOL_NS(mtl_dsp_core_get, "SND_SOC_SOF_INTEL_MTL");
-int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
+static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
int ret;
@@ -709,45 +701,41 @@ int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
return 0;
}
-EXPORT_SYMBOL_NS(mtl_dsp_core_put, "SND_SOC_SOF_INTEL_MTL");
-/* Meteorlake ops */
-struct snd_sof_dsp_ops sof_mtl_ops;
-
-int sof_mtl_ops_init(struct snd_sof_dev *sdev)
+int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
{
struct sof_ipc4_fw_data *ipc4_data;
/* common defaults */
- memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+ memcpy(dsp_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* shutdown */
- sof_mtl_ops.shutdown = hda_dsp_shutdown;
+ dsp_ops->shutdown = hda_dsp_shutdown;
/* doorbell */
- sof_mtl_ops.irq_thread = mtl_ipc_irq_thread;
+ dsp_ops->irq_thread = mtl_ipc_irq_thread;
/* ipc */
- sof_mtl_ops.send_msg = mtl_ipc_send_msg;
- sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
- sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
+ dsp_ops->send_msg = mtl_ipc_send_msg;
+ dsp_ops->get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
+ dsp_ops->get_window_offset = mtl_dsp_ipc_get_window_offset;
/* debug */
- sof_mtl_ops.debug_map = mtl_dsp_debugfs;
- sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);
- sof_mtl_ops.dbg_dump = mtl_dsp_dump;
- sof_mtl_ops.ipc_dump = mtl_ipc_dump;
+ dsp_ops->debug_map = mtl_dsp_debugfs;
+ dsp_ops->debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);
+ dsp_ops->dbg_dump = mtl_dsp_dump;
+ dsp_ops->ipc_dump = mtl_ipc_dump;
/* pre/post fw run */
- sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
- sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run;
+ dsp_ops->pre_fw_run = mtl_dsp_pre_fw_run;
+ dsp_ops->post_fw_run = mtl_dsp_post_fw_run;
/* parse platform specific extended manifest */
- sof_mtl_ops.parse_platform_ext_manifest = NULL;
+ dsp_ops->parse_platform_ext_manifest = NULL;
/* dsp core get/put */
- sof_mtl_ops.core_get = mtl_dsp_core_get;
- sof_mtl_ops.core_put = mtl_dsp_core_put;
+ dsp_ops->core_get = mtl_dsp_core_get;
+ dsp_ops->core_put = mtl_dsp_core_put;
sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
if (!sdev->private)
@@ -763,13 +751,14 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
/* External library loading support */
ipc4_data->load_library = hda_dsp_ipc4_load_library;
- /* set DAI ops */
- hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
+ dsp_ops->set_power_state = hda_dsp_set_power_state_ipc4;
- sof_mtl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
+ /* set DAI ops */
+ hda_set_dai_drv_ops(sdev, dsp_ops);
return 0;
-};
+}
+EXPORT_SYMBOL_NS(sof_mtl_set_ops, "SND_SOC_SOF_INTEL_MTL");
const struct sof_intel_dsp_desc mtl_chip_info = {
.cores_num = 3,
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index 9ab4b21c960e..e01a1536709e 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -122,26 +122,13 @@
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)
bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
-int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
-int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev);
-int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev);
-void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
-
int mtl_power_down_dsp(struct snd_sof_dev *sdev);
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
-irqreturn_t mtl_ipc_irq_thread(int irq, void *context);
-
-int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
-int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
-
-void mtl_ipc_dump(struct snd_sof_dev *sdev);
-
-int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core);
-int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core);
+int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index 94ab3c61e3f7..0bf7ee753bc3 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -99,7 +99,7 @@ static struct pci_driver snd_sof_pci_intel_apl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_apl_driver);
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index 739c352c3860..de48640024e4 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -137,7 +137,7 @@ static struct pci_driver snd_sof_pci_intel_cnl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_cnl_driver);
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 8545ab95eac8..fd219e654844 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -102,7 +102,7 @@ static struct pci_driver snd_sof_pci_intel_icl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_icl_driver);
diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c
index 8d4d74ac4398..ae379c23f008 100644
--- a/sound/soc/sof/intel/pci-lnl.c
+++ b/sound/soc/sof/intel/pci-lnl.c
@@ -18,7 +18,15 @@
/* platform specific devices */
#include "hda.h"
-#include "mtl.h"
+#include "lnl.h"
+
+/* LunarLake ops */
+static struct snd_sof_dsp_ops sof_lnl_ops;
+
+static int sof_lnl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_lnl_set_ops(sdev, &sof_lnl_ops);
+}
static const struct sof_dev_desc lnl_desc = {
.use_acpi_target_states = true,
@@ -64,7 +72,7 @@ static struct pci_driver snd_sof_pci_intel_lnl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_lnl_driver);
@@ -73,6 +81,4 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for LunarLake platforms");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
-MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
-MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c
index 71f711cf8599..7b2533999195 100644
--- a/sound/soc/sof/intel/pci-mtl.c
+++ b/sound/soc/sof/intel/pci-mtl.c
@@ -20,6 +20,14 @@
#include "hda.h"
#include "mtl.h"
+/* Meteorlake ops */
+static struct snd_sof_dsp_ops sof_mtl_ops;
+
+static int sof_mtl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_mtl_set_ops(sdev, &sof_mtl_ops);
+}
+
static const struct sof_dev_desc mtl_desc = {
.use_acpi_target_states = true,
.machines = snd_soc_acpi_intel_mtl_machines,
@@ -127,7 +135,7 @@ static struct pci_driver snd_sof_pci_intel_mtl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_mtl_driver);
diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c
index 0aacdfac9fb4..7d4c46f56931 100644
--- a/sound/soc/sof/intel/pci-ptl.c
+++ b/sound/soc/sof/intel/pci-ptl.c
@@ -16,7 +16,15 @@
/* platform specific devices */
#include "hda.h"
-#include "mtl.h"
+#include "ptl.h"
+
+/* PantherLake ops */
+static struct snd_sof_dsp_ops sof_ptl_ops;
+
+static int sof_ptl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_ptl_set_ops(sdev, &sof_ptl_ops);
+}
static const struct sof_dev_desc ptl_desc = {
.use_acpi_target_states = true,
@@ -43,13 +51,14 @@ static const struct sof_dev_desc ptl_desc = {
[SOF_IPC_TYPE_4] = "sof-ptl.ri",
},
.nocodec_tplg_filename = "sof-ptl-nocodec.tplg",
- .ops = &sof_lnl_ops,
- .ops_init = sof_lnl_ops_init,
+ .ops = &sof_ptl_ops,
+ .ops_init = sof_ptl_ops_init,
};
/* PCI IDs */
static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_PTL, &ptl_desc) }, /* PTL */
+ { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, &ptl_desc) }, /* PTL-H */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -62,7 +71,7 @@ static struct pci_driver snd_sof_pci_intel_ptl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_ptl_driver);
@@ -71,7 +80,4 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for PantherLake platforms");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
-MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL");
-MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
-MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c
index bd9daae51e4c..a16945dc35f7 100644
--- a/sound/soc/sof/intel/pci-skl.c
+++ b/sound/soc/sof/intel/pci-skl.c
@@ -83,7 +83,7 @@ static struct pci_driver snd_sof_pci_intel_skl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_skl_driver);
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index f76a7197f6ca..437c43819825 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -311,7 +311,7 @@ static struct pci_driver snd_sof_pci_intel_tgl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_tgl_driver);
diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c
index b585ac4a85c2..0c11cc1fd820 100644
--- a/sound/soc/sof/intel/pci-tng.c
+++ b/sound/soc/sof/intel/pci-tng.c
@@ -238,14 +238,13 @@ static struct pci_driver snd_sof_pci_intel_tng_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_tng_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Tangier platforms");
-MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC");
MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c
new file mode 100644
index 000000000000..8fa4bdceedd9
--- /dev/null
+++ b/sound/soc/sof/intel/ptl.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2025 Intel Corporation
+
+/*
+ * Hardware interface for audio DSP on PantherLake.
+ */
+
+#include <sound/hda_register.h>
+#include <sound/hda-mlink.h>
+#include <sound/sof/ipc4/header.h>
+#include "../ipc4-priv.h"
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+#include "mtl.h"
+#include "lnl.h"
+#include "ptl.h"
+
+static bool sof_ptl_check_mic_privacy_irq(struct snd_sof_dev *sdev, bool alt,
+ int elid)
+{
+ if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW)
+ return false;
+
+ return hdac_bus_eml_is_mic_privacy_changed(sof_to_bus(sdev), alt, elid);
+}
+
+static void sof_ptl_process_mic_privacy(struct snd_sof_dev *sdev, bool alt,
+ int elid)
+{
+ bool state;
+
+ if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW)
+ return;
+
+ state = hdac_bus_eml_get_mic_privacy_state(sof_to_bus(sdev), alt, elid);
+
+ sof_ipc4_mic_privacy_state_change(sdev, state);
+}
+
+static void sof_ptl_set_mic_privacy(struct snd_sof_dev *sdev,
+ struct sof_ipc4_intel_mic_privacy_cap *caps)
+{
+ u32 micpvcp;
+
+ if (!caps || !caps->capabilities_length)
+ return;
+
+ micpvcp = caps->capabilities[0];
+
+ /* No need to set the mic privacy if it is not enabled or forced */
+ if (!(micpvcp & PTL_MICPVCP_DDZE_ENABLED) ||
+ micpvcp & PTL_MICPVCP_DDZE_FORCED)
+ return;
+
+ hdac_bus_eml_set_mic_privacy_mask(sof_to_bus(sdev), true,
+ AZX_REG_ML_LEPTR_ID_SDW,
+ PTL_MICPVCP_GET_SDW_MASK(micpvcp));
+}
+
+int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
+{
+ struct sof_ipc4_fw_data *ipc4_data;
+ int ret;
+
+ ret = sof_lnl_set_ops(sdev, dsp_ops);
+ if (ret)
+ return ret;
+
+ ipc4_data = sdev->private;
+ ipc4_data->intel_configure_mic_privacy = sof_ptl_set_mic_privacy;
+
+ return 0;
+};
+EXPORT_SYMBOL_NS(sof_ptl_set_ops, "SND_SOC_SOF_INTEL_PTL");
+
+const struct sof_intel_dsp_desc ptl_chip_info = {
+ .cores_num = 5,
+ .init_core_mask = BIT(0),
+ .host_managed_cores_mask = BIT(0),
+ .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+ .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+ .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+ .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+ .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+ .rom_status_reg = LNL_DSP_REG_HFDSC,
+ .rom_init_timeout = 300,
+ .ssp_count = MTL_SSP_COUNT,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_ext,
+ .check_sdw_irq = lnl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
+ .check_ipc_irq = mtl_dsp_check_ipc_irq,
+ .check_mic_privacy_irq = sof_ptl_check_mic_privacy_irq,
+ .process_mic_privacy = sof_ptl_process_mic_privacy,
+ .cl_init = mtl_dsp_cl_init,
+ .power_down_dsp = mtl_power_down_dsp,
+ .disable_interrupts = lnl_dsp_disable_interrupts,
+ .hw_ip_version = SOF_INTEL_ACE_3_0,
+};
+
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
diff --git a/sound/soc/sof/intel/ptl.h b/sound/soc/sof/intel/ptl.h
new file mode 100644
index 000000000000..6a7ef11f411e
--- /dev/null
+++ b/sound/soc/sof/intel/ptl.h
@@ -0,0 +1,19 @@
+/* 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 Intel Corporation
+ */
+
+#ifndef __SOF_INTEL_PTL_H
+#define __SOF_INTEL_PTL_H
+
+#define PTL_MICPVCP_DDZE_FORCED BIT(16)
+#define PTL_MICPVCP_DDZE_ENABLED BIT(17)
+#define PTL_MICPVCP_DDZLS_SDW GENMASK(26, 20)
+#define PTL_MICPVCP_GET_SDW_MASK(x) (((x) & PTL_MICPVCP_DDZLS_SDW) >> 20)
+
+int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
+
+#endif /* __SOF_INTEL_PTL_H */
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index 8709b750a11e..d4372f0bff7e 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -193,6 +193,8 @@ struct sof_intel_dsp_desc {
bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev);
void (*sdw_process_wakeen)(struct snd_sof_dev *sdev);
bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
+ bool (*check_mic_privacy_irq)(struct snd_sof_dev *sdev, bool alt, int elid);
+ void (*process_mic_privacy)(struct snd_sof_dev *sdev, bool alt, int elid);
int (*power_down_dsp)(struct snd_sof_dev *sdev);
int (*disable_interrupts)(struct snd_sof_dev *sdev);
int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 1c1b8f595367..90ef5d99f626 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -117,22 +117,23 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
if (platform_params->cont_update_posn)
pcm.params.cont_update_posn = 1;
- dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
+ spcm_dbg(spcm, substream->stream, "stream_tag %d\n",
+ pcm.params.stream_tag);
/* send hw_params IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
- dev_err(component->dev, "HW params ipc failed for stream %d\n",
- pcm.params.stream_tag);
+ spcm_err(spcm, substream->stream,
+ "STREAM_PCM_PARAMS ipc failed for stream_tag %d\n",
+ pcm.params.stream_tag);
return ret;
}
ret = snd_sof_set_stream_data_offset(sdev, &spcm->stream[substream->stream],
ipc_params_reply.posn_offset);
if (ret < 0) {
- dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n",
- __func__, spcm->pcm.pcm_id);
+ spcm_err(spcm, substream->stream, "invalid stream data offset\n");
return ret;
}
@@ -171,7 +172,7 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component,
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
break;
default:
- dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
+ spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd);
return -EINVAL;
}
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index e98b53b67d12..473d416bc910 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -2386,28 +2386,16 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
{
struct snd_sof_widget *swidget;
- struct snd_sof_pcm *spcm;
- int dir, ret;
+ int ret;
/*
* free all PCMs and their associated DAPM widgets if their connected DAPM widget
* list is not NULL. This should only be true for paused streams at this point.
* This is equivalent to the handling of FE DAI suspend trigger for running streams.
*/
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream = spcm->stream[dir].substream;
-
- if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
- continue;
-
- if (spcm->stream[dir].list) {
- ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
- if (ret < 0)
- return ret;
- }
- }
- }
+ ret = sof_pcm_free_all_streams(sdev);
+ if (ret)
+ return ret;
/*
* free any left over DAI widgets. This is equivalent to the handling of suspend trigger
diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c
index 7de5e3d285e7..4a194a705ace 100644
--- a/sound/soc/sof/ipc3.c
+++ b/sound/soc/sof/ipc3.c
@@ -801,20 +801,16 @@ int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev)
return -EINVAL;
}
- if (ready->flags & SOF_IPC_INFO_BUILD) {
+ if (ready->flags & SOF_IPC_INFO_BUILD)
dev_info(sdev->dev,
"Firmware debug build %d on %s-%s - options:\n"
" GDB: %s\n"
" lock debug: %s\n"
" lock vdebug: %s\n",
v->build, v->date, v->time,
- (ready->flags & SOF_IPC_INFO_GDB) ?
- "enabled" : "disabled",
- (ready->flags & SOF_IPC_INFO_LOCKS) ?
- "enabled" : "disabled",
- (ready->flags & SOF_IPC_INFO_LOCKSV) ?
- "enabled" : "disabled");
- }
+ str_enabled_disabled(ready->flags & SOF_IPC_INFO_GDB),
+ str_enabled_disabled(ready->flags & SOF_IPC_INFO_LOCKS),
+ str_enabled_disabled(ready->flags & SOF_IPC_INFO_LOCKSV));
/* copy the fw_version into debugfs at first boot */
memcpy(&sdev->fw_version, v, sizeof(*v));
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index bcdb33d03682..d2f534d65edf 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -169,21 +169,14 @@ static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev)
return payload_offset;
}
-static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
- unsigned long lib_id, const guid_t *uuid)
+static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id,
+ const char *lib_filename, bool optional)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct sof_ipc4_fw_library *fw_lib;
- const char *fw_filename;
ssize_t payload_offset;
int ret, i, err;
- if (!sdev->pdata->fw_lib_prefix) {
- dev_err(sdev->dev,
- "Library loading is not supported due to not set library path\n");
- return -EINVAL;
- }
-
if (!ipc4_data->load_library) {
dev_err(sdev->dev, "Library loading is not supported on this platform\n");
return -EOPNOTSUPP;
@@ -193,21 +186,26 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
if (!fw_lib)
return -ENOMEM;
- fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
- sdev->pdata->fw_lib_prefix, uuid);
- if (!fw_filename) {
- ret = -ENOMEM;
- goto free_fw_lib;
- }
-
- ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev);
- if (ret < 0) {
- dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename);
- goto free_filename;
+ if (optional) {
+ ret = firmware_request_nowarn(&fw_lib->sof_fw.fw, lib_filename,
+ sdev->dev);
+ if (ret < 0) {
+ /* optional library, override the error */
+ ret = 0;
+ goto free_fw_lib;
+ }
} else {
- dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename);
+ ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename,
+ sdev->dev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "Library file '%s' is missing\n",
+ lib_filename);
+ goto free_fw_lib;
+ }
}
+ dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename);
+
payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib);
if (payload_offset <= 0) {
if (!payload_offset)
@@ -251,22 +249,117 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
if (unlikely(ret))
goto release;
- kfree(fw_filename);
-
return 0;
release:
release_firmware(fw_lib->sof_fw.fw);
/* Allocated within sof_ipc4_fw_parse_ext_man() */
devm_kfree(sdev->dev, fw_lib->modules);
-free_filename:
- kfree(fw_filename);
free_fw_lib:
devm_kfree(sdev->dev, fw_lib);
return ret;
}
+/**
+ * sof_ipc4_complete_split_release - loads the library parts of a split firmware
+ * @sdev: SOF device
+ *
+ * With IPC4 the firmware can be a single binary or a split release.
+ * - single binary: only the basefw
+ * - split release: basefw and two libraries (openmodules, debug)
+ *
+ * With split firmware release it is also allowed that for example only the
+ * debug library is present (the openmodules content is built in the basefw).
+ *
+ * To handle the permutations try to load the openmodules then the debug
+ * libraries as optional ones after the basefw boot.
+ *
+ * The libraries for the split release are stored alongside the basefw on the
+ * filesystem.
+ */
+int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev)
+{
+ static const char * const lib_bundle[] = { "openmodules", "debug" };
+ const char *fw_filename = sdev->pdata->fw_filename;
+ const char *lib_filename, *p;
+ size_t lib_name_base_size;
+ unsigned long lib_id = 1;
+ char *lib_name_base;
+ int i;
+
+ p = strstr(fw_filename, ".ri");
+ if (!p || strlen(p) != 3) {
+ dev_info(sdev->dev,
+ "%s: Firmware name '%s' is missing .ri extension\n",
+ __func__, fw_filename);
+ return 0;
+ }
+
+ /* Space for the firmware basename + '\0', without the extension */
+ lib_name_base_size = strlen(fw_filename) - 2;
+ lib_name_base = kzalloc(lib_name_base_size, GFP_KERNEL);
+ if (!lib_name_base)
+ return -ENOMEM;
+
+ /*
+ * strscpy will 0 terminate the copied string, removing the '.ri' from
+ * the end of the fw_filename, for example:
+ * fw_filename: "sof-ptl.ri\0"
+ * lib_name_base: "sof-ptl\0"
+ */
+ strscpy(lib_name_base, fw_filename, lib_name_base_size);
+
+ for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) {
+ int ret;
+
+ lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri",
+ sdev->pdata->fw_filename_prefix,
+ lib_name_base, lib_bundle[i]);
+ if (!lib_filename) {
+ kfree(lib_name_base);
+ return -ENOMEM;
+ }
+
+ ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, true);
+ if (ret)
+ dev_warn(sdev->dev, "%s: Failed to load %s: %d\n",
+ __func__, lib_filename, ret);
+ else
+ lib_id++;
+
+ kfree(lib_filename);
+ }
+
+ kfree(lib_name_base);
+
+ return 0;
+}
+
+static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev,
+ unsigned long lib_id, const guid_t *uuid)
+{
+ const char *lib_filename;
+ int ret;
+
+ if (!sdev->pdata->fw_lib_prefix) {
+ dev_err(sdev->dev,
+ "Library loading is not supported due to not set library path\n");
+ return -EINVAL;
+ }
+
+ lib_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin",
+ sdev->pdata->fw_lib_prefix, uuid);
+ if (!lib_filename)
+ return -ENOMEM;
+
+ ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, false);
+
+ kfree(lib_filename);
+
+ return ret;
+}
+
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
const guid_t *uuid)
{
@@ -409,6 +502,39 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
offset += sizeof(*tuple) + tuple->size;
}
+ /* Get the hardware configuration */
+ msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID);
+ msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID);
+ msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_HW_CONFIG_GET);
+
+ msg.data_size = sdev->ipc->max_payload_size;
+
+ ret = iops->set_get_data(sdev, &msg, msg.data_size, false);
+ if (ret)
+ goto out;
+
+ offset = 0;
+ while (offset < msg.data_size) {
+ tuple = (struct sof_ipc4_tuple *)((u8 *)msg.data_ptr + offset);
+
+ switch (tuple->type) {
+ case SOF_IPC4_HW_CFG_INTEL_MIC_PRIVACY_CAPS:
+ if (ipc4_data->intel_configure_mic_privacy) {
+ struct sof_ipc4_intel_mic_privacy_cap *caps;
+
+ caps = (struct sof_ipc4_intel_mic_privacy_cap *)tuple->value;
+ ipc4_data->intel_configure_mic_privacy(sdev, caps);
+ }
+ break;
+ default:
+ break;
+ }
+
+ offset += sizeof(*tuple) + tuple->size;
+ }
+
out:
kfree(msg.data_ptr);
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index 18fff2df76f9..1a2841899ff5 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -313,7 +313,7 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
set_fifo_size = false;
break;
default:
- dev_err(sdev->dev, "Unexpected state %d", state);
+ spcm_err(spcm, direction, "Unexpected pipeline state %d\n", state);
return -EINVAL;
}
@@ -333,8 +333,8 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev,
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
if (!pipeline->use_chain_dma) {
- dev_err(sdev->dev,
- "All pipelines in chained DMA stream should have use_chain_dma attribute set.");
+ spcm_err(spcm, direction,
+ "All pipelines in chained DMA path should have use_chain_dma attribute set.");
return -EINVAL;
}
@@ -389,12 +389,12 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
int ret;
int i;
- dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state);
-
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
+ spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state);
+
pipeline_list = &spcm->stream[substream->stream].pipeline_list;
/* nothing to trigger if the list is empty */
@@ -465,7 +465,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
*/
ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list);
if (ret < 0) {
- dev_err(sdev->dev, "failed to pause all pipelines\n");
+ spcm_err(spcm, substream->stream, "failed to pause all pipelines\n");
goto free;
}
@@ -494,7 +494,9 @@ skip_pause_transition:
/* else set the RUNNING/RESET state in the DSP */
ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list);
if (ret < 0) {
- dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state);
+ spcm_err(spcm, substream->stream,
+ "failed to set final state %d for all pipelines\n",
+ state);
/*
* workaround: if the firmware is crashed while setting the
* pipelines to reset state we must ignore the error code and
@@ -610,12 +612,11 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev,
* Copier does not change sampling rate, so we
* need to only consider the input pin information.
*/
+ be_rate = pin_fmts[0].audio_fmt.sampling_frequency;
for (i = 0; i < num_input_formats; i++) {
unsigned int val = pin_fmts[i].audio_fmt.sampling_frequency;
- if (i == 0)
- be_rate = val;
- else if (val != be_rate)
+ if (val != be_rate)
single_be_rate = false;
if (val == fe_rate) {
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index ea3323b90343..58b032820683 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -11,6 +11,7 @@
#include <linux/idr.h>
#include <sound/sof/ext_manifest4.h>
+#include <sound/sof/ipc4/header.h>
#include "sof-priv.h"
/* The DSP window indices are fixed */
@@ -89,6 +90,8 @@ struct sof_ipc4_fw_data {
int (*load_library)(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload);
+ void (*intel_configure_mic_privacy)(struct snd_sof_dev *sdev,
+ struct sof_ipc4_intel_mic_privacy_cap *caps);
struct mutex pipeline_state_mutex; /* protect pipeline triggers, ref counts and states */
};
@@ -101,6 +104,7 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops;
int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state);
int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core);
+int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev);
int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev);
int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
@@ -117,4 +121,6 @@ void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
size_t sof_ipc4_find_debug_slot_offset_by_type(struct snd_sof_dev *sdev,
u32 slot_type);
+void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state);
+
#endif
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index b55eb977e443..540ba140e155 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -7,6 +7,7 @@
//
//
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <uapi/sound/sof/tokens.h>
#include <sound/pcm_params.h>
#include <sound/sof/ext_manifest4.h>
@@ -765,10 +766,16 @@ static int sof_ipc4_widget_setup_comp_dai(struct snd_sof_widget *swidget)
}
list_for_each_entry(w, &sdev->widget_list, list) {
- if (w->widget->sname &&
+ struct snd_sof_dai *alh_dai;
+
+ if (!WIDGET_IS_DAI(w->id) || !w->widget->sname ||
strcmp(w->widget->sname, swidget->widget->sname))
continue;
+ alh_dai = w->private;
+ if (alh_dai->type != SOF_DAI_INTEL_ALH)
+ continue;
+
blob->alh_cfg.device_count++;
}
@@ -1801,8 +1808,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc4_copier_data *copier_data;
int input_fmt_index, output_fmt_index;
- struct snd_pcm_hw_params ref_params;
struct sof_ipc4_copier *ipc4_copier;
+ struct snd_pcm_hw_params *ref_params __free(kfree) = NULL;
struct snd_sof_dai *dai;
u32 gtw_cfg_config_length;
u32 dma_config_tlv_size = 0;
@@ -1815,15 +1822,19 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
bool single_output_bitdepth;
int i;
- dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id);
-
switch (swidget->id) {
case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out:
{
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
struct sof_ipc4_gtw_attributes *gtw_attr;
- struct snd_sof_widget *pipe_widget;
- struct sof_ipc4_pipeline *pipeline;
+
+ dev_dbg(sdev->dev,
+ "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n",
+ swidget->widget->name, swidget->id,
+ str_yes_no(pipeline->use_chain_dma),
+ platform_params->stream_tag);
/* parse the deep buffer dma size */
ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms,
@@ -1840,9 +1851,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
- pipe_widget = swidget->spipe->pipe_widget;
- pipeline = pipe_widget->private;
-
if (pipeline->use_chain_dma) {
u32 host_dma_id;
u32 fifo_size;
@@ -1878,9 +1886,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
* for capture.
*/
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- ref_params = *fe_params;
+ ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
else
- ref_params = *pipeline_params;
+ ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL);
+ if (!ref_params)
+ return -ENOMEM;
copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK;
copier_data->gtw_cfg.node_id |=
@@ -1896,6 +1906,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
+ dev_dbg(sdev->dev, "Dai copier %s, type %d, ChainDMA: %s\n",
+ swidget->widget->name, swidget->id,
+ str_yes_no(pipeline->use_chain_dma));
+
if (pipeline->use_chain_dma)
return 0;
@@ -1913,8 +1927,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
* In case of capture the ref_params returned will be used to
* find the input configuration of the copier.
*/
- ref_params = *fe_params;
- ret = sof_ipc4_prepare_dai_copier(sdev, dai, &ref_params, dir);
+ ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL);
+ if (!ref_params)
+ return -ENOMEM;
+
+ ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir);
if (ret < 0)
return ret;
@@ -1923,16 +1940,22 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
* input configuration of the copier.
*/
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
- ref_params = *pipeline_params;
+ memcpy(ref_params, pipeline_params, sizeof(*ref_params));
break;
}
case snd_soc_dapm_buffer:
{
+ dev_dbg(sdev->dev, "Module copier %s, type %d\n",
+ swidget->widget->name, swidget->id);
+
ipc4_copier = (struct sof_ipc4_copier *)swidget->private;
copier_data = &ipc4_copier->data;
available_fmt = &ipc4_copier->available_fmt;
- ref_params = *pipeline_params;
+
+ ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL);
+ if (!ref_params)
+ return -ENOMEM;
break;
}
@@ -1945,7 +1968,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
/* set input and output audio formats */
input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget,
&copier_data->base_config,
- &ref_params, available_fmt);
+ ref_params, available_fmt);
if (input_fmt_index < 0)
return input_fmt_index;
@@ -2061,11 +2084,13 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
list_for_each_entry(w, &sdev->widget_list, list) {
u32 node_type;
- if (w->widget->sname &&
+ if (!WIDGET_IS_DAI(w->id) || !w->widget->sname ||
strcmp(w->widget->sname, swidget->widget->sname))
continue;
dai = w->private;
+ if (dai->type != SOF_DAI_INTEL_ALH)
+ continue;
alh_copier = (struct sof_ipc4_copier *)dai->private;
alh_data = &alh_copier->data;
node_type = SOF_IPC4_GET_NODE_TYPE(alh_data->gtw_cfg.node_id);
@@ -2827,7 +2852,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
- msg->extension |= ipc_size >> 2;
+ msg->extension |= SOF_IPC4_MOD_EXT_PARAM_SIZE(ipc_size >> 2);
msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
@@ -3401,9 +3426,6 @@ static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai *
static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
{
- struct snd_sof_pcm *spcm;
- int dir, ret;
-
/*
* This function is called during system suspend, we need to make sure
* that all streams have been freed up.
@@ -3415,21 +3437,8 @@ static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
*
* This will also make sure that paused streams handled correctly.
*/
- list_for_each_entry(spcm, &sdev->pcm_list, list) {
- for_each_pcm_streams(dir) {
- struct snd_pcm_substream *substream = spcm->stream[dir].substream;
- if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored)
- continue;
-
- if (spcm->stream[dir].list) {
- ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
- if (ret < 0)
- return ret;
- }
- }
- }
- return 0;
+ return sof_pcm_free_all_streams(sdev);
}
static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link)
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 4386cbae16d4..37e837b22ac8 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -825,8 +825,14 @@ static void sof_ipc4_exit(struct snd_sof_dev *sdev)
static int sof_ipc4_post_boot(struct snd_sof_dev *sdev)
{
- if (sdev->first_boot)
+ if (sdev->first_boot) {
+ int ret = sof_ipc4_complete_split_release(sdev);
+
+ if (ret)
+ return ret;
+
return sof_ipc4_query_fw_configuration(sdev);
+ }
return sof_ipc4_reload_fw_libraries(sdev);
}
@@ -845,3 +851,21 @@ const struct sof_ipc_ops ipc4_ops = {
.pcm = &ipc4_pcm_ops,
.fw_tracing = &ipc4_mtrace_ops,
};
+
+void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state)
+{
+ struct sof_ipc4_msg msg;
+ u32 data = state;
+
+ msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID);
+ msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID);
+ msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_MIC_PRIVACY_STATE_CHANGE);
+
+ msg.data_size = sizeof(data);
+ msg.data_ptr = &data;
+
+ sof_ipc4_set_get_data(sdev, &msg, msg.data_size, true);
+}
+EXPORT_SYMBOL(sof_ipc4_mic_privacy_state_change);
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index 9955dfa520ae..7ff080452cbe 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -22,7 +22,6 @@
#include <sound/sof/xtensa.h>
#include "../../ops.h"
#include "../../sof-of-dev.h"
-#include "../../sof-audio.h"
#include "../adsp_helper.h"
#include "../mtk-adsp-common.h"
#include "mt8186.h"
@@ -38,53 +37,9 @@ static int mt8186_get_window_offset(struct snd_sof_dev *sdev, u32 id)
return MBOX_OFFSET;
}
-static int mt8186_send_msg(struct snd_sof_dev *sdev,
- struct snd_sof_ipc_msg *msg)
-{
- struct adsp_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
-
- return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
-}
-
-static void mt8186_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
-{
- struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- snd_sof_ipc_process_reply(priv->sdev, 0);
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc)
-{
- struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
- u32 p; /* panic code */
- int ret;
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4,
- &p, sizeof(p));
-
- /* Check to see if the message is a panic code 0x0dead*** */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
- snd_sof_dsp_panic(priv->sdev, p, true);
- } else {
- snd_sof_ipc_msgs_rx(priv->sdev);
-
- /* tell DSP cmd is done */
- ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP);
- if (ret)
- dev_err(priv->dev, "request send ipc failed");
- }
-}
-
static const struct mtk_adsp_ipc_ops dsp_ops = {
- .handle_reply = mt8186_dsp_handle_reply,
- .handle_request = mt8186_dsp_handle_request,
+ .handle_reply = mtk_adsp_handle_reply,
+ .handle_request = mtk_adsp_handle_request,
};
static int platform_parse_resource(struct platform_device *pdev, void *data)
@@ -238,7 +193,7 @@ static int mt8186_run(struct snd_sof_dev *sdev)
static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
{
- struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
struct adsp_priv *priv;
int ret;
@@ -381,54 +336,6 @@ static int mt8186_dsp_resume(struct snd_sof_dev *sdev)
return ret;
}
-/* on mt8186 there is 1 to 1 match between type and BAR idx */
-static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- return type;
-}
-
-static int mt8186_pcm_hw_params(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_sof_platform_stream_params *platform_params)
-{
- platform_params->cont_update_posn = 1;
-
- return 0;
-}
-
-static snd_pcm_uframes_t mt8186_pcm_pointer(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream)
-{
- int ret;
- snd_pcm_uframes_t pos;
- struct snd_sof_pcm *spcm;
- struct sof_ipc_stream_posn posn;
- struct snd_sof_pcm_stream *stream;
- struct snd_soc_component *scomp = sdev->component;
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-
- spcm = snd_sof_find_spcm_dai(scomp, rtd);
- if (!spcm) {
- dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
- rtd->dai_link->id);
- return 0;
- }
-
- stream = &spcm->stream[substream->stream];
- ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn));
- if (ret < 0) {
- dev_warn(sdev->dev, "failed to read stream position: %d\n", ret);
- return 0;
- }
-
- memcpy(&stream->posn, &posn, sizeof(posn));
- pos = spcm->stream[substream->stream].posn.host_posn;
- pos = bytes_to_frames(substream->runtime, pos);
-
- return pos;
-}
-
static void mt8186_adsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
u32 dbg_pc, dbg_data, dbg_inst, dbg_ls0stat, dbg_status, faultinfo;
@@ -505,19 +412,19 @@ static const struct snd_sof_dsp_ops sof_mt8186_ops = {
.read64 = sof_io_read64,
/* ipc */
- .send_msg = mt8186_send_msg,
+ .send_msg = mtk_adsp_send_msg,
.get_mailbox_offset = mt8186_get_mailbox_offset,
.get_window_offset = mt8186_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset,
/* misc */
- .get_bar_index = mt8186_get_bar_index,
+ .get_bar_index = mtk_adsp_get_bar_index,
/* stream callbacks */
.pcm_open = sof_stream_pcm_open,
- .pcm_hw_params = mt8186_pcm_hw_params,
- .pcm_pointer = mt8186_pcm_pointer,
+ .pcm_hw_params = mtk_adsp_stream_pcm_hw_params,
+ .pcm_pointer = mtk_adsp_stream_pcm_pointer,
.pcm_close = sof_stream_pcm_close,
/* firmware loading */
@@ -660,7 +567,7 @@ static struct platform_driver snd_sof_of_mt8186_driver = {
.shutdown = sof_of_shutdown,
.driver = {
.name = "sof-audio-of-mt8186",
- .pm = &sof_of_pm,
+ .pm = pm_ptr(&sof_of_pm),
.of_match_table = sof_of_mt8186_ids,
},
};
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
index 7cffcad00f9b..2c2c4cd323fc 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/string_choices.h>
#include "mt8195.h"
#include "mt8195-clk.h"
#include "../adsp_helper.h"
@@ -114,7 +115,7 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable)
struct adsp_priv *priv = sdev->pdata->hw_pdata;
int ret;
- dev_dbg(dev, "%s: %s\n", __func__, enable ? "on" : "off");
+ dev_dbg(dev, "%s: %s\n", __func__, str_on_off(enable));
if (enable) {
ret = clk_set_parent(priv->clk[CLK_TOP_ADSP],
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index 6032b566c679..3b3582d74510 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -22,7 +22,6 @@
#include <sound/sof/xtensa.h>
#include "../../ops.h"
#include "../../sof-of-dev.h"
-#include "../../sof-audio.h"
#include "../adsp_helper.h"
#include "../mtk-adsp-common.h"
#include "mt8195.h"
@@ -38,53 +37,9 @@ static int mt8195_get_window_offset(struct snd_sof_dev *sdev, u32 id)
return MBOX_OFFSET;
}
-static int mt8195_send_msg(struct snd_sof_dev *sdev,
- struct snd_sof_ipc_msg *msg)
-{
- struct adsp_priv *priv = sdev->pdata->hw_pdata;
-
- sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
- msg->msg_size);
-
- return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
-}
-
-static void mt8195_dsp_handle_reply(struct mtk_adsp_ipc *ipc)
-{
- struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
- snd_sof_ipc_process_reply(priv->sdev, 0);
- spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
-}
-
-static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc)
-{
- struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
- u32 p; /* panic code */
- int ret;
-
- /* Read the message from the debug box. */
- sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4,
- &p, sizeof(p));
-
- /* Check to see if the message is a panic code 0x0dead*** */
- if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
- snd_sof_dsp_panic(priv->sdev, p, true);
- } else {
- snd_sof_ipc_msgs_rx(priv->sdev);
-
- /* tell DSP cmd is done */
- ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP);
- if (ret)
- dev_err(priv->dev, "request send ipc failed");
- }
-}
-
static const struct mtk_adsp_ipc_ops dsp_ops = {
- .handle_reply = mt8195_dsp_handle_reply,
- .handle_request = mt8195_dsp_handle_request,
+ .handle_reply = mtk_adsp_handle_reply,
+ .handle_request = mtk_adsp_handle_request,
};
static int platform_parse_resource(struct platform_device *pdev, void *data)
@@ -228,7 +183,7 @@ static int mt8195_run(struct snd_sof_dev *sdev)
static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
{
- struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
struct adsp_priv *priv;
int ret;
@@ -341,7 +296,7 @@ static int mt8195_dsp_shutdown(struct snd_sof_dev *sdev)
static void mt8195_dsp_remove(struct snd_sof_dev *sdev)
{
- struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
struct adsp_priv *priv = sdev->pdata->hw_pdata;
platform_device_unregister(priv->ipc_dev);
@@ -351,7 +306,7 @@ static void mt8195_dsp_remove(struct snd_sof_dev *sdev)
static int mt8195_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
- struct platform_device *pdev = container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
int ret;
u32 reset_sw, dbg_pc;
@@ -400,54 +355,6 @@ static int mt8195_dsp_resume(struct snd_sof_dev *sdev)
return ret;
}
-/* on mt8195 there is 1 to 1 match between type and BAR idx */
-static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type)
-{
- return type;
-}
-
-static int mt8195_pcm_hw_params(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_sof_platform_stream_params *platform_params)
-{
- platform_params->cont_update_posn = 1;
-
- return 0;
-}
-
-static snd_pcm_uframes_t mt8195_pcm_pointer(struct snd_sof_dev *sdev,
- struct snd_pcm_substream *substream)
-{
- int ret;
- snd_pcm_uframes_t pos;
- struct snd_sof_pcm *spcm;
- struct sof_ipc_stream_posn posn;
- struct snd_sof_pcm_stream *stream;
- struct snd_soc_component *scomp = sdev->component;
- struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-
- spcm = snd_sof_find_spcm_dai(scomp, rtd);
- if (!spcm) {
- dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
- rtd->dai_link->id);
- return 0;
- }
-
- stream = &spcm->stream[substream->stream];
- ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn));
- if (ret < 0) {
- dev_warn(sdev->dev, "failed to read stream position: %d\n", ret);
- return 0;
- }
-
- memcpy(&stream->posn, &posn, sizeof(posn));
- pos = spcm->stream[substream->stream].posn.host_posn;
- pos = bytes_to_frames(substream->runtime, pos);
-
- return pos;
-}
-
static void mt8195_adsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
u32 dbg_pc, dbg_data, dbg_bus0, dbg_bus1, dbg_inst;
@@ -529,19 +436,19 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = {
.read64 = sof_io_read64,
/* ipc */
- .send_msg = mt8195_send_msg,
+ .send_msg = mtk_adsp_send_msg,
.get_mailbox_offset = mt8195_get_mailbox_offset,
.get_window_offset = mt8195_get_window_offset,
.ipc_msg_data = sof_ipc_msg_data,
.set_stream_data_offset = sof_set_stream_data_offset,
/* misc */
- .get_bar_index = mt8195_get_bar_index,
+ .get_bar_index = mtk_adsp_get_bar_index,
/* stream callbacks */
.pcm_open = sof_stream_pcm_open,
- .pcm_hw_params = mt8195_pcm_hw_params,
- .pcm_pointer = mt8195_pcm_pointer,
+ .pcm_hw_params = mtk_adsp_stream_pcm_hw_params,
+ .pcm_pointer = mtk_adsp_stream_pcm_pointer,
.pcm_close = sof_stream_pcm_close,
/* firmware loading */
@@ -616,7 +523,7 @@ static struct platform_driver snd_sof_of_mt8195_driver = {
.shutdown = sof_of_shutdown,
.driver = {
.name = "sof-audio-of-mt8195",
- .pm = &sof_of_pm,
+ .pm = pm_ptr(&sof_of_pm),
.of_match_table = sof_of_mt8195_ids,
},
};
diff --git a/sound/soc/sof/mediatek/mtk-adsp-common.c b/sound/soc/sof/mediatek/mtk-adsp-common.c
index 20bcf5590eb8..01bbadb160ff 100644
--- a/sound/soc/sof/mediatek/mtk-adsp-common.c
+++ b/sound/soc/sof/mediatek/mtk-adsp-common.c
@@ -12,8 +12,11 @@
*/
#include <linux/module.h>
+#include <sound/asound.h>
#include <sound/sof/xtensa.h>
#include "../ops.h"
+#include "../sof-audio.h"
+#include "adsp_helper.h"
#include "mtk-adsp-common.h"
/**
@@ -81,5 +84,132 @@ void mtk_adsp_dump(struct snd_sof_dev *sdev, u32 flags)
}
EXPORT_SYMBOL(mtk_adsp_dump);
+/**
+ * mtk_adsp_send_msg - Send message to Audio DSP
+ * @sdev: SOF device
+ * @msg: SOF IPC Message to send
+ */
+int mtk_adsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+{
+ struct adsp_priv *priv = sdev->pdata->hw_pdata;
+
+ sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data,
+ msg->msg_size);
+
+ return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ);
+}
+EXPORT_SYMBOL(mtk_adsp_send_msg);
+
+/**
+ * mtk_adsp_handle_reply - Handle reply from the Audio DSP through Mailbox
+ * @ipc: ADSP IPC handle
+ */
+void mtk_adsp_handle_reply(struct mtk_adsp_ipc *ipc)
+{
+ struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sdev->ipc_lock, flags);
+ snd_sof_ipc_process_reply(priv->sdev, 0);
+ spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags);
+}
+EXPORT_SYMBOL(mtk_adsp_handle_reply);
+
+/**
+ * mtk_adsp_handle_request - Handle request from the Audio DSP through Mailbox
+ * @ipc: ADSP IPC handle
+ */
+void mtk_adsp_handle_request(struct mtk_adsp_ipc *ipc)
+{
+ struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc);
+ u32 panic_code;
+ int ret;
+
+ /* Read the message from the debug box. */
+ sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4,
+ &panic_code, sizeof(panic_code));
+
+ /* Check to see if the message is a panic code 0x0dead*** */
+ if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) {
+ snd_sof_dsp_panic(priv->sdev, panic_code, true);
+ } else {
+ snd_sof_ipc_msgs_rx(priv->sdev);
+
+ /* Tell DSP cmd is done */
+ ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP);
+ if (ret)
+ dev_err(priv->dev, "request send ipc failed");
+ }
+}
+EXPORT_SYMBOL(mtk_adsp_handle_request);
+
+/**
+ * mtk_adsp_get_bar_index - Map section type with BAR idx
+ * @sdev: SOF device
+ * @type: Section type as described by snd_sof_fw_blk_type
+ *
+ * MediaTek Audio DSPs have a 1:1 match between type and BAR idx
+ */
+int mtk_adsp_get_bar_index(struct snd_sof_dev *sdev, u32 type)
+{
+ return type;
+}
+EXPORT_SYMBOL(mtk_adsp_get_bar_index);
+
+/**
+ * mtk_adsp_stream_pcm_hw_params - Platform specific host stream hw params
+ * @sdev: SOF device
+ * @substream: PCM Substream
+ * @params: hw params
+ * @platform_params: Platform specific SOF stream parameters
+ */
+int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_sof_platform_stream_params *platform_params)
+{
+ platform_params->cont_update_posn = 1;
+ return 0;
+}
+EXPORT_SYMBOL(mtk_adsp_stream_pcm_hw_params);
+
+/**
+ * mtk_adsp_stream_pcm_pointer - Get host stream pointer
+ * @sdev: SOF device
+ * @substream: PCM substream
+ */
+snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_component *scomp = sdev->component;
+ struct snd_sof_pcm_stream *stream;
+ struct sof_ipc_stream_posn posn;
+ struct snd_sof_pcm *spcm;
+ snd_pcm_uframes_t pos;
+ int ret;
+
+ spcm = snd_sof_find_spcm_dai(scomp, rtd);
+ if (!spcm) {
+ dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
+ rtd->dai_link->id);
+ return 0;
+ }
+
+ stream = &spcm->stream[substream->stream];
+ ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn));
+ if (ret < 0) {
+ dev_warn(sdev->dev, "failed to read stream position: %d\n", ret);
+ return 0;
+ }
+
+ memcpy(&stream->posn, &posn, sizeof(posn));
+ pos = spcm->stream[substream->stream].posn.host_posn;
+ pos = bytes_to_frames(substream->runtime, pos);
+
+ return pos;
+}
+EXPORT_SYMBOL(mtk_adsp_stream_pcm_pointer);
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF helpers for MTK ADSP platforms");
diff --git a/sound/soc/sof/mediatek/mtk-adsp-common.h b/sound/soc/sof/mediatek/mtk-adsp-common.h
index 612cff1f38f7..dc36b91d6779 100644
--- a/sound/soc/sof/mediatek/mtk-adsp-common.h
+++ b/sound/soc/sof/mediatek/mtk-adsp-common.h
@@ -7,4 +7,14 @@
#define MTK_ADSP_STACK_DUMP_SIZE 32
void mtk_adsp_dump(struct snd_sof_dev *sdev, u32 flags);
+int mtk_adsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
+void mtk_adsp_handle_reply(struct mtk_adsp_ipc *ipc);
+void mtk_adsp_handle_request(struct mtk_adsp_ipc *ipc);
+int mtk_adsp_get_bar_index(struct snd_sof_dev *sdev, u32 type);
+int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_sof_platform_stream_params *platform_params);
+snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream);
#endif
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
index 35a7462d8b69..d584a72e6f52 100644
--- a/sound/soc/sof/pcm.c
+++ b/sound/soc/sof/pcm.c
@@ -99,8 +99,8 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run
ret = snd_soc_dapm_dai_get_connected_widgets(dai, dir, &list,
dpcm_end_walk_at_be);
if (ret < 0) {
- dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name,
- snd_pcm_direction_name(dir));
+ spcm_err(spcm, dir, "dai %s has no valid %s path\n",
+ dai->name, snd_pcm_direction_name(dir));
return ret;
}
@@ -108,8 +108,7 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run
ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir);
if (ret < 0) {
- dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n",
- spcm->pcm.pcm_id, dir);
+ spcm_err(spcm, dir, "Widget list set up failed\n");
spcm->stream[dir].list = NULL;
snd_soc_dapm_dai_free_widgets(&list);
return ret;
@@ -139,6 +138,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
+ spcm_dbg(spcm, substream->stream, "Entry: hw_params\n");
+
/*
* Handle repeated calls to hw_params() without free_pcm() in
* between. At least ALSA OSS emulation depends on this.
@@ -151,12 +152,9 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
spcm->prepared[substream->stream] = false;
}
- dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
-
ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
if (ret < 0) {
- dev_err(component->dev, "platform hw params failed\n");
+ spcm_err(spcm, substream->stream, "platform hw params failed\n");
return ret;
}
@@ -191,6 +189,84 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
+static int sof_pcm_stream_free(struct snd_sof_dev *sdev,
+ struct snd_pcm_substream *substream,
+ struct snd_sof_pcm *spcm, int dir,
+ bool free_widget_list)
+{
+ const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
+ int ret;
+ int err = 0;
+
+ if (spcm->prepared[substream->stream]) {
+ /* stop DMA first if needed */
+ if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
+ snd_sof_pcm_platform_trigger(sdev, substream,
+ SNDRV_PCM_TRIGGER_STOP);
+
+ /* free PCM in the DSP */
+ if (pcm_ops && pcm_ops->hw_free) {
+ ret = pcm_ops->hw_free(sdev->component, substream);
+ if (ret < 0) {
+ spcm_err(spcm, substream->stream,
+ "pcm_ops->hw_free failed %d\n", ret);
+ err = ret;
+ }
+ }
+
+ spcm->prepared[substream->stream] = false;
+ spcm->pending_stop[substream->stream] = false;
+ }
+
+ /* reset the DMA */
+ ret = snd_sof_pcm_platform_hw_free(sdev, substream);
+ if (ret < 0) {
+ spcm_err(spcm, substream->stream,
+ "platform hw free failed %d\n", ret);
+ if (!err)
+ err = ret;
+ }
+
+ /* free widget list */
+ if (free_widget_list) {
+ ret = sof_widget_list_free(sdev, spcm, dir);
+ if (ret < 0) {
+ spcm_err(spcm, substream->stream,
+ "sof_widget_list_free failed %d\n", ret);
+ if (!err)
+ err = ret;
+ }
+ }
+
+ return err;
+}
+
+int sof_pcm_free_all_streams(struct snd_sof_dev *sdev)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_sof_pcm *spcm;
+ int dir, ret;
+
+ list_for_each_entry(spcm, &sdev->pcm_list, list) {
+ for_each_pcm_streams(dir) {
+ substream = spcm->stream[dir].substream;
+
+ if (!substream || !substream->runtime ||
+ spcm->stream[dir].suspend_ignored)
+ continue;
+
+ if (spcm->stream[dir].list) {
+ ret = sof_pcm_stream_free(sdev, substream, spcm,
+ dir, true);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int sof_pcm_hw_free(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
@@ -207,8 +283,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
+ spcm_dbg(spcm, substream->stream, "Entry: hw_free\n");
ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true);
@@ -233,6 +308,8 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
+ spcm_dbg(spcm, substream->stream, "Entry: prepare\n");
+
if (spcm->prepared[substream->stream]) {
if (!spcm->pending_stop[substream->stream])
return 0;
@@ -246,15 +323,12 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
return ret;
}
- dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
-
/* set hw_params */
ret = sof_pcm_hw_params(component,
substream, &spcm->params[substream->stream]);
if (ret < 0) {
- dev_err(component->dev,
- "error: set pcm hw_params after resume\n");
+ spcm_err(spcm, substream->stream,
+ "failed to set hw_params after resume\n");
return ret;
}
@@ -284,8 +358,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n",
- spcm->pcm.pcm_id, substream->stream, cmd);
+ spcm_dbg(spcm, substream->stream, "Entry: trigger (cmd: %d)\n", cmd);
spcm->pending_stop[substream->stream] = false;
@@ -334,7 +407,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
reset_hw_params = true;
break;
default:
- dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd);
+ spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd);
return -EINVAL;
}
@@ -436,9 +509,7 @@ static int sof_pcm_open(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: open stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
-
+ spcm_dbg(spcm, substream->stream, "Entry: open\n");
caps = &spcm->pcm.caps[substream->stream];
@@ -458,15 +529,6 @@ static int sof_pcm_open(struct snd_soc_component *component,
*/
runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
- dev_dbg(component->dev, "period min %zd max %zd bytes\n",
- runtime->hw.period_bytes_min,
- runtime->hw.period_bytes_max);
- dev_dbg(component->dev, "period count %d max %d\n",
- runtime->hw.periods_min,
- runtime->hw.periods_max);
- dev_dbg(component->dev, "buffer max %zd bytes\n",
- runtime->hw.buffer_bytes_max);
-
/* set wait time - TODO: come from topology */
substream->wait_time = 500;
@@ -476,10 +538,19 @@ static int sof_pcm_open(struct snd_soc_component *component,
spcm->prepared[substream->stream] = false;
ret = snd_sof_pcm_platform_open(sdev, substream);
- if (ret < 0)
- dev_err(component->dev, "error: pcm open failed %d\n", ret);
+ if (ret < 0) {
+ spcm_err(spcm, substream->stream,
+ "platform pcm open failed %d\n", ret);
+ return ret;
+ }
- return ret;
+ spcm_dbg(spcm, substream->stream, "period bytes min %zd, max %zd\n",
+ runtime->hw.period_bytes_min, runtime->hw.period_bytes_max);
+ spcm_dbg(spcm, substream->stream, "period count min %d, max %d\n",
+ runtime->hw.periods_min, runtime->hw.periods_max);
+ spcm_dbg(spcm, substream->stream, "buffer bytes max %zd\n", runtime->hw.buffer_bytes_max);
+
+ return 0;
}
static int sof_pcm_close(struct snd_soc_component *component,
@@ -498,19 +569,20 @@ static int sof_pcm_close(struct snd_soc_component *component,
if (!spcm)
return -EINVAL;
- dev_dbg(component->dev, "pcm: close stream %d dir %d\n",
- spcm->pcm.pcm_id, substream->stream);
+ spcm_dbg(spcm, substream->stream, "Entry: close\n");
err = snd_sof_pcm_platform_close(sdev, substream);
if (err < 0) {
- dev_err(component->dev, "error: pcm close failed %d\n",
- err);
+ spcm_err(spcm, substream->stream,
+ "platform pcm close failed %d\n", err);
/*
* keep going, no point in preventing the close
* from happening
*/
}
+ spcm->stream[substream->stream].substream = NULL;
+
return 0;
}
@@ -536,7 +608,8 @@ static int sof_pcm_new(struct snd_soc_component *component,
return 0;
}
- dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
+ dev_dbg(spcm->scomp->dev, "pcm%u (%s): Entry: pcm_construct\n",
+ spcm->pcm.pcm_id, spcm->pcm.pcm_name);
/* do we need to pre-allocate playback audio buffer pages */
if (!spcm->pcm.playback)
@@ -544,16 +617,15 @@ static int sof_pcm_new(struct snd_soc_component *component,
caps = &spcm->pcm.caps[stream];
- /* pre-allocate playback audio buffer pages */
- dev_dbg(component->dev,
- "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
- caps->name, caps->buffer_size_min, caps->buffer_size_max);
-
if (!pcm->streams[stream].substream) {
- dev_err(component->dev, "error: NULL playback substream!\n");
+ spcm_err(spcm, stream, "NULL playback substream!\n");
return -EINVAL;
}
+ /* pre-allocate playback audio buffer pages */
+ spcm_dbg(spcm, stream, "allocate %s playback DMA buffer size 0x%x max 0x%x\n",
+ caps->name, caps->buffer_size_min, caps->buffer_size_max);
+
snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
0, le32_to_cpu(caps->buffer_size_max));
@@ -566,16 +638,15 @@ capture:
caps = &spcm->pcm.caps[stream];
- /* pre-allocate capture audio buffer pages */
- dev_dbg(component->dev,
- "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
- caps->name, caps->buffer_size_min, caps->buffer_size_max);
-
if (!pcm->streams[stream].substream) {
- dev_err(component->dev, "error: NULL capture substream!\n");
+ spcm_err(spcm, stream, "NULL capture substream!\n");
return -EINVAL;
}
+ /* pre-allocate capture audio buffer pages */
+ spcm_dbg(spcm, stream, "allocate %s capture DMA buffer size 0x%x max 0x%x\n",
+ caps->name, caps->buffer_size_min, caps->buffer_size_max);
+
snd_pcm_set_managed_buffer(pcm->streams[stream].substream,
SNDRV_DMA_TYPE_DEV_SG, sdev->dev,
0, le32_to_cpu(caps->buffer_size_max));
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index 58fd5f7c7905..68bf1b57093e 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -36,12 +36,11 @@ MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)");
#define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0)
-const struct dev_pm_ops sof_acpi_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
- SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
- snd_sof_runtime_idle)
+EXPORT_NS_DEV_PM_OPS(sof_acpi_pm, SND_SOC_SOF_ACPI_DEV) = {
+ SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
+ RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
+ snd_sof_runtime_idle)
};
-EXPORT_SYMBOL_NS(sof_acpi_pm, "SND_SOC_SOF_ACPI_DEV");
static void sof_acpi_probe_complete(struct device *dev)
{
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 9a52781bf8d8..a9664b4cf43f 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -829,55 +829,6 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev)
return false;
}
-int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
- struct snd_sof_pcm *spcm, int dir, bool free_widget_list)
-{
- const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm);
- int ret;
- int err = 0;
-
- if (spcm->prepared[substream->stream]) {
- /* stop DMA first if needed */
- if (pcm_ops && pcm_ops->platform_stop_during_hw_free)
- snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP);
-
- /* free PCM in the DSP */
- if (pcm_ops && pcm_ops->hw_free) {
- ret = pcm_ops->hw_free(sdev->component, substream);
- if (ret < 0) {
- dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n",
- __func__, ret);
- err = ret;
- }
- }
-
- spcm->prepared[substream->stream] = false;
- spcm->pending_stop[substream->stream] = false;
- }
-
- /* reset the DMA */
- ret = snd_sof_pcm_platform_hw_free(sdev, substream);
- if (ret < 0) {
- dev_err(sdev->dev, "%s: platform hw free failed %d\n",
- __func__, ret);
- if (!err)
- err = ret;
- }
-
- /* free widget list */
- if (free_widget_list) {
- ret = sof_widget_list_free(sdev, spcm, dir);
- if (ret < 0) {
- dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n",
- __func__, ret);
- if (!err)
- err = ret;
- }
- }
-
- return err;
-}
-
/*
* Generic object lookup APIs.
*/
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index 01b819dd8498..36ab75e11779 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -332,6 +332,7 @@ struct snd_sof_pcm_stream {
struct work_struct period_elapsed_work;
struct snd_soc_dapm_widget_list *list; /* list of connected DAPM widgets */
bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
+ bool pause_supported; /* PCM device supports PAUSE operation */
unsigned int dsp_max_burst_size_in_ms; /* The maximum size of the host DMA burst in ms */
/*
* flag to indicate that the DSP pipelines should be kept
@@ -616,6 +617,20 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
void snd_sof_pcm_init_elapsed_work(struct work_struct *work);
+/*
+ * snd_sof_pcm specific wrappers for dev_dbg() and dev_err() to provide
+ * consistent and useful prints.
+ */
+#define spcm_dbg(__spcm, __dir, __fmt, ...) \
+ dev_dbg((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \
+ (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
+ ##__VA_ARGS__)
+
+#define spcm_err(__spcm, __dir, __fmt, ...) \
+ dev_err((__spcm)->scomp->dev, "%s: pcm%u (%s), dir %d: " __fmt, \
+ __func__, (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
+ ##__VA_ARGS__)
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS)
void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream);
void snd_sof_compr_init_elapsed_work(struct work_struct *work);
@@ -648,8 +663,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir);
int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm);
-int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream,
- struct snd_sof_pcm *spcm, int dir, bool free_widget_list);
+int sof_pcm_free_all_streams(struct snd_sof_dev *sdev);
int get_token_u32(void *elem, void *object, u32 offset);
int get_token_u16(void *elem, void *object, u32 offset);
int get_token_comp_format(void *elem, void *object, u32 offset);
diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c
index b35c98896968..11b6f7da2882 100644
--- a/sound/soc/sof/sof-client-ipc-flood-test.c
+++ b/sound/soc/sof/sof-client-ipc-flood-test.c
@@ -158,7 +158,6 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf
unsigned long ipc_duration_ms = 0;
bool flood_duration_test = false;
unsigned long ipc_count = 0;
- struct dentry *dentry;
int err;
char *string;
int ret;
@@ -182,14 +181,7 @@ static ssize_t sof_ipc_flood_dfs_write(struct file *file, const char __user *buf
* ipc_duration_ms test floods the DSP for the time specified
* in the debugfs entry.
*/
- dentry = file->f_path.dentry;
- if (strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) &&
- strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) {
- ret = -EINVAL;
- goto out;
- }
-
- if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION))
+ if (debugfs_get_aux_num(file))
flood_duration_test = true;
/* test completion criterion */
@@ -252,22 +244,15 @@ static ssize_t sof_ipc_flood_dfs_read(struct file *file, char __user *buffer,
struct sof_ipc_flood_priv *priv = cdev->data;
size_t size_ret;
- struct dentry *dentry;
+ if (*ppos)
+ return 0;
- dentry = file->f_path.dentry;
- if (!strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_COUNT) ||
- !strcmp(dentry->d_name.name, DEBUGFS_IPC_FLOOD_DURATION)) {
- if (*ppos)
- return 0;
+ count = min_t(size_t, count, strlen(priv->buf));
+ size_ret = copy_to_user(buffer, priv->buf, count);
+ if (size_ret)
+ return -EFAULT;
- count = min_t(size_t, count, strlen(priv->buf));
- size_ret = copy_to_user(buffer, priv->buf, count);
- if (size_ret)
- return -EFAULT;
-
- *ppos += count;
- return count;
- }
+ *ppos += count;
return count;
}
@@ -320,12 +305,12 @@ static int sof_ipc_flood_probe(struct auxiliary_device *auxdev,
priv->dfs_root = debugfs_create_dir(dev_name(dev), debugfs_root);
if (!IS_ERR_OR_NULL(priv->dfs_root)) {
/* create read-write ipc_flood_count debugfs entry */
- debugfs_create_file(DEBUGFS_IPC_FLOOD_COUNT, 0644, priv->dfs_root,
- cdev, &sof_ipc_flood_fops);
+ debugfs_create_file_aux_num(DEBUGFS_IPC_FLOOD_COUNT, 0644,
+ priv->dfs_root, cdev, 0, &sof_ipc_flood_fops);
/* create read-write ipc_flood_duration_ms debugfs entry */
- debugfs_create_file(DEBUGFS_IPC_FLOOD_DURATION, 0644,
- priv->dfs_root, cdev, &sof_ipc_flood_fops);
+ debugfs_create_file_aux_num(DEBUGFS_IPC_FLOOD_DURATION, 0644,
+ priv->dfs_root, cdev, 1, &sof_ipc_flood_fops);
if (auxdev->id == 0) {
/*
diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c
index fb8c8a14d885..3ccfcfb142b7 100644
--- a/sound/soc/sof/sof-of-dev.c
+++ b/sound/soc/sof/sof-of-dev.c
@@ -30,14 +30,12 @@ static char *tplg_filename;
module_param(tplg_filename, charp, 0444);
MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module.");
-const struct dev_pm_ops sof_of_pm = {
+EXPORT_DEV_PM_OPS(sof_of_pm) = {
.prepare = snd_sof_prepare,
.complete = snd_sof_complete,
- SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
- SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
- NULL)
+ SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
+ RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL)
};
-EXPORT_SYMBOL(sof_of_pm);
static void sof_of_probe_complete(struct device *dev)
{
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 103377e2caaf..2fc14b9a33d4 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -155,14 +155,13 @@ static const struct dmi_system_id community_key_platforms[] = {
{},
};
-const struct dev_pm_ops sof_pci_pm = {
+EXPORT_NS_DEV_PM_OPS(sof_pci_pm, SND_SOC_SOF_PCI_DEV) = {
.prepare = snd_sof_prepare,
.complete = snd_sof_complete,
- SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
- SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
- snd_sof_runtime_idle)
+ SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume)
+ RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume,
+ snd_sof_runtime_idle)
};
-EXPORT_SYMBOL_NS(sof_pci_pm, "SND_SOC_SOF_PCI_DEV");
static void sof_pci_probe_complete(struct device *dev)
{
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index 843be3b6415d..abbb5ee7e08c 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -76,14 +76,6 @@ bool sof_debug_check_flag(int mask);
#define SOF_IPC_DSP_REPLY 0
#define SOF_IPC_HOST_REPLY 1
-/* convenience constructor for DAI driver streams */
-#define SOF_DAI_STREAM(sname, scmin, scmax, srates, sfmt) \
- {.stream_name = sname, .channels_min = scmin, .channels_max = scmax, \
- .rates = srates, .formats = sfmt}
-
-#define SOF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
- SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_FLOAT)
-
/* So far the primary core on all DSPs has ID 0 */
#define SOF_DSP_PRIMARY_CORE 0
diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c
index 794c7bbccbaf..8262443ac89a 100644
--- a/sound/soc/sof/stream-ipc.c
+++ b/sound/soc/sof/stream-ipc.c
@@ -43,7 +43,7 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev,
return -ESTRPIPE;
posn_offset = stream->posn_offset;
- } else {
+ } else if (sps->cstream) {
struct sof_compr_stream *sstream = sps->cstream->runtime->private_data;
@@ -51,6 +51,10 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev,
return -ESTRPIPE;
posn_offset = sstream->posn_offset;
+
+ } else {
+ dev_err(sdev->dev, "%s: No stream opened\n", __func__);
+ return -EINVAL;
}
snd_sof_dsp_mailbox_read(sdev, posn_offset, p, sz);
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index b3fca5fd87d6..dc9cb8324067 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -407,6 +407,10 @@ static const struct sof_topology_token stream_tokens[] = {
offsetof(struct snd_sof_pcm, stream[0].d0i3_compatible)},
{SOF_TKN_STREAM_CAPTURE_COMPATIBLE_D0I3, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
offsetof(struct snd_sof_pcm, stream[1].d0i3_compatible)},
+ {SOF_TKN_STREAM_PLAYBACK_PAUSE_SUPPORTED, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
+ offsetof(struct snd_sof_pcm, stream[0].pause_supported)},
+ {SOF_TKN_STREAM_CAPTURE_PAUSE_SUPPORTED, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16,
+ offsetof(struct snd_sof_pcm, stream[1].pause_supported)},
};
/* Leds */
@@ -1269,8 +1273,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
struct snd_sof_tuple *new_tuples;
num_tuples += token_list[object_token_list[i]].count * (num_sets - 1);
- new_tuples = krealloc(swidget->tuples,
- sizeof(*new_tuples) * num_tuples, GFP_KERNEL);
+ new_tuples = krealloc_array(swidget->tuples,
+ num_tuples, sizeof(*new_tuples), GFP_KERNEL);
if (!new_tuples) {
ret = -ENOMEM;
goto err;
diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c
index 19dc61008a75..6037b7a9c97b 100644
--- a/sound/soc/stm/stm32_i2s.c
+++ b/sound/soc/stm/stm32_i2s.c
@@ -1352,7 +1352,6 @@ error:
MODULE_DEVICE_TABLE(of, stm32_i2s_ids);
-#ifdef CONFIG_PM_SLEEP
static int stm32_i2s_suspend(struct device *dev)
{
struct stm32_i2s_data *i2s = dev_get_drvdata(dev);
@@ -1370,17 +1369,16 @@ static int stm32_i2s_resume(struct device *dev)
regcache_cache_only(i2s->regmap, false);
return regcache_sync(i2s->regmap);
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops stm32_i2s_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(stm32_i2s_suspend, stm32_i2s_resume)
+ SYSTEM_SLEEP_PM_OPS(stm32_i2s_suspend, stm32_i2s_resume)
};
static struct platform_driver stm32_i2s_driver = {
.driver = {
.name = "st,stm32-i2s",
.of_match_table = stm32_i2s_ids,
- .pm = &stm32_i2s_pm_ops,
+ .pm = pm_ptr(&stm32_i2s_pm_ops),
},
.probe = stm32_i2s_probe,
.remove = stm32_i2s_remove,
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
index bc8180fc8462..504a14584765 100644
--- a/sound/soc/stm/stm32_sai.c
+++ b/sound/soc/stm/stm32_sai.c
@@ -270,7 +270,6 @@ static int stm32_sai_probe(struct platform_device *pdev)
return devm_of_platform_populate(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
/*
* When pins are shared by two sai sub instances, pins have to be defined
* in sai parent node. In this case, pins state is not managed by alsa fw.
@@ -305,10 +304,9 @@ static int stm32_sai_resume(struct device *dev)
return pinctrl_pm_select_default_state(dev);
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops stm32_sai_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume)
+ SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume)
};
MODULE_DEVICE_TABLE(of, stm32_sai_ids);
@@ -317,7 +315,7 @@ static struct platform_driver stm32_sai_driver = {
.driver = {
.name = "st,stm32-sai",
.of_match_table = stm32_sai_ids,
- .pm = &stm32_sai_pm_ops,
+ .pm = pm_ptr(&stm32_sai_pm_ops),
},
.probe = stm32_sai_probe,
};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
index 3efbf4aaf965..e8c1abf1ae0a 100644
--- a/sound/soc/stm/stm32_sai_sub.c
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -1704,7 +1704,6 @@ static void stm32_sai_sub_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int stm32_sai_sub_suspend(struct device *dev)
{
struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
@@ -1738,17 +1737,16 @@ static int stm32_sai_sub_resume(struct device *dev)
return ret;
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops stm32_sai_sub_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume)
+ SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume)
};
static struct platform_driver stm32_sai_sub_driver = {
.driver = {
.name = "st,stm32-sai-sub",
.of_match_table = stm32_sai_sub_ids,
- .pm = &stm32_sai_sub_pm_ops,
+ .pm = pm_ptr(&stm32_sai_sub_pm_ops),
},
.probe = stm32_sai_sub_probe,
.remove = stm32_sai_sub_remove,
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c
index 9e30852de93c..57b711c44278 100644
--- a/sound/soc/stm/stm32_spdifrx.c
+++ b/sound/soc/stm/stm32_spdifrx.c
@@ -1040,7 +1040,6 @@ error:
MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids);
-#ifdef CONFIG_PM_SLEEP
static int stm32_spdifrx_suspend(struct device *dev)
{
struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev);
@@ -1059,17 +1058,16 @@ static int stm32_spdifrx_resume(struct device *dev)
return regcache_sync(spdifrx->regmap);
}
-#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops stm32_spdifrx_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume)
+ SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume)
};
static struct platform_driver stm32_spdifrx_driver = {
.driver = {
.name = "st,stm32-spdifrx",
.of_match_table = stm32_spdifrx_ids,
- .pm = &stm32_spdifrx_pm_ops,
+ .pm = pm_ptr(&stm32_spdifrx_pm_ops),
},
.probe = stm32_spdifrx_probe,
.remove = stm32_spdifrx_remove,
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 933a0913237c..93733ff2e32a 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -5,6 +5,7 @@
* Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
* Copyright 2015 Adam Sampson <ats@offog.org>
* Copyright 2016 Chen-Yu Tsai <wens@csie.org>
+ * Copyright 2018 Mesih Kilinc <mesihkilinc@gmail.com>
*
* Based on the Allwinner SDK driver, released under the GPL.
*/
@@ -21,6 +22,7 @@
#include <linux/gpio/consumer.h>
#include <sound/core.h>
+#include <sound/jack.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -265,6 +267,64 @@
/* TODO H3 DAP (Digital Audio Processing) bits */
+#define SUN4I_DMA_MAX_BURST (8)
+
+/* suniv specific registers */
+
+#define SUNIV_DMA_MAX_BURST (4)
+
+/* Codec DAC digital controls and FIFO registers */
+#define SUNIV_CODEC_ADC_FIFOC (0x10)
+#define SUNIV_CODEC_ADC_FIFOC_EN_AD (28)
+#define SUNIV_CODEC_ADC_FIFOS (0x14)
+#define SUNIV_CODEC_ADC_RXDATA (0x18)
+
+/* Output mixer and gain controls */
+#define SUNIV_CODEC_OM_DACA_CTRL (0x20)
+#define SUNIV_CODEC_OM_DACA_CTRL_DACAREN (31)
+#define SUNIV_CODEC_OM_DACA_CTRL_DACALEN (30)
+#define SUNIV_CODEC_OM_DACA_CTRL_RMIXEN (29)
+#define SUNIV_CODEC_OM_DACA_CTRL_LMIXEN (28)
+#define SUNIV_CODEC_OM_DACA_CTRL_RHPPAMUTE (27)
+#define SUNIV_CODEC_OM_DACA_CTRL_LHPPAMUTE (26)
+#define SUNIV_CODEC_OM_DACA_CTRL_RHPIS (25)
+#define SUNIV_CODEC_OM_DACA_CTRL_LHPIS (24)
+#define SUNIV_CODEC_OM_DACA_CTRL_HPCOM_CTL (22)
+#define SUNIV_CODEC_OM_DACA_CTRL_COMPTEN (21)
+#define SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_MICIN (20)
+#define SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_LINEIN (19)
+#define SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_FMIN (18)
+#define SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_RDAC (17)
+#define SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_LDAC (16)
+#define SUNIV_CODEC_OM_DACA_CTRL_HPPAEN (15)
+#define SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_MICIN (12)
+#define SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_LINEIN (11)
+#define SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_FMIN (10)
+#define SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_LDAC (9)
+#define SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_RDAC (8)
+#define SUNIV_CODEC_OM_DACA_CTRL_LTLNMUTE (7)
+#define SUNIV_CODEC_OM_DACA_CTRL_RTLNMUTE (6)
+#define SUNIV_CODEC_OM_DACA_CTRL_HPVOL (0)
+
+/* Analog Input Mixer controls */
+#define SUNIV_CODEC_ADC_ACTL (0x24)
+#define SUNIV_CODEC_ADC_ADCEN (31)
+#define SUNIV_CODEC_ADC_MICG (24)
+#define SUNIV_CODEC_ADC_LINEINVOL (21)
+#define SUNIV_CODEC_ADC_ADCG (16)
+#define SUNIV_CODEC_ADC_ADCMIX_MIC (13)
+#define SUNIV_CODEC_ADC_ADCMIX_FMINL (12)
+#define SUNIV_CODEC_ADC_ADCMIX_FMINR (11)
+#define SUNIV_CODEC_ADC_ADCMIX_LINEIN (10)
+#define SUNIV_CODEC_ADC_ADCMIX_LOUT (9)
+#define SUNIV_CODEC_ADC_ADCMIX_ROUT (8)
+#define SUNIV_CODEC_ADC_PASPEEDSELECT (7)
+#define SUNIV_CODEC_ADC_FMINVOL (4)
+#define SUNIV_CODEC_ADC_MICAMPEN (3)
+#define SUNIV_CODEC_ADC_MICBOOST (0)
+
+#define SUNIV_CODEC_ADC_DBG (0x4c)
+
struct sun4i_codec {
struct device *dev;
struct regmap *regmap;
@@ -272,6 +332,7 @@ struct sun4i_codec {
struct clk *clk_module;
struct reset_control *rst;
struct gpio_desc *gpio_pa;
+ struct gpio_desc *gpio_hp;
/* ADC_FIFOC register is at different offset on different SoCs */
struct regmap_field *reg_adc_fifoc;
@@ -1255,6 +1316,228 @@ static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
.endianness = 1,
};
+/*suniv F1C100s codec */
+
+/* headphone controls */
+static const char * const suniv_codec_hp_src_enum_text[] = {
+ "DAC", "Mixer",
+};
+
+static SOC_ENUM_DOUBLE_DECL(suniv_codec_hp_src_enum,
+ SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LHPIS,
+ SUNIV_CODEC_OM_DACA_CTRL_RHPIS,
+ suniv_codec_hp_src_enum_text);
+
+static const struct snd_kcontrol_new suniv_codec_hp_src[] = {
+ SOC_DAPM_ENUM("Headphone Source Playback Route",
+ suniv_codec_hp_src_enum),
+};
+
+/* mixer controls */
+static const struct snd_kcontrol_new suniv_codec_adc_mixer_controls[] = {
+ SOC_DAPM_SINGLE("Right Out Capture Switch", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCMIX_ROUT, 1, 0),
+ SOC_DAPM_SINGLE("Left Out Capture Switch", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCMIX_LOUT, 1, 0),
+ SOC_DAPM_SINGLE("Line In Capture Switch", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCMIX_LINEIN, 1, 0),
+ SOC_DAPM_SINGLE("Right FM In Capture Switch", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCMIX_FMINR, 1, 0),
+ SOC_DAPM_SINGLE("Left FM In Capture Switch", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCMIX_FMINL, 1, 0),
+ SOC_DAPM_SINGLE("Mic Capture Switch", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCMIX_MIC, 1, 0),
+};
+
+static const struct snd_kcontrol_new suniv_codec_dac_lmixer_controls[] = {
+ SOC_DAPM_SINGLE("Right DAC Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_RDAC, 1, 0),
+ SOC_DAPM_SINGLE("Left DAC Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_LDAC, 1, 0),
+ SOC_DAPM_SINGLE("FM In Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_FMIN, 1, 0),
+ SOC_DAPM_SINGLE("Line In Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_LINEIN, 1, 0),
+ SOC_DAPM_SINGLE("Mic In Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LMIXMUTE_MICIN, 1, 0),
+};
+
+static const struct snd_kcontrol_new suniv_codec_dac_rmixer_controls[] = {
+ SOC_DAPM_SINGLE("Left DAC Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_LDAC, 1, 0),
+ SOC_DAPM_SINGLE("Right DAC Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_RDAC, 1, 0),
+ SOC_DAPM_SINGLE("FM In Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_FMIN, 1, 0),
+ SOC_DAPM_SINGLE("Line In Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_LINEIN, 1, 0),
+ SOC_DAPM_SINGLE("Mic In Playback Switch", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_RMIXMUTE_MICIN, 1, 0),
+};
+
+static const DECLARE_TLV_DB_SCALE(suniv_codec_dvol_scale, -7308, 116, 0);
+static const DECLARE_TLV_DB_SCALE(suniv_codec_hp_vol_scale, -6300, 100, 1);
+static const DECLARE_TLV_DB_SCALE(suniv_codec_out_mixer_pregain_scale,
+ -450, 150, 0);
+
+static const DECLARE_TLV_DB_RANGE(suniv_codec_mic_gain_scale,
+ 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
+ 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
+);
+
+static const struct snd_kcontrol_new suniv_codec_codec_widgets[] = {
+ SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1,
+ suniv_codec_dvol_scale),
+ SOC_SINGLE_TLV("Headphone Playback Volume",
+ SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0,
+ suniv_codec_hp_vol_scale),
+ SOC_DOUBLE("Headphone Playback Switch",
+ SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LHPPAMUTE,
+ SUNIV_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0),
+ SOC_SINGLE_TLV("Line In Playback Volume",
+ SUNIV_CODEC_ADC_ACTL, SUNIV_CODEC_ADC_LINEINVOL,
+ 0x7, 0, suniv_codec_out_mixer_pregain_scale),
+ SOC_SINGLE_TLV("FM In Playback Volume",
+ SUNIV_CODEC_ADC_ACTL, SUNIV_CODEC_ADC_FMINVOL,
+ 0x7, 0, suniv_codec_out_mixer_pregain_scale),
+ SOC_SINGLE_TLV("Mic In Playback Volume",
+ SUNIV_CODEC_ADC_ACTL, SUNIV_CODEC_ADC_MICG,
+ 0x7, 0, suniv_codec_out_mixer_pregain_scale),
+
+ /* Microphone Amp boost gains */
+ SOC_SINGLE_TLV("Mic Boost Volume", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_MICBOOST, 0x7, 0,
+ suniv_codec_mic_gain_scale),
+ SOC_SINGLE_TLV("ADC Capture Volume",
+ SUNIV_CODEC_ADC_ACTL, SUNIV_CODEC_ADC_ADCG,
+ 0x7, 0, suniv_codec_out_mixer_pregain_scale),
+};
+
+static const struct snd_soc_dapm_widget suniv_codec_codec_dapm_widgets[] = {
+ /* Microphone inputs */
+ SND_SOC_DAPM_INPUT("MIC"),
+
+ /* Microphone Bias */
+ /* deleted: HBIAS, MBIAS */
+
+ /* Mic input path */
+ SND_SOC_DAPM_PGA("Mic Amplifier", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_MICAMPEN, 0, NULL, 0),
+
+ /* Line In */
+ SND_SOC_DAPM_INPUT("LINEIN"),
+
+ /* FM In */
+ SND_SOC_DAPM_INPUT("FMINR"),
+ SND_SOC_DAPM_INPUT("FMINL"),
+
+ /* Digital parts of the ADCs */
+ SND_SOC_DAPM_SUPPLY("ADC Enable", SUNIV_CODEC_ADC_FIFOC,
+ SUNIV_CODEC_ADC_FIFOC_EN_AD, 0,
+ NULL, 0),
+
+ /* Analog parts of the ADCs */
+ SND_SOC_DAPM_ADC("ADC", "Codec Capture", SUNIV_CODEC_ADC_ACTL,
+ SUNIV_CODEC_ADC_ADCEN, 0),
+
+ /* ADC Mixers */
+ SOC_MIXER_ARRAY("ADC Mixer", SUNIV_CODEC_ADC_ACTL,
+ SND_SOC_NOPM, 0,
+ suniv_codec_adc_mixer_controls),
+
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC,
+ SUN4I_CODEC_DAC_DPC_EN_DA, 0,
+ NULL, 0),
+
+ /* Analog parts of the DACs */
+ SND_SOC_DAPM_DAC("Left DAC", "Codec Playback",
+ SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_DACALEN, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Codec Playback",
+ SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_DACAREN, 0),
+
+ /* Mixers */
+ SOC_MIXER_ARRAY("Left Mixer", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_LMIXEN, 0,
+ suniv_codec_dac_lmixer_controls),
+ SOC_MIXER_ARRAY("Right Mixer", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_RMIXEN, 0,
+ suniv_codec_dac_rmixer_controls),
+
+ /* Headphone output path */
+ SND_SOC_DAPM_MUX("Headphone Source Playback Route",
+ SND_SOC_NOPM, 0, 0, suniv_codec_hp_src),
+ SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_HPPAEN, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_COMPTEN, 0, NULL, 0),
+ SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUNIV_CODEC_OM_DACA_CTRL,
+ SUNIV_CODEC_OM_DACA_CTRL_HPCOM_CTL, 0x3, 0x3, 0),
+ SND_SOC_DAPM_OUTPUT("HP"),
+};
+
+static const struct snd_soc_dapm_route suniv_codec_codec_dapm_routes[] = {
+ /* DAC Routes */
+ { "Left DAC", NULL, "DAC Enable" },
+ { "Right DAC", NULL, "DAC Enable" },
+
+ /* Microphone Routes */
+ { "Mic Amplifier", NULL, "MIC"},
+
+ /* Left Mixer Routes */
+ { "Left Mixer", "Right DAC Playback Switch", "Right DAC" },
+ { "Left Mixer", "Left DAC Playback Switch", "Left DAC" },
+ { "Left Mixer", "FM In Playback Switch", "FMINL" },
+ { "Left Mixer", "Line In Playback Switch", "LINEIN" },
+ { "Left Mixer", "Mic In Playback Switch", "Mic Amplifier" },
+
+ /* Right Mixer Routes */
+ { "Right Mixer", "Left DAC Playback Switch", "Left DAC" },
+ { "Right Mixer", "Right DAC Playback Switch", "Right DAC" },
+ { "Right Mixer", "FM In Playback Switch", "FMINR" },
+ { "Right Mixer", "Line In Playback Switch", "LINEIN" },
+ { "Right Mixer", "Mic In Playback Switch", "Mic Amplifier" },
+
+ /* ADC Mixer Routes */
+ { "ADC Mixer", "Right Out Capture Switch", "Right Mixer" },
+ { "ADC Mixer", "Left Out Capture Switch", "Left Mixer" },
+ { "ADC Mixer", "Line In Capture Switch", "LINEIN" },
+ { "ADC Mixer", "Right FM In Capture Switch", "FMINR" },
+ { "ADC Mixer", "Left FM In Capture Switch", "FMINL" },
+ { "ADC Mixer", "Mic Capture Switch", "Mic Amplifier" },
+
+ /* Headphone Routes */
+ { "Headphone Source Playback Route", "DAC", "Left DAC" },
+ { "Headphone Source Playback Route", "DAC", "Right DAC" },
+ { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
+ { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
+ { "Headphone Amp", NULL, "Headphone Source Playback Route" },
+ { "HP", NULL, "Headphone Amp" },
+ { "HPCOM", NULL, "HPCOM Protection" },
+
+ /* ADC Routes */
+ { "ADC", NULL, "ADC Mixer" },
+ { "ADC", NULL, "ADC Enable" },
+};
+
+static const struct snd_soc_component_driver suniv_codec_codec = {
+ .controls = suniv_codec_codec_widgets,
+ .num_controls = ARRAY_SIZE(suniv_codec_codec_widgets),
+ .dapm_widgets = suniv_codec_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(suniv_codec_codec_dapm_widgets),
+ .dapm_routes = suniv_codec_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(suniv_codec_codec_dapm_routes),
+ .idle_bias_on = 1,
+ .use_pmdown_time = 1,
+ .endianness = 1,
+};
+
static const struct snd_soc_component_driver sun4i_codec_component = {
.name = "sun4i-codec",
.legacy_dai_naming = 1,
@@ -1302,6 +1585,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
.ops = &dummy_dai_ops,
};
+static struct snd_soc_jack sun4i_headphone_jack;
+
+static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = {
+ { .pin = "Headphone", .mask = SND_JACK_HEADPHONE },
+};
+
+static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = {
+ .name = "hp-det",
+ .report = SND_JACK_HEADPHONE,
+ .debounce_time = 150,
+};
+
+static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_card *card = rtd->card;
+ struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+ int ret;
+
+ if (scodec->gpio_hp) {
+ ret = snd_soc_card_jack_new_pins(card, "Headphone Jack",
+ SND_JACK_HEADPHONE,
+ &sun4i_headphone_jack,
+ sun4i_headphone_jack_pins,
+ ARRAY_SIZE(sun4i_headphone_jack_pins));
+ if (ret) {
+ dev_err(rtd->dev,
+ "Headphone jack creation failed: %d\n", ret);
+ return ret;
+ }
+
+ sun4i_headphone_jack_gpio.desc = scodec->gpio_hp;
+ ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1,
+ &sun4i_headphone_jack_gpio);
+
+ if (ret) {
+ dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
int *num_links)
{
@@ -1327,6 +1653,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
link->codecs->name = dev_name(dev);
link->platforms->name = dev_name(dev);
link->dai_fmt = SND_SOC_DAIFMT_I2S;
+ link->init = sun4i_codec_machine_init;
*num_links = 1;
@@ -1635,10 +1962,11 @@ static const struct snd_soc_component_driver sun50i_h616_codec_codec = {
};
static const struct snd_kcontrol_new sun50i_h616_card_controls[] = {
- SOC_DAPM_PIN_SWITCH("LINEOUT"),
+ SOC_DAPM_PIN_SWITCH("Speaker"),
};
static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_LINE("Line Out", NULL),
SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
};
@@ -1685,6 +2013,7 @@ static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev)
card->dev = dev;
card->owner = THIS_MODULE;
card->name = "H616 Audio Codec";
+ card->long_name = "h616-audio-codec";
card->driver_name = "sun4i-codec";
card->controls = sun50i_h616_card_controls;
card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls);
@@ -1701,6 +2030,56 @@ static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev)
return card;
};
+static const struct snd_soc_dapm_widget suniv_codec_card_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_LINE("Line In", NULL),
+ SND_SOC_DAPM_LINE("Right FM In", NULL),
+ SND_SOC_DAPM_LINE("Left FM In", NULL),
+ SND_SOC_DAPM_MIC("Mic", NULL),
+ SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event),
+};
+
+/* Connect digital side enables to analog side widgets */
+static const struct snd_soc_dapm_route suniv_codec_card_routes[] = {
+ /* ADC Routes */
+ { "ADC", NULL, "ADC Enable" },
+ { "Codec Capture", NULL, "ADC" },
+
+ /* DAC Routes */
+ { "Left DAC", NULL, "DAC Enable" },
+ { "Right DAC", NULL, "DAC Enable" },
+ { "Left DAC", NULL, "Codec Playback" },
+ { "Right DAC", NULL, "Codec Playback" },
+};
+
+static struct snd_soc_card *suniv_codec_create_card(struct device *dev)
+{
+ struct snd_soc_card *card;
+ int ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
+ if (!card->dai_link)
+ return ERR_PTR(-ENOMEM);
+
+ card->dev = dev;
+ card->name = "F1C100s Audio Codec";
+ card->dapm_widgets = suniv_codec_card_dapm_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(suniv_codec_card_dapm_widgets);
+ card->dapm_routes = suniv_codec_card_routes;
+ card->num_dapm_routes = ARRAY_SIZE(suniv_codec_card_routes);
+ card->fully_routed = true;
+
+ ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing");
+ if (ret)
+ dev_warn(dev, "failed to parse audio-routing: %d\n", ret);
+
+ return card;
+};
+
static const struct regmap_config sun4i_codec_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -1751,6 +2130,13 @@ static const struct regmap_config sun50i_h616_codec_regmap_config = {
.cache_type = REGCACHE_NONE,
};
+static const struct regmap_config suniv_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUNIV_CODEC_ADC_DBG,
+};
+
struct sun4i_codec_quirks {
const struct regmap_config *regmap_config;
const struct snd_soc_component_driver *codec;
@@ -1761,6 +2147,7 @@ struct sun4i_codec_quirks {
unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */
bool has_reset;
bool playback_only;
+ u32 dma_max_burst;
};
static const struct sun4i_codec_quirks sun4i_codec_quirks = {
@@ -1771,6 +2158,7 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = {
.reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
};
static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
@@ -1782,6 +2170,7 @@ static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = {
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
.has_reset = true,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
};
static const struct sun4i_codec_quirks sun7i_codec_quirks = {
@@ -1792,6 +2181,7 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = {
.reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
};
static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
@@ -1803,6 +2193,7 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = {
.reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
.has_reset = true,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
};
static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
@@ -1819,6 +2210,7 @@ static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = {
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
.has_reset = true,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
};
static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
@@ -1834,6 +2226,7 @@ static const struct sun4i_codec_quirks sun8i_v3s_codec_quirks = {
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
.reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA,
.has_reset = true,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
};
static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = {
@@ -1843,6 +2236,19 @@ static const struct sun4i_codec_quirks sun50i_h616_codec_quirks = {
.reg_dac_fifoc = REG_FIELD(SUN50I_H616_CODEC_DAC_FIFOC, 0, 31),
.reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA,
.has_reset = true,
+ .dma_max_burst = SUN4I_DMA_MAX_BURST,
+};
+
+static const struct sun4i_codec_quirks suniv_f1c100s_codec_quirks = {
+ .regmap_config = &suniv_codec_regmap_config,
+ .codec = &suniv_codec_codec,
+ .create_card = suniv_codec_create_card,
+ .reg_adc_fifoc = REG_FIELD(SUNIV_CODEC_ADC_FIFOC, 0, 31),
+ .reg_dac_fifoc = REG_FIELD(SUN4I_CODEC_DAC_FIFOC, 0, 31),
+ .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA,
+ .reg_adc_rxdata = SUNIV_CODEC_ADC_RXDATA,
+ .has_reset = true,
+ .dma_max_burst = SUNIV_DMA_MAX_BURST,
};
static const struct of_device_id sun4i_codec_of_match[] = {
@@ -1874,6 +2280,10 @@ static const struct of_device_id sun4i_codec_of_match[] = {
.compatible = "allwinner,sun50i-h616-codec",
.data = &sun50i_h616_codec_quirks,
},
+ {
+ .compatible = "allwinner,suniv-f1c100s-codec",
+ .data = &suniv_f1c100s_codec_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
@@ -1911,7 +2321,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
}
/* Get the clocks from the DT */
- scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
+ 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);
@@ -1924,8 +2334,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
}
if (quirks->has_reset) {
- scodec->rst = devm_reset_control_get_exclusive(&pdev->dev,
- NULL);
+ 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);
@@ -1940,6 +2349,13 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return ret;
}
+ 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;
+ }
+
/* reg_field setup */
scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
scodec->regmap,
@@ -1961,32 +2377,16 @@ static int sun4i_codec_probe(struct platform_device *pdev)
return ret;
}
- /* Enable the bus clock */
- if (clk_prepare_enable(scodec->clk_apb)) {
- dev_err(&pdev->dev, "Failed to enable the APB clock\n");
- return -EINVAL;
- }
-
- /* Deassert the reset control */
- if (scodec->rst) {
- ret = reset_control_deassert(scodec->rst);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to deassert the reset control\n");
- goto err_clk_disable;
- }
- }
-
/* DMA configuration for TX FIFO */
scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata;
- scodec->playback_dma_data.maxburst = 8;
+ scodec->playback_dma_data.maxburst = quirks->dma_max_burst;
scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
if (!quirks->playback_only) {
/* DMA configuration for RX FIFO */
scodec->capture_dma_data.addr = res->start +
quirks->reg_adc_rxdata;
- scodec->capture_dma_data.maxburst = 8;
+ scodec->capture_dma_data.maxburst = quirks->dma_max_burst;
scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
}
@@ -1994,7 +2394,7 @@ static int sun4i_codec_probe(struct platform_device *pdev)
&sun4i_codec_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our codec\n");
- goto err_assert_reset;
+ return ret;
}
ret = devm_snd_soc_register_component(&pdev->dev,
@@ -2002,20 +2402,20 @@ static int sun4i_codec_probe(struct platform_device *pdev)
&dummy_cpu_dai, 1);
if (ret) {
dev_err(&pdev->dev, "Failed to register our DAI\n");
- goto err_assert_reset;
+ return ret;
}
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
- goto err_assert_reset;
+ 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");
- goto err_assert_reset;
+ return ret;
}
snd_soc_card_set_drvdata(card, scodec);
@@ -2023,28 +2423,17 @@ static int sun4i_codec_probe(struct platform_device *pdev)
ret = snd_soc_register_card(card);
if (ret) {
dev_err_probe(&pdev->dev, ret, "Failed to register our card\n");
- goto err_assert_reset;
+ return ret;
}
return 0;
-
-err_assert_reset:
- if (scodec->rst)
- reset_control_assert(scodec->rst);
-err_clk_disable:
- clk_disable_unprepare(scodec->clk_apb);
- return ret;
}
static void sun4i_codec_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card);
- if (scodec->rst)
- reset_control_assert(scodec->rst);
- clk_disable_unprepare(scodec->clk_apb);
}
static struct platform_driver sun4i_codec_driver = {
@@ -2063,4 +2452,5 @@ MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com");
+MODULE_AUTHOR("Mesih Kilinc <mesikilinc@gmail.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c
index 0aa416423246..34e5bd94e9af 100644
--- a/sound/soc/sunxi/sun4i-spdif.c
+++ b/sound/soc/sunxi/sun4i-spdif.c
@@ -176,6 +176,7 @@ struct sun4i_spdif_quirks {
unsigned int reg_dac_txdata;
bool has_reset;
unsigned int val_fctl_ftx;
+ unsigned int mclk_multiplier;
};
struct sun4i_spdif_dev {
@@ -201,6 +202,10 @@ static void sun4i_spdif_configure(struct sun4i_spdif_dev *host)
regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
quirks->val_fctl_ftx, quirks->val_fctl_ftx);
+ /* Valid data at the MSB of TXFIFO Register */
+ regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
+ SUN4I_SPDIF_FCTL_TXIM, 0);
+
/* clear TX counter */
regmap_write(host->regmap, SUN4I_SPDIF_TXCNT, 0);
}
@@ -282,14 +287,17 @@ static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
fmt |= SUN4I_SPDIF_TXCFG_FMT16BIT;
+ host->dma_params_tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
fmt |= SUN4I_SPDIF_TXCFG_FMT20BIT;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S32_LE:
fmt |= SUN4I_SPDIF_TXCFG_FMT24BIT;
break;
default:
@@ -313,6 +321,7 @@ static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
default:
return -EINVAL;
}
+ mclk *= host->quirks->mclk_multiplier;
ret = clk_set_rate(host->spdif_clk, mclk);
if (ret < 0) {
@@ -321,9 +330,6 @@ static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- regmap_update_bits(host->regmap, SUN4I_SPDIF_FCTL,
- SUN4I_SPDIF_FCTL_TXIM, SUN4I_SPDIF_FCTL_TXIM);
-
switch (rate) {
case 22050:
case 24000:
@@ -347,6 +353,7 @@ static int sun4i_spdif_hw_params(struct snd_pcm_substream *substream,
default:
return -EINVAL;
}
+ mclk_div *= host->quirks->mclk_multiplier;
reg_val = 0;
reg_val |= SUN4I_SPDIF_TXCFG_ASS;
@@ -522,9 +529,10 @@ static const struct regmap_config sun4i_spdif_regmap_config = {
#define SUN4I_RATES SNDRV_PCM_RATE_8000_192000
-#define SUN4I_FORMATS (SNDRV_PCM_FORMAT_S16_LE | \
- SNDRV_PCM_FORMAT_S20_3LE | \
- SNDRV_PCM_FORMAT_S24_LE)
+#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver sun4i_spdif_dai = {
.playback = {
@@ -540,24 +548,28 @@ static struct snd_soc_dai_driver sun4i_spdif_dai = {
static const struct sun4i_spdif_quirks sun4i_a10_spdif_quirks = {
.reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
.val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX,
+ .mclk_multiplier = 1,
};
static const struct sun4i_spdif_quirks sun6i_a31_spdif_quirks = {
.reg_dac_txdata = SUN4I_SPDIF_TXFIFO,
.val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX,
.has_reset = true,
+ .mclk_multiplier = 1,
};
static const struct sun4i_spdif_quirks sun8i_h3_spdif_quirks = {
.reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
.val_fctl_ftx = SUN4I_SPDIF_FCTL_FTX,
.has_reset = true,
+ .mclk_multiplier = 4,
};
static const struct sun4i_spdif_quirks sun50i_h6_spdif_quirks = {
.reg_dac_txdata = SUN8I_SPDIF_TXFIFO,
.val_fctl_ftx = SUN50I_H6_SPDIF_FCTL_FTX,
.has_reset = true,
+ .mclk_multiplier = 1,
};
static const struct of_device_id sun4i_spdif_of_match[] = {
@@ -715,15 +727,15 @@ static void sun4i_spdif_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops sun4i_spdif_pm = {
- SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
- sun4i_spdif_runtime_resume, NULL)
+ RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend,
+ sun4i_spdif_runtime_resume, NULL)
};
static struct platform_driver sun4i_spdif_driver = {
.driver = {
.name = "sun4i-spdif",
.of_match_table = sun4i_spdif_of_match,
- .pm = &sun4i_spdif_pm,
+ .pm = pm_ptr(&sun4i_spdif_pm),
},
.probe = sun4i_spdif_probe,
.remove = sun4i_spdif_remove,
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
index 3e751b5694fe..bab1e29c9988 100644
--- a/sound/soc/sunxi/sun50i-dmic.c
+++ b/sound/soc/sunxi/sun50i-dmic.c
@@ -415,15 +415,15 @@ static void sun50i_dmic_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops sun50i_dmic_pm = {
- SET_RUNTIME_PM_OPS(sun50i_dmic_runtime_suspend,
- sun50i_dmic_runtime_resume, NULL)
+ RUNTIME_PM_OPS(sun50i_dmic_runtime_suspend,
+ sun50i_dmic_runtime_resume, NULL)
};
static struct platform_driver sun50i_dmic_driver = {
.driver = {
.name = "sun50i-dmic",
.of_match_table = sun50i_dmic_of_match,
- .pm = &sun50i_dmic_pm,
+ .pm = pm_ptr(&sun50i_dmic_pm),
},
.probe = sun50i_dmic_probe,
.remove = sun50i_dmic_remove,
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
index 8c645e04d571..8b9eb1a202f7 100644
--- a/sound/soc/sunxi/sun8i-codec.c
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -1702,15 +1702,15 @@ static const struct of_device_id sun8i_codec_of_match[] = {
MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
static const struct dev_pm_ops sun8i_codec_pm_ops = {
- SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
- sun8i_codec_runtime_resume, NULL)
+ RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
+ sun8i_codec_runtime_resume, NULL)
};
static struct platform_driver sun8i_codec_driver = {
.driver = {
.name = "sun8i-codec",
.of_match_table = sun8i_codec_of_match,
- .pm = &sun8i_codec_pm_ops,
+ .pm = pm_ptr(&sun8i_codec_pm_ops),
},
.probe = sun8i_codec_probe,
.remove = sun8i_codec_remove,
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index cea4b0d54378..defea7f53f11 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -13,7 +13,7 @@ snd-soc-tegra210-dmic-y := tegra210_dmic.o
snd-soc-tegra210-i2s-y := tegra210_i2s.o
snd-soc-tegra186-asrc-y := tegra186_asrc.o
snd-soc-tegra186-dspk-y := tegra186_dspk.o
-snd-soc-tegra210-admaif-y := tegra210_admaif.o
+snd-soc-tegra210-admaif-y := tegra210_admaif.o tegra_isomgr_bw.o
snd-soc-tegra210-mvc-y := tegra210_mvc.o
snd-soc-tegra210-sfc-y := tegra210_sfc.o
snd-soc-tegra210-amx-y := tegra210_amx.o
diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c
index d914dba56013..5c67e1f01d9b 100644
--- a/sound/soc/tegra/tegra186_asrc.c
+++ b/sound/soc/tegra/tegra186_asrc.c
@@ -76,7 +76,7 @@ static void tegra186_asrc_lock_stream(struct tegra186_asrc *asrc,
1);
}
-static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev)
+static int tegra186_asrc_runtime_suspend(struct device *dev)
{
struct tegra186_asrc *asrc = dev_get_drvdata(dev);
@@ -86,7 +86,7 @@ static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra186_asrc_runtime_resume(struct device *dev)
+static int tegra186_asrc_runtime_resume(struct device *dev)
{
struct tegra186_asrc *asrc = dev_get_drvdata(dev);
int id;
@@ -1021,17 +1021,16 @@ static void tegra186_asrc_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra186_asrc_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend,
- tegra186_asrc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend,
+ tegra186_asrc_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra186_asrc_driver = {
.driver = {
.name = "tegra186-asrc",
.of_match_table = tegra186_asrc_of_match,
- .pm = &tegra186_asrc_pm_ops,
+ .pm = pm_ptr(&tegra186_asrc_pm_ops),
},
.probe = tegra186_asrc_platform_probe,
.remove = tegra186_asrc_platform_remove,
diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c
index 1be6c09cbe1a..21fdab2a1977 100644
--- a/sound/soc/tegra/tegra186_dspk.c
+++ b/sound/soc/tegra/tegra186_dspk.c
@@ -181,7 +181,7 @@ static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol *kcontrol,
return 1;
}
-static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev)
+static int tegra186_dspk_runtime_suspend(struct device *dev)
{
struct tegra186_dspk *dspk = dev_get_drvdata(dev);
@@ -193,7 +193,7 @@ static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra186_dspk_runtime_resume(struct device *dev)
+static int tegra186_dspk_runtime_resume(struct device *dev)
{
struct tegra186_dspk *dspk = dev_get_drvdata(dev);
int err;
@@ -532,17 +532,16 @@ static void tegra186_dspk_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra186_dspk_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend,
- tegra186_dspk_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend,
+ tegra186_dspk_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra186_dspk_driver = {
.driver = {
.name = "tegra186-dspk",
.of_match_table = tegra186_dspk_of_match,
- .pm = &tegra186_dspk_pm_ops,
+ .pm = pm_ptr(&tegra186_dspk_pm_ops),
},
.probe = tegra186_dspk_platform_probe,
.remove = tegra186_dspk_platform_remove,
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 3b9823d1a87a..51df0835ce3e 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -34,7 +34,7 @@
#define DRV_NAME "tegra20-i2s"
-static __maybe_unused int tegra20_i2s_runtime_suspend(struct device *dev)
+static int tegra20_i2s_runtime_suspend(struct device *dev)
{
struct tegra20_i2s *i2s = dev_get_drvdata(dev);
@@ -45,7 +45,7 @@ static __maybe_unused int tegra20_i2s_runtime_suspend(struct device *dev)
return 0;
}
-static __maybe_unused int tegra20_i2s_runtime_resume(struct device *dev)
+static int tegra20_i2s_runtime_resume(struct device *dev)
{
struct tegra20_i2s *i2s = dev_get_drvdata(dev);
int ret;
@@ -487,17 +487,16 @@ static const struct of_device_id tegra20_i2s_of_match[] = {
};
static const struct dev_pm_ops tegra20_i2s_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
- tegra20_i2s_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
+ tegra20_i2s_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra20_i2s_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = tegra20_i2s_of_match,
- .pm = &tegra20_i2s_pm_ops,
+ .pm = pm_ptr(&tegra20_i2s_pm_ops),
},
.probe = tegra20_i2s_platform_probe,
.remove = tegra20_i2s_platform_remove,
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 380011233eb1..38661d9b4a7c 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -25,7 +25,7 @@
#include "tegra20_spdif.h"
-static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev)
+static int tegra20_spdif_runtime_suspend(struct device *dev)
{
struct tegra20_spdif *spdif = dev_get_drvdata(dev);
@@ -36,7 +36,7 @@ static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev)
return 0;
}
-static __maybe_unused int tegra20_spdif_runtime_resume(struct device *dev)
+static int tegra20_spdif_runtime_resume(struct device *dev)
{
struct tegra20_spdif *spdif = dev_get_drvdata(dev);
int ret;
@@ -403,10 +403,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra20_spdif_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
- tegra20_spdif_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
+ tegra20_spdif_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct of_device_id tegra20_spdif_of_match[] = {
@@ -418,7 +417,7 @@ MODULE_DEVICE_TABLE(of, tegra20_spdif_of_match);
static struct platform_driver tegra20_spdif_driver = {
.driver = {
.name = "tegra20-spdif",
- .pm = &tegra20_spdif_pm_ops,
+ .pm = pm_ptr(&tegra20_spdif_pm_ops),
.of_match_table = tegra20_spdif_of_match,
},
.probe = tegra20_spdif_platform_probe,
diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c
index 58fdb0e79954..76ff4fe40f65 100644
--- a/sound/soc/tegra/tegra210_admaif.c
+++ b/sound/soc/tegra/tegra210_admaif.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES.
+// SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES.
// All rights reserved.
//
// tegra210_admaif.c - Tegra ADMAIF driver
@@ -13,6 +13,7 @@
#include <linux/regmap.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include "tegra_isomgr_bw.h"
#include "tegra210_admaif.h"
#include "tegra_cif.h"
#include "tegra_pcm.h"
@@ -219,7 +220,7 @@ static const struct regmap_config tegra186_admaif_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
-static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)
+static int tegra_admaif_runtime_suspend(struct device *dev)
{
struct tegra_admaif *admaif = dev_get_drvdata(dev);
@@ -229,7 +230,7 @@ static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra_admaif_runtime_resume(struct device *dev)
+static int tegra_admaif_runtime_resume(struct device *dev)
{
struct tegra_admaif *admaif = dev_get_drvdata(dev);
@@ -262,6 +263,18 @@ static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg,
return 0;
}
+static int tegra_admaif_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ return tegra_isomgr_adma_setbw(substream, dai, true);
+}
+
+static void tegra_admaif_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ tegra_isomgr_adma_setbw(substream, dai, false);
+}
+
static int tegra_admaif_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -554,6 +567,8 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
.probe = tegra_admaif_dai_probe,
.hw_params = tegra_admaif_hw_params,
.trigger = tegra_admaif_trigger,
+ .shutdown = tegra_admaif_shutdown,
+ .prepare = tegra_admaif_prepare,
};
#define DAI(dai_name) \
@@ -800,6 +815,12 @@ static int tegra_admaif_probe(struct platform_device *pdev)
regcache_cache_only(admaif->regmap, true);
+ err = tegra_isomgr_adma_register(&pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add interconnect path\n");
+ return err;
+ }
+
regmap_update_bits(admaif->regmap, admaif->soc_data->global_base +
TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1);
@@ -851,14 +872,14 @@ static int tegra_admaif_probe(struct platform_device *pdev)
static void tegra_admaif_remove(struct platform_device *pdev)
{
+ tegra_isomgr_adma_unregister(&pdev->dev);
pm_runtime_disable(&pdev->dev);
}
static const struct dev_pm_ops tegra_admaif_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
- tegra_admaif_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra_admaif_runtime_suspend,
+ tegra_admaif_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra_admaif_driver = {
@@ -867,7 +888,7 @@ static struct platform_driver tegra_admaif_driver = {
.driver = {
.name = "tegra210-admaif",
.of_match_table = tegra_admaif_of_match,
- .pm = &tegra_admaif_pm_ops,
+ .pm = pm_ptr(&tegra_admaif_pm_ops),
},
};
module_platform_driver(tegra_admaif_driver);
diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h
index 96686dc92081..748f886ee74e 100644
--- a/sound/soc/tegra/tegra210_admaif.h
+++ b/sound/soc/tegra/tegra210_admaif.h
@@ -1,8 +1,8 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * tegra210_admaif.h - Tegra ADMAIF registers
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES.
+ * All rights reserved.
*
- * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved.
+ * tegra210_admaif.h - Tegra ADMAIF registers
*
*/
@@ -157,6 +157,7 @@ struct tegra_admaif {
unsigned int *mono_to_stereo[ADMAIF_PATHS];
unsigned int *stereo_to_mono[ADMAIF_PATHS];
struct regmap *regmap;
+ struct tegra_adma_isomgr *adma_isomgr;
};
#endif
diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c
index 3e6e8f51f380..b6c798baedea 100644
--- a/sound/soc/tegra/tegra210_adx.c
+++ b/sound/soc/tegra/tegra210_adx.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES.
+// SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES.
// All rights reserved.
//
// tegra210_adx.c - Tegra210 ADX driver
@@ -57,8 +57,8 @@ static int tegra210_adx_startup(struct snd_pcm_substream *substream,
int err;
/* Ensure if ADX status is disabled */
- err = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS,
- val, !(val & 0x1), 10, 10000);
+ err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_STATUS,
+ val, !(val & 0x1), 10, 10000);
if (err < 0) {
dev_err(dai->dev, "failed to stop ADX, err = %d\n", err);
return err;
@@ -84,7 +84,7 @@ static int tegra210_adx_startup(struct snd_pcm_substream *substream,
return 0;
}
-static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev)
+static int tegra210_adx_runtime_suspend(struct device *dev)
{
struct tegra210_adx *adx = dev_get_drvdata(dev);
@@ -94,7 +94,7 @@ static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev)
+static int tegra210_adx_runtime_resume(struct device *dev)
{
struct tegra210_adx *adx = dev_get_drvdata(dev);
@@ -264,7 +264,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = {
.rates = SNDRV_PCM_RATE_8000_192000, \
.formats = SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE, \
}, \
.capture = { \
@@ -274,7 +274,7 @@ static const struct snd_soc_dai_ops tegra210_adx_out_dai_ops = {
.rates = SNDRV_PCM_RATE_8000_192000, \
.formats = SNDRV_PCM_FMTBIT_S8 | \
SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE, \
}, \
.ops = &tegra210_adx_out_dai_ops, \
@@ -524,17 +524,16 @@ static void tegra210_adx_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_adx_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
- tegra210_adx_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
+ tegra210_adx_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra210_adx_driver = {
.driver = {
.name = "tegra210-adx",
.of_match_table = tegra210_adx_of_match,
- .pm = &tegra210_adx_pm_ops,
+ .pm = pm_ptr(&tegra210_adx_pm_ops),
},
.probe = tegra210_adx_platform_probe,
.remove = tegra210_adx_platform_remove,
diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c
index 1920b996e9aa..99683f292b5d 100644
--- a/sound/soc/tegra/tegra210_ahub.c
+++ b/sound/soc/tegra/tegra210_ahub.c
@@ -1319,7 +1319,7 @@ static const struct of_device_id tegra_ahub_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_ahub_of_match);
-static int __maybe_unused tegra_ahub_runtime_suspend(struct device *dev)
+static int tegra_ahub_runtime_suspend(struct device *dev)
{
struct tegra_ahub *ahub = dev_get_drvdata(dev);
@@ -1331,7 +1331,7 @@ static int __maybe_unused tegra_ahub_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra_ahub_runtime_resume(struct device *dev)
+static int tegra_ahub_runtime_resume(struct device *dev)
{
struct tegra_ahub *ahub = dev_get_drvdata(dev);
int err;
@@ -1408,10 +1408,9 @@ static void tegra_ahub_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra_ahub_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
- tegra_ahub_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra_ahub_runtime_suspend,
+ tegra_ahub_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra_ahub_driver = {
@@ -1420,7 +1419,7 @@ static struct platform_driver tegra_ahub_driver = {
.driver = {
.name = "tegra210-ahub",
.of_match_table = tegra_ahub_of_match,
- .pm = &tegra_ahub_pm_ops,
+ .pm = pm_ptr(&tegra_ahub_pm_ops),
},
};
module_platform_driver(tegra_ahub_driver);
diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c
index a9ef22c19e81..1981b94009cf 100644
--- a/sound/soc/tegra/tegra210_amx.c
+++ b/sound/soc/tegra/tegra210_amx.c
@@ -98,7 +98,7 @@ static int tegra210_amx_startup(struct snd_pcm_substream *substream,
return 0;
}
-static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev)
+static int tegra210_amx_runtime_suspend(struct device *dev)
{
struct tegra210_amx *amx = dev_get_drvdata(dev);
@@ -108,7 +108,7 @@ static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_amx_runtime_resume(struct device *dev)
+static int tegra210_amx_runtime_resume(struct device *dev)
{
struct tegra210_amx *amx = dev_get_drvdata(dev);
@@ -581,17 +581,16 @@ static void tegra210_amx_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_amx_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
- tegra210_amx_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
+ tegra210_amx_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra210_amx_driver = {
.driver = {
.name = "tegra210-amx",
.of_match_table = tegra210_amx_of_match,
- .pm = &tegra210_amx_pm_ops,
+ .pm = pm_ptr(&tegra210_amx_pm_ops),
},
.probe = tegra210_amx_platform_probe,
.remove = tegra210_amx_platform_remove,
diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c
index 7986be71f43d..e4a144571265 100644
--- a/sound/soc/tegra/tegra210_dmic.c
+++ b/sound/soc/tegra/tegra210_dmic.c
@@ -40,7 +40,7 @@ static const struct reg_default tegra210_dmic_reg_defaults[] = {
{ TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 },
};
-static int __maybe_unused tegra210_dmic_runtime_suspend(struct device *dev)
+static int tegra210_dmic_runtime_suspend(struct device *dev)
{
struct tegra210_dmic *dmic = dev_get_drvdata(dev);
@@ -52,7 +52,7 @@ static int __maybe_unused tegra210_dmic_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_dmic_runtime_resume(struct device *dev)
+static int tegra210_dmic_runtime_resume(struct device *dev)
{
struct tegra210_dmic *dmic = dev_get_drvdata(dev);
int err;
@@ -543,10 +543,9 @@ static void tegra210_dmic_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_dmic_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
- tegra210_dmic_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend,
+ tegra210_dmic_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct of_device_id tegra210_dmic_of_match[] = {
@@ -559,7 +558,7 @@ static struct platform_driver tegra210_dmic_driver = {
.driver = {
.name = "tegra210-dmic",
.of_match_table = tegra210_dmic_of_match,
- .pm = &tegra210_dmic_pm_ops,
+ .pm = pm_ptr(&tegra210_dmic_pm_ops),
},
.probe = tegra210_dmic_probe,
.remove = tegra210_dmic_remove,
diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c
index 07ce2dbe6c00..766cddebd5f6 100644
--- a/sound/soc/tegra/tegra210_i2s.c
+++ b/sound/soc/tegra/tegra210_i2s.c
@@ -166,7 +166,7 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w,
return tegra210_i2s_sw_reset(compnt, stream);
}
-static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev)
+static int tegra210_i2s_runtime_suspend(struct device *dev)
{
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
@@ -178,7 +178,7 @@ static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_i2s_runtime_resume(struct device *dev)
+static int tegra210_i2s_runtime_resume(struct device *dev)
{
struct tegra210_i2s *i2s = dev_get_drvdata(dev);
int err;
@@ -1010,10 +1010,9 @@ static void tegra210_i2s_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_i2s_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
- tegra210_i2s_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend,
+ tegra210_i2s_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct of_device_id tegra210_i2s_of_match[] = {
@@ -1026,7 +1025,7 @@ static struct platform_driver tegra210_i2s_driver = {
.driver = {
.name = "tegra210-i2s",
.of_match_table = tegra210_i2s_of_match,
- .pm = &tegra210_i2s_pm_ops,
+ .pm = pm_ptr(&tegra210_i2s_pm_ops),
},
.probe = tegra210_i2s_probe,
.remove = tegra210_i2s_remove,
diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c
index 410259d98dfb..95d69a7e027f 100644
--- a/sound/soc/tegra/tegra210_mixer.c
+++ b/sound/soc/tegra/tegra210_mixer.c
@@ -73,7 +73,7 @@ static const struct tegra210_mixer_gain_params gain_params = {
{ 0, 0, 0x400, 0x8000000 },
};
-static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev)
+static int tegra210_mixer_runtime_suspend(struct device *dev)
{
struct tegra210_mixer *mixer = dev_get_drvdata(dev);
@@ -83,7 +83,7 @@ static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev)
+static int tegra210_mixer_runtime_resume(struct device *dev)
{
struct tegra210_mixer *mixer = dev_get_drvdata(dev);
@@ -666,17 +666,16 @@ static void tegra210_mixer_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_mixer_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
- tegra210_mixer_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
+ tegra210_mixer_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra210_mixer_driver = {
.driver = {
.name = "tegra210_mixer",
.of_match_table = tegra210_mixer_of_match,
- .pm = &tegra210_mixer_pm_ops,
+ .pm = pm_ptr(&tegra210_mixer_pm_ops),
},
.probe = tegra210_mixer_platform_probe,
.remove = tegra210_mixer_platform_remove,
diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c
index 119f17501478..35b14c8396f4 100644
--- a/sound/soc/tegra/tegra210_mvc.c
+++ b/sound/soc/tegra/tegra210_mvc.c
@@ -47,7 +47,7 @@ static const struct tegra210_mvc_gain_params gain_params = {
.duration_inv = 14316558,
};
-static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev)
+static int tegra210_mvc_runtime_suspend(struct device *dev)
{
struct tegra210_mvc *mvc = dev_get_drvdata(dev);
@@ -59,7 +59,7 @@ static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_mvc_runtime_resume(struct device *dev)
+static int tegra210_mvc_runtime_resume(struct device *dev)
{
struct tegra210_mvc *mvc = dev_get_drvdata(dev);
@@ -758,17 +758,16 @@ static void tegra210_mvc_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_mvc_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend,
- tegra210_mvc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend,
+ tegra210_mvc_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra210_mvc_driver = {
.driver = {
.name = "tegra210-mvc",
.of_match_table = tegra210_mvc_of_match,
- .pm = &tegra210_mvc_pm_ops,
+ .pm = pm_ptr(&tegra210_mvc_pm_ops),
},
.probe = tegra210_mvc_platform_probe,
.remove = tegra210_mvc_platform_remove,
diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c
index c595cec9baab..5036bcfe0828 100644
--- a/sound/soc/tegra/tegra210_ope.c
+++ b/sound/soc/tegra/tegra210_ope.c
@@ -356,7 +356,7 @@ static void tegra210_ope_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
+static int tegra210_ope_runtime_suspend(struct device *dev)
{
struct tegra210_ope *ope = dev_get_drvdata(dev);
@@ -374,7 +374,7 @@ static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
+static int tegra210_ope_runtime_resume(struct device *dev)
{
struct tegra210_ope *ope = dev_get_drvdata(dev);
@@ -393,10 +393,9 @@ static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev)
}
static const struct dev_pm_ops tegra210_ope_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
- tegra210_ope_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_ope_runtime_suspend,
+ tegra210_ope_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static const struct of_device_id tegra210_ope_of_match[] = {
@@ -409,7 +408,7 @@ static struct platform_driver tegra210_ope_driver = {
.driver = {
.name = "tegra210-ope",
.of_match_table = tegra210_ope_of_match,
- .pm = &tegra210_ope_pm_ops,
+ .pm = pm_ptr(&tegra210_ope_pm_ops),
},
.probe = tegra210_ope_probe,
.remove = tegra210_ope_remove,
diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c
index df88708c733c..a0bd36f12c68 100644
--- a/sound/soc/tegra/tegra210_sfc.c
+++ b/sound/soc/tegra/tegra210_sfc.c
@@ -3056,7 +3056,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = {
},
};
-static int __maybe_unused tegra210_sfc_runtime_suspend(struct device *dev)
+static int tegra210_sfc_runtime_suspend(struct device *dev)
{
struct tegra210_sfc *sfc = dev_get_drvdata(dev);
@@ -3066,7 +3066,7 @@ static int __maybe_unused tegra210_sfc_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused tegra210_sfc_runtime_resume(struct device *dev)
+static int tegra210_sfc_runtime_resume(struct device *dev)
{
struct tegra210_sfc *sfc = dev_get_drvdata(dev);
@@ -3623,17 +3623,16 @@ static void tegra210_sfc_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra210_sfc_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend,
- tegra210_sfc_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend,
+ tegra210_sfc_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra210_sfc_driver = {
.driver = {
.name = "tegra210-sfc",
.of_match_table = tegra210_sfc_of_match,
- .pm = &tegra210_sfc_pm_ops,
+ .pm = pm_ptr(&tegra210_sfc_pm_ops),
},
.probe = tegra210_sfc_platform_probe,
.remove = tegra210_sfc_platform_remove,
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index c9b52f54cea8..51e5ab6c276b 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -40,7 +40,7 @@ static inline void tegra30_audio_write(u32 reg, u32 val)
regmap_write(ahub->regmap_ahub, reg, val);
}
-static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev)
+static int tegra30_ahub_runtime_suspend(struct device *dev)
{
regcache_cache_only(ahub->regmap_apbif, true);
regcache_cache_only(ahub->regmap_ahub, true);
@@ -61,7 +61,7 @@ static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev)
* stopping streams should dynamically adjust the clock as required. However,
* this is not yet implemented.
*/
-static __maybe_unused int tegra30_ahub_runtime_resume(struct device *dev)
+static int tegra30_ahub_runtime_resume(struct device *dev)
{
int ret;
@@ -600,10 +600,9 @@ static void tegra30_ahub_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra30_ahub_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
- tegra30_ahub_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
+ tegra30_ahub_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra30_ahub_driver = {
@@ -612,7 +611,7 @@ static struct platform_driver tegra30_ahub_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = tegra30_ahub_of_match,
- .pm = &tegra30_ahub_pm_ops,
+ .pm = pm_ptr(&tegra30_ahub_pm_ops),
},
};
module_platform_driver(tegra30_ahub_driver);
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 0d3badfbe143..b121af9ef8ed 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -35,7 +35,7 @@
#define DRV_NAME "tegra30-i2s"
-static __maybe_unused int tegra30_i2s_runtime_suspend(struct device *dev)
+static int tegra30_i2s_runtime_suspend(struct device *dev)
{
struct tegra30_i2s *i2s = dev_get_drvdata(dev);
@@ -46,7 +46,7 @@ static __maybe_unused int tegra30_i2s_runtime_suspend(struct device *dev)
return 0;
}
-static __maybe_unused int tegra30_i2s_runtime_resume(struct device *dev)
+static int tegra30_i2s_runtime_resume(struct device *dev)
{
struct tegra30_i2s *i2s = dev_get_drvdata(dev);
int ret;
@@ -547,17 +547,16 @@ static void tegra30_i2s_platform_remove(struct platform_device *pdev)
}
static const struct dev_pm_ops tegra30_i2s_pm_ops = {
- SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
- tegra30_i2s_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
+ tegra30_i2s_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};
static struct platform_driver tegra30_i2s_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = tegra30_i2s_of_match,
- .pm = &tegra30_i2s_pm_ops,
+ .pm = pm_ptr(&tegra30_i2s_pm_ops),
},
.probe = tegra30_i2s_platform_probe,
.remove = tegra30_i2s_platform_remove,
diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c
index 775ce433fdbf..62f896772731 100644
--- a/sound/soc/tegra/tegra_asoc_machine.c
+++ b/sound/soc/tegra/tegra_asoc_machine.c
@@ -637,7 +637,7 @@ static struct snd_soc_dai_link tegra_wm8753_dai = {
.stream_name = "WM8753 PCM",
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(wm8753_hifi),
};
@@ -701,7 +701,7 @@ static struct snd_soc_dai_link tegra_max98090_dai = {
.init = tegra_asoc_machine_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(max98090_hifi),
};
@@ -736,7 +736,7 @@ static struct snd_soc_dai_link tegra_max98088_dai = {
.init = tegra_asoc_machine_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(max98088_hifi),
};
@@ -769,7 +769,7 @@ static struct snd_soc_dai_link tegra_sgtl5000_dai = {
.stream_name = "HiFi",
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(sgtl5000_hifi),
};
@@ -812,7 +812,7 @@ static struct snd_soc_dai_link tegra_tlv320aic23_dai = {
.stream_name = "AIC23",
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(tlv320aic23_hifi),
};
@@ -861,7 +861,7 @@ static struct snd_soc_dai_link tegra_rt5677_dai = {
.init = tegra_rt5677_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(rt5677_aif1),
};
@@ -895,7 +895,7 @@ static struct snd_soc_dai_link tegra_rt5640_dai = {
.init = tegra_asoc_machine_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(rt5640_aif1),
};
@@ -928,7 +928,7 @@ static struct snd_soc_dai_link tegra_rt5632_dai = {
.init = tegra_rt5677_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(rt5632_hifi),
};
@@ -961,7 +961,7 @@ static struct snd_soc_dai_link tegra_rt5631_dai = {
.init = tegra_asoc_machine_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(rt5631_hifi),
};
diff --git a/sound/soc/tegra/tegra_isomgr_bw.c b/sound/soc/tegra/tegra_isomgr_bw.c
new file mode 100644
index 000000000000..18e802bca6a6
--- /dev/null
+++ b/sound/soc/tegra/tegra_isomgr_bw.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+// All rights reserved.
+//
+// ADMA bandwidth calculation
+
+#include <linux/interconnect.h>
+#include <linux/module.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "tegra_isomgr_bw.h"
+#include "tegra210_admaif.h"
+
+/* Max possible rate is 192KHz x 16channel x 4bytes */
+#define MAX_BW_PER_DEV 12288
+
+int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai, bool is_running)
+{
+ struct device *dev = dai->dev;
+ struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
+ struct tegra_adma_isomgr *adma_isomgr = admaif->adma_isomgr;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm *pcm = substream->pcm;
+ u32 type = substream->stream, bandwidth = 0;
+ int sample_bytes;
+
+ if (!adma_isomgr)
+ return 0;
+
+ if (!runtime || !pcm)
+ return -EINVAL;
+
+ if (pcm->device >= adma_isomgr->max_pcm_device) {
+ dev_err(dev, "%s: PCM device number %d is greater than %d\n", __func__,
+ pcm->device, adma_isomgr->max_pcm_device);
+ return -EINVAL;
+ }
+
+ /*
+ * No action if stream is running and bandwidth is already set or
+ * stream is not running and bandwidth is already reset
+ */
+ if ((adma_isomgr->bw_per_dev[type][pcm->device] && is_running) ||
+ (!adma_isomgr->bw_per_dev[type][pcm->device] && !is_running))
+ return 0;
+
+ if (is_running) {
+ sample_bytes = snd_pcm_format_width(runtime->format) / 8;
+ if (sample_bytes < 0)
+ return sample_bytes;
+
+ /* KB/s kilo bytes per sec */
+ bandwidth = runtime->channels * (runtime->rate / 1000) *
+ sample_bytes;
+ }
+
+ mutex_lock(&adma_isomgr->mutex);
+
+ if (is_running) {
+ if (bandwidth + adma_isomgr->current_bandwidth > adma_isomgr->max_bw)
+ bandwidth = adma_isomgr->max_bw - adma_isomgr->current_bandwidth;
+
+ adma_isomgr->current_bandwidth += bandwidth;
+ } else {
+ adma_isomgr->current_bandwidth -= adma_isomgr->bw_per_dev[type][pcm->device];
+ }
+
+ mutex_unlock(&adma_isomgr->mutex);
+
+ adma_isomgr->bw_per_dev[type][pcm->device] = bandwidth;
+
+ dev_dbg(dev, "Setting up bandwidth to %d KBps\n", adma_isomgr->current_bandwidth);
+
+ return icc_set_bw(adma_isomgr->icc_path_handle,
+ adma_isomgr->current_bandwidth, adma_isomgr->max_bw);
+}
+
+int tegra_isomgr_adma_register(struct device *dev)
+{
+ struct tegra_admaif *admaif = dev_get_drvdata(dev);
+ struct tegra_adma_isomgr *adma_isomgr;
+ int i;
+
+ adma_isomgr = devm_kzalloc(dev, sizeof(struct tegra_adma_isomgr), GFP_KERNEL);
+ if (!adma_isomgr)
+ return -ENOMEM;
+
+ adma_isomgr->icc_path_handle = devm_of_icc_get(dev, "write");
+ if (IS_ERR(adma_isomgr->icc_path_handle))
+ return dev_err_probe(dev, PTR_ERR(adma_isomgr->icc_path_handle),
+ "failed to acquire interconnect path\n");
+
+ /* Either INTERCONNECT config OR interconnect property is not defined */
+ if (!adma_isomgr->icc_path_handle) {
+ devm_kfree(dev, adma_isomgr);
+ return 0;
+ }
+
+ adma_isomgr->max_pcm_device = admaif->soc_data->num_ch;
+ adma_isomgr->max_bw = STREAM_TYPE * MAX_BW_PER_DEV * adma_isomgr->max_pcm_device;
+
+ for (i = 0; i < STREAM_TYPE; i++) {
+ adma_isomgr->bw_per_dev[i] = devm_kzalloc(dev, adma_isomgr->max_pcm_device *
+ sizeof(u32), GFP_KERNEL);
+ if (!adma_isomgr->bw_per_dev[i])
+ return -ENOMEM;
+ }
+
+ adma_isomgr->current_bandwidth = 0;
+ mutex_init(&adma_isomgr->mutex);
+ admaif->adma_isomgr = adma_isomgr;
+
+ return 0;
+}
+
+void tegra_isomgr_adma_unregister(struct device *dev)
+{
+ struct tegra_admaif *admaif = dev_get_drvdata(dev);
+
+ if (!admaif->adma_isomgr)
+ return;
+
+ mutex_destroy(&admaif->adma_isomgr->mutex);
+}
+
+MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>");
+MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/tegra/tegra_isomgr_bw.h b/sound/soc/tegra/tegra_isomgr_bw.h
new file mode 100644
index 000000000000..86db3cfd4e43
--- /dev/null
+++ b/sound/soc/tegra/tegra_isomgr_bw.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+ * All rights reserved.
+ *
+ * tegra_isomgr_bw.h - Definitions for ADMA bandwidth calculation
+ *
+ */
+
+#ifndef __TEGRA_ISOMGR_BW_H__
+#define __TEGRA_ISOMGR_BW_H__
+
+/* Playback and Capture streams */
+#define STREAM_TYPE 2
+
+struct tegra_adma_isomgr {
+ /* Protect pcm devices bandwidth */
+ struct mutex mutex;
+ /* interconnect path handle */
+ struct icc_path *icc_path_handle;
+ u32 *bw_per_dev[STREAM_TYPE];
+ u32 current_bandwidth;
+ u32 max_pcm_device;
+ u32 max_bw;
+};
+
+int tegra_isomgr_adma_register(struct device *dev);
+void tegra_isomgr_adma_unregister(struct device *dev);
+int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai, bool is_running);
+
+#endif
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 6116d2e30fca..78b02c64d95c 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -124,7 +124,7 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
.init = tegra_wm8903_init,
.dai_fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
SND_SOC_DAILINK_REG(hifi),
};
diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c
index 94645f275495..8a4423646aea 100644
--- a/sound/soc/ti/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
@@ -532,7 +532,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
.init = ams_delta_cx20442_init,
.ops = &ams_delta_ops,
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(cx20442),
};
diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c
index 1bf333d2740d..2a2f5bc95576 100644
--- a/sound/soc/ti/davinci-evm.c
+++ b/sound/soc/ti/davinci-evm.c
@@ -152,7 +152,7 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
.stream_name = "AIC3X",
.ops = &evm_ops,
.init = evm_aic3x_init,
- .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM |
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBP_CFP |
SND_SOC_DAIFMT_IB_NF,
SND_SOC_DAILINK_REG(evm),
};
diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c
index d682b98d6848..059967f0e632 100644
--- a/sound/soc/ti/davinci-i2s.c
+++ b/sound/soc/ti/davinci-i2s.c
@@ -892,8 +892,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
err_unregister_component:
snd_soc_unregister_component(&pdev->dev);
err_disable_ext_clk:
- if (dev->ext_clk)
- clk_disable_unprepare(dev->ext_clk);
+ clk_disable_unprepare(dev->ext_clk);
err_disable_clk:
clk_disable_unprepare(dev->clk);
@@ -908,8 +907,7 @@ static void davinci_i2s_remove(struct platform_device *pdev)
clk_disable_unprepare(dev->clk);
- if (dev->ext_clk)
- clk_disable_unprepare(dev->ext_clk);
+ clk_disable_unprepare(dev->ext_clk);
}
static const struct of_device_id davinci_i2s_match[] __maybe_unused = {
diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c
index d9d1e021f5b2..0e7e4ff950b5 100644
--- a/sound/soc/ti/j721e-evm.c
+++ b/sound/soc/ti/j721e-evm.c
@@ -37,7 +37,7 @@ enum j721e_audio_domain_id {
#define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \
SND_SOC_DAIFMT_NB_NF | \
- SND_SOC_DAIFMT_CBS_CFS)
+ SND_SOC_DAIFMT_CBC_CFC)
enum j721e_board_type {
J721E_BOARD_CPB = 1,
@@ -182,6 +182,8 @@ static int j721e_configure_refclk(struct j721e_priv *priv,
clk_id = J721E_CLK_PARENT_48000;
else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100])
clk_id = J721E_CLK_PARENT_44100;
+ else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_48000])
+ clk_id = J721E_CLK_PARENT_48000;
else
return ret;
@@ -913,8 +915,9 @@ static int j721e_soc_probe(struct platform_device *pdev)
mutex_init(&priv->mutex);
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: %d\n",
+ ret);
return ret;
}
diff --git a/sound/soc/ti/n810.c b/sound/soc/ti/n810.c
index 50a8ec97cf20..345c98765380 100644
--- a/sound/soc/ti/n810.c
+++ b/sound/soc/ti/n810.c
@@ -258,7 +258,7 @@ static struct snd_soc_dai_link n810_dai = {
.name = "TLV320AIC33",
.stream_name = "AIC33",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ops = &n810_ops,
SND_SOC_DAILINK_REG(aic33),
};
diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c
index a402d66e4f4d..3548b58002c4 100644
--- a/sound/soc/ti/omap-twl4030.c
+++ b/sound/soc/ti/omap-twl4030.c
@@ -42,12 +42,12 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
case 2: /* Stereo I2S mode */
fmt = SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM;
+ SND_SOC_DAIFMT_CBP_CFP;
break;
case 4: /* Four channel TDM mode */
fmt = SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM;
+ SND_SOC_DAIFMT_CBP_CFP;
break;
default:
return -EINVAL;
@@ -218,7 +218,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = {
.name = "TWL4030 Voice",
.stream_name = "TWL4030 Voice",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
SND_SOC_DAILINK_REG(voice),
},
};
diff --git a/sound/soc/ti/omap3pandora.c b/sound/soc/ti/omap3pandora.c
index be69476e59d6..808fb6765c05 100644
--- a/sound/soc/ti/omap3pandora.c
+++ b/sound/soc/ti/omap3pandora.c
@@ -189,7 +189,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.name = "PCM1773",
.stream_name = "HiFi Out",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &omap3pandora_ops,
.init = omap3pandora_out_init,
SND_SOC_DAILINK_REG(out),
@@ -197,7 +197,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
.name = "TWL4030",
.stream_name = "Line/Mic In",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAIFMT_CBC_CFC,
.ops = &omap3pandora_ops,
.init = omap3pandora_in_init,
SND_SOC_DAILINK_REG(in),
diff --git a/sound/soc/ti/osk5912.c b/sound/soc/ti/osk5912.c
index 98714c593496..fa5ef7814dab 100644
--- a/sound/soc/ti/osk5912.c
+++ b/sound/soc/ti/osk5912.c
@@ -86,7 +86,7 @@ static struct snd_soc_dai_link osk_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
.dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.ops = &osk_ops,
SND_SOC_DAILINK_REG(aic23),
};
diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c
index d9900c69e536..e969031657e9 100644
--- a/sound/soc/ti/rx51.c
+++ b/sound/soc/ti/rx51.c
@@ -307,7 +307,7 @@ static struct snd_soc_dai_link rx51_dai[] = {
.name = "TLV320AIC34",
.stream_name = "AIC34",
.dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF |
- SND_SOC_DAIFMT_CBM_CFM,
+ SND_SOC_DAIFMT_CBP_CFP,
.init = rx51_aic34_init,
.ops = &rx51_ops,
SND_SOC_DAILINK_REG(aic34),
diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c
index 470f129166a4..3224c11a527f 100644
--- a/sound/soc/uniphier/aio-cpu.c
+++ b/sound/soc/uniphier/aio-cpu.c
@@ -762,14 +762,10 @@ int uniphier_aio_probe(struct platform_device *pdev)
return -ENOMEM;
chip->num_plls = chip->chip_spec->num_plls;
- chip->plls = devm_kcalloc(dev,
- chip->num_plls,
- sizeof(struct uniphier_aio_pll),
- GFP_KERNEL);
+ chip->plls = devm_kmemdup_array(dev, chip->chip_spec->plls, chip->num_plls,
+ sizeof(*chip->chip_spec->plls), GFP_KERNEL);
if (!chip->plls)
return -ENOMEM;
- memcpy(chip->plls, chip->chip_spec->plls,
- sizeof(struct uniphier_aio_pll) * chip->num_plls);
for (i = 0; i < chip->num_aios; i++) {
struct uniphier_aio *aio = &chip->aios[i];
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c
index 710b6744e013..5246f73ef12e 100644
--- a/sound/soc/ux500/mop500_ab8500.c
+++ b/sound/soc/ux500/mop500_ab8500.c
@@ -275,12 +275,12 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
if (driver_mode == DRIVERMODE_NORMAL) {
fmt = SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_CBP_CFP |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CONT;
} else {
fmt = SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_CBP_CFP |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_GATED;
}
diff --git a/sound/soc/xilinx/xlnx_spdif.c b/sound/soc/xilinx/xlnx_spdif.c
index 7febb3830dc2..017a64ab9f1e 100644
--- a/sound/soc/xilinx/xlnx_spdif.c
+++ b/sound/soc/xilinx/xlnx_spdif.c
@@ -248,41 +248,35 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ctx->axi_clk = devm_clk_get(dev, "s_axi_aclk");
+ 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;
}
- ret = clk_prepare_enable(ctx->axi_clk);
- if (ret) {
- dev_err(dev, "failed to enable s_axi_aclk(%d)\n", ret);
- return ret;
- }
ctx->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(ctx->base)) {
- ret = PTR_ERR(ctx->base);
- goto clk_err;
- }
+ 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");
- goto clk_err;
+ return ret;
}
if (ctx->mode) {
dai_drv = &xlnx_spdif_tx_dai;
} else {
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto clk_err;
+ return ret;
+
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");
- ret = -ENODEV;
- goto clk_err;
+ return -ENODEV;
}
init_waitqueue_head(&ctx->chsts_q);
@@ -292,7 +286,7 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
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");
- goto clk_err;
+ return ret;
}
dev_set_drvdata(dev, ctx);
@@ -301,22 +295,13 @@ static int xlnx_spdif_probe(struct platform_device *pdev)
dai_drv, 1);
if (ret) {
dev_err(dev, "SPDIF component registration failed\n");
- goto clk_err;
+ return ret;
}
writel(XSPDIF_SOFT_RESET_VALUE, ctx->base + XSPDIF_SOFT_RESET_REG);
dev_info(dev, "%s DAI registered\n", dai_drv->name);
-clk_err:
- clk_disable_unprepare(ctx->axi_clk);
- return ret;
-}
-
-static void xlnx_spdif_remove(struct platform_device *pdev)
-{
- struct spdif_dev_data *ctx = dev_get_drvdata(&pdev->dev);
-
- clk_disable_unprepare(ctx->axi_clk);
+ return 0;
}
static struct platform_driver xlnx_spdif_driver = {
@@ -325,7 +310,6 @@ static struct platform_driver xlnx_spdif_driver = {
.of_match_table = xlnx_spdif_of_match,
},
.probe = xlnx_spdif_probe,
- .remove = xlnx_spdif_remove,
};
module_platform_driver(xlnx_spdif_driver);
diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c
index 4eaa9011405f..678ded059b95 100644
--- a/sound/soc/xtensa/xtfpga-i2s.c
+++ b/sound/soc/xtensa/xtfpga-i2s.c
@@ -629,8 +629,8 @@ MODULE_DEVICE_TABLE(of, xtfpga_i2s_of_match);
#endif
static const struct dev_pm_ops xtfpga_i2s_pm_ops = {
- SET_RUNTIME_PM_OPS(xtfpga_i2s_runtime_suspend,
- xtfpga_i2s_runtime_resume, NULL)
+ RUNTIME_PM_OPS(xtfpga_i2s_runtime_suspend,
+ xtfpga_i2s_runtime_resume, NULL)
};
static struct platform_driver xtfpga_i2s_driver = {
@@ -639,7 +639,7 @@ static struct platform_driver xtfpga_i2s_driver = {
.driver = {
.name = "xtfpga-i2s",
.of_match_table = of_match_ptr(xtfpga_i2s_of_match),
- .pm = &xtfpga_i2s_pm_ops,
+ .pm = pm_ptr(&xtfpga_i2s_pm_ops),
},
};
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 0532499dbc6d..30bd5348477b 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -6,6 +6,7 @@
snd-usb-audio-y := card.o \
clock.o \
endpoint.o \
+ fcp.o \
format.o \
helper.o \
implicit.o \
diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c
new file mode 100644
index 000000000000..7df65041ace5
--- /dev/null
+++ b/sound/usb/fcp.c
@@ -0,0 +1,1134 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Focusrite Control Protocol Driver for ALSA
+ *
+ * Copyright (c) 2024-2025 by Geoffrey D. Bennett <g at b4.vu>
+ */
+/*
+ * DOC: Theory of Operation
+ *
+ * The Focusrite Control Protocol (FCP) driver provides a minimal
+ * kernel interface that allows a user-space driver (primarily
+ * fcp-server) to communicate with Focusrite USB audio interfaces
+ * using their vendor-specific protocol. This protocol is used by
+ * Scarlett 2nd Gen, 3rd Gen, 4th Gen, Clarett USB, Clarett+, and
+ * Vocaster series devices.
+ *
+ * Unlike the existing scarlett2 driver which implements all controls
+ * in kernel space, this driver takes a lighter-weight approach by
+ * moving most functionality to user space. The only control
+ * implemented in kernel space is the Level Meter, since it requires
+ * frequent polling of volatile data.
+ *
+ * The driver provides an hwdep interface that allows the user-space
+ * driver to:
+ * - Initialise the protocol
+ * - Send arbitrary FCP commands to the device
+ * - Receive notifications from the device
+ * - Configure the Level Meter control
+ *
+ * Usage Flow
+ * ----------
+ * 1. Open the hwdep device (requires CAP_SYS_RAWIO)
+ * 2. Get protocol version using FCP_IOCTL_PVERSION
+ * 3. Initialise protocol using FCP_IOCTL_INIT
+ * 4. Send commands using FCP_IOCTL_CMD
+ * 5. Receive notifications using read()
+ * 6. Optionally set up the Level Meter control using
+ * FCP_IOCTL_SET_METER_MAP
+ * 7. Optionally add labels to the Level Meter control using
+ * FCP_IOCTL_SET_METER_LABELS
+ *
+ * Level Meter
+ * -----------
+ * The Level Meter is implemented as an ALSA control that provides
+ * real-time level monitoring. When the control is read, the driver
+ * requests the current meter levels from the device, translates the
+ * levels using the configured mapping, and returns the result to the
+ * user. The mapping between device meters and the ALSA control's
+ * channels is configured with FCP_IOCTL_SET_METER_MAP.
+ *
+ * Labels for the Level Meter channels can be set using
+ * FCP_IOCTL_SET_METER_LABELS and read by applications through the
+ * control's TLV data. The labels are transferred as a sequence of
+ * null-terminated strings.
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <sound/control.h>
+#include <sound/hwdep.h>
+#include <sound/tlv.h>
+
+#include <uapi/sound/fcp.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+
+#include "fcp.h"
+
+/* notify waiting to send to *file */
+struct fcp_notify {
+ wait_queue_head_t queue;
+ u32 event;
+ spinlock_t lock;
+};
+
+struct fcp_data {
+ struct usb_mixer_interface *mixer;
+
+ struct mutex mutex; /* serialise access to the device */
+ struct completion cmd_done; /* wait for command completion */
+ struct file *file; /* hwdep file */
+
+ struct fcp_notify notify;
+
+ u8 bInterfaceNumber;
+ u8 bEndpointAddress;
+ u16 wMaxPacketSize;
+ u8 bInterval;
+
+ uint16_t step0_resp_size;
+ uint16_t step2_resp_size;
+ uint32_t init1_opcode;
+ uint32_t init2_opcode;
+
+ u8 init;
+ u16 seq;
+
+ u8 num_meter_slots;
+ s16 *meter_level_map;
+ __le32 *meter_levels;
+ struct snd_kcontrol *meter_ctl;
+
+ unsigned int *meter_labels_tlv;
+ int meter_labels_tlv_size;
+};
+
+/*** USB Interactions ***/
+
+/* FCP Command ACK notification bit */
+#define FCP_NOTIFY_ACK 1
+
+/* Vendor-specific USB control requests */
+#define FCP_USB_REQ_STEP0 0
+#define FCP_USB_REQ_CMD_TX 2
+#define FCP_USB_REQ_CMD_RX 3
+
+/* Focusrite Control Protocol opcodes that the kernel side needs to
+ * know about
+ */
+#define FCP_USB_REBOOT 0x00000003
+#define FCP_USB_GET_METER 0x00001001
+#define FCP_USB_FLASH_ERASE 0x00004002
+#define FCP_USB_FLASH_WRITE 0x00004004
+
+#define FCP_USB_METER_LEVELS_GET_MAGIC 1
+
+#define FCP_SEGMENT_APP_GOLD 0
+
+/* Forward declarations */
+static int fcp_init(struct usb_mixer_interface *mixer,
+ void *step0_resp, void *step2_resp);
+
+/* FCP command request/response format */
+struct fcp_usb_packet {
+ __le32 opcode;
+ __le16 size;
+ __le16 seq;
+ __le32 error;
+ __le32 pad;
+ u8 data[];
+};
+
+static void fcp_fill_request_header(struct fcp_data *private,
+ struct fcp_usb_packet *req,
+ u32 opcode, u16 req_size)
+{
+ /* sequence must go up by 1 for each request */
+ u16 seq = private->seq++;
+
+ req->opcode = cpu_to_le32(opcode);
+ req->size = cpu_to_le16(req_size);
+ req->seq = cpu_to_le16(seq);
+ req->error = 0;
+ req->pad = 0;
+}
+
+static int fcp_usb_tx(struct usb_device *dev, int interface,
+ void *buf, u16 size)
+{
+ return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+ FCP_USB_REQ_CMD_TX,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ 0, interface, buf, size);
+}
+
+static int fcp_usb_rx(struct usb_device *dev, int interface,
+ void *buf, u16 size)
+{
+ return snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+ FCP_USB_REQ_CMD_RX,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ 0, interface, buf, size);
+}
+
+/* Send an FCP command and get the response */
+static int fcp_usb(struct usb_mixer_interface *mixer, u32 opcode,
+ const void *req_data, u16 req_size,
+ void *resp_data, u16 resp_size)
+{
+ struct fcp_data *private = mixer->private_data;
+ struct usb_device *dev = mixer->chip->dev;
+ struct fcp_usb_packet *req __free(kfree) = NULL;
+ struct fcp_usb_packet *resp __free(kfree) = NULL;
+ size_t req_buf_size = struct_size(req, data, req_size);
+ size_t resp_buf_size = struct_size(resp, data, resp_size);
+ int retries = 0;
+ const int max_retries = 5;
+ int err;
+
+ if (!mixer->urb)
+ return -ENODEV;
+
+ req = kmalloc(req_buf_size, GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ resp = kmalloc(resp_buf_size, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ /* build request message */
+ fcp_fill_request_header(private, req, opcode, req_size);
+ if (req_size)
+ memcpy(req->data, req_data, req_size);
+
+ /* send the request and retry on EPROTO */
+retry:
+ err = fcp_usb_tx(dev, private->bInterfaceNumber, req, req_buf_size);
+ if (err == -EPROTO && ++retries <= max_retries) {
+ msleep(1 << (retries - 1));
+ goto retry;
+ }
+
+ if (err != req_buf_size) {
+ usb_audio_err(mixer->chip,
+ "FCP request %08x failed: %d\n", opcode, err);
+ return -EINVAL;
+ }
+
+ if (!wait_for_completion_timeout(&private->cmd_done,
+ msecs_to_jiffies(1000))) {
+ usb_audio_err(mixer->chip,
+ "FCP request %08x timed out\n", opcode);
+
+ return -ETIMEDOUT;
+ }
+
+ /* send a second message to get the response */
+ err = fcp_usb_rx(dev, private->bInterfaceNumber, resp, resp_buf_size);
+
+ /* validate the response */
+
+ if (err < 0) {
+
+ /* ESHUTDOWN and EPROTO are valid responses to a
+ * reboot request
+ */
+ if (opcode == FCP_USB_REBOOT &&
+ (err == -ESHUTDOWN || err == -EPROTO))
+ return 0;
+
+ usb_audio_err(mixer->chip,
+ "FCP read response %08x failed: %d\n",
+ opcode, err);
+ return -EINVAL;
+ }
+
+ if (err < sizeof(*resp)) {
+ usb_audio_err(mixer->chip,
+ "FCP response %08x too short: %d\n",
+ opcode, err);
+ return -EINVAL;
+ }
+
+ if (req->seq != resp->seq) {
+ usb_audio_err(mixer->chip,
+ "FCP response %08x seq mismatch %d/%d\n",
+ opcode,
+ le16_to_cpu(req->seq), le16_to_cpu(resp->seq));
+ return -EINVAL;
+ }
+
+ if (req->opcode != resp->opcode) {
+ usb_audio_err(mixer->chip,
+ "FCP response %08x opcode mismatch %08x\n",
+ opcode, le32_to_cpu(resp->opcode));
+ return -EINVAL;
+ }
+
+ if (resp->error) {
+ usb_audio_err(mixer->chip,
+ "FCP response %08x error %d\n",
+ opcode, le32_to_cpu(resp->error));
+ return -EINVAL;
+ }
+
+ if (err != resp_buf_size) {
+ usb_audio_err(mixer->chip,
+ "FCP response %08x buffer size mismatch %d/%zu\n",
+ opcode, err, resp_buf_size);
+ return -EINVAL;
+ }
+
+ if (resp_size != le16_to_cpu(resp->size)) {
+ usb_audio_err(mixer->chip,
+ "FCP response %08x size mismatch %d/%d\n",
+ opcode, resp_size, le16_to_cpu(resp->size));
+ return -EINVAL;
+ }
+
+ if (resp_data && resp_size > 0)
+ memcpy(resp_data, resp->data, resp_size);
+
+ return 0;
+}
+
+static int fcp_reinit(struct usb_mixer_interface *mixer)
+{
+ struct fcp_data *private = mixer->private_data;
+ void *step0_resp __free(kfree) = NULL;
+ void *step2_resp __free(kfree) = NULL;
+
+ if (mixer->urb)
+ return 0;
+
+ step0_resp = kmalloc(private->step0_resp_size, GFP_KERNEL);
+ if (!step0_resp)
+ return -ENOMEM;
+ step2_resp = kmalloc(private->step2_resp_size, GFP_KERNEL);
+ if (!step2_resp)
+ return -ENOMEM;
+
+ return fcp_init(mixer, step0_resp, step2_resp);
+}
+
+/*** Control Functions ***/
+
+/* helper function to create a new control */
+static int fcp_add_new_ctl(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *ncontrol,
+ int index, int channels, const char *name,
+ struct snd_kcontrol **kctl_return)
+{
+ struct snd_kcontrol *kctl;
+ struct usb_mixer_elem_info *elem;
+ int err;
+
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ /* We set USB_MIXER_BESPOKEN type, so that the core USB mixer code
+ * ignores them for resume and other operations.
+ * Also, the head.id field is set to 0, as we don't use this field.
+ */
+ elem->head.mixer = mixer;
+ elem->control = index;
+ elem->head.id = 0;
+ elem->channels = channels;
+ elem->val_type = USB_MIXER_BESPOKEN;
+
+ kctl = snd_ctl_new1(ncontrol, elem);
+ if (!kctl) {
+ kfree(elem);
+ return -ENOMEM;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+
+ strscpy(kctl->id.name, name, sizeof(kctl->id.name));
+
+ err = snd_usb_mixer_add_control(&elem->head, kctl);
+ if (err < 0)
+ return err;
+
+ if (kctl_return)
+ *kctl_return = kctl;
+
+ return 0;
+}
+
+/*** Level Meter Control ***/
+
+static int fcp_meter_ctl_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = elem->channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 4095;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int fcp_meter_ctl_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct usb_mixer_interface *mixer = elem->head.mixer;
+ struct fcp_data *private = mixer->private_data;
+ int num_meter_slots, resp_size;
+ __le32 *resp = private->meter_levels;
+ int i, err = 0;
+
+ struct {
+ __le16 pad;
+ __le16 num_meters;
+ __le32 magic;
+ } __packed req;
+
+ guard(mutex)(&private->mutex);
+
+ err = fcp_reinit(mixer);
+ if (err < 0)
+ return err;
+
+ num_meter_slots = private->num_meter_slots;
+ resp_size = num_meter_slots * sizeof(u32);
+
+ req.pad = 0;
+ req.num_meters = cpu_to_le16(num_meter_slots);
+ req.magic = cpu_to_le32(FCP_USB_METER_LEVELS_GET_MAGIC);
+ err = fcp_usb(mixer, FCP_USB_GET_METER,
+ &req, sizeof(req), resp, resp_size);
+ if (err < 0)
+ return err;
+
+ /* copy & translate from resp[] using meter_level_map[] */
+ for (i = 0; i < elem->channels; i++) {
+ int idx = private->meter_level_map[i];
+ int value = idx < 0 ? 0 : le32_to_cpu(resp[idx]);
+
+ ucontrol->value.integer.value[i] = value;
+ }
+
+ return 0;
+}
+
+static int fcp_meter_tlv_callback(struct snd_kcontrol *kctl,
+ int op_flag, unsigned int size,
+ unsigned int __user *tlv)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct usb_mixer_interface *mixer = elem->head.mixer;
+ struct fcp_data *private = mixer->private_data;
+
+ guard(mutex)(&private->mutex);
+
+ if (op_flag == SNDRV_CTL_TLV_OP_READ) {
+ if (private->meter_labels_tlv_size == 0)
+ return 0;
+
+ if (size > private->meter_labels_tlv_size)
+ size = private->meter_labels_tlv_size;
+
+ if (copy_to_user(tlv, private->meter_labels_tlv, size))
+ return -EFAULT;
+
+ return size;
+ }
+
+ return -EINVAL;
+}
+
+static const struct snd_kcontrol_new fcp_meter_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = fcp_meter_ctl_info,
+ .get = fcp_meter_ctl_get,
+ .tlv = { .c = fcp_meter_tlv_callback },
+};
+
+/*** hwdep interface ***/
+
+/* FCP initialisation */
+static int fcp_ioctl_init(struct usb_mixer_interface *mixer,
+ struct fcp_init __user *arg)
+{
+ struct fcp_init init;
+ struct usb_device *dev = mixer->chip->dev;
+ struct fcp_data *private = mixer->private_data;
+ void *resp __free(kfree) = NULL;
+ void *step2_resp;
+ int err, buf_size;
+
+ if (usb_pipe_type_check(dev, usb_sndctrlpipe(dev, 0)))
+ return -EINVAL;
+
+ /* Get initialisation parameters */
+ if (copy_from_user(&init, arg, sizeof(init)))
+ return -EFAULT;
+
+ /* Validate the response sizes */
+ if (init.step0_resp_size < 1 ||
+ init.step0_resp_size > 255 ||
+ init.step2_resp_size < 1 ||
+ init.step2_resp_size > 255)
+ return -EINVAL;
+
+ /* Allocate response buffer */
+ buf_size = init.step0_resp_size + init.step2_resp_size;
+
+ resp = kmalloc(buf_size, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ private->step0_resp_size = init.step0_resp_size;
+ private->step2_resp_size = init.step2_resp_size;
+ private->init1_opcode = init.init1_opcode;
+ private->init2_opcode = init.init2_opcode;
+
+ step2_resp = resp + private->step0_resp_size;
+
+ err = fcp_init(mixer, resp, step2_resp);
+ if (err < 0)
+ return err;
+
+ if (copy_to_user(arg->resp, resp, buf_size))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* Check that the command is allowed
+ * Don't permit erasing/writing segment 0 (App_Gold)
+ */
+static int fcp_validate_cmd(u32 opcode, void *data, u16 size)
+{
+ if (opcode == FCP_USB_FLASH_ERASE) {
+ struct {
+ __le32 segment_num;
+ __le32 pad;
+ } __packed *req = data;
+
+ if (size != sizeof(*req))
+ return -EINVAL;
+
+ if (le32_to_cpu(req->segment_num) == FCP_SEGMENT_APP_GOLD)
+ return -EPERM;
+
+ if (req->pad != 0)
+ return -EINVAL;
+
+ } else if (opcode == FCP_USB_FLASH_WRITE) {
+ struct {
+ __le32 segment_num;
+ __le32 offset;
+ __le32 pad;
+ u8 data[];
+ } __packed *req = data;
+
+ if (size < sizeof(*req))
+ return -EINVAL;
+
+ if (le32_to_cpu(req->segment_num) == FCP_SEGMENT_APP_GOLD)
+ return -EPERM;
+
+ if (req->pad != 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Execute an FCP command specified by the user */
+static int fcp_ioctl_cmd(struct usb_mixer_interface *mixer,
+ struct fcp_cmd __user *arg)
+{
+ struct fcp_cmd cmd;
+ int err, buf_size;
+ void *data __free(kfree) = NULL;
+
+ /* get opcode and request/response size */
+ if (copy_from_user(&cmd, arg, sizeof(cmd)))
+ return -EFAULT;
+
+ /* validate request and response sizes */
+ if (cmd.req_size > 4096 || cmd.resp_size > 4096)
+ return -EINVAL;
+
+ /* reinit if needed */
+ err = fcp_reinit(mixer);
+ if (err < 0)
+ return err;
+
+ /* allocate request/response buffer */
+ buf_size = max(cmd.req_size, cmd.resp_size);
+
+ if (buf_size > 0) {
+ data = kmalloc(buf_size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ }
+
+ /* copy request from user */
+ if (cmd.req_size > 0)
+ if (copy_from_user(data, arg->data, cmd.req_size))
+ return -EFAULT;
+
+ /* check that the command is allowed */
+ err = fcp_validate_cmd(cmd.opcode, data, cmd.req_size);
+ if (err < 0)
+ return err;
+
+ /* send request, get response */
+ err = fcp_usb(mixer, cmd.opcode,
+ data, cmd.req_size, data, cmd.resp_size);
+ if (err < 0)
+ return err;
+
+ /* copy response to user */
+ if (cmd.resp_size > 0)
+ if (copy_to_user(arg->data, data, cmd.resp_size))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* Validate the Level Meter map passed by the user */
+static int validate_meter_map(const s16 *map, int map_size, int meter_slots)
+{
+ int i;
+
+ for (i = 0; i < map_size; i++)
+ if (map[i] < -1 || map[i] >= meter_slots)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Set the Level Meter map and add the control */
+static int fcp_ioctl_set_meter_map(struct usb_mixer_interface *mixer,
+ struct fcp_meter_map __user *arg)
+{
+ struct fcp_meter_map map;
+ struct fcp_data *private = mixer->private_data;
+ s16 *tmp_map __free(kfree) = NULL;
+ int err;
+
+ if (copy_from_user(&map, arg, sizeof(map)))
+ return -EFAULT;
+
+ /* Don't allow changing the map size or meter slots once set */
+ if (private->meter_ctl) {
+ struct usb_mixer_elem_info *elem =
+ private->meter_ctl->private_data;
+
+ if (map.map_size != elem->channels ||
+ map.meter_slots != private->num_meter_slots)
+ return -EINVAL;
+ }
+
+ /* Validate the map size */
+ if (map.map_size < 1 || map.map_size > 255 ||
+ map.meter_slots < 1 || map.meter_slots > 255)
+ return -EINVAL;
+
+ /* Allocate and copy the map data */
+ tmp_map = kmalloc_array(map.map_size, sizeof(s16), GFP_KERNEL);
+ if (!tmp_map)
+ return -ENOMEM;
+
+ if (copy_from_user(tmp_map, arg->map, map.map_size * sizeof(s16)))
+ return -EFAULT;
+
+ err = validate_meter_map(tmp_map, map.map_size, map.meter_slots);
+ if (err < 0)
+ return err;
+
+ /* If the control doesn't exist, create it */
+ if (!private->meter_ctl) {
+ s16 *new_map __free(kfree) = NULL;
+ __le32 *meter_levels __free(kfree) = NULL;
+
+ /* Allocate buffer for the map */
+ new_map = kmalloc_array(map.map_size, sizeof(s16), GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ /* Allocate buffer for reading meter levels */
+ meter_levels = kmalloc_array(map.meter_slots, sizeof(__le32),
+ GFP_KERNEL);
+ if (!meter_levels)
+ return -ENOMEM;
+
+ /* Create the Level Meter control */
+ err = fcp_add_new_ctl(mixer, &fcp_meter_ctl, 0, map.map_size,
+ "Level Meter", &private->meter_ctl);
+ if (err < 0)
+ return err;
+
+ /* Success; save the pointers in private and don't free them */
+ private->meter_level_map = new_map;
+ private->meter_levels = meter_levels;
+ private->num_meter_slots = map.meter_slots;
+ new_map = NULL;
+ meter_levels = NULL;
+ }
+
+ /* Install the new map */
+ memcpy(private->meter_level_map, tmp_map, map.map_size * sizeof(s16));
+
+ return 0;
+}
+
+/* Set the Level Meter labels */
+static int fcp_ioctl_set_meter_labels(struct usb_mixer_interface *mixer,
+ struct fcp_meter_labels __user *arg)
+{
+ struct fcp_meter_labels labels;
+ struct fcp_data *private = mixer->private_data;
+ unsigned int *tlv_data;
+ unsigned int tlv_size, data_size;
+
+ if (copy_from_user(&labels, arg, sizeof(labels)))
+ return -EFAULT;
+
+ /* Remove existing labels if size is zero */
+ if (!labels.labels_size) {
+
+ /* Clear TLV read/callback bits if labels were present */
+ if (private->meter_labels_tlv) {
+ private->meter_ctl->vd[0].access &=
+ ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
+ snd_ctl_notify(mixer->chip->card,
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &private->meter_ctl->id);
+ }
+
+ kfree(private->meter_labels_tlv);
+ private->meter_labels_tlv = NULL;
+ private->meter_labels_tlv_size = 0;
+
+ return 0;
+ }
+
+ /* Validate size */
+ if (labels.labels_size > 4096)
+ return -EINVAL;
+
+ /* Calculate padded data size */
+ data_size = ALIGN(labels.labels_size, sizeof(unsigned int));
+
+ /* Calculate total TLV size including header */
+ tlv_size = sizeof(unsigned int) * 2 + data_size;
+
+ /* Allocate, set up TLV header, and copy the labels data */
+ tlv_data = kzalloc(tlv_size, GFP_KERNEL);
+ if (!tlv_data)
+ return -ENOMEM;
+ tlv_data[0] = SNDRV_CTL_TLVT_FCP_CHANNEL_LABELS;
+ tlv_data[1] = data_size;
+ if (copy_from_user(&tlv_data[2], arg->labels, labels.labels_size)) {
+ kfree(tlv_data);
+ return -EFAULT;
+ }
+
+ /* Set TLV read/callback bits if labels weren't present */
+ if (!private->meter_labels_tlv) {
+ private->meter_ctl->vd[0].access |=
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+ snd_ctl_notify(mixer->chip->card,
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &private->meter_ctl->id);
+ }
+
+ /* Swap in the new labels */
+ kfree(private->meter_labels_tlv);
+ private->meter_labels_tlv = tlv_data;
+ private->meter_labels_tlv_size = tlv_size;
+
+ return 0;
+}
+
+static int fcp_hwdep_open(struct snd_hwdep *hw, struct file *file)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+ struct fcp_data *private = mixer->private_data;
+
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ private->file = file;
+
+ return 0;
+}
+
+static int fcp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+ struct fcp_data *private = mixer->private_data;
+ void __user *argp = (void __user *)arg;
+
+ guard(mutex)(&private->mutex);
+
+ switch (cmd) {
+
+ case FCP_IOCTL_PVERSION:
+ return put_user(FCP_HWDEP_VERSION,
+ (int __user *)argp) ? -EFAULT : 0;
+ break;
+
+ case FCP_IOCTL_INIT:
+ return fcp_ioctl_init(mixer, argp);
+
+ case FCP_IOCTL_CMD:
+ if (!private->init)
+ return -EINVAL;
+ return fcp_ioctl_cmd(mixer, argp);
+
+ case FCP_IOCTL_SET_METER_MAP:
+ if (!private->init)
+ return -EINVAL;
+ return fcp_ioctl_set_meter_map(mixer, argp);
+
+ case FCP_IOCTL_SET_METER_LABELS:
+ if (!private->init)
+ return -EINVAL;
+ if (!private->meter_ctl)
+ return -EINVAL;
+ return fcp_ioctl_set_meter_labels(mixer, argp);
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ /* not reached */
+}
+
+static long fcp_hwdep_read(struct snd_hwdep *hw, char __user *buf,
+ long count, loff_t *offset)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+ struct fcp_data *private = mixer->private_data;
+ unsigned long flags;
+ long ret = 0;
+ u32 event;
+
+ if (count < sizeof(event))
+ return -EINVAL;
+
+ ret = wait_event_interruptible(private->notify.queue,
+ private->notify.event);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&private->notify.lock, flags);
+ event = private->notify.event;
+ private->notify.event = 0;
+ spin_unlock_irqrestore(&private->notify.lock, flags);
+
+ if (copy_to_user(buf, &event, sizeof(event)))
+ return -EFAULT;
+
+ return sizeof(event);
+}
+
+static __poll_t fcp_hwdep_poll(struct snd_hwdep *hw,
+ struct file *file,
+ poll_table *wait)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+ struct fcp_data *private = mixer->private_data;
+ __poll_t mask = 0;
+
+ poll_wait(file, &private->notify.queue, wait);
+
+ if (private->notify.event)
+ mask |= EPOLLIN | EPOLLRDNORM;
+
+ return mask;
+}
+
+static int fcp_hwdep_release(struct snd_hwdep *hw, struct file *file)
+{
+ struct usb_mixer_interface *mixer = hw->private_data;
+ struct fcp_data *private = mixer->private_data;
+
+ if (!private)
+ return 0;
+
+ private->file = NULL;
+
+ return 0;
+}
+
+static int fcp_hwdep_init(struct usb_mixer_interface *mixer)
+{
+ struct snd_hwdep *hw;
+ int err;
+
+ err = snd_hwdep_new(mixer->chip->card, "Focusrite Control", 0, &hw);
+ if (err < 0)
+ return err;
+
+ hw->private_data = mixer;
+ hw->exclusive = 1;
+ hw->ops.open = fcp_hwdep_open;
+ hw->ops.ioctl = fcp_hwdep_ioctl;
+ hw->ops.ioctl_compat = fcp_hwdep_ioctl;
+ hw->ops.read = fcp_hwdep_read;
+ hw->ops.poll = fcp_hwdep_poll;
+ hw->ops.release = fcp_hwdep_release;
+
+ return 0;
+}
+
+/*** Cleanup ***/
+
+static void fcp_cleanup_urb(struct usb_mixer_interface *mixer)
+{
+ if (!mixer->urb)
+ return;
+
+ usb_kill_urb(mixer->urb);
+ kfree(mixer->urb->transfer_buffer);
+ usb_free_urb(mixer->urb);
+ mixer->urb = NULL;
+}
+
+static void fcp_private_free(struct usb_mixer_interface *mixer)
+{
+ struct fcp_data *private = mixer->private_data;
+
+ fcp_cleanup_urb(mixer);
+
+ kfree(private->meter_level_map);
+ kfree(private->meter_levels);
+ kfree(private->meter_labels_tlv);
+ kfree(private);
+ mixer->private_data = NULL;
+}
+
+static void fcp_private_suspend(struct usb_mixer_interface *mixer)
+{
+ fcp_cleanup_urb(mixer);
+}
+
+/*** Callbacks ***/
+
+static void fcp_notify(struct urb *urb)
+{
+ struct usb_mixer_interface *mixer = urb->context;
+ struct fcp_data *private = mixer->private_data;
+ int len = urb->actual_length;
+ int ustatus = urb->status;
+ u32 data;
+
+ if (ustatus != 0 || len != 8)
+ goto requeue;
+
+ data = le32_to_cpu(*(__le32 *)urb->transfer_buffer);
+
+ /* Handle command acknowledgement */
+ if (data & FCP_NOTIFY_ACK) {
+ complete(&private->cmd_done);
+ data &= ~FCP_NOTIFY_ACK;
+ }
+
+ if (data) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&private->notify.lock, flags);
+ private->notify.event |= data;
+ spin_unlock_irqrestore(&private->notify.lock, flags);
+
+ wake_up_interruptible(&private->notify.queue);
+ }
+
+requeue:
+ if (ustatus != -ENOENT &&
+ ustatus != -ECONNRESET &&
+ ustatus != -ESHUTDOWN) {
+ urb->dev = mixer->chip->dev;
+ usb_submit_urb(urb, GFP_ATOMIC);
+ } else {
+ complete(&private->cmd_done);
+ }
+}
+
+/* Submit a URB to receive notifications from the device */
+static int fcp_init_notify(struct usb_mixer_interface *mixer)
+{
+ struct usb_device *dev = mixer->chip->dev;
+ struct fcp_data *private = mixer->private_data;
+ unsigned int pipe = usb_rcvintpipe(dev, private->bEndpointAddress);
+ void *transfer_buffer;
+ int err;
+
+ /* Already set up */
+ if (mixer->urb)
+ 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) {
+ usb_free_urb(mixer->urb);
+ mixer->urb = NULL;
+ return -ENOMEM;
+ }
+
+ usb_fill_int_urb(mixer->urb, dev, pipe,
+ transfer_buffer, private->wMaxPacketSize,
+ fcp_notify, mixer, private->bInterval);
+
+ init_completion(&private->cmd_done);
+
+ err = usb_submit_urb(mixer->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;
+ }
+
+ return err;
+}
+
+/*** Initialisation ***/
+
+static int fcp_init(struct usb_mixer_interface *mixer,
+ void *step0_resp, void *step2_resp)
+{
+ struct fcp_data *private = mixer->private_data;
+ struct usb_device *dev = mixer->chip->dev;
+ int err;
+
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+ FCP_USB_REQ_STEP0,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ 0, private->bInterfaceNumber,
+ step0_resp, private->step0_resp_size);
+ if (err < 0)
+ return err;
+
+ err = fcp_init_notify(mixer);
+ if (err < 0)
+ return err;
+
+ private->seq = 0;
+ private->init = 1;
+
+ err = fcp_usb(mixer, private->init1_opcode, NULL, 0, NULL, 0);
+ if (err < 0)
+ return err;
+
+ err = fcp_usb(mixer, private->init2_opcode,
+ NULL, 0, step2_resp, private->step2_resp_size);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int fcp_init_private(struct usb_mixer_interface *mixer)
+{
+ struct fcp_data *private =
+ kzalloc(sizeof(struct fcp_data), GFP_KERNEL);
+
+ if (!private)
+ return -ENOMEM;
+
+ mutex_init(&private->mutex);
+ init_waitqueue_head(&private->notify.queue);
+ spin_lock_init(&private->notify.lock);
+
+ mixer->private_data = private;
+ mixer->private_free = fcp_private_free;
+ mixer->private_suspend = fcp_private_suspend;
+
+ private->mixer = mixer;
+
+ return 0;
+}
+
+/* Look through the interface descriptors for the Focusrite Control
+ * interface (bInterfaceClass = 255 Vendor Specific Class) and set
+ * bInterfaceNumber, bEndpointAddress, wMaxPacketSize, and bInterval
+ * in private
+ */
+static int fcp_find_fc_interface(struct usb_mixer_interface *mixer)
+{
+ struct snd_usb_audio *chip = mixer->chip;
+ struct fcp_data *private = mixer->private_data;
+ struct usb_host_config *config = chip->dev->actconfig;
+ int i;
+
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ struct usb_interface *intf = config->interface[i];
+ struct usb_interface_descriptor *desc =
+ &intf->altsetting[0].desc;
+ struct usb_endpoint_descriptor *epd;
+
+ if (desc->bInterfaceClass != 255)
+ continue;
+
+ epd = get_endpoint(intf->altsetting, 0);
+ private->bInterfaceNumber = desc->bInterfaceNumber;
+ private->bEndpointAddress = epd->bEndpointAddress &
+ USB_ENDPOINT_NUMBER_MASK;
+ private->wMaxPacketSize = le16_to_cpu(epd->wMaxPacketSize);
+ private->bInterval = epd->bInterval;
+ return 0;
+ }
+
+ usb_audio_err(chip, "Focusrite vendor-specific interface not found\n");
+ return -EINVAL;
+}
+
+int snd_fcp_init(struct usb_mixer_interface *mixer)
+{
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
+
+ /* only use UAC_VERSION_2 */
+ if (!mixer->protocol)
+ return 0;
+
+ err = fcp_init_private(mixer);
+ if (err < 0)
+ return err;
+
+ err = fcp_find_fc_interface(mixer);
+ if (err < 0)
+ return err;
+
+ err = fcp_hwdep_init(mixer);
+ if (err < 0)
+ return err;
+
+ usb_audio_info(chip,
+ "Focusrite Control Protocol Driver ready (pid=0x%04x); "
+ "report any issues to "
+ "https://github.com/geoffreybennett/fcp-support/issues",
+ USB_ID_PRODUCT(chip->usb_id));
+
+ return err;
+}
diff --git a/sound/usb/fcp.h b/sound/usb/fcp.h
new file mode 100644
index 000000000000..d58cc7db75b1
--- /dev/null
+++ b/sound/usb/fcp.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __USBAUDIO_FCP_H
+#define __USBAUDIO_FCP_H
+
+int snd_fcp_init(struct usb_mixer_interface *mixer);
+
+#endif /* __USBAUDIO_FCP_H */
diff --git a/sound/usb/format.c b/sound/usb/format.c
index 6049d957694c..9d32b21a5fbb 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -384,6 +384,10 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,
if (chip->usb_id == USB_ID(0x194f, 0x010c) &&
!s1810c_valid_sample_rate(fp, rate))
goto skip_rate;
+ /* Filter out invalid rates on Presonus Studio 1824c */
+ if (chip->usb_id == USB_ID(0x194f, 0x010d) &&
+ !s1810c_valid_sample_rate(fp, rate))
+ goto skip_rate;
/* Filter out invalid rates on Focusrite devices */
if (USB_ID_VENDOR(chip->usb_id) == 0x1235 &&
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index ca2c6f5de407..c073b38cd673 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -386,7 +386,7 @@ static int toneport_setup(struct usb_line6_toneport *toneport)
toneport_update_led(toneport);
schedule_delayed_work(&toneport->line6.startup_work,
- msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));
+ secs_to_jiffies(TONEPORT_PCM_DELAY));
return 0;
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 737dd00e97b1..826ac870f246 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -489,16 +489,84 @@ static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
/*
* CME protocol: like the standard protocol, but SysEx commands are sent as a
- * single USB packet preceded by a 0x0F byte.
+ * single USB packet preceded by a 0x0F byte, as are system realtime
+ * messages and MIDI Active Sensing.
+ * Also, multiple messages can be sent in the same packet.
*/
static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep,
uint8_t *buffer, int buffer_length)
{
- if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f)
- snd_usbmidi_standard_input(ep, buffer, buffer_length);
- else
- snd_usbmidi_input_data(ep, buffer[0] >> 4,
- &buffer[1], buffer_length - 1);
+ int remaining = buffer_length;
+
+ /*
+ * CME send sysex, song position pointer, system realtime
+ * and active sensing using CIN 0x0f, which in the standard
+ * is only intended for single byte unparsed data.
+ * So we need to interpret these here before sending them on.
+ * By default, we assume single byte data, which is true
+ * for system realtime (midi clock, start, stop and continue)
+ * and active sensing, and handle the other (known) cases
+ * separately.
+ * In contrast to the standard, CME does not split sysex
+ * into multiple 4-byte packets, but lumps everything together
+ * into one. In addition, CME can string multiple messages
+ * together in the same packet; pressing the Record button
+ * on an UF6 sends a sysex message directly followed
+ * by a song position pointer in the same packet.
+ * For it to have any reasonable meaning, a sysex message
+ * needs to be at least 3 bytes in length (0xf0, id, 0xf7),
+ * corresponding to a packet size of 4 bytes, and the ones sent
+ * by CME devices are 6 or 7 bytes, making the packet fragments
+ * 7 or 8 bytes long (six or seven bytes plus preceding CN+CIN byte).
+ * For the other types, the packet size is always 4 bytes,
+ * as per the standard, with the data size being 3 for SPP
+ * and 1 for the others.
+ * Thus all packet fragments are at least 4 bytes long, so we can
+ * skip anything that is shorter; this also conveniantly skips
+ * packets with size 0, which CME devices continuously send when
+ * they have nothing better to do.
+ * Another quirk is that sometimes multiple messages are sent
+ * in the same packet. This has been observed for midi clock
+ * and active sensing i.e. 0x0f 0xf8 0x00 0x00 0x0f 0xfe 0x00 0x00,
+ * but also multiple note ons/offs, and control change together
+ * with MIDI clock. Similarly, some sysex messages are followed by
+ * the song position pointer in the same packet, and occasionally
+ * additionally by a midi clock or active sensing.
+ * We handle this by looping over all data and parsing it along the way.
+ */
+ while (remaining >= 4) {
+ int source_length = 4; /* default */
+
+ if ((buffer[0] & 0x0f) == 0x0f) {
+ int data_length = 1; /* default */
+
+ if (buffer[1] == 0xf0) {
+ /* Sysex: Find EOX and send on whole message. */
+ /* To kick off the search, skip the first
+ * two bytes (CN+CIN and SYSEX (0xf0).
+ */
+ uint8_t *tmp_buf = buffer + 2;
+ int tmp_length = remaining - 2;
+
+ while (tmp_length > 1 && *tmp_buf != 0xf7) {
+ tmp_buf++;
+ tmp_length--;
+ }
+ data_length = tmp_buf - buffer;
+ source_length = data_length + 1;
+ } else if (buffer[1] == 0xf2) {
+ /* Three byte song position pointer */
+ data_length = 3;
+ }
+ snd_usbmidi_input_data(ep, buffer[0] >> 4,
+ &buffer[1], data_length);
+ } else {
+ /* normal channel events */
+ snd_usbmidi_standard_input(ep, buffer, source_length);
+ }
+ buffer += source_length;
+ remaining -= source_length;
+ }
}
/*
@@ -1145,7 +1213,7 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
{
struct usbmidi_out_port *port = substream->runtime->private_data;
- cancel_work_sync(&port->ep->work);
+ flush_work(&port->ep->work);
return substream_open(substream, 0, 0);
}
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 23fcd680167d..a90673d43822 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -38,6 +38,7 @@
#include "mixer_us16x08.h"
#include "mixer_s1810c.h"
#include "helper.h"
+#include "fcp.h"
struct std_mono_table {
unsigned int unitid, control, cmask;
@@ -3687,8 +3688,7 @@ static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex)
// common DJM capture level option values
static const u16 snd_djm_opts_cap_level[] = {
- 0x0000, 0x0100, 0x0200, 0x0300, 0x400, 0x500 };
-
+ 0x0000, 0x0100, 0x0200, 0x0300 };
// DJM-250MK2
static const u16 snd_djm_opts_250mk2_cap1[] = {
@@ -3830,6 +3830,8 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = {
// DJM-A9
+static const u16 snd_djm_opts_a9_cap_level[] = {
+ 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 };
static const u16 snd_djm_opts_a9_cap1[] = {
0x0107, 0x0108, 0x0109, 0x010a, 0x010e,
0x111, 0x112, 0x113, 0x114, 0x0131, 0x132, 0x133, 0x134 };
@@ -3843,7 +3845,7 @@ static const u16 snd_djm_opts_a9_cap5[] = {
0x0501, 0x0502, 0x0503, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050a, 0x050e };
static const struct snd_djm_ctl snd_djm_ctls_a9[] = {
- SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
+ SND_DJM_CTL("Capture Level", a9_cap_level, 0, SND_DJM_WINDEX_CAPLVL),
SND_DJM_CTL("Master Input", a9_cap1, 3, SND_DJM_WINDEX_CAP),
SND_DJM_CTL("Ch1 Input", a9_cap2, 2, SND_DJM_WINDEX_CAP),
SND_DJM_CTL("Ch2 Input", a9_cap3, 2, SND_DJM_WINDEX_CAP),
@@ -4090,6 +4092,12 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
err = snd_scarlett2_init(mixer);
break;
+ case USB_ID(0x1235, 0x821b): /* Focusrite Scarlett 16i16 4th Gen */
+ case USB_ID(0x1235, 0x821c): /* Focusrite Scarlett 18i16 4th Gen */
+ case USB_ID(0x1235, 0x821d): /* Focusrite Scarlett 18i20 4th Gen */
+ err = snd_fcp_init(mixer);
+ break;
+
case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */
err = snd_soundblaster_e1_switch_create(mixer);
break;
@@ -4112,6 +4120,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x194f, 0x010c): /* Presonus Studio 1810c */
err = snd_sc1810_init_mixer(mixer);
break;
+ case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */
+ err = snd_sc1810_init_mixer(mixer);
+ break;
case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
err = snd_bbfpro_controls_create(mixer);
break;
@@ -4216,6 +4227,52 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
}
}
+/*
+ * Some Plantronics headsets have control names that don't meet ALSA naming
+ * standards. This function fixes nonstandard source names. By the time
+ * this function is called the control name should look like one of these:
+ * "source names Playback Volume"
+ * "source names Playback Switch"
+ * "source names Capture Volume"
+ * "source names Capture Switch"
+ * If any of the trigger words are found in the name then the name will
+ * be changed to:
+ * "Headset Playback Volume"
+ * "Headset Playback Switch"
+ * "Headset Capture Volume"
+ * "Headset Capture Switch"
+ * depending on the current suffix.
+ */
+static void snd_fix_plt_name(struct snd_usb_audio *chip,
+ struct snd_ctl_elem_id *id)
+{
+ /* no variant of "Sidetone" should be added to this list */
+ static const char * const trigger[] = {
+ "Earphone", "Microphone", "Receive", "Transmit"
+ };
+ static const char * const suffix[] = {
+ " Playback Volume", " Playback Switch",
+ " Capture Volume", " Capture Switch"
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(trigger); i++)
+ if (strstr(id->name, trigger[i]))
+ goto triggered;
+ usb_audio_dbg(chip, "no change in %s\n", id->name);
+ return;
+
+triggered:
+ for (i = 0; i < ARRAY_SIZE(suffix); i++)
+ if (strstr(id->name, suffix[i])) {
+ usb_audio_dbg(chip, "fixing kctl name %s\n", id->name);
+ snprintf(id->name, sizeof(id->name), "Headset%s",
+ suffix[i]);
+ return;
+ }
+ usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name);
+}
+
void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
struct usb_mixer_elem_info *cval, int unitid,
struct snd_kcontrol *kctl)
@@ -4233,5 +4290,10 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
cval->min_mute = 1;
break;
}
+
+ /* ALSA-ify some Plantronics headset control names */
+ if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f &&
+ (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME))
+ snd_fix_plt_name(mixer->chip, &kctl->id);
}
diff --git a/sound/usb/mixer_scarlett2.c b/sound/usb/mixer_scarlett2.c
index 7f595c1752a5..288d22e6a0b2 100644
--- a/sound/usb/mixer_scarlett2.c
+++ b/sound/usb/mixer_scarlett2.c
@@ -166,6 +166,7 @@
#include "helper.h"
#include "mixer_scarlett2.h"
+#include "fcp.h"
/* device_setup value to allow turning MSD mode back on */
#define SCARLETT2_MSD_ENABLE 0x02
@@ -173,6 +174,9 @@
/* device_setup value to disable this mixer driver */
#define SCARLETT2_DISABLE 0x04
+/* device_setup value to use the FCP driver instead */
+#define SCARLETT2_USE_FCP_DRIVER 0x08
+
/* some gui mixers can't handle negative ctl values */
#define SCARLETT2_VOLUME_BIAS 127
@@ -9702,6 +9706,10 @@ int snd_scarlett2_init(struct usb_mixer_interface *mixer)
if (!mixer->protocol)
return 0;
+ /* check if the user wants to use the FCP driver instead */
+ if (chip->setup & SCARLETT2_USE_FCP_DRIVER)
+ return snd_fcp_init(mixer);
+
/* find entry in scarlett2_devices */
entry = get_scarlett2_device_entry(mixer);
if (!entry) {
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 8ba0aff8be2e..9112313a9dbc 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1599,7 +1599,9 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
/* presonus studio 1810c: skip altsets incompatible with device_setup */
if (chip->usb_id == USB_ID(0x194f, 0x010c))
return s1810c_skip_setting_quirk(chip, iface, altno);
-
+ /* presonus studio 1824c: skip altsets incompatible with device_setup */
+ if (chip->usb_id == USB_ID(0x194f, 0x010d))
+ return s1810c_skip_setting_quirk(chip, iface, altno);
return 0;
}
@@ -1868,6 +1870,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
subs->stream_offset_adj = 2;
break;
+ case USB_ID(0x2b73, 0x000a): /* Pioneer DJM-900NXS2 */
case USB_ID(0x2b73, 0x0013): /* Pioneer DJM-450 */
pioneer_djm_set_format_quirk(subs, 0x0082);
break;
@@ -2239,6 +2242,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x0c45, 0x6340, /* Sonix HD USB Camera */
QUIRK_FLAG_GET_SAMPLE_RATE),
+ DEVICE_FLG(0x0d8c, 0x0014, /* USB Audio Device */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
QUIRK_FLAG_FIXED_RATE),
DEVICE_FLG(0x0ecb, 0x2069, /* JBL Quantum810 Wireless */
@@ -2341,6 +2346,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x2d95, 0x8021, /* VIVO USB-C-XE710 HEADSET */
QUIRK_FLAG_CTL_MSG_DELAY_1M),
+ DEVICE_FLG(0x2fc6, 0xf0b7, /* iBasso DC07 Pro */
+ QUIRK_FLAG_CTL_MSG_DELAY_1M),
DEVICE_FLG(0x30be, 0x0101, /* Schiit Hel */
QUIRK_FLAG_IGNORE_CTL_ERROR),
DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index 5f81c68fd42b..5756ff3528a2 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -151,6 +151,12 @@ static int snd_usx2y_card_used[SNDRV_CARDS];
static void snd_usx2y_card_private_free(struct snd_card *card);
static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s);
+#ifdef USX2Y_NRPACKS_VARIABLE
+int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
+module_param(nrpacks, int, 0444);
+MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
+#endif
+
/*
* pipe 4 is used for switching the lamps, setting samplerate, volumes ....
*/
@@ -432,6 +438,11 @@ static int snd_usx2y_probe(struct usb_interface *intf,
struct snd_card *card;
int err;
+#ifdef USX2Y_NRPACKS_VARIABLE
+ if (nrpacks < 0 || nrpacks > USX2Y_NRPACKS_MAX)
+ return -EINVAL;
+#endif
+
if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 ||
(le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 &&
le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 &&
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index 391fd7b4ed5e..6a76d04bf1c7 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -7,6 +7,32 @@
#define NRURBS 2
+/* Default value used for nr of packs per urb.
+ * 1 to 4 have been tested ok on uhci.
+ * To use 3 on ohci, you'd need a patch:
+ * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
+ * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
+ *
+ * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
+ * Bigger is safer operation, smaller gives lower latencies.
+ */
+#define USX2Y_NRPACKS 4
+
+#define USX2Y_NRPACKS_MAX 1024
+
+/* If your system works ok with this module's parameter
+ * nrpacks set to 1, you might as well comment
+ * this define out, and thereby produce smaller, faster code.
+ * You'd also set USX2Y_NRPACKS to 1 then.
+ */
+#define USX2Y_NRPACKS_VARIABLE 1
+
+#ifdef USX2Y_NRPACKS_VARIABLE
+extern int nrpacks;
+#define nr_of_packs() nrpacks
+#else
+#define nr_of_packs() USX2Y_NRPACKS
+#endif
#define URBS_ASYNC_SEQ 10
#define URB_DATA_LEN_ASYNC_SEQ 32
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index f540f46a0b14..acca8bead82e 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -28,33 +28,6 @@
#include "usx2y.h"
#include "usbusx2y.h"
-/* Default value used for nr of packs per urb.
- * 1 to 4 have been tested ok on uhci.
- * To use 3 on ohci, you'd need a patch:
- * look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
- * "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
- *
- * 1, 2 and 4 work out of the box on ohci, if I recall correctly.
- * Bigger is safer operation, smaller gives lower latencies.
- */
-#define USX2Y_NRPACKS 4
-
-/* If your system works ok with this module's parameter
- * nrpacks set to 1, you might as well comment
- * this define out, and thereby produce smaller, faster code.
- * You'd also set USX2Y_NRPACKS to 1 then.
- */
-#define USX2Y_NRPACKS_VARIABLE 1
-
-#ifdef USX2Y_NRPACKS_VARIABLE
-static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
-#define nr_of_packs() nrpacks
-module_param(nrpacks, int, 0444);
-MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
-#else
-#define nr_of_packs() USX2Y_NRPACKS
-#endif
-
static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
{
struct urb *urb = subs->completed_urb;
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index d41ea09ffbe5..7fcc528a0204 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -1617,7 +1617,7 @@ static int had_create_jack(struct snd_intelhad *ctx,
* PM callbacks
*/
-static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
+static int hdmi_lpe_audio_suspend(struct device *dev)
{
struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
@@ -1626,7 +1626,7 @@ static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev)
+static int hdmi_lpe_audio_resume(struct device *dev)
{
struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev);
@@ -1833,13 +1833,13 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
}
static const struct dev_pm_ops hdmi_lpe_audio_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
+ SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
};
static struct platform_driver hdmi_lpe_audio_driver = {
.driver = {
.name = "hdmi-lpe-audio",
- .pm = &hdmi_lpe_audio_pm,
+ .pm = pm_ptr(&hdmi_lpe_audio_pm),
},
.probe = hdmi_lpe_audio_probe,
};